跳到主要内容

触摸事件 (旧版)

简介

处理旧版 触摸事件 以响应滑动、捏合和点击等手势的 Web 应用程序,可以通过手动调度 TouchEvent 到页面进行测试。以下示例演示了如何使用 locator.dispatchEvent() 并传递 Touch 点作为参数。

模拟平移手势

在下面的示例中,我们模拟了预计会移动地图的平移手势。被测应用程序仅使用触摸点的 clientX/clientY 坐标,因此我们仅初始化这些坐标。在更复杂的场景中,如果您的应用程序需要,您可能还需要设置 pageX/pageY/screenX/screenY

import { test, expect, devices, type Locator } from '@playwright/test';

test.use({ ...devices['Pixel 7'] });

async function pan(locator: Locator, deltaX?: number, deltaY?: number, steps?: number) {
const { centerX, centerY } = await locator.evaluate((target: HTMLElement) => {
const bounds = target.getBoundingClientRect();
const centerX = bounds.left + bounds.width / 2;
const centerY = bounds.top + bounds.height / 2;
return { centerX, centerY };
});

// Providing only clientX and clientY as the app only cares about those.
const touches = [{
identifier: 0,
clientX: centerX,
clientY: centerY,
}];
await locator.dispatchEvent('touchstart',
{ touches, changedTouches: touches, targetTouches: touches });

steps = steps ?? 5;
deltaX = deltaX ?? 0;
deltaY = deltaY ?? 0;
for (let i = 1; i <= steps; i++) {
const touches = [{
identifier: 0,
clientX: centerX + deltaX * i / steps,
clientY: centerY + deltaY * i / steps,
}];
await locator.dispatchEvent('touchmove',
{ touches, changedTouches: touches, targetTouches: touches });
}

await locator.dispatchEvent('touchend');
}

test(`pan gesture to move the map`, async ({ page }) => {
await page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z',
{ waitUntil: 'commit' });
await page.getByRole('button', { name: 'Keep using web' }).click();
await expect(page.getByRole('button', { name: 'Keep using web' })).not.toBeVisible();
// Get the map element.
const met = page.locator('[data-test-id="met"]');
for (let i = 0; i < 5; i++)
await pan(met, 200, 100);
// Ensure the map has been moved.
await expect(met).toHaveScreenshot();
});

模拟捏合手势

在下面的示例中,我们模拟捏合手势,即两个触摸点相互靠近。预计会缩小地图。被测应用程序仅使用触摸点的 clientX/clientY 坐标,因此我们仅初始化这些坐标。在更复杂的场景中,如果您的应用程序需要,您可能还需要设置 pageX/pageY/screenX/screenY

import { test, expect, devices, type Locator } from '@playwright/test';

test.use({ ...devices['Pixel 7'] });

async function pinch(locator: Locator,
arg: { deltaX?: number, deltaY?: number, steps?: number, direction?: 'in' | 'out' }) {
const { centerX, centerY } = await locator.evaluate((target: HTMLElement) => {
const bounds = target.getBoundingClientRect();
const centerX = bounds.left + bounds.width / 2;
const centerY = bounds.top + bounds.height / 2;
return { centerX, centerY };
});

const deltaX = arg.deltaX ?? 50;
const steps = arg.steps ?? 5;
const stepDeltaX = deltaX / (steps + 1);

// Two touch points equally distant from the center of the element.
const touches = [
{
identifier: 0,
clientX: centerX - (arg.direction === 'in' ? deltaX : stepDeltaX),
clientY: centerY,
},
{
identifier: 1,
clientX: centerX + (arg.direction === 'in' ? deltaX : stepDeltaX),
clientY: centerY,
},
];
await locator.dispatchEvent('touchstart',
{ touches, changedTouches: touches, targetTouches: touches });

// Move the touch points towards or away from each other.
for (let i = 1; i <= steps; i++) {
const offset = (arg.direction === 'in' ? (deltaX - i * stepDeltaX) : (stepDeltaX * (i + 1)));
const touches = [
{
identifier: 0,
clientX: centerX - offset,
clientY: centerY,
},
{
identifier: 0,
clientX: centerX + offset,
clientY: centerY,
},
];
await locator.dispatchEvent('touchmove',
{ touches, changedTouches: touches, targetTouches: touches });
}

await locator.dispatchEvent('touchend', { touches: [], changedTouches: [], targetTouches: [] });
}

test(`pinch in gesture to zoom out the map`, async ({ page }) => {
await page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z',
{ waitUntil: 'commit' });
await page.getByRole('button', { name: 'Keep using web' }).click();
await expect(page.getByRole('button', { name: 'Keep using web' })).not.toBeVisible();
// Get the map element.
const met = page.locator('[data-test-id="met"]');
for (let i = 0; i < 5; i++)
await pinch(met, { deltaX: 40, direction: 'in' });
// Ensure the map has been zoomed out.
await expect(met).toHaveScreenshot();
});