LoginSignup
2
2

More than 5 years have passed since last update.

drag & dropをRspecでテストする(結果:ダメだった)

Posted at

注意

結果:やりたいことはできなかった。
結果としての回避策:URLによって、Dataをhtmlタグのdata attributeなどにセットして、そこからJSを動かすようにして、テストを書くことで回避した。

以下で書いたものは、自分が調べたもので、紆余曲折があるので、暇な人だけが見るべき!

やりたいこと

http://dev.classmethod.jp/references/html5-drag-drop-api-review-dom/ を参考にして、ドラッグ・アンド・ドロップを実装

(DOM = Document Object Model:

などの要素にアクセスする仕組み(参照:http://piyo-js.com/05/dom.html ))

$('.draggable-span').on 'dragstart', (e) ->
  e.originalEvent.dataTransfer.setData 'val', this.val()

$('.droppable-span').on 'drop', (e) ->
  e.preventDefault()
  e.stopPropagation()
  # ドラッグされたものの名前などを書いたりする処理

このコードをCapybaraでテストしたい!

参考

D&Dのテスト書いてるのは、
http://ria10.hatenablog.com/entry/20131230/1388372110
これが一番近そう

参考にして、 drag_toを使って以下のように書いてみた。

draggable = page.find('#draggable')
target = page.find('#goal')
draggable.drag_to target
screenshot_and_open_image

問題

うまく移動されていない。
Capybaraでdrag_to がうまくいかない。

理由: 呼ばれるイベントの違い

細かく、drag_toで何がされてるかを見てみると、以下のmouseイベントがとれていた。(今回は、driverにpoltergeistを利用。実は、capybara-webkitだと下のmouseeventすら取れ無かった。)

draggableの方で、
1. mouseover
2. mouseenter
3. mousemove
4. mousedown
5. mouseleave
6. mouseout
Dropされる方で、
7. mouseover
8. mouseenter
9. mousemove
10. mouseup

しかし、重要な、'dragstart', 'drop'などのドラッグイベントはとれない!マウスイベントのみ。

おそらくjquery-sortableは、mouseeventで、実装されているよう。

まとめると、

ドラッグイベントマウスイベントは別物である!(以下に簡単にドラッグ・アンド・ドロップに関連しそうなイベントをまとめておく。)

主なドラッグイベント
1. drag
2. dragend
3. dragenter
4. dragexit
5. dragleave
6. dragover
7. dragstart
8. drop

主なマウスイベント(drag_toで取れていたイベントを載せた)
1. mouseover
2. mouseenter
3. mousemove
4. mousedown
5. mouseleave
6. mouseout
7. mouseup

解決策: Triggerでdragstart を発火させる(未解決)

やってみる

jQueryで画像やリンクのクリック状態(マウスイベント)やキーボード入力状態を強制的に作り出すを参考にdragstartというDragEventを発火させてみる。

ちなみにDragEventとは

DOM event

問題:e.originalEvent.dataTransferで使っているoriginalEventがない。

実際にドラッグした場合:

jy.Event {originalEvent: DragEvent, type: "dragstart", timeStamp: 8800.24, jQuery1113048166412157867233: true, which: 1}

$('#some_id').trigger('dragstart')で発火した場合:

y.Event {type: "dragstart", timeStamp: 1472621534967, jQuery1113048166412157867233: true, isTrigger: 3, namespace: ""}

実際には、originalEvent: DragEventがあるのに対して、triggerには、ない!

そもそもoriginalEventとは、

jQueryのbindを使うとdataTransferプロパティがイベントから取得出来ない現象が起こりました。原因は、わかってしまえば単純で、jQueryのイベントハンドラに渡されるeventオブジェクトはjQueryがブラウザ互換性の為に作成した独自オブジェクトだからでした。HTML5等で新たに追加されたプロパティにアクセスするには、大元のeventオブジェクトを取得する必要があります。

と書かれている。

イベントをもう少し細かく作ってやってみる!

ただtriggerするとダメそうなので、

jQueryのtrigger()みたいに、イベントを作ったり発火させたりしてみよう。
これを参考に、
js
event = new DragEvent('dragstart', {bubbles: true})
el = document.querySelector('#col_0')
el.dispatchEvent(event)

と書いてみると、originalEventに関してはできた。だが、originalEventがdatatransferを持っていない。Defaultでは、nullになるため。。(ここでうまく初期化する方法がわからん。)

  • DragEventは、ここ に書いてあるようにDragEventオブジェクトを総合的に作るコンストラクタである。
  • DragEvent interfaceは、DOM eventである。
  • MouseEventEventを継承している
  • DragEvent.dataTransfer(read only): drag & drop の間にデータが送られる(Although this interface has a constructor, it is not possible to create a useful DataTransfer object from script, since DataTransfer objects have a processing and security model that is coordinated by the browser during drag-and-drops.)
  • Document.querySelector()は、Selectorに合うDocumentのなかの最初のElementを返す。

上の例で$('#col_0')では動かない。これでは帰ってくるのが、[<span...></span>]こんなかんじである。
逆に、Document.querySelector()の方は、html tagそのままが取れている。<span class="draggable-span"...></span>

しょうがない解決策

coffeeのクラスをGlobalにして、rspecから、execute_script()で無理矢理トリガーする。。。

ただ、テストのために、不必要にGlobalにするのが嫌だ。

ドラッグ・アンド・ドロップの詳細

draggableにするには、

draggable属性与えて、dragstartのEventListenerをあたえる。(ドラッグされたデータを保存する。)

event handlerは

ドラッグされたテクスト選択ではなく、 DataTransfer object にデータを保存し、許可された効果をセットする(copy, move, link, など)

dropされる側は、

  • dropzoneの属性を与えて、drop イベントリスナーをつける
  • dropzoneの値は、データ・タイプを指定する。 ('string:text/plain', 'file:image/png'など)

dragされたOriginalのものを消したい場合は、

dragend eventを使う

DataTransfer interface

  • このObjectは、ドラッグデータをとるときに使われる。
  • ドラッグドロップのがFireされている間のみ有効

結論

dragEventは、無理ww

調べ漏れや、もっといい方法があるかもしれないので、何かあればコメントいただければ嬉しいです。

他の参考資料

  1. Native HTML5 Drag and Drop
  2. HTML 5 drag and drop API
  3. https://github.com/thoughtbot/capybara-webkit/issues/804
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2