feat: implement improved Drag n' Drop APIs (#10651)

This commit is contained in:
jrandolf 2023-09-14 11:14:30 +02:00 committed by GitHub
parent 67f72de274
commit 9342bac263
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 284 additions and 214 deletions

View File

@ -4,7 +4,7 @@ sidebar_label: ElementHandle.drag
# ElementHandle.drag() method # ElementHandle.drag() method
This method creates and captures a dragevent from the element. Drags an element over the given element or point.
#### Signature: #### Signature:
@ -12,18 +12,20 @@ This method creates and captures a dragevent from the element.
class ElementHandle { class ElementHandle {
drag( drag(
this: ElementHandle<Element>, this: ElementHandle<Element>,
target: Point target: Point | ElementHandle<Element>
): Promise<Protocol.Input.DragData>; ): Promise<Protocol.Input.DragData | void>;
} }
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ----------- | | --------- | --------------------------------------------------------------------------------------------- | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | | | this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| target | [Point](./puppeteer.point.md) | | | target | [Point](./puppeteer.point.md) \| [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
**Returns:** **Returns:**
Promise&lt;Protocol.Input.DragData&gt; Promise&lt;Protocol.Input.DragData \| void&gt;
DEPRECATED. When drag interception is enabled, the drag payload is returned.

View File

@ -4,7 +4,9 @@ sidebar_label: ElementHandle.dragAndDrop
# ElementHandle.dragAndDrop() method # ElementHandle.dragAndDrop() method
This method triggers a dragenter, dragover, and drop on the element. > Warning: This API is now obsolete.
>
> Use `ElementHandle.drop` instead.
#### Signature: #### Signature:

View File

@ -4,7 +4,9 @@ sidebar_label: ElementHandle.dragEnter
# ElementHandle.dragEnter() method # ElementHandle.dragEnter() method
This method creates a `dragenter` event on the element. > Warning: This API is now obsolete.
>
> Do not use. `dragenter` will automatically be performed during dragging.
#### Signature: #### Signature:

View File

@ -4,7 +4,9 @@ sidebar_label: ElementHandle.dragOver
# ElementHandle.dragOver() method # ElementHandle.dragOver() method
This method creates a `dragover` event on the element. > Warning: This API is now obsolete.
>
> Do not use. `dragover` will automatically be performed during dragging.
#### Signature: #### Signature:

View File

@ -4,7 +4,7 @@ sidebar_label: ElementHandle.drop
# ElementHandle.drop() method # ElementHandle.drop() method
This method triggers a drop on the element. Drops the given element onto the current one.
#### Signature: #### Signature:
@ -12,17 +12,17 @@ This method triggers a drop on the element.
class ElementHandle { class ElementHandle {
drop( drop(
this: ElementHandle<Element>, this: ElementHandle<Element>,
data?: Protocol.Input.DragData element: ElementHandle<Element>
): Promise<void>; ): Promise<void>;
} }
``` ```
## Parameters ## Parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ------------ | | --------- | ------------------------------------------------------------ | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | | | this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| data | Protocol.Input.DragData | _(Optional)_ | | element | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
**Returns:** **Returns:**

View File

@ -0,0 +1,31 @@
---
sidebar_label: ElementHandle.drop_1
---
# ElementHandle.drop() method
> Warning: This API is now obsolete.
>
> No longer supported.
#### Signature:
```typescript
class ElementHandle {
drop(
this: ElementHandle<Element>,
data?: Protocol.Input.DragData
): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ------------ |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| data | Protocol.Input.DragData | _(Optional)_ |
**Returns:**
Promise&lt;void&gt;

View File

@ -61,11 +61,12 @@ The constructor for this class is marked as internal. Third-party code should no
| [clickablePoint(offset)](./puppeteer.elementhandle.clickablepoint.md) | | Returns the middle point within an element unless a specific offset is provided. | | [clickablePoint(offset)](./puppeteer.elementhandle.clickablepoint.md) | | Returns the middle point within an element unless a specific offset is provided. |
| [contentFrame(this)](./puppeteer.elementhandle.contentframe.md) | | Resolves the frame associated with the element, if any. Always exists for HTMLIFrameElements. | | [contentFrame(this)](./puppeteer.elementhandle.contentframe.md) | | Resolves the frame associated with the element, if any. Always exists for HTMLIFrameElements. |
| [contentFrame()](./puppeteer.elementhandle.contentframe_1.md) | | | | [contentFrame()](./puppeteer.elementhandle.contentframe_1.md) | | |
| [drag(this, target)](./puppeteer.elementhandle.drag.md) | | This method creates and captures a dragevent from the element. | | [drag(this, target)](./puppeteer.elementhandle.drag.md) | | Drags an element over the given element or point. |
| [dragAndDrop(this, target, options)](./puppeteer.elementhandle.draganddrop.md) | | This method triggers a dragenter, dragover, and drop on the element. | | [dragAndDrop(this, target, options)](./puppeteer.elementhandle.draganddrop.md) | | |
| [dragEnter(this, data)](./puppeteer.elementhandle.dragenter.md) | | This method creates a <code>dragenter</code> event on the element. | | [dragEnter(this, data)](./puppeteer.elementhandle.dragenter.md) | | |
| [dragOver(this, data)](./puppeteer.elementhandle.dragover.md) | | This method creates a <code>dragover</code> event on the element. | | [dragOver(this, data)](./puppeteer.elementhandle.dragover.md) | | |
| [drop(this, data)](./puppeteer.elementhandle.drop.md) | | This method triggers a drop on the element. | | [drop(this, element)](./puppeteer.elementhandle.drop.md) | | Drops the given element onto the current one. |
| [drop(this, data)](./puppeteer.elementhandle.drop_1.md) | | |
| [focus()](./puppeteer.elementhandle.focus.md) | | Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element. | | [focus()](./puppeteer.elementhandle.focus.md) | | Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element. |
| [hover(this)](./puppeteer.elementhandle.hover.md) | | This method scrolls element into view if needed, and then uses [Page](./puppeteer.page.md) to hover over the center of the element. If the element is detached from DOM, the method throws an error. | | [hover(this)](./puppeteer.elementhandle.hover.md) | | This method scrolls element into view if needed, and then uses [Page](./puppeteer.page.md) to hover over the center of the element. If the element is detached from DOM, the method throws an error. |
| [isHidden()](./puppeteer.elementhandle.ishidden.md) | | Checks if an element is hidden using the same mechanism as [ElementHandle.waitForSelector()](./puppeteer.elementhandle.waitforselector.md). | | [isHidden()](./puppeteer.elementhandle.ishidden.md) | | Checks if an element is hidden using the same mechanism as [ElementHandle.waitForSelector()](./puppeteer.elementhandle.waitforselector.md). |

View File

@ -4,6 +4,10 @@ sidebar_label: Page.isDragInterceptionEnabled
# Page.isDragInterceptionEnabled() method # Page.isDragInterceptionEnabled() method
> Warning: This API is now obsolete.
>
> We no longer support intercepting drag payloads. Use the new drag APIs found on [ElementHandle](./puppeteer.elementhandle.md) to drag (or just use the [Page.mouse](./puppeteer.page.mouse.md)).
`true` if drag events are being intercepted, `false` otherwise. `true` if drag events are being intercepted, `false` otherwise.
#### Signature: #### Signature:

View File

@ -4,6 +4,10 @@ sidebar_label: Page.setDragInterception
# Page.setDragInterception() method # Page.setDragInterception() method
> Warning: This API is now obsolete.
>
> We no longer support intercepting drag payloads. Use the new drag APIs found on [ElementHandle](./puppeteer.elementhandle.md) to drag (or just use the [Page.mouse](./puppeteer.page.mouse.md)).
#### Signature: #### Signature:
```typescript ```typescript
@ -21,7 +25,3 @@ class Page {
**Returns:** **Returns:**
Promise&lt;void&gt; Promise&lt;void&gt;
## Remarks
Activating drag interception enables the `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.

View File

@ -31,6 +31,7 @@ import {KeyInput} from '../common/USKeyboardLayout.js';
import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js'; import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js';
import {assert} from '../util/assert.js'; import {assert} from '../util/assert.js';
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js'; import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
import {throwIfDisposed} from '../util/decorators.js';
import { import {
KeyboardTypeOptions, KeyboardTypeOptions,
@ -731,59 +732,134 @@ export abstract class ElementHandle<
} }
/** /**
* This method creates and captures a dragevent from the element. * Drags an element over the given element or point.
*
* @returns DEPRECATED. When drag interception is enabled, the drag payload is
* returned.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
async drag( async drag(
this: ElementHandle<Element>, this: ElementHandle<Element>,
target: Point target: Point | ElementHandle<Element>
): Promise<Protocol.Input.DragData>; ): Promise<Protocol.Input.DragData | void> {
async drag(this: ElementHandle<Element>): Promise<Protocol.Input.DragData> { await this.scrollIntoViewIfNeeded();
throw new Error('Not implemented'); const page = this.frame.page();
if (page.isDragInterceptionEnabled()) {
const source = await this.clickablePoint();
if (target instanceof ElementHandle) {
target = await target.clickablePoint();
}
return await page.mouse.drag(source, target);
}
try {
if (!page._isDragging) {
page._isDragging = true;
await this.hover();
await page.mouse.down();
}
if (target instanceof ElementHandle) {
await target.hover();
} else {
await page.mouse.move(target.x, target.y);
}
} catch (error) {
page._isDragging = false;
throw error;
}
} }
/** /**
* This method creates a `dragenter` event on the element. * @deprecated Do not use. `dragenter` will automatically be performed during dragging.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
async dragEnter( async dragEnter(
this: ElementHandle<Element>, this: ElementHandle<Element>,
data?: Protocol.Input.DragData data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void>; ): Promise<void> {
async dragEnter(this: ElementHandle<Element>): Promise<void> { const page = this.frame.page();
throw new Error('Not implemented'); await this.scrollIntoViewIfNeeded();
const target = await this.clickablePoint();
await page.mouse.dragEnter(target, data);
} }
/** /**
* This method creates a `dragover` event on the element. * @deprecated Do not use. `dragover` will automatically be performed during dragging.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
async dragOver( async dragOver(
this: ElementHandle<Element>, this: ElementHandle<Element>,
data?: Protocol.Input.DragData data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void>; ): Promise<void> {
async dragOver(this: ElementHandle<Element>): Promise<void> { const page = this.frame.page();
throw new Error('Not implemented'); await this.scrollIntoViewIfNeeded();
const target = await this.clickablePoint();
await page.mouse.dragOver(target, data);
} }
/** /**
* This method triggers a drop on the element. * Drops the given element onto the current one.
*/
async drop(
this: ElementHandle<Element>,
element: ElementHandle<Element>
): Promise<void>;
/**
* @deprecated No longer supported.
*/ */
async drop( async drop(
this: ElementHandle<Element>, this: ElementHandle<Element>,
data?: Protocol.Input.DragData data?: Protocol.Input.DragData
): Promise<void>; ): Promise<void>;
async drop(this: ElementHandle<Element>): Promise<void> {
throw new Error('Not implemented'); /**
* @internal
*/
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
async drop(
this: ElementHandle<Element>,
dataOrElement: ElementHandle<Element> | Protocol.Input.DragData = {
items: [],
dragOperationsMask: 1,
}
): Promise<void> {
const page = this.frame.page();
if ('items' in dataOrElement) {
await this.scrollIntoViewIfNeeded();
const destination = await this.clickablePoint();
await page.mouse.drop(destination, dataOrElement);
} else {
// Note if the rest errors, we still want dragging off because the errors
// is most likely something implying the mouse is no longer dragging.
await dataOrElement.drag(this);
page._isDragging = false;
await page.mouse.up();
}
} }
/** /**
* This method triggers a dragenter, dragover, and drop on the element. * @deprecated Use `ElementHandle.drop` instead.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
async dragAndDrop( async dragAndDrop(
this: ElementHandle<Element>, this: ElementHandle<Element>,
target: ElementHandle<Node>, target: ElementHandle<Node>,
options?: {delay: number} options?: {delay: number}
): Promise<void>; ): Promise<void> {
async dragAndDrop(this: ElementHandle<Element>): Promise<void> { const page = this.frame.page();
throw new Error('Not implemented'); assert(
page.isDragInterceptionEnabled(),
'Drag Interception is not enabled!'
);
await this.scrollIntoViewIfNeeded();
const startPoint = await this.clickablePoint();
const targetPoint = await target.clickablePoint();
await page.mouse.dragAndDrop(startPoint, targetPoint, options);
} }
/** /**

View File

@ -509,6 +509,11 @@ export abstract class Page
extends EventEmitter<PageEvents> extends EventEmitter<PageEvents>
implements AsyncDisposable, Disposable implements AsyncDisposable, Disposable
{ {
/**
* @internal
*/
_isDragging = false;
#requestHandlers = new WeakMap<Handler<HTTPRequest>, Handler<HTTPRequest>>(); #requestHandlers = new WeakMap<Handler<HTTPRequest>, Handler<HTTPRequest>>();
/** /**
@ -527,6 +532,10 @@ export abstract class Page
/** /**
* `true` if drag events are being intercepted, `false` otherwise. * `true` if drag events are being intercepted, `false` otherwise.
*
* @deprecated We no longer support intercepting drag payloads. Use the new
* drag APIs found on {@link ElementHandle} to drag (or just use the
* {@link Page.mouse}).
*/ */
isDragInterceptionEnabled(): boolean { isDragInterceptionEnabled(): boolean {
throw new Error('Not implemented'); throw new Error('Not implemented');
@ -791,10 +800,9 @@ export abstract class Page
/** /**
* @param enabled - Whether to enable drag interception. * @param enabled - Whether to enable drag interception.
* *
* @remarks * @deprecated We no longer support intercepting drag payloads. Use the new
* Activating drag interception enables the `Input.drag`, * drag APIs found on {@link ElementHandle} to drag (or just use the
* methods This provides the capability to capture drag events emitted * {@link Page.mouse}).
* on the page, which can then be used to simulate drag-and-drop.
*/ */
async setDragInterception(enabled: boolean): Promise<void>; async setDragInterception(enabled: boolean): Promise<void>;
async setDragInterception(): Promise<void> { async setDragInterception(): Promise<void> {

View File

@ -17,7 +17,7 @@
import {Protocol} from 'devtools-protocol'; import {Protocol} from 'devtools-protocol';
import {CDPSession} from '../api/CDPSession.js'; import {CDPSession} from '../api/CDPSession.js';
import {AutofillData, ElementHandle, Point} from '../api/ElementHandle.js'; import {AutofillData, ElementHandle} from '../api/ElementHandle.js';
import {Page, ScreenshotOptions} from '../api/Page.js'; import {Page, ScreenshotOptions} from '../api/Page.js';
import {assert} from '../util/assert.js'; import {assert} from '../util/assert.js';
import {throwIfDisposed} from '../util/decorators.js'; import {throwIfDisposed} from '../util/decorators.js';
@ -103,74 +103,6 @@ export class CdpElementHandle<
} }
} }
/**
* This method creates and captures a dragevent from the element.
*/
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
override async drag(
this: CdpElementHandle<Element>,
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);
}
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
override async dragEnter(
this: CdpElementHandle<Element>,
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> {
await this.scrollIntoViewIfNeeded();
const target = await this.clickablePoint();
await this.#page.mouse.dragEnter(target, data);
}
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
override async dragOver(
this: CdpElementHandle<Element>,
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> {
await this.scrollIntoViewIfNeeded();
const target = await this.clickablePoint();
await this.#page.mouse.dragOver(target, data);
}
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
override async drop(
this: CdpElementHandle<Element>,
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> {
await this.scrollIntoViewIfNeeded();
const destination = await this.clickablePoint();
await this.#page.mouse.drop(destination, data);
}
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle
override async dragAndDrop(
this: CdpElementHandle<Element>,
target: CdpElementHandle<Node>,
options?: {delay: number}
): Promise<void> {
assert(
this.#page.isDragInterceptionEnabled(),
'Drag Interception is not enabled!'
);
await this.scrollIntoViewIfNeeded();
const startPoint = await this.clickablePoint();
const targetPoint = await target.clickablePoint();
await this.#page.mouse.dragAndDrop(startPoint, targetPoint, options);
}
@throwIfDisposed() @throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
override async uploadFile( override async uploadFile(

View File

@ -702,6 +702,10 @@ export class BidiPage extends Page {
'default' in pptrFunction ? pptrFunction.default : pptrFunction 'default' in pptrFunction ? pptrFunction.default : pptrFunction
); );
} }
override isDragInterceptionEnabled(): boolean {
return false;
}
} }
function isConsoleLogEntry( function isConsoleLogEntry(

View File

@ -41,6 +41,24 @@
"parameters": ["webDriverBiDi"], "parameters": ["webDriverBiDi"],
"expectations": ["PASS"] "expectations": ["PASS"]
}, },
{
"testIdPattern": "[drag-and-drop.spec] *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[drag-and-drop.spec] *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[drag-and-drop.spec] Legacy Drag n' Drop *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["SKIP"]
},
{ {
"testIdPattern": "[elementhandle.spec] *", "testIdPattern": "[elementhandle.spec] *",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
@ -1691,6 +1709,12 @@
"parameters": ["cdp", "firefox"], "parameters": ["cdp", "firefox"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[drag-and-drop.spec] Drag n' Drop should drag and drop",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "chrome"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should handle nested frames", "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should handle nested frames",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],

View File

@ -13,24 +13,21 @@
<body> <body>
<div id="drag" draggable="true">drag me</div> <div id="drag" draggable="true">drag me</div>
<div id="drop"></div> <div id="drop"></div>
<div id="drag-state">0</div>
<script> <script>
window.didDragStart = false;
window.didDragEnter = false;
window.didDragOver = false;
window.didDrop = false;
const drag = document.getElementById('drag'); const drag = document.getElementById('drag');
const drop = document.getElementById('drop'); const drop = document.getElementById('drop');
drag.addEventListener('dragstart', function(event) { drag.addEventListener('dragstart', function(event) {
event.dataTransfer.setData('id', event.target.id); event.dataTransfer.setData('id', event.target.id);
window.didDragStart = true; document.getElementById('drag-state').textContent += '1';
}); });
drop.addEventListener('dragenter', function(event) { drop.addEventListener('dragenter', function(event) {
event.preventDefault(); event.preventDefault();
window.didDragEnter = true; document.getElementById('drag-state').textContent += '2';
}); });
drop.addEventListener('dragover', function(event) { drop.addEventListener('dragover', function(event) {
event.preventDefault(); event.preventDefault();
window.didDragOver = true; document.getElementById('drag-state').textContent += '3';
}); });
drop.addEventListener('drop', function(event) { drop.addEventListener('drop', function(event) {
event.preventDefault(); event.preventDefault();
@ -38,7 +35,7 @@
const el = document.getElementById(id); const el = document.getElementById(id);
if (el) { if (el) {
event.target.appendChild(el); event.target.appendChild(el);
window.didDrop = true; document.getElementById('drag-state').textContent += '4';
} }
}); });
</script> </script>

View File

@ -14,11 +14,23 @@
* limitations under the License. * limitations under the License.
*/ */
import assert from 'assert';
import expect from 'expect'; import expect from 'expect';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js'; import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Input.drag', function () { async function getDragState() {
const {page} = await getTestState({skipLaunch: true});
return parseInt(
await page.$eval('#drag-state', element => {
return element.innerHTML;
}),
10
);
}
describe("Legacy Drag n' Drop", function () {
setupTestBrowserHooks(); setupTestBrowserHooks();
it('should throw an exception if not enabled before usage', async () => { it('should throw an exception if not enabled before usage', async () => {
@ -45,12 +57,9 @@ describe('Input.drag', function () {
using draggable = (await page.$('#drag'))!; using draggable = (await page.$('#drag'))!;
const data = await draggable.drag({x: 1, y: 1}); const data = await draggable.drag({x: 1, y: 1});
assert(data instanceof Object);
expect(data.items).toHaveLength(1); expect(data.items).toHaveLength(1);
expect( expect(await getDragState()).toBe(1);
await page.evaluate(() => {
return (globalThis as any).didDragStart;
})
).toBe(true);
}); });
it('should emit a dragEnter', async () => { it('should emit a dragEnter', async () => {
const {page, server} = await getTestState(); const {page, server} = await getTestState();
@ -61,19 +70,11 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(true); expect(page.isDragInterceptionEnabled()).toBe(true);
using draggable = (await page.$('#drag'))!; using draggable = (await page.$('#drag'))!;
const data = await draggable.drag({x: 1, y: 1}); const data = await draggable.drag({x: 1, y: 1});
assert(data instanceof Object);
using dropzone = (await page.$('#drop'))!; using dropzone = (await page.$('#drop'))!;
await dropzone.dragEnter(data); await dropzone.dragEnter(data);
expect( expect(await getDragState()).toBe(12);
await page.evaluate(() => {
return (globalThis as any).didDragStart;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDragEnter;
})
).toBe(true);
}); });
it('should emit a dragOver event', async () => { it('should emit a dragOver event', async () => {
const {page, server} = await getTestState(); const {page, server} = await getTestState();
@ -84,25 +85,12 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(true); expect(page.isDragInterceptionEnabled()).toBe(true);
using draggable = (await page.$('#drag'))!; using draggable = (await page.$('#drag'))!;
const data = await draggable.drag({x: 1, y: 1}); const data = await draggable.drag({x: 1, y: 1});
assert(data instanceof Object);
using dropzone = (await page.$('#drop'))!; using dropzone = (await page.$('#drop'))!;
await dropzone.dragEnter(data); await dropzone.dragEnter(data);
await dropzone.dragOver(data); await dropzone.dragOver(data);
expect( expect(await getDragState()).toBe(123);
await page.evaluate(() => {
return (globalThis as any).didDragStart;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDragEnter;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDragOver;
})
).toBe(true);
}); });
it('can be dropped', async () => { it('can be dropped', async () => {
const {page, server} = await getTestState(); const {page, server} = await getTestState();
@ -114,30 +102,12 @@ describe('Input.drag', function () {
using draggable = (await page.$('#drag'))!; using draggable = (await page.$('#drag'))!;
using dropzone = (await page.$('#drop'))!; using dropzone = (await page.$('#drop'))!;
const data = await draggable.drag({x: 1, y: 1}); const data = await draggable.drag({x: 1, y: 1});
assert(data instanceof Object);
await dropzone.dragEnter(data); await dropzone.dragEnter(data);
await dropzone.dragOver(data); await dropzone.dragOver(data);
await dropzone.drop(data); await dropzone.drop(data);
expect( expect(await getDragState()).toBe(12334);
await page.evaluate(() => {
return (globalThis as any).didDragStart;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDragEnter;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDragOver;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDrop;
})
).toBe(true);
}); });
it('can be dragged and dropped with a single function', async () => { it('can be dragged and dropped with a single function', async () => {
const {page, server} = await getTestState(); const {page, server} = await getTestState();
@ -150,44 +120,59 @@ describe('Input.drag', function () {
using dropzone = (await page.$('#drop'))!; using dropzone = (await page.$('#drop'))!;
await draggable.dragAndDrop(dropzone); await draggable.dragAndDrop(dropzone);
expect( expect(await getDragState()).toBe(12334);
await page.evaluate(() => {
return (globalThis as any).didDragStart;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDragEnter;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDragOver;
})
).toBe(true);
expect(
await page.evaluate(() => {
return (globalThis as any).didDrop;
})
).toBe(true);
}); });
it('can be disabled', async () => { });
describe("Drag n' Drop", () => {
setupTestBrowserHooks();
it('should drop', async () => {
const {page, server} = await getTestState(); const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html'); await page.goto(server.PREFIX + '/input/drag-and-drop.html');
expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true);
using draggable = (await page.$('#drag'))!;
await draggable.drag({x: 1, y: 1});
await page.setDragInterception(false);
try { using draggable = await page.$('#drag');
await draggable.drag({x: 1, y: 1}); assert(draggable);
} catch (error) { using dropzone = await page.$('#drop');
expect((error as Error).message).toContain( assert(dropzone);
'Drag Interception is not enabled!'
); await dropzone.drop(draggable);
}
expect(await getDragState()).toBe(1234);
});
it('should drop using mouse', async () => {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
using draggable = await page.$('#drag');
assert(draggable);
using dropzone = await page.$('#drop');
assert(dropzone);
await draggable.hover();
await page.mouse.down();
await dropzone.hover();
expect(await getDragState()).toBe(123);
await page.mouse.up();
expect(await getDragState()).toBe(1234);
});
it('should drag and drop', async () => {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
using draggable = await page.$('#drag');
assert(draggable);
using dropzone = await page.$('#drop');
assert(dropzone);
await draggable.drag(dropzone);
await dropzone.drop(draggable);
expect(await getDragState()).toBe(1234);
}); });
}); });