mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: add drag-and-drop support (#7150)
This commit adds drag-and-drop support, leveraging new additions to the CDP Input domain (Input.setInterceptDrags, Input.dispatchDragEvent, and Input.dragIntercepted).
This commit is contained in:
parent
0295b1c773
commit
a91b8aca37
125
docs/api.md
125
docs/api.md
@ -155,6 +155,7 @@
|
||||
* [page.goto(url[, options])](#pagegotourl-options)
|
||||
* [page.hover(selector)](#pagehoverselector)
|
||||
* [page.isClosed()](#pageisclosed)
|
||||
* [page.isDragInterceptionEnabled](#pageisdraginterceptionenabled)
|
||||
* [page.isJavaScriptEnabled()](#pageisjavascriptenabled)
|
||||
* [page.keyboard](#pagekeyboard)
|
||||
* [page.mainFrame()](#pagemainframe)
|
||||
@ -171,6 +172,7 @@
|
||||
* [page.setCookie(...cookies)](#pagesetcookiecookies)
|
||||
* [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout)
|
||||
* [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout)
|
||||
* [page.setDragInterception(enabled)](#pagesetdraginterceptionenabled)
|
||||
* [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
|
||||
* [page.setGeolocation(options)](#pagesetgeolocationoptions)
|
||||
* [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled)
|
||||
@ -214,6 +216,11 @@
|
||||
- [class: Mouse](#class-mouse)
|
||||
* [mouse.click(x, y[, options])](#mouseclickx-y-options)
|
||||
* [mouse.down([options])](#mousedownoptions)
|
||||
* [mouse.drag(start, target)](#mousedragstart-target)
|
||||
* [mouse.dragAndDrop(start, target[, options])](#mousedraganddropstart-target-options)
|
||||
* [mouse.dragEnter(target, data)](#mousedragentertarget-data)
|
||||
* [mouse.dragOver(target, data)](#mousedragovertarget-data)
|
||||
* [mouse.drop(target, data)](#mousedroptarget-data)
|
||||
* [mouse.move(x, y[, options])](#mousemovex-y-options)
|
||||
* [mouse.up([options])](#mouseupoptions)
|
||||
* [mouse.wheel([options])](#mousewheeloptions)
|
||||
@ -294,8 +301,14 @@
|
||||
* [elementHandle.boundingBox()](#elementhandleboundingbox)
|
||||
* [elementHandle.boxModel()](#elementhandleboxmodel)
|
||||
* [elementHandle.click([options])](#elementhandleclickoptions)
|
||||
* [elementHandle.clickablePoint()](#elementhandleclickablepoint)
|
||||
* [elementHandle.contentFrame()](#elementhandlecontentframe)
|
||||
* [elementHandle.dispose()](#elementhandledispose)
|
||||
* [elementHandle.drag(target)](#elementhandledragtarget)
|
||||
* [elementHandle.dragAndDrop(target[, options])](#elementhandledraganddroptarget-options)
|
||||
* [elementHandle.dragEnter([data])](#elementhandledragenterdata)
|
||||
* [elementHandle.dragOver([data])](#elementhandledragoverdata)
|
||||
* [elementHandle.drop([data])](#elementhandledropdata)
|
||||
* [elementHandle.evaluate(pageFunction[, ...args])](#elementhandleevaluatepagefunction-args)
|
||||
* [elementHandle.evaluateHandle(pageFunction[, ...args])](#elementhandleevaluatehandlepagefunction-args)
|
||||
* [elementHandle.executionContext()](#elementhandleexecutioncontext)
|
||||
@ -1919,6 +1932,12 @@ Shortcut for [page.mainFrame().hover(selector)](#framehoverselector).
|
||||
|
||||
Indicates that the page has been closed.
|
||||
|
||||
#### page.isDragInterceptionEnabled
|
||||
|
||||
- returns: <[boolean]>
|
||||
|
||||
Indicates that drag events are being intercepted.
|
||||
|
||||
#### page.isJavaScriptEnabled()
|
||||
|
||||
- returns: <[boolean]>
|
||||
@ -2183,6 +2202,13 @@ This setting will change the default maximum time for the following methods and
|
||||
|
||||
> **NOTE** [`page.setDefaultNavigationTimeout`](#pagesetdefaultnavigationtimeouttimeout) takes priority over [`page.setDefaultTimeout`](#pagesetdefaulttimeouttimeout)
|
||||
|
||||
#### page.setDragInterception(enabled)
|
||||
|
||||
- `enabled` <[boolean]>
|
||||
- returns: <[Promise]>
|
||||
|
||||
Enables the Input.drag methods. This provides the capability to cpature drag events emitted on the page, which can then be used to simulate drag-and-drop.
|
||||
|
||||
#### page.setExtraHTTPHeaders(headers)
|
||||
|
||||
- `headers` <[Object]> An object containing additional HTTP headers to be sent with every request. All header values must be strings.
|
||||
@ -2958,6 +2984,62 @@ Shortcut for [`mouse.move`](#mousemovex-y-options), [`mouse.down`](#mousedownopt
|
||||
|
||||
Dispatches a `mousedown` event.
|
||||
|
||||
#### mouse.drag(start, target)
|
||||
|
||||
- `start` <[Object]> the position to start dragging from
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- `target` <[Object]> the position to drag to
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- returns: <[Promise<[DragData]>]>
|
||||
|
||||
This method creates and captures a dragevent from a given point.
|
||||
|
||||
#### mouse.dragAndDrop(start, target[, options])
|
||||
|
||||
- `start` <[Object]>
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- `target` <[Object]>
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- `options` <[Object]>
|
||||
- `delay` <[number]> how long to delay before dropping onto the target point
|
||||
- returns: <[Promise<[DragData]>]>
|
||||
|
||||
This method drags from a given start point and drops onto a target point.
|
||||
|
||||
#### mouse.dragEnter(target, data)
|
||||
|
||||
- `target` <[Object]>
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- `data` <[Object]>
|
||||
- returns: <[Promise]]>
|
||||
|
||||
This method triggers a dragenter event from the target point.
|
||||
|
||||
#### mouse.dragOver(target, data)
|
||||
|
||||
- `target` <[Object]>
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- `data` <[Object]>
|
||||
- returns: <[Promise]]>
|
||||
|
||||
This method triggers a dragover event from the target point.
|
||||
|
||||
#### mouse.drop(target, data)
|
||||
|
||||
- `target` <[Object]>
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- `data` <[Object]>
|
||||
- returns: <[Promise]]>
|
||||
|
||||
This method triggers a drop event from the target point.
|
||||
|
||||
#### mouse.move(x, y[, options])
|
||||
|
||||
- `x` <[number]>
|
||||
@ -4033,6 +4115,10 @@ This method returns boxes of the element, or `null` if the element is not visibl
|
||||
This method scrolls element into view if needed, and then uses [page.mouse](#pagemouse) to click in the center of the element.
|
||||
If the element is detached from DOM, the method throws an error.
|
||||
|
||||
#### elementHandle.clickablePoint()
|
||||
|
||||
- returns: <[Promise<[Point]>]> Resolves to the x, y point that describes the element's position.
|
||||
|
||||
#### elementHandle.contentFrame()
|
||||
|
||||
- returns: <[Promise]<?[Frame]>> Resolves to the content frame for element handles referencing iframe nodes, or null otherwise
|
||||
@ -4043,6 +4129,45 @@ If the element is detached from DOM, the method throws an error.
|
||||
|
||||
The `elementHandle.dispose` method stops referencing the element handle.
|
||||
|
||||
#### elementHandle.drag(target)
|
||||
|
||||
- `target` <[Object]>
|
||||
- `x` <[number]> x coordinate
|
||||
- `y` <[number]> y coordinate
|
||||
- returns: <[Promise<[DragData]>]>
|
||||
|
||||
This method creates and captures a drag event from the element.
|
||||
|
||||
#### elementHandle.dragAndDrop(target[, options])
|
||||
|
||||
- `target` <[ElementHandle]>
|
||||
- `options` <[Object]>
|
||||
- `delay` <[number]> how long to delay before dropping onto the target element
|
||||
- returns: <[Promise]>
|
||||
|
||||
This method will drag a given element and drop it onto a target element.
|
||||
|
||||
#### elementHandle.dragEnter([data])
|
||||
|
||||
- `data` <[Object]> drag data created from `element.drag`
|
||||
- returns: <[Promise]>
|
||||
|
||||
This method will trigger a dragenter event from the given element.
|
||||
|
||||
#### elementHandle.dragOver([data])
|
||||
|
||||
- `data` <[Object]> drag data created from `element.drag`
|
||||
- returns: <[Promise]>
|
||||
|
||||
This method will trigger a dragover event from the given element.
|
||||
|
||||
#### elementHandle.drop([data])
|
||||
|
||||
- `data` <[Object]> drag data created from `element.drag`
|
||||
- returns: <[Promise]>
|
||||
|
||||
This method will trigger a drop event from the given element.
|
||||
|
||||
#### elementHandle.evaluate(pageFunction[, ...args])
|
||||
|
||||
- `pageFunction` <[function]\([Object]\)> Function to be evaluated in browser context
|
||||
|
@ -17,6 +17,8 @@
|
||||
import { assert } from './assert.js';
|
||||
import { CDPSession } from './Connection.js';
|
||||
import { keyDefinitions, KeyDefinition, KeyInput } from './USKeyboardLayout.js';
|
||||
import { Protocol } from 'devtools-protocol';
|
||||
import { Point } from './JSHandle.js';
|
||||
|
||||
type KeyDescription = Required<
|
||||
Pick<KeyDefinition, 'keyCode' | 'key' | 'text' | 'code' | 'location'>
|
||||
@ -485,6 +487,98 @@ export class Mouse {
|
||||
pointerType: 'mouse',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a `drag` event.
|
||||
* @param start - starting point for drag
|
||||
* @param target - point to drag to
|
||||
* ```
|
||||
*/
|
||||
async drag(start: Point, target: Point): Promise<Protocol.Input.DragData> {
|
||||
const promise = new Promise<Protocol.Input.DragData>((resolve) => {
|
||||
this._client.once('Input.dragIntercepted', (event) =>
|
||||
resolve(event.data)
|
||||
);
|
||||
});
|
||||
await this.move(start.x, start.y);
|
||||
await this.down();
|
||||
await this.move(target.x, target.y);
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a `dragenter` event.
|
||||
* @param target - point for emitting `dragenter` event
|
||||
* ```
|
||||
*/
|
||||
async dragEnter(target: Point, data: Protocol.Input.DragData): Promise<void> {
|
||||
await this._client.send('Input.dispatchDragEvent', {
|
||||
type: 'dragEnter',
|
||||
x: target.x,
|
||||
y: target.y,
|
||||
modifiers: this._keyboard._modifiers,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a `dragover` event.
|
||||
* @param target - point for emitting `dragover` event
|
||||
* ```
|
||||
*/
|
||||
async dragOver(target: Point, data: Protocol.Input.DragData): Promise<void> {
|
||||
await this._client.send('Input.dispatchDragEvent', {
|
||||
type: 'dragOver',
|
||||
x: target.x,
|
||||
y: target.y,
|
||||
modifiers: this._keyboard._modifiers,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a dragenter, dragover, and drop in sequence.
|
||||
* @param target - point to drop on
|
||||
* @param data - drag data containing items and operations mask
|
||||
* @param options - An object of options. Accepts delay which,
|
||||
* if specified, is the time to wait between `dragover` and `drop` in milliseconds.
|
||||
* Defaults to 0.
|
||||
* ```
|
||||
*/
|
||||
async drop(target: Point, data: Protocol.Input.DragData): Promise<void> {
|
||||
await this._client.send('Input.dispatchDragEvent', {
|
||||
type: 'drop',
|
||||
x: target.x,
|
||||
y: target.y,
|
||||
modifiers: this._keyboard._modifiers,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a drag, dragenter, dragover, and drop in sequence.
|
||||
* @param target - point to drag from
|
||||
* @param target - point to drop on
|
||||
* @param options - An object of options. Accepts delay which,
|
||||
* if specified, is the time to wait between `dragover` and `drop` in milliseconds.
|
||||
* Defaults to 0.
|
||||
* ```
|
||||
*/
|
||||
async dragAndDrop(
|
||||
start: Point,
|
||||
target: Point,
|
||||
options: { delay?: number } = {}
|
||||
): Promise<void> {
|
||||
const { delay = null } = options;
|
||||
const data = await this.drag(start, target);
|
||||
await this.dragEnter(target, data);
|
||||
await this.dragOver(target, data);
|
||||
if (delay) {
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
}
|
||||
await this.drop(target, data);
|
||||
await this.up();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -411,7 +411,7 @@ export class ElementHandle<
|
||||
if (error) throw new Error(error);
|
||||
}
|
||||
|
||||
private async _clickablePoint(): Promise<{ x: number; y: number }> {
|
||||
async clickablePoint(): Promise<Point> {
|
||||
const [result, layoutMetrics] = await Promise.all([
|
||||
this._client
|
||||
.send('DOM.getContentQuads', {
|
||||
@ -482,7 +482,7 @@ export class ElementHandle<
|
||||
*/
|
||||
async hover(): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const { x, y } = await this._clickablePoint();
|
||||
const { x, y } = await this.clickablePoint();
|
||||
await this._page.mouse.move(x, y);
|
||||
}
|
||||
|
||||
@ -493,10 +493,69 @@ export class ElementHandle<
|
||||
*/
|
||||
async click(options: ClickOptions = {}): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const { x, y } = await this._clickablePoint();
|
||||
const { x, y } = await this.clickablePoint();
|
||||
await this._page.mouse.click(x, y, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates and captures a dragevent from the element.
|
||||
*/
|
||||
async drag(target: Point): Promise<Protocol.Input.DragData> {
|
||||
assert(
|
||||
this._page.isDragInterceptionEnabled,
|
||||
'Drag Interception is not enabled!'
|
||||
);
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const start = await this.clickablePoint();
|
||||
return await this._page.mouse.drag(start, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a `dragenter` event on the element.
|
||||
*/
|
||||
async dragEnter(
|
||||
data: Protocol.Input.DragData = { items: [], dragOperationsMask: 1 }
|
||||
): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const target = await this.clickablePoint();
|
||||
await this._page.mouse.dragEnter(target, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a `dragover` event on the element.
|
||||
*/
|
||||
async dragOver(
|
||||
data: Protocol.Input.DragData = { items: [], dragOperationsMask: 1 }
|
||||
): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const target = await this.clickablePoint();
|
||||
await this._page.mouse.dragOver(target, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method triggers a drop on the element.
|
||||
*/
|
||||
async drop(
|
||||
data: Protocol.Input.DragData = { items: [], dragOperationsMask: 1 }
|
||||
): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const destination = await this.clickablePoint();
|
||||
await this._page.mouse.drop(destination, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method triggers a dragenter, dragover, and drop on the element.
|
||||
*/
|
||||
async dragAndDrop(
|
||||
target: ElementHandle,
|
||||
options?: { delay: number }
|
||||
): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const startPoint = await this.clickablePoint();
|
||||
const targetPoint = await target.clickablePoint();
|
||||
await this._page.mouse.dragAndDrop(startPoint, targetPoint, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a `change` and `input` event once all the provided options have been
|
||||
* selected. If there's no `<select>` element matching `selector`, the method
|
||||
@ -621,7 +680,7 @@ export class ElementHandle<
|
||||
*/
|
||||
async tap(): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const { x, y } = await this._clickablePoint();
|
||||
const { x, y } = await this.clickablePoint();
|
||||
await this._page.touchscreen.tap(x, y);
|
||||
}
|
||||
|
||||
@ -982,6 +1041,14 @@ export interface PressOptions {
|
||||
text?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
function computeQuadArea(quad: Array<{ x: number; y: number }>): number {
|
||||
/* Compute sum of all directed areas of adjacent triangles
|
||||
https://en.wikipedia.org/wiki/Polygon#Simple_polygons
|
||||
|
@ -463,6 +463,7 @@ export class Page extends EventEmitter {
|
||||
private _fileChooserInterceptors = new Set<Function>();
|
||||
|
||||
private _disconnectPromise?: Promise<Error>;
|
||||
private _userDragInterceptionEnabled = false;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -748,6 +749,10 @@ export class Page extends EventEmitter {
|
||||
return this._accessibility;
|
||||
}
|
||||
|
||||
get isDragInterceptionEnabled(): boolean {
|
||||
return this._userDragInterceptionEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns An array of all frames attached to the page.
|
||||
*/
|
||||
@ -799,6 +804,19 @@ export class Page extends EventEmitter {
|
||||
return this._frameManager.networkManager().setRequestInterception(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param enabled - Whether to enable drag interception.
|
||||
*
|
||||
* @remarks
|
||||
* Activating drag interception enables the {@link Input.drag},
|
||||
* methods This provides the capability to capture drag events emitted
|
||||
* on the page, which can then be used to simulate drag-and-drop.
|
||||
*/
|
||||
async setDragInterception(enabled: boolean): Promise<void> {
|
||||
this._userDragInterceptionEnabled = enabled;
|
||||
return this._client.send('Input.setInterceptDrags', { enabled });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param enabled - When `true`, enables offline mode for the page.
|
||||
*/
|
||||
|
46
test/assets/input/drag-and-drop.html
Normal file
46
test/assets/input/drag-and-drop.html
Normal file
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Drag-and-drop test</title>
|
||||
<style>
|
||||
#drop {
|
||||
width: 5em;
|
||||
height: 5em;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="drag" draggable="true">drag me</div>
|
||||
<div id="drop"></div>
|
||||
<script>
|
||||
window.didDragStart = false;
|
||||
window.didDragEnter = false;
|
||||
window.didDragOver = false;
|
||||
window.didDrop = false;
|
||||
var drag = document.getElementById('drag');
|
||||
var drop = document.getElementById('drop');
|
||||
drag.addEventListener('dragstart', function(e) {
|
||||
e.dataTransfer.setData('id', e.target.id);
|
||||
window.didDragStart = true;
|
||||
});
|
||||
drop.addEventListener('dragenter', function(e) {
|
||||
e.preventDefault();
|
||||
window.didDragEnter = true;
|
||||
});
|
||||
drop.addEventListener('dragover', function(e) {
|
||||
e.preventDefault();
|
||||
window.didDragOver = true;
|
||||
});
|
||||
drop.addEventListener('drop', function(e) {
|
||||
e.preventDefault();
|
||||
var id = e.dataTransfer.getData('id');
|
||||
var el = document.getElementById(id);
|
||||
if (el) {
|
||||
e.target.appendChild(el);
|
||||
window.didDrop = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
125
test/drag-and-drop.spec.ts
Normal file
125
test/drag-and-drop.spec.ts
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright 2021 Google Inc. All rights reserved.
|
||||
*
|
||||
* 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 expect from 'expect';
|
||||
import {
|
||||
getTestState,
|
||||
setupTestPageAndContextHooks,
|
||||
setupTestBrowserHooks,
|
||||
describeChromeOnly,
|
||||
} from './mocha-utils'; // eslint-disable-line import/extensions
|
||||
|
||||
describeChromeOnly('Input.drag', function () {
|
||||
setupTestBrowserHooks();
|
||||
setupTestPageAndContextHooks();
|
||||
it('should throw an exception if not enabled before usage', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
|
||||
const draggable = await page.$('#drag');
|
||||
|
||||
try {
|
||||
await draggable.drag({ x: 1, y: 1 });
|
||||
} catch (error) {
|
||||
expect(error.message).toContain('Drag Interception is not enabled!');
|
||||
}
|
||||
});
|
||||
it('should emit a dragIntercepted event when dragged', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
|
||||
await page.setDragInterception(true);
|
||||
const draggable = await page.$('#drag');
|
||||
const data = await draggable.drag({ x: 1, y: 1 });
|
||||
|
||||
expect(data.items.length).toBe(1);
|
||||
expect(await page.evaluate(() => globalThis.didDragStart)).toBe(true);
|
||||
});
|
||||
it('should emit a dragEnter', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
|
||||
await page.setDragInterception(true);
|
||||
const draggable = await page.$('#drag');
|
||||
const data = await draggable.drag({ x: 1, y: 1 });
|
||||
const dropzone = await page.$('#drop');
|
||||
await dropzone.dragEnter(data);
|
||||
|
||||
expect(await page.evaluate(() => globalThis.didDragStart)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDragEnter)).toBe(true);
|
||||
});
|
||||
it('should emit a dragOver event', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
|
||||
await page.setDragInterception(true);
|
||||
const draggable = await page.$('#drag');
|
||||
const data = await draggable.drag({ x: 1, y: 1 });
|
||||
const dropzone = await page.$('#drop');
|
||||
await dropzone.dragEnter(data);
|
||||
await dropzone.dragOver(data);
|
||||
|
||||
expect(await page.evaluate(() => globalThis.didDragStart)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDragEnter)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDragOver)).toBe(true);
|
||||
});
|
||||
it('can be dropped', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
|
||||
await page.setDragInterception(true);
|
||||
const draggable = await page.$('#drag');
|
||||
const dropzone = await page.$('#drop');
|
||||
const data = await draggable.drag({ x: 1, y: 1 });
|
||||
await dropzone.dragEnter(data);
|
||||
await dropzone.dragOver(data);
|
||||
await dropzone.drop(data);
|
||||
|
||||
expect(await page.evaluate(() => globalThis.didDragStart)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDragEnter)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDragOver)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDrop)).toBe(true);
|
||||
});
|
||||
it('can be dragged and dropped with a single function', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
|
||||
await page.setDragInterception(true);
|
||||
const draggable = await page.$('#drag');
|
||||
const dropzone = await page.$('#drop');
|
||||
await draggable.dragAndDrop(dropzone);
|
||||
|
||||
expect(await page.evaluate(() => globalThis.didDragStart)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDragEnter)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDragOver)).toBe(true);
|
||||
expect(await page.evaluate(() => globalThis.didDrop)).toBe(true);
|
||||
});
|
||||
it('can be disabled', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
|
||||
await page.setDragInterception(true);
|
||||
const draggable = await page.$('#drag');
|
||||
await draggable.drag({ x: 1, y: 1 });
|
||||
await page.setDragInterception(false);
|
||||
|
||||
try {
|
||||
await draggable.drag({ x: 1, y: 1 });
|
||||
} catch (error) {
|
||||
expect(error.message).toContain('Drag Interception is not enabled!');
|
||||
}
|
||||
});
|
||||
});
|
@ -385,6 +385,41 @@ function compareDocumentations(actual, expected) {
|
||||
expectedName: 'KeyInput',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method ElementHandle.drag() target',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method ElementHandle.dragAndDrop() target',
|
||||
{
|
||||
actualName: 'ElementHandle',
|
||||
expectedName: 'ElementHandle<Element>',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method ElementHandle.dragEnter() data',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'DragData',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method ElementHandle.dragOver() data',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'DragData',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method ElementHandle.drop() data',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'DragData',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Keyboard.down() key',
|
||||
{
|
||||
@ -413,6 +448,83 @@ function compareDocumentations(actual, expected) {
|
||||
expectedName: 'MouseOptions',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.drag() start',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.drag() target',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.dragAndDrop() start',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.dragAndDrop() target',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.dragAndDrop() target',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.dragEnter() target',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.dragEnter() data',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'DragData',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.dragOver() target',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.dragOver() data',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'DragData',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.drop() target',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'Point',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.drop() data',
|
||||
{
|
||||
actualName: 'Object',
|
||||
expectedName: 'DragData',
|
||||
},
|
||||
],
|
||||
[
|
||||
'Method Mouse.up() options',
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user