microsoft/playwright · error · Error
hasTouch must be enabled on the browser context before using
Error message
hasTouch must be enabled on the browser context before using the touchscreen.
What it means
Thrown by Touchscreen.apiTap() when the browser context was not created with hasTouch: true. This is the same constraint as Frame.tap() but enforced at the Touchscreen API level. The touchscreen object requires touch event emulation, which is a context-level option that cannot be toggled per-page or per-action.
Source
Thrown at packages/playwright-core/src/server/input.ts:372
return result;
}
export interface RawTouchscreen {
tap(progress: Progress, x: number, y: number, modifiers: Set<types.KeyboardModifier>): Promise<void>;
}
export class Touchscreen {
private _raw: RawTouchscreen;
private _page: Page;
constructor(raw: RawTouchscreen, page: Page) {
this._raw = raw;
this._page = page;
}
async apiTap(progress: Progress, x: number, y: number) {
if (!this._page.browserContext._options.hasTouch)
throw new Error('hasTouch must be enabled on the browser context before using the touchscreen.');
await this._page.instrumentation.onBeforeInputAction(progress, this._page, { x, y });
await this.tap(progress, x, y);
}
async tap(progress: Progress, x: number, y: number) {
await this._raw.tap(progress, x, y, this._page.keyboard._modifiers());
}
}
View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Create the browser context with hasTouch: true: const context = await browser.newContext({ hasTouch: true }).
- Use a device descriptor that includes hasTouch: const context = await browser.newContext({ ...devices['iPhone 13'] }).
- Use page.mouse.click(x, y) instead of page.touchscreen.tap(x, y) if touch emulation is not needed.
Example fix
// before
const context = await browser.newContext();
const page = await context.newPage();
await page.touchscreen.tap(100, 200); // throws [333]
// after
const context = await browser.newContext({ hasTouch: true });
const page = await context.newPage();
await page.touchscreen.tap(100, 200); Defensive patterns
Strategy: validation
Validate before calling
const context = await browser.newContext({ hasTouch: true });
// touchscreen.tap is now safe to use Type guard
function contextSupportsTouch(context: import('@playwright/test').BrowserContext): boolean {
return (context.options() as any).hasTouch === true;
} Prevention
- Create context with { hasTouch: true } before using touchscreen APIs.
- Use device descriptors that include hasTouch for mobile emulation.
- Use page.mouse.click() if touch emulation is not needed.
When it happens
Trigger: Calling page.touchscreen.tap(x, y) on a page whose context was created with default options (hasTouch is false). This is distinct from Frame.tap() in that it taps raw coordinates rather than a selector, but the underlying touch emulation requirement is identical.
Common situations: Test code accesses page.touchscreen directly for coordinate-based taps without enabling hasTouch on the context. Reusing a desktop context fixture for a test that calls touchscreen.tap(). Porting code from a mobile test suite to a shared context without updating context options.
Related errors
- The page does not support tap. Use hasTouch context option t
- Unknown button: ${button}
- Cannot set input files to detached input element
- Invalid timezone ID: ${timezoneId}
- No mapping for ${text[i]} found
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/2a141832d814c95d.
Report an issue: GitHub.