/** * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import fs from 'fs'; import { test as it, expect } from './pageTest'; import type { Page } from 'playwright-core'; it.skip(({ isAndroid }) => isAndroid, 'No drag&drop on Android.'); async function setupDropzone(page: Page) { await page.setContent(`
`); } async function getDropInfo(page: Page) { return await page.waitForFunction(() => (window as any).__dropInfo).then(h => h.jsonValue()); } it('should drop a file payload', async ({ page }) => { await setupDropzone(page); await page.locator('#dropzone').drop({ files: { name: 'note.txt', mimeType: 'text/plain', buffer: Buffer.from('hello') }, }); expect(await getDropInfo(page)).toEqual({ files: [{ name: 'note.txt', type: 'text/plain', size: 5, text: 'hello' }], data: {}, }); }); it('should drop multiple file payloads', async ({ page }) => { await setupDropzone(page); await page.locator('#dropzone').drop({ files: [ { name: 'a.txt', mimeType: 'text/plain', buffer: Buffer.from('AAA') }, { name: 'b.txt', mimeType: 'text/plain', buffer: Buffer.from('BB') }, ], }); const info = await getDropInfo(page); expect(info.files.map((f: any) => [f.name, f.text])).toEqual([['a.txt', 'AAA'], ['b.txt', 'BB']]); }); it('should drop a file by local path', async ({ page }, testInfo) => { await setupDropzone(page); const filePath = testInfo.outputPath('hello.txt'); await fs.promises.writeFile(filePath, 'path-content'); await page.locator('#dropzone').drop({ files: filePath }); const info = await getDropInfo(page); expect(info.files).toHaveLength(1); expect(info.files[0].name).toBe('hello.txt'); expect(info.files[0].text).toBe('path-content'); }); it('should drop clipboard-like data', async ({ page }) => { await setupDropzone(page); await page.locator('#dropzone').drop({ data: { 'text/plain': 'hello world', 'text/uri-list': 'https://example.com', }, }); const info = await getDropInfo(page); expect(info.files).toEqual([]); expect(info.data['text/plain']).toBe('hello world'); expect(info.data['text/uri-list']).toBe('https://example.com'); }); it('should drop files and data together', async ({ page }) => { await setupDropzone(page); await page.locator('#dropzone').drop({ files: { name: 'mix.txt', mimeType: 'text/plain', buffer: Buffer.from('mix') }, data: { 'text/plain': 'label' }, }); const info = await getDropInfo(page); expect(info.files[0].text).toBe('mix'); expect(info.data['text/plain']).toBe('label'); }); it('should throw when target does not accept drop', async ({ page }) => { // Dropzone without preventDefault on dragover. await page.setContent(` `); await expect(page.locator('#dropzone').drop({ data: { 'text/plain': 'nope' }, })).rejects.toThrow(/drop target did not accept the drop/i); }); it('should throw when neither files nor data provided', async ({ page }) => { await setupDropzone(page); await expect(page.locator('#dropzone').drop({})).rejects.toThrow(/At least one of "files" or "data"/); });