/** * 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 type { ElementHandle, Route } from 'playwright-core'; import { test as it, expect } from './pageTest'; import { attachFrame } from '../config/utils'; it.describe('Drag and drop', () => { it.skip(({ browserName, browserMajorVersion }) => browserName === 'chromium' && browserMajorVersion < 91); it.skip(({ isAndroid }) => isAndroid, 'No drag&drop on Android.'); it('should work @smoke', async ({ page, server }) => { await page.goto(server.PREFIX + '/drag-n-drop.html'); await page.hover('#source'); await page.mouse.down(); await page.hover('#target'); await page.mouse.up(); expect(await page.$eval('#target', target => target.contains(document.querySelector('#source')))).toBe(true); // could not find source in target }); it('should send the right events', async ({ server, page, browserName }) => { await page.goto(server.PREFIX + '/drag-n-drop.html'); const events = await trackEvents(await page.$('body')); await page.hover('#source'); await page.mouse.down(); await page.hover('#target'); await page.mouse.up(); expect(await events.jsonValue()).toEqual([ 'mousemove at 120;86', 'mousedown at 120;86', browserName === 'firefox' ? 'dragstart at 120;86' : 'mousemove at 240;350', browserName === 'firefox' ? 'mousemove at 240;350' : 'dragstart at 120;86', 'dragenter at 240;350', 'dragover at 240;350', 'drop at 240;350', 'dragend', ]); }); it('should not send dragover on the first mousemove', async ({ server, page, browserName }) => { it.fixme(browserName !== 'chromium'); await page.goto(server.PREFIX + '/drag-n-drop.html'); const events = await trackEvents(await page.$('body')); await page.hover('#source'); await page.mouse.down(); await page.hover('#target'); expect(await events.jsonValue()).toEqual([ 'mousemove at 120;86', 'mousedown at 120;86', browserName === 'firefox' ? 'dragstart at 120;86' : 'mousemove at 240;350', browserName === 'firefox' ? 'mousemove at 240;350' : 'dragstart at 120;86', 'dragenter at 240;350', ]); }); it('should work inside iframe', async ({ page, server, browserName, isElectron, isWindows }) => { it.fixme(isElectron && isWindows, 'Fails on the bots'); await page.goto(server.EMPTY_PAGE); const frame = await attachFrame(page, 'myframe', server.PREFIX + '/drag-n-drop.html'); await page.$eval('iframe', iframe => { iframe.style.width = '500px'; iframe.style.height = '600px'; iframe.style.marginLeft = '80px'; iframe.style.marginTop = '60px'; }); const pageEvents = await trackEvents(await page.$('body')); const frameEvents = await trackEvents(await frame.$('body')); await frame.hover('#source'); await page.mouse.down(); await frame.hover('#target'); await page.mouse.up(); expect(await frame.$eval('#target', target => target.contains(document.querySelector('#source')))).toBe(true); // could not find source in target expect(await frameEvents.jsonValue()).toEqual([ 'mousemove at 120;86', 'mousedown at 120;86', browserName === 'firefox' ? 'dragstart at 120;86' : 'mousemove at 240;350', browserName === 'firefox' ? 'mousemove at 240;350' : 'dragstart at 120;86', 'dragenter at 240;350', 'dragover at 240;350', 'drop at 240;350', 'dragend', ]); expect(await pageEvents.jsonValue()).toEqual([]); }); it('should cancel on escape', async ({ server, page, browserName }) => { await page.goto(server.PREFIX + '/drag-n-drop.html'); const events = await trackEvents(await page.$('body')); await page.hover('#source'); await page.mouse.down(); await page.hover('#target'); await page.keyboard.press('Escape'); await page.mouse.up(); expect(await page.$eval('#target', target => target.contains(document.querySelector('#source')))).toBe(false); // found source in target expect(await events.jsonValue()).toEqual([ 'mousemove at 120;86', 'mousedown at 120;86', browserName === 'firefox' ? 'dragstart at 120;86' : 'mousemove at 240;350', browserName === 'firefox' ? 'mousemove at 240;350' : 'dragstart at 120;86', 'dragenter at 240;350', browserName === 'chromium' ? null : 'dragover at 240;350', 'dragend', 'mouseup at 240;350', ].filter(Boolean)); }); it.describe('iframe', () => { it.fixme(true, 'implement dragging with iframes'); it('should drag into an iframe', async ({ server, page, browserName }) => { await page.goto(server.PREFIX + '/drag-n-drop.html'); const frame = await attachFrame(page, 'oopif', server.PREFIX + '/drag-n-drop.html'); await page.$eval('iframe', iframe => { iframe.style.width = '500px'; iframe.style.height = '600px'; iframe.style.marginLeft = '500px'; iframe.style.marginTop = '60px'; }); await page.waitForTimeout(5000); const pageEvents = await trackEvents(await page.$('body')); const frameEvents = await trackEvents(await frame.$('body')); await page.hover('#source'); await page.mouse.down(); await frame.hover('#target'); await page.mouse.up(); expect(await frame.$eval('#target', target => target.contains(document.querySelector('#source')))).toBe(true); // could not find source in target expect(await pageEvents.jsonValue()).toEqual([ 'mousemove', 'mousedown', browserName === 'firefox' ? 'dragstart' : 'mousemove', browserName === 'firefox' ? 'mousemove' : 'dragstart', ]); expect(await frameEvents.jsonValue()).toEqual([ 'dragenter', 'dragover', 'drop', ]); }); it('should drag out of an iframe', async ({ server, page }) => { await page.goto(server.PREFIX + '/drag-n-drop.html'); const frame = await attachFrame(page, 'oopif', server.PREFIX + '/drag-n-drop.html'); const pageEvents = await trackEvents(await page.$('body')); const frameEvents = await trackEvents(await frame.$('body')); await frame.hover('#source'); await page.mouse.down(); await page.hover('#target'); await page.mouse.up(); expect(await page.$eval('#target', target => target.contains(document.querySelector('#source')))).toBe(true); // could not find source in target expect(await frameEvents.jsonValue()).toEqual([ 'mousemove', 'mousedown', 'dragstart', 'dragend', ]); expect(await pageEvents.jsonValue()).toEqual([ 'dragenter', 'dragover', 'drop', ]); }); }); it('should respect the drop effect', async ({ page, browserName, isLinux, isMac, headless, trace }) => { it.fixme(browserName === 'webkit' && !isLinux, 'WebKit doesn\'t handle the drop effect correctly outside of linux.'); it.fixme(browserName === 'webkit' && isLinux && !headless, 'https://github.com/microsoft/playwright/issues/21646'); it.fixme(browserName === 'chromium' && !isMac && !headless, 'https://github.com/microsoft/playwright/issues/21646'); it.slow(trace === 'on'); expect(await testIfDropped('copy', 'copy')).toBe(true); expect(await testIfDropped('copy', 'move')).toBe(false); expect(await testIfDropped('all', 'link')).toBe(true); expect(await testIfDropped('all', 'none')).toBe(false); expect(await testIfDropped('copyMove', 'copy')).toBe(true); expect(await testIfDropped('copyLink', 'copy')).toBe(true); expect(await testIfDropped('linkMove', 'copy')).toBe(false); expect(await testIfDropped('copyMove', 'link')).toBe(false); expect(await testIfDropped('copyLink', 'link')).toBe(true); expect(await testIfDropped('linkMove', 'link')).toBe(true); expect(await testIfDropped('copyMove', 'move')).toBe(true); expect(await testIfDropped('copyLink', 'move')).toBe(false); expect(await testIfDropped('linkMove', 'move')).toBe(true); expect(await testIfDropped('uninitialized', 'copy')).toBe(true); async function testIfDropped(effectAllowed: string, dropEffect: string) { await page.setContent(`