magcho's blog

cypressでドラッグ & ドロップとCtrl-vのファイルアップロードをテストする

Created at: Last updated at:

ファイルアップロードをするUIとしてクリックするとOSのファイラーが開いて選択するタイプ、ドラッグ&ドロップでブラウザ外からファイルを持ってくるタイプ、クリップボードにファイルを保持した状態でCtrl-vで貼り付けるタイプなどさまざまなUIがあります。 それらについてE2EテストフレームワークであるCypressでどのようにユーザー行動を再現するかのメモです

ドラッグ&ドロップでファイル選択

例えばこんなUIです↓

CypressにはClickやTypeなど、ユーザー行動をエミュレートするいくつかのAction1が用意されていますが、ドラッグ&ドロップに相当するDropイベントは用意されていなため自分でActionを追加して対応します。

Actionを自分で追加するにはCostom Commands2という仕組みを利用します、似たようなことをされている方もいたので参考にしています https://gist.github.com/nickytonline/bcdef8ef00211b0faf7c7c0e7777aaf6

こういったドロップのUIを作る際にはJSのdropイベント3を利用すると思いますのでCypressでは対象のエレメントにdropイベントをdispatchするActionを追加する時は以下の記述です。

cypress/support/commands.js
Cypress.Commands.add('dropFile', { prevSubject: true }, (subject, options) => {
  const { file } = options
  // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer
  const dataTransfer = new DataTransfer()
  dataTransfer.items.add(file)

  // https://developer.mozilla.org/ja/docs/Web/API/DragEvent/DragEvent
  const dropEvent = new DragEvent('drop', {
    dataTransfer,
  })

  subject[0].dispatchEvent(dropEvent)

  return subject
})

利用する際にはcy.readfile4を利用してこのようになります

hoge.spec.js
describe('ファイルフォーム', () => {
  it('ドラッグ&ドロップでファイルを選択できる', () => {
    cy.readFile('cypress/fixtures/hoge.png', null).then((file) => {
      const fileObject = new File([file.buffer], 'test.png', { type: 'image/png' })
      cy.get('#upload-area').dropFile({
        file: fileObject,
      })
    })
  })
})

DataTransferItemsにfileを追加する方法は何通りかあるかと思いますがここではDataTransfer.items.add()を使っています、対象ブラウザによって動かない場合がありますので調整してください。執筆時点のChrome/Firefoxでは動きました。

Ctrl-vでファイル貼り付け

こちらも同様に以下のコマンドを追加します。

cypress/support/commands.js
Cypress.Commands.add('pasteFile', { prevSubject: true }, (subject, options) => {
  const { file } = options
  // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer
  const clipboardData = new DataTransfer()
  clipboardData.items.add(file)

  // https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
  const pasteEvent = new ClipboardEvent('paste', {
    bubbles: true,
    cancelable: true,
    dataType: file.type,
    clipboardData,
  })

  subject[0].dispatchEvent(pasteEvent)

  return subject
})
hoge.spec.js
describe('ファイルフォーム', () => {
  it('Ctrl-vでファイルを選択できる', () => {
    cy.readFile('cypress/fixtures/hoge.png', null).then((file) => {
      const fileObject = new File([file.buffer], 'test.png', { type: 'image/png' })
      cy.get('#upload-area').pasteFile({
        file: fileObject,
      })
    })
  })
})

これでファイルアップロード周りの検証をE2Eに任せて安眠できます、おしまい。

google analyticsを導入しています