chore: remove emulation from touchscreen tests (#11003)

This commit is contained in:
jrandolf 2023-10-06 11:08:44 +02:00 committed by GitHub
parent 12d7d7247f
commit 9c0c299f0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1863 additions and 1294 deletions

View File

@ -73,7 +73,7 @@ The constructor for this class is marked as internal. Third-party code should no
| [isIntersectingViewport(this, options)](./puppeteer.elementhandle.isintersectingviewport.md) | | Resolves to true if the element is visible in the current viewport. If an element is an SVG, we check if the svg owner element is in the viewport instead. See https://crbug.com/963246. |
| [isVisible()](./puppeteer.elementhandle.isvisible.md) | | Checks if an element is visible using the same mechanism as [ElementHandle.waitForSelector()](./puppeteer.elementhandle.waitforselector.md). |
| [press(key, options)](./puppeteer.elementhandle.press.md) | | Focuses the element, and then uses [Keyboard.down()](./puppeteer.keyboard.down.md) and [Keyboard.up()](./puppeteer.keyboard.up.md). |
| [screenshot(this, options)](./puppeteer.elementhandle.screenshot.md) | | This method scrolls element into view if needed, and then uses to take a screenshot of the element. If the element is detached from DOM, the method throws an error. |
| [screenshot(this, options)](./puppeteer.elementhandle.screenshot.md) | | This method scrolls element into view if needed, and then uses [Page.screenshot()](./puppeteer.page.screenshot_1.md) to take a screenshot of the element. If the element is detached from DOM, the method throws an error. |
| [scrollIntoView(this)](./puppeteer.elementhandle.scrollintoview.md) | | Scrolls the element into view using either the automation protocol client or by calling element.scrollIntoView. |
| [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. |

View File

@ -4,7 +4,7 @@ sidebar_label: ElementHandle.screenshot
# ElementHandle.screenshot() method
This method scrolls element into view if needed, and then uses to take a screenshot of the element. If the element is detached from DOM, the method throws an error.
This method scrolls element into view if needed, and then uses [Page.screenshot()](./puppeteer.page.screenshot_1.md) to take a screenshot of the element. If the element is detached from DOM, the method throws an error.
#### Signature:

View File

@ -9,7 +9,7 @@ The Touchscreen class exposes touchscreen events.
#### Signature:
```typescript
export declare class Touchscreen
export declare abstract class Touchscreen
```
## Remarks

View File

@ -10,7 +10,7 @@ Dispatches a `touchend` event.
```typescript
class Touchscreen {
touchEnd(): Promise<void>;
abstract touchEnd(): Promise<void>;
}
```

View File

@ -10,7 +10,7 @@ Dispatches a `touchMove` event.
```typescript
class Touchscreen {
touchMove(x: number, y: number): Promise<void>;
abstract touchMove(x: number, y: number): Promise<void>;
}
```

View File

@ -10,7 +10,7 @@ Dispatches a `touchstart` event.
```typescript
class Touchscreen {
touchStart(x: number, y: number): Promise<void>;
abstract touchStart(x: number, y: number): Promise<void>;
}
```

2651
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -141,7 +141,7 @@
"license": "Apache-2.0",
"dependencies": {
"@puppeteer/browsers": "1.7.1",
"chromium-bidi": "0.4.30",
"chromium-bidi": "0.4.31",
"cross-fetch": "4.0.0",
"debug": "4.3.4",
"devtools-protocol": "0.0.1179426",

View File

@ -974,8 +974,7 @@ export abstract class ElementHandle<
async tap(this: ElementHandle<Element>): Promise<void> {
await this.scrollIntoViewIfNeeded();
const {x, y} = await this.clickablePoint();
await this.frame.page().touchscreen.touchStart(x, y);
await this.frame.page().touchscreen.touchEnd();
await this.frame.page().touchscreen.tap(x, y);
}
@throwIfDisposed()
@ -1326,7 +1325,7 @@ export abstract class ElementHandle<
/**
* This method scrolls element into view if needed, and then uses
* {@link Page.(screenshot:3) } to take a screenshot of the element.
* {@link Page.(screenshot:2) } to take a screenshot of the element.
* If the element is detached from DOM, the method throws an error.
*/
@throwIfDisposed()

View File

@ -510,7 +510,7 @@ export class Mouse {
* The Touchscreen class exposes touchscreen events.
* @public
*/
export class Touchscreen {
export abstract class Touchscreen {
/**
* @internal
*/
@ -521,9 +521,9 @@ export class Touchscreen {
* @param x - Horizontal position of the tap.
* @param y - Vertical position of the tap.
*/
async tap(x: number, y: number): Promise<void>;
async tap(): Promise<void> {
throw new Error('Not implemented');
async tap(x: number, y: number): Promise<void> {
await this.touchStart(x, y);
await this.touchEnd();
}
/**
@ -531,10 +531,7 @@ export class Touchscreen {
* @param x - Horizontal position of the tap.
* @param y - Vertical position of the tap.
*/
async touchStart(x: number, y: number): Promise<void>;
async touchStart(): Promise<void> {
throw new Error('Not implemented');
}
abstract touchStart(x: number, y: number): Promise<void>;
/**
* Dispatches a `touchMove` event.
@ -548,16 +545,10 @@ export class Touchscreen {
* {@link https://developer.chrome.com/blog/a-more-compatible-smoother-touch/#chromes-new-model-the-throttled-async-touchmove-model | throttles}
* touch move events.
*/
async touchMove(x: number, y: number): Promise<void>;
async touchMove(): Promise<void> {
throw new Error('Not implemented');
}
abstract touchMove(x: number, y: number): Promise<void>;
/**
* Dispatches a `touchend` event.
*/
async touchEnd(): Promise<void>;
async touchEnd(): Promise<void> {
throw new Error('Not implemented');
}
abstract touchEnd(): Promise<void>;
}

View File

@ -640,15 +640,6 @@ export class BidiTouchscreen extends Touchscreen {
this.#context = context;
}
override async tap(
x: number,
y: number,
options: BidiTouchMoveOptions = {}
): Promise<void> {
await this.touchStart(x, y, options);
await this.touchEnd();
}
override async touchStart(
x: number,
y: number,

View File

@ -574,25 +574,32 @@ export class CdpTouchscreen extends Touchscreen {
this.#client = client;
}
override async tap(x: number, y: number): Promise<void> {
await this.touchStart(x, y);
await this.touchEnd();
}
override async touchStart(x: number, y: number): Promise<void> {
const touchPoints = [{x: Math.round(x), y: Math.round(y)}];
await this.#client.send('Input.dispatchTouchEvent', {
type: 'touchStart',
touchPoints,
touchPoints: [
{
x: Math.round(x),
y: Math.round(y),
radiusX: 0.5,
radiusY: 0.5,
},
],
modifiers: this.#keyboard._modifiers,
});
}
override 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,
touchPoints: [
{
x: Math.round(x),
y: Math.round(y),
radiusX: 0.5,
radiusY: 0.5,
},
],
modifiers: this.#keyboard._modifiers,
});
}

View File

@ -1259,6 +1259,12 @@
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL", "SKIP"]
},
{
"testIdPattern": "[touchscreen.spec] *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[tracing.spec] *",
"platforms": ["darwin", "linux", "win32"],
@ -3558,43 +3564,13 @@
"expectations": ["SKIP"]
},
{
"testIdPattern": "[target.spec] Target should report when a target url changes",
"testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.touchMove should work",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[touchscreen.spec] Touchscreen should report touches",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"parameters": ["cdp", "chrome"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[touchscreen.spec] Touchscreen should report touchMove",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["SKIP"]
},
{
"testIdPattern": "[touchscreen.spec] Touchscreen should report touchMove",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[touchscreen.spec] Touchscreen should tap the button",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[touchscreen.spec] Touchscreen should tap the button",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[tracing.spec] Tracing should throw if tracing on two pages",
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
@ -3605,12 +3581,6 @@
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive navigations",
"platforms": ["darwin", "linux", "win32"],
@ -3624,10 +3594,10 @@
"expectations": ["SKIP"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work when resolved right before execution context disposal",
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL", "PASS"]
"expectations": ["FAIL"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy",
@ -3636,7 +3606,7 @@
"expectations": ["FAIL"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy",
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
@ -3648,7 +3618,7 @@
"expectations": ["SKIP"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame",
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
@ -3659,35 +3629,23 @@
"parameters": ["cdp", "firefox"],
"expectations": ["SKIP"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["FAIL", "TIMEOUT"]
"expectations": ["TIMEOUT"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached",
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["SKIP"]
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached",
@ -3695,6 +3653,12 @@
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["SKIP"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should work with removed MutationObserver",
"platforms": ["darwin", "linux", "win32"],
@ -3713,12 +3677,6 @@
"parameters": ["cdp", "firefox"],
"expectations": ["SKIP"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should throw when frame is detached",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["PASS", "TIMEOUT"]
},
{
"testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should throw when frame is detached",
"platforms": ["darwin", "linux", "win32"],

View File

@ -1,65 +0,0 @@
<!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

@ -1,35 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Touch test</title>
</head>
<body>
<script src="mouse-helper.js"></script>
<button onclick="clicked();">Click target</button>
<script>
window.result = [];
const button = document.querySelector('button');
button.style.height = '200px';
button.style.width = '200px';
button.focus();
button.addEventListener('touchstart', event => {
log('Touchstart:', ...Array.from(event.changedTouches).map(touch => touch.identifier));
});
button.addEventListener('touchend', event => {
log('Touchend:', ...Array.from(event.changedTouches).map(touch => touch.identifier));
});
button.addEventListener('touchmove', event => {
log('Touchmove:', ...Array.from(event.changedTouches).map(touch => touch.identifier));
});
function log(...args) {
console.log.apply(console, args);
result.push(args.join(' '));
}
function getResult() {
let temp = result;
result = [];
return temp;
}
</script>
</body>
</html>

View File

@ -0,0 +1,122 @@
<!doctype html>
<html>
<head>
<title>Touch test</title>
</head>
<body>
<style>
button {
box-sizing: border-box;
position: absolute;
left: 0;
top: 0;
width: 10px;
height: 10px;
padding: 0;
margin: 0;
}
</style>
<button>Click target</button>
<script>
var allEvents = [];
globalThis.addEventListener(
"touchstart",
(event) => {
allEvents.push({
type: "touchstart",
touches: [...event.changedTouches].map((touch) => [
touch.clientX,
touch.clientY,
touch.radiusX,
touch.radiusY,
]),
});
},
true,
);
globalThis.addEventListener(
"touchmove",
(event) => {
allEvents.push({
type: "touchmove",
touches: [...event.changedTouches].map((touch) => [
touch.clientX,
touch.clientY,
touch.radiusX,
touch.radiusY,
]),
});
},
true,
);
globalThis.addEventListener(
"touchend",
(event) => {
allEvents.push({
type: "touchend",
touches: [...event.changedTouches].map((touch) => [
touch.clientX,
touch.clientY,
touch.radiusX,
touch.radiusY,
])
});
},
true,
);
globalThis.addEventListener(
"pointerdown",
(event) => {
allEvents.push({
type: "pointerdown",
x: event.x,
y: event.y,
width: event.width,
height: event.height,
});
},
true,
);
globalThis.addEventListener(
"pointermove",
(event) => {
allEvents.push({
type: "pointermove",
x: event.x,
y: event.y,
width: event.width,
height: event.height,
});
},
true,
);
globalThis.addEventListener(
"pointerup",
(event) => {
allEvents.push({
type: "pointerup",
x: event.x,
y: event.y,
width: event.width,
height: event.height,
});
},
true,
);
globalThis.addEventListener(
"click",
(event) => {
allEvents.push({
type: "click",
x: event.x,
y: event.y,
width: event.width,
height: event.height,
});
},
true,
);
</script>
</body>
</html>

View File

@ -15,61 +15,75 @@
*/
import expect from 'expect';
import {KnownDevices, type BoundingBox} from 'puppeteer';
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
describe('Touchscreen', function () {
declare const allEvents: Array<{type: string}>;
describe('Touchscreen', () => {
setupTestBrowserHooks();
it('should tap the button', async () => {
const {page, server} = await getTestState();
const iPhone = KnownDevices['iPhone 6']!;
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/button.html');
await page.tap('button');
expect(
await page.evaluate(() => {
return (globalThis as any).result;
})
).toBe('Clicked');
describe('Touchscreen.prototype.tap', () => {
it('should work', async () => {
const {page, server, isHeadless} = await getTestState();
await page.goto(server.PREFIX + '/input/touchscreen.html');
await page.tap('button');
expect(
(
await page.evaluate(() => {
return allEvents;
})
).filter(({type}) => {
return type !== 'pointermove' || isHeadless;
})
).toMatchObject([
{height: 1, type: 'pointerdown', width: 1, x: 5, y: 5},
{touches: [[5, 5, 0.5, 0.5]], type: 'touchstart'},
{height: 1, type: 'pointerup', width: 1, x: 5, y: 5},
{touches: [[5, 5, 0.5, 0.5]], type: 'touchend'},
{height: 1, type: 'click', width: 1, x: 5, y: 5},
]);
});
});
it('should report touches', async () => {
const {page, server} = await getTestState();
const iPhone = KnownDevices['iPhone 6']!;
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/touches.html');
using button = (await page.$('button'))!;
await button.tap();
expect(
await page.evaluate(() => {
return (globalThis as any).getResult();
})
).toEqual(['Touchstart: 0', 'Touchend: 0']);
});
describe('Touchscreen.prototype.touchMove', () => {
it('should work', async () => {
const {page, server, isHeadless} = await getTestState();
await page.goto(server.PREFIX + '/input/touchscreen.html');
it('should report touchMove', async () => {
const {page, server} = await getTestState();
const iPhone = KnownDevices['iPhone 6']!;
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/touches-move.html');
using 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);
await page.touchscreen.touchStart(0, 0);
await page.touchscreen.touchMove(10, 10);
await page.touchscreen.touchMove(15.5, 15);
await page.touchscreen.touchMove(20, 20.4);
await page.touchscreen.touchMove(40, 30);
await page.touchscreen.touchEnd();
expect(
(
await page.evaluate(() => {
return allEvents;
})
).filter(({type}) => {
return type !== 'pointermove' || isHeadless;
})
).toMatchObject(
[
{type: 'pointerdown', x: 0, y: 0, width: 1, height: 1},
{type: 'touchstart', touches: [[0, 0, 0.5, 0.5]]},
{type: 'pointermove', x: 10, y: 10, width: 1, height: 1},
{type: 'touchmove', touches: [[10, 10, 0.5, 0.5]]},
{type: 'pointermove', x: 16, y: 15, width: 1, height: 1},
{type: 'touchmove', touches: [[16, 15, 0.5, 0.5]]},
{type: 'pointermove', x: 20, y: 20, width: 1, height: 1},
{type: 'touchmove', touches: [[20, 20, 0.5, 0.5]]},
{type: 'pointermove', x: 40, y: 30, width: 1, height: 1},
{type: 'touchmove', touches: [[40, 30, 0.5, 0.5]]},
{type: 'pointerup', x: 40, y: 30, width: 1, height: 1},
{type: 'touchend', touches: [[40, 30, 0.5, 0.5]]},
].filter(({type}) => {
return type !== 'pointermove' || isHeadless;
})
);
});
});
});