Skip to content

Commit a75abfd

Browse files
DavertMikclaude
andcommitted
feat: add dropzone support to attachFile
When the target element is not an <input type="file">, attachFile now falls back to dispatching synthetic drag-and-drop events (dragenter, dragover, drop) with a DataTransfer containing the file. This enables file uploads to dropzone libraries (Dropzone.js, react-dropzone, etc.). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 68a058d commit a75abfd

File tree

4 files changed

+32
-42
lines changed

4 files changed

+32
-42
lines changed

lib/helper/Playwright.js

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import RemoteBrowserConnectionRefused from './errors/RemoteBrowserConnectionRefu
3636
import Popup from './extras/Popup.js'
3737
import Console from './extras/Console.js'
3838
import { findReact, findVue, findByPlaywrightLocator } from './extras/PlaywrightReactVueLocator.js'
39+
import { dropFile } from './scripts/dropFile.js'
3940
import WebElement from '../element/WebElement.js'
4041

4142
let playwright
@@ -2347,20 +2348,12 @@ class Playwright extends Helper {
23472348

23482349
const targetEls = els.length ? els : await this._locate(locator)
23492350
assertElementExists(targetEls, locator, 'Element')
2350-
const base64Content = base64EncodeFile(file)
2351-
const fileName = path.basename(file)
2352-
const mimeType = getMimeType(fileName)
2353-
await targetEls[0].evaluate((el, { base64Content, fileName, mimeType }) => {
2354-
const binaryStr = atob(base64Content)
2355-
const bytes = new Uint8Array(binaryStr.length)
2356-
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i)
2357-
const fileObj = new File([bytes], fileName, { type: mimeType })
2358-
const dataTransfer = new DataTransfer()
2359-
dataTransfer.items.add(fileObj)
2360-
el.dispatchEvent(new DragEvent('dragenter', { dataTransfer, bubbles: true }))
2361-
el.dispatchEvent(new DragEvent('dragover', { dataTransfer, bubbles: true }))
2362-
el.dispatchEvent(new DragEvent('drop', { dataTransfer, bubbles: true }))
2363-
}, { base64Content, fileName, mimeType })
2351+
const fileData = {
2352+
base64Content: base64EncodeFile(file),
2353+
fileName: path.basename(file),
2354+
mimeType: getMimeType(path.basename(file)),
2355+
}
2356+
await targetEls[0].evaluate(dropFile, fileData)
23642357
return this._waitForAction()
23652358
}
23662359

lib/helper/Puppeteer.js

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import Popup from './extras/Popup.js'
3838
import Console from './extras/Console.js'
3939
import { highlightElement } from './scripts/highlightElement.js'
4040
import { blurElement } from './scripts/blurElement.js'
41+
import { dropFile } from './scripts/dropFile.js'
4142
import { dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElementInDOMError } from './errors/ElementAssertion.js'
4243
import { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } from './network/actions.js'
4344
import WebElement from '../element/WebElement.js'
@@ -1639,20 +1640,12 @@ class Puppeteer extends Helper {
16391640

16401641
const targetEls = els.length ? els : await this._locate(locator)
16411642
assertElementExists(targetEls, locator, 'Element')
1642-
const base64Content = base64EncodeFile(file)
1643-
const fileName = path.basename(file)
1644-
const mimeType = getMimeType(fileName)
1645-
await targetEls[0].evaluate((el, { base64Content, fileName, mimeType }) => {
1646-
const binaryStr = atob(base64Content)
1647-
const bytes = new Uint8Array(binaryStr.length)
1648-
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i)
1649-
const fileObj = new File([bytes], fileName, { type: mimeType })
1650-
const dataTransfer = new DataTransfer()
1651-
dataTransfer.items.add(fileObj)
1652-
el.dispatchEvent(new DragEvent('dragenter', { dataTransfer, bubbles: true }))
1653-
el.dispatchEvent(new DragEvent('dragover', { dataTransfer, bubbles: true }))
1654-
el.dispatchEvent(new DragEvent('drop', { dataTransfer, bubbles: true }))
1655-
}, { base64Content, fileName, mimeType })
1643+
const fileData = {
1644+
base64Content: base64EncodeFile(file),
1645+
fileName: path.basename(file),
1646+
mimeType: getMimeType(path.basename(file)),
1647+
}
1648+
await targetEls[0].evaluate(dropFile, fileData)
16561649
return this._waitForAction()
16571650
}
16581651

lib/helper/WebDriver.js

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { highlightElement } from './scripts/highlightElement.js'
3636
import { focusElement } from './scripts/focusElement.js'
3737
import { blurElement } from './scripts/blurElement.js'
3838
import { dontSeeElementError, seeElementError, seeElementInDOMError, dontSeeElementInDOMError } from './errors/ElementAssertion.js'
39+
import { dropFile } from './scripts/dropFile.js'
3940
import { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } from './network/actions.js'
4041
import WebElement from '../element/WebElement.js'
4142

@@ -1376,20 +1377,12 @@ class WebDriver extends Helper {
13761377
const targetRes = res.length ? res : await this._locate(locator)
13771378
assertElementExists(targetRes, locator, 'Element')
13781379
const targetEl = usingFirstElement(targetRes)
1379-
const base64Content = base64EncodeFile(file)
1380-
const fileName = path.basename(file)
1381-
const mimeType = getMimeType(fileName)
1382-
return this.browser.execute(function (el, data) {
1383-
var binaryStr = atob(data.base64Content)
1384-
var bytes = new Uint8Array(binaryStr.length)
1385-
for (var i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i)
1386-
var fileObj = new File([bytes], data.fileName, { type: data.mimeType })
1387-
var dataTransfer = new DataTransfer()
1388-
dataTransfer.items.add(fileObj)
1389-
el.dispatchEvent(new DragEvent('dragenter', { dataTransfer: dataTransfer, bubbles: true }))
1390-
el.dispatchEvent(new DragEvent('dragover', { dataTransfer: dataTransfer, bubbles: true }))
1391-
el.dispatchEvent(new DragEvent('drop', { dataTransfer: dataTransfer, bubbles: true }))
1392-
}, targetEl, { base64Content, fileName, mimeType })
1380+
const fileData = {
1381+
base64Content: base64EncodeFile(file),
1382+
fileName: path.basename(file),
1383+
mimeType: getMimeType(path.basename(file)),
1384+
}
1385+
return this.browser.execute(dropFile, targetEl, fileData)
13931386
}
13941387

13951388
/**

lib/helper/scripts/dropFile.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const dropFile = (el, { base64Content, fileName, mimeType }) => {
2+
const binaryStr = atob(base64Content)
3+
const bytes = new Uint8Array(binaryStr.length)
4+
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i)
5+
const fileObj = new File([bytes], fileName, { type: mimeType })
6+
const dataTransfer = new DataTransfer()
7+
dataTransfer.items.add(fileObj)
8+
el.dispatchEvent(new DragEvent('dragenter', { dataTransfer, bubbles: true }))
9+
el.dispatchEvent(new DragEvent('dragover', { dataTransfer, bubbles: true }))
10+
el.dispatchEvent(new DragEvent('drop', { dataTransfer, bubbles: true }))
11+
}

0 commit comments

Comments
 (0)