feat: add touchstart, touchmove and touchend methods (#9622)

This commit is contained in:
charlieinitialdigital 2023-02-03 18:59:21 +08:00 committed by GitHub
parent 6e226bcc22
commit c8bb11adfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 293 additions and 5 deletions

View File

@ -73,6 +73,9 @@ The constructor for this class is marked as internal. Third-party code should no
| [select(values)](./puppeteer.elementhandle.select.md) | | Triggers a <code>change</code> and <code>input</code> event once all the provided options have been selected. If there's no <code>&lt;select&gt;</code> element matching <code>selector</code>, the method throws an error. | | [select(values)](./puppeteer.elementhandle.select.md) | | Triggers a <code>change</code> and <code>input</code> event once all the provided options have been selected. If there's no <code>&lt;select&gt;</code> element matching <code>selector</code>, the method throws an error. |
| [tap(this)](./puppeteer.elementhandle.tap.md) | | This method scrolls element into view if needed, and then uses [Touchscreen.tap()](./puppeteer.touchscreen.tap.md) to tap in the center of the element. If the element is detached from DOM, the method throws an error. | | [tap(this)](./puppeteer.elementhandle.tap.md) | | This method scrolls element into view if needed, and then uses [Touchscreen.tap()](./puppeteer.touchscreen.tap.md) to tap in the center of the element. If the element is detached from DOM, the method throws an error. |
| [toElement(tagName)](./puppeteer.elementhandle.toelement.md) | | Converts the current handle to the given element type. | | [toElement(tagName)](./puppeteer.elementhandle.toelement.md) | | Converts the current handle to the given element type. |
| [touchEnd(this)](./puppeteer.elementhandle.touchend.md) | | |
| [touchMove(this)](./puppeteer.elementhandle.touchmove.md) | | |
| [touchStart(this)](./puppeteer.elementhandle.touchstart.md) | | |
| [type(text, options)](./puppeteer.elementhandle.type.md) | | <p>Focuses the element, and then sends a <code>keydown</code>, <code>keypress</code>/<code>input</code>, and <code>keyup</code> event for each character in the text.</p><p>To press a special key, like <code>Control</code> or <code>ArrowDown</code>, use [ElementHandle.press()](./puppeteer.elementhandle.press.md).</p> | | [type(text, options)](./puppeteer.elementhandle.type.md) | | <p>Focuses the element, and then sends a <code>keydown</code>, <code>keypress</code>/<code>input</code>, and <code>keyup</code> event for each character in the text.</p><p>To press a special key, like <code>Control</code> or <code>ArrowDown</code>, use [ElementHandle.press()](./puppeteer.elementhandle.press.md).</p> |
| [uploadFile(this, filePaths)](./puppeteer.elementhandle.uploadfile.md) | | This method expects <code>elementHandle</code> to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). | | [uploadFile(this, filePaths)](./puppeteer.elementhandle.uploadfile.md) | | This method expects <code>elementHandle</code> to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). |
| [waitForSelector(selector, options)](./puppeteer.elementhandle.waitforselector.md) | | <p>Wait for an element matching the given selector to appear in the current element.</p><p>Unlike [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md), this method does not work across navigations or if the element is detached from DOM.</p> | | [waitForSelector(selector, options)](./puppeteer.elementhandle.waitforselector.md) | | <p>Wait for an element matching the given selector to appear in the current element.</p><p>Unlike [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md), this method does not work across navigations or if the element is detached from DOM.</p> |

View File

@ -0,0 +1,23 @@
---
sidebar_label: ElementHandle.touchEnd
---
# ElementHandle.touchEnd() method
#### Signature:
```typescript
class ElementHandle {
touchEnd(this: ElementHandle<Element>): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
**Returns:**
Promise&lt;void&gt;

View File

@ -0,0 +1,23 @@
---
sidebar_label: ElementHandle.touchMove
---
# ElementHandle.touchMove() method
#### Signature:
```typescript
class ElementHandle {
touchMove(this: ElementHandle<Element>): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
**Returns:**
Promise&lt;void&gt;

View File

@ -0,0 +1,23 @@
---
sidebar_label: ElementHandle.touchStart
---
# ElementHandle.touchStart() method
#### Signature:
```typescript
class ElementHandle {
touchStart(this: ElementHandle<Element>): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
**Returns:**
Promise&lt;void&gt;

View File

@ -18,6 +18,9 @@ The constructor for this class is marked as internal. Third-party code should no
## Methods ## Methods
| Method | Modifiers | Description | | Method | Modifiers | Description |
| ------------------------------------------- | --------- | --------------------------------------------------------------------- | | --------------------------------------------------------- | --------- | --------------------------------------------------------------------- |
| [tap(x, y)](./puppeteer.touchscreen.tap.md) | | Dispatches a <code>touchstart</code> and <code>touchend</code> event. | | [tap(x, y)](./puppeteer.touchscreen.tap.md) | | Dispatches a <code>touchstart</code> and <code>touchend</code> event. |
| [touchEnd()](./puppeteer.touchscreen.touchend.md) | | Dispatches a <code>touchend</code> event. |
| [touchMove(x, y)](./puppeteer.touchscreen.touchmove.md) | | Dispatches a <code>touchMove</code> event. |
| [touchStart(x, y)](./puppeteer.touchscreen.touchstart.md) | | Dispatches a <code>touchstart</code> event. |

View File

@ -0,0 +1,19 @@
---
sidebar_label: Touchscreen.touchEnd
---
# Touchscreen.touchEnd() method
Dispatches a `touchend` event.
#### Signature:
```typescript
class Touchscreen {
touchEnd(): Promise<void>;
}
```
**Returns:**
Promise&lt;void&gt;

View File

@ -0,0 +1,26 @@
---
sidebar_label: Touchscreen.touchMove
---
# Touchscreen.touchMove() method
Dispatches a `touchMove` event.
#### Signature:
```typescript
class Touchscreen {
touchMove(x: number, y: number): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | -------------------------------- |
| x | number | Horizontal position of the move. |
| y | number | Vertical position of the move. |
**Returns:**
Promise&lt;void&gt;

View File

@ -0,0 +1,26 @@
---
sidebar_label: Touchscreen.touchStart
---
# Touchscreen.touchStart() method
Dispatches a `touchstart` event.
#### Signature:
```typescript
class Touchscreen {
touchStart(x: number, y: number): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | ------------------------------- |
| x | number | Horizontal position of the tap. |
| y | number | Vertical position of the tap. |
**Returns:**
Promise&lt;void&gt;

View File

@ -869,7 +869,25 @@ export class ElementHandle<
async tap(this: ElementHandle<Element>): Promise<void> { async tap(this: ElementHandle<Element>): Promise<void> {
await this.#scrollIntoViewIfNeeded(); await this.#scrollIntoViewIfNeeded();
const {x, y} = await this.clickablePoint(); const {x, y} = await this.clickablePoint();
await this.#page.touchscreen.tap(x, y); await this.#page.touchscreen.touchStart(x, y);
await this.#page.touchscreen.touchEnd();
}
async touchStart(this: ElementHandle<Element>): Promise<void> {
await this.#scrollIntoViewIfNeeded();
const {x, y} = await this.clickablePoint();
await this.#page.touchscreen.touchStart(x, y);
}
async touchMove(this: ElementHandle<Element>): Promise<void> {
await this.#scrollIntoViewIfNeeded();
const {x, y} = await this.clickablePoint();
await this.#page.touchscreen.touchMove(x, y);
}
async touchEnd(this: ElementHandle<Element>): Promise<void> {
await this.#scrollIntoViewIfNeeded();
await this.#page.touchscreen.touchEnd();
} }
/** /**

View File

@ -670,12 +670,40 @@ export class Touchscreen {
* @param y - Vertical position of the tap. * @param y - Vertical position of the tap.
*/ */
async tap(x: number, y: number): Promise<void> { async tap(x: number, y: number): Promise<void> {
await this.touchStart(x, y);
await this.touchEnd();
}
/**
* Dispatches a `touchstart` event.
* @param x - Horizontal position of the tap.
* @param y - Vertical position of the tap.
*/
async touchStart(x: number, y: number): Promise<void> {
const touchPoints = [{x: Math.round(x), y: Math.round(y)}]; const touchPoints = [{x: Math.round(x), y: Math.round(y)}];
await this.#client.send('Input.dispatchTouchEvent', { await this.#client.send('Input.dispatchTouchEvent', {
type: 'touchStart', type: 'touchStart',
touchPoints, touchPoints,
modifiers: this.#keyboard._modifiers, modifiers: this.#keyboard._modifiers,
}); });
}
/**
* Dispatches a `touchMove` event.
* @param x - Horizontal position of the move.
* @param y - Vertical position of the move.
*/
async touchMove(x: number, y: number): Promise<void> {
const movePoints = [{x: Math.round(x), y: Math.round(y)}];
await this.#client.send('Input.dispatchTouchEvent', {
type: 'touchMove',
touchPoints: movePoints,
modifiers: this.#keyboard._modifiers,
});
}
/**
* Dispatches a `touchend` event.
*/
async touchEnd(): Promise<void> {
await this.#client.send('Input.dispatchTouchEvent', { await this.#client.send('Input.dispatchTouchEvent', {
type: 'touchEnd', type: 'touchEnd',
touchPoints: [], touchPoints: [],

View File

@ -2975,6 +2975,12 @@
"parameters": ["firefox"], "parameters": ["firefox"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[touchscreen.spec] Touchscreen should report touchMove",
"platforms": ["linux"],
"parameters": ["firefox"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[tracing.spec]", "testIdPattern": "[tracing.spec]",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],

View File

@ -0,0 +1,65 @@
<!DOCTYPE html>
<html>
<head>
<title>Drag-and-drop test</title>
<style>
#drop {
width: 5em;
height: 5em;
border: 1px solid black;
position: absolute;
top: 30px;
left: 0px;
}
#drag {
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div id="touch" draggable="true">touch me</div>
<script>
window.result = [];
function log(...args) {
console.log.apply(console, args);
result.push(args.join(' '));
}
window.didTouchStart = false;
window.didDragEnter = false;
window.didTouchMove = false;
window.didTouchEnd = false;
const drag = document.getElementById('touch');
drag.addEventListener('touchstart', function (event) {
console.log("touchstart")
window.didTouchStart = true;
});
drag.addEventListener('touchmove', function (event) {
event.preventDefault();
log('Touchmove:', ...Array.from(event.changedTouches).map(touch => "x: "+ Math.round(touch.clientX) +" y: "+ Math.round(touch.clientY)));
window.didTouchMove = true;
var touchLocation = event.targetTouches[0];
var moveLoction = event.changedTouches[0];
drag.style.left = touchLocation.pageX + 'px';
drag.style.top = touchLocation.pageY + 'px';
});
drag.addEventListener('touchend', function (event) {
console.log("touch end")
log('Touchend:', ...Array.from(event.changedTouches).map(touch => touch.identifier));
if(Array.from(event.changedTouches).map((touch) => {
console.log("x: "+ Math.round(touch.clientX) +" y: "+ Math.round(touch.clientY))
window.touchX = touch.clientX;
window.touchY = touch.clientY;
}))
event.preventDefault();
window.didTouchEnd = true;
});
</script>
</body>
</html>

View File

@ -15,7 +15,7 @@
*/ */
import expect from 'expect'; import expect from 'expect';
import {KnownDevices} from 'puppeteer'; import {KnownDevices, BoundingBox} from 'puppeteer';
import { import {
getTestState, getTestState,
setupTestBrowserHooks, setupTestBrowserHooks,
@ -38,6 +38,7 @@ describe('Touchscreen', function () {
}) })
).toBe('Clicked'); ).toBe('Clicked');
}); });
it('should report touches', async () => { it('should report touches', async () => {
const {page, server} = getTestState(); const {page, server} = getTestState();
const iPhone = KnownDevices['iPhone 6']!; const iPhone = KnownDevices['iPhone 6']!;
@ -51,4 +52,28 @@ describe('Touchscreen', function () {
}) })
).toEqual(['Touchstart: 0', 'Touchend: 0']); ).toEqual(['Touchstart: 0', 'Touchend: 0']);
}); });
it('should report touchMove', async () => {
const {page, server} = getTestState();
const iPhone = KnownDevices['iPhone 6']!;
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/touches-move.html');
const touch = (await page.$('#touch'))!;
const touchObj = (await touch.boundingBox()) as BoundingBox;
await page.touchscreen.touchStart(touchObj.x, touchObj.y);
const movePosx = 100;
const movePosy = 100;
await page.touchscreen.touchMove(movePosx, movePosy);
await page.touchscreen.touchEnd();
expect(
await page.evaluate(() => {
return (globalThis as any).touchX;
})
).toBe(movePosx);
expect(
await page.evaluate(() => {
return (globalThis as any).touchY;
})
).toBe(movePosy);
});
}); });