Supported Playwright commands for iOS
Learn which Playwright commands are supported for iOS app automation on BrowserStack. Use our comprehensive list to build and run your tests successfully.
BrowserStack supports a wide range of Playwright commands for automating iOS applications. This page lists the available commands, along with a brief description of their functionality and usage.
Use this reference to quickly find supported actions and ensure your test scripts are compatible with BrowserStackβs iOS automation platform.
| Commands | Description |
|---|---|
| Commands supported from May 2025 | Β |
page.getByRole() |
Finds an element by ARIA role |
page.getByLabel() |
Finds an element by associated label |
page.waitForSelector() |
Returns an ElementHandle |
page.evaluate() |
Returns real values |
locator.innerText() |
Returns rendered text |
locator.getChecked() |
Returns checked status |
locator.elementHandle() |
Returns an element handle |
locator.blur() |
Blurs the element. Note: change event does not fire after input modification. The change event does not fire on blur after the input value was modified, which breaks form-validation patterns. Workaround: manually dispatch the change event after blur. |
page.$() |
Handles returned |
locator.filter() |
Filters locators |
locator.first() |
Gets the first matching element |
locator.last() |
Gets the last matching element |
locator.nth(index) |
Gets the element at specified index |
page.content() |
Returns the full page HTML content |
elementHandle.contentFrame() |
Returns the content frame |
locator.boundingBox() |
Returns bounding box coordinates |
page.screenshot() |
Takes a page screenshot (viewport, fullpage, or element) |
page.on('request') |
Listens for request events; does not emit for subresource requests (XHR, fetch, images) on iOS β only main-navigation requests fire |
page.on('response') |
Listens for response events |
page.on('requestfinished') |
Listens for request finished events |
page.on('requestfailed') |
Listens for request failed events |
page.on('dialog') |
Listens for dialog events |
route.fallback() |
Fallback route handling |
response.json() |
Parses response body as JSON |
response.buffer() |
Returns response body as Buffer |
response.text() |
Returns response body as text |
response.headers() |
Returns response headers |
response.body() |
Returns the response body |
response.failed() |
Checks if response failed |
response.headersArray() |
Returns response headers as an array of {name, value} objects |
response.securityDetails() |
Returns SSL/TLS security details for the response |
response.serverAddr() |
Returns the server IP address and port for the response |
response.timing() |
Returns response timing information |
response.ok() |
Checks if response status is OK (200-299) |
response.url() |
Returns the response URL |
response.status() |
Returns the HTTP status code |
page.clock.install() |
Installs fake clock for time-based testing. Note: setSystemTime does not fire pending timers. Not implemented: clock.fastForward, clock.runFor, clock.pauseAt, clock.resume, clock.setFixedTime. |
browserContext.clearCookies() |
Clears all cookies |
page.goto(url) |
Open a URL |
page.waitForNavigation() / page.waitForURL()
|
Wait for navigation to complete |
page.click(selector) |
Click an element |
page.locator(selector) |
Finds an element |
page.fill(selector, text) |
Enter text in an input field |
page.textContent(selector) |
Retrieve text content of an element |
page.title() |
Get the page title |
page.isClosed() |
Check if the page is closed |
page.context().addCookies(cookies) |
Add cookies for session handling |
PageAssertions.toHaveTitle() |
Validate the page title |
page.keyboard.press(key) |
Simulate a key press |
page.keyboard.type(text) |
Simulate typing |
page.reload() |
Reload the current page |
page.goBack() / page.goForward()
|
Navigate browser history |
page.focus(selector) |
Focus on an input field |
page.hover(selector) |
Hover over an element |
locator.click() |
Click on an element |
locator.fill() |
Fill a text field |
locator.getByText(text) |
Find an element by text content |
locator.getByTestId(testId) |
Find an element using test ID |
locator.waitFor() |
Wait for an element to be ready |
locator.getByPlaceholder(placeholderText) |
Find input fields by placeholder |
locator.getByAltText(altText) |
Find elements by alt text (useful for images) |
locator.getByTitle(title) |
Locate elements by title attribute |
locator.selectOption() |
Select a dropdown option |
locatorAssertions.toBeVisible() |
Ensure an element is visible |
context.addCookies() |
Add cookies for session persistence |
context.cookies() |
Retrieve current cookies |
context.clearCookies() |
Clear cookies |
Response.url() |
Get the URL of the response |
Response.status() |
Get the HTTP status code |
Response.request() |
Get the request object linked to a response |
Route.request().url() |
Get the intercepted request URL |
Route.request().method() |
Get the HTTP method (GET, POST, etc.) |
Route.request().resourceType() |
Get the resource type (document, script, etc.) |
| Commands supported from August 2025 | Β |
Browser.getVersion |
Β |
tap |
Β |
isHidden |
Β |
isVisible |
Β |
boundingBox |
Β |
isEnabled |
Β |
content |
Β |
waitForFunction |
Β |
| Commands supported from October 2025 | Β |
httpCredential |
Β |
ignoreHTTPSErrors |
Only false property value is supported by default |
| Commands supported from November 2025 | Β |
press |
Β |
check |
Β |
inputValue |
Β |
isChecked |
Β |
newContext |
Only one browser context per session is allowed |
newPage |
Only one page per session is allowed; a second newPage() returns "Only one browser session is allowed"
|
uncheck |
Β |
waitForTimeout |
Β |
| Commands supported from March 2026 | Β |
setExtraHTTPHeaders |
Β |
setNetworkInterceptionPatterns |
Β |
await page.addInitScript |
Β |
await page.goto(baseURL, { waitUntil: 'domcontentloaded' }); |
Β |
scrollIntoViewIfNeeded |
Β |
.toHaveText() |
Β |
toBeHidden() |
Β |
.toBeAttached() |
Β |
hover |
Β |
toBeEnabled() |
Β |
clear |
Β |
dblclick |
Β |
grant.permission |
Β |
httpCredentials |
Β |
contentFrame |
Β |
textContent |
Β |
setViewportSize |
Β |
fulfill |
Β |
continue |
Β |
abort |
Β |
setInputFiles |
Β |
addScriptTag |
Β |
addStyleTag |
Β |
getAttribute |
Β |
element.elementHandle() |
Β |
toBeFocus() |
Β |
toBeChecked() |
Β |
not.toBeFocus() |
Β |
not.toBeChecked() |
Β |
accept |
Β |
dismiss |
Β |
toContainText() |
Β |
toHaveAtttribute() |
Β |
toHaveCount() |
Β |
toBeDisabled() |
Β |
| Commands supported from June 2026 | Β |
locator.elementHandles() / page.$$()
|
Returns all matching element handles as an array. The following methods throw when called on a returned handle: hover(), focus(), type(), innerText(), selectOption(), isVisible(), isEnabled(), isHidden(). Use page.locator() instead. getAttribute() on a missing attribute throws instead of returning null as it does on desktop. Extra arguments to evaluate(fn, arg) are not forwarded. dispose() is a no-op. handle.$(selector) searches the whole document, not the handleβs subtree. Methods that work on a returned handle: click(), textContent(), getAttribute(), boundingBox(), evaluate(fn), and fill(). |
page.on('console') |
Listens for console messages emitted by the page. |
page.waitForEvent('response') |
Waits for the response event to fire. If the response is on an unsupported path, the client receives no error. |
response.serverAddr() |
Returns the server IP address and port for the response. Returns null for cached responses. The IP address may reflect the BrowserStack network hop rather than the origin server. |
expect(page).toHaveURL() |
Asserts that the page URL matches the expected value. ENG-documented limitations: the assertion may fail after cross-domain navigation and can hang under concurrent navigation. The predicate form requires Playwright client 1.51 or later. |
locator.ariaSnapshot() |
Returns an ARIA snapshot of the locatorβs subtree. The command cannot snapshot iframe elements. BrowserStack does not support expect(locator).toMatchAriaSnapshot(). Output format matches an older Playwright format, which may differ from newer baselines. |
browserContext.storageState() |
Reads the current storage state. Saving captures localStorage for the current origin, cookies for the current domain, and IndexedDB on a best-effort basis. Restoring state via newContext({ storageState }) restores localStorage only, not cookies. Using the saved state to persist and replay authentication cookies does not work. BrowserStack has not yet shipped cross-domain cookie restore. |
expect(locator).toHaveCSS() |
Asserts that a locator has the specified CSS property value. |
locator.count() |
Returns the number of elements matching the locator. Exotic or compound selectors may have edge cases due to selector translation. |
type(text, { delay }) |
Types text with a configurable delay between key presses. Delay timing is approximate on real devices. |
context.request.get() / context.request.post()
|
Makes HTTP GET or POST requests using the browser contextβs request API. The command accepts maxRetries without error, but the request executes once with no retry. |
browser.newContext({ timezoneId }) |
Sets the context timezone. Date, Intl.DateTimeFormat, and toLocaleString reflect the context timezone. |
| Commands supported from July 2026 | Β |
page.evaluateHandle() |
Executes JavaScript in the page and returns a handle to the result. elementHandle.evaluateHandle() called with an element argument returns null. Use page-level page.evaluateHandle() instead. |
jsHandle.jsonValue() |
Serializes the referenced JavaScript object to a JSON value. The value is cached once at serialization time. Re-reading after the page mutates the object returns the stale value. Calling ElementHandle.jsonValue() directly on a DOM node throws instead of returning null as it does on desktop. |
jsHandle.getProperty(propertyName) |
Returns the value of a named property from a JSHandle. The value is cached once at serialization time. Re-reading after the page mutates the object returns the stale value. |
page.touchscreen.tap(x, y) |
Taps at the specified coordinates on the touchscreen. The resulting click event has isTrusted: false. Handlers that check event.isTrusted === true receive false. Closed shadow DOM elements and cross-origin iframe elements donβt produce trusted events. |
locator.selectText() |
Selects the text content of the matched element. Selecting text does not focus the element. On iOS Safari, the visible highlight is only painted when the element is focused, so call .focus() before selectText() to make the selection visible. |
expect(page).toHaveScreenshot() / expect(page).toMatchSnapshot()
|
Asserts that the page matches a screenshot or snapshot baseline. page.screenshot({ fullPage: true }) works, but toHaveScreenshot({ fullPage: true }) is not supported. BrowserStack accepts omitBackground: true without error but silently ignores the transparent background on iOS. animations: 'disabled' and caret: 'hide' are CSS approximations, not native suppression. Known issue: on real iOS devices, screenshot capture may intermittently time out in long or screenshot-heavy sessions. A fix is in progress. |
page.waitForLoadState('networkidle') / page.goto(url, { waitUntil: 'networkidle' })
|
Waits until there are no active network connections for at least 500ms. frame.waitForLoadState('networkidle') reflects the whole-page network state, not the individual iframeβs. |
page.bringToFront() |
Resolves successfully but performs no action. Does not fire visibilitychange, framenavigated, or window.focus. iOS Safari tab UI is not scriptable from a web context. |
page.clock.setSystemTime(time) |
Jumps the fake clock to a specific time. Note: Does not fire pending timers. Date.parse, Date.UTC, new Date(0), and new Date(y, m, d, ...) pass through unpatched. |
page.setContent(html, options) |
Replaces the pageβs HTML content |
request.allHeaders() |
All request headers as sent on the wire, lower-cased. Note: Subresource requests (XHR, fetch, images) are unreachable; page.on('request') does not emit for them on iOS. |
request.headersArray() |
Request headers as an array; preserves casing and duplicates. Note: Subresource requests are unreachable on iOS. |
request.headerValue(name) |
Case-insensitive single-header lookup; null when absent. Note: Subresource requests are unreachable on iOS. |
| Commands supported from August 2026 | Β |
page.mouse.click(x, y) |
Clicks at the given viewport coordinates. Note: Right button fires contextmenu but not click. Middle button fires mousedown/mouseup only. Coordinate-based clicks do not trigger native CSS :hover. |
page.mouse.move(x, y) |
Moves the mouse pointer to the given viewport coordinates. Note: Coordinate-based moves do not trigger native CSS :hover. |
page.mouse.wheel(deltaX, deltaY) |
Dispatches a wheel event and scrolls the nearest scrollable ancestor. Note: Implemented as JavaScript .scrollBy(). No compositor-driven scrolling, no momentum, no inertia. If a listener calls preventDefault(), no scroll occurs. |
page.dispatchEvent(selector, type, eventInit) / locator.dispatchEvent()
|
Dispatches a DOM event on the matched element. Note: ElementHandle references work end-to-end; other JSHandles arrive as plain objects. |
locator.isDisabled() β also page., frame., elementHandle. forms |
Returns whether the element is disabled. Note: Returns false rather than throwing when selector matches nothing. <div disabled> is not disabled; only aria-disabled="true" marks a non-form element as disabled. |
locator.isEditable() β also page., frame., elementHandle. forms |
Returns whether the element is editable. Note: Returns false for a missing element instead of throwing. An enabled <select> is editable; a <button> is not. |
jsHandle.getProperties() / elementHandle.getProperties()
|
Returns a Map of own enumerable property names to handles. Note: Non-enumerable own properties are not returned. Circular references are not returned as usable values. |
page.$$eval(selector, fn, arg) / locator.evaluateAll(fn, arg) / elementHandle.$$eval()
|
Runs fn against all matching elements and returns the result. Note: arg must be a plain serializable value. Passing an ElementHandle or JSHandle, or an object with repeated or circular references, is rejected with error: "evalOnSelectorAll does not yet support arg values containing element/JS handles" or "evalOnSelectorAll does not yet support repeated or circular object references in arg". |
Supported command options
The following table lists command options and their support level on iOS.
| Handler | Option | Behavior on iOS |
|---|---|---|
locator.click |
force |
Accepted, but does not deliver on a blocked or covered element. |
locator.click |
trial |
Supported - runs actionability checks and performs zero clicks |
locator.click |
delay |
Supported - timing is approximate on real devices |
locator.click |
noWaitAfter |
Supported - click and subsequent navigation both work |
locator.click |
position |
Supported - honored exactly |
locator.click |
button |
Supported - right fires contextmenu, middle fires auxclick
|
locator.click with button and delay
|
Both options together | Not supported - button wins and delay is ignored |
locator.check |
force |
Accepted, but does not deliver on a blocked or covered element (same limitation as click) |
locator.check |
trial |
Blocked - returns an error |
locator.tap |
position |
Supported - honored exactly |
locator.tap |
force |
Accepted, but does not deliver on a blocked or covered element (same limitation as click) |
locator.hover |
force |
Supported - resolves on hidden elements, matching desktop behavior |
locator.selectOption |
force |
Accepted, but results in a silent no-op - the call resolves but the selected value is unchanged |
page.goto |
referer |
Supported |
page.reload |
waitUntil |
Supported with the exception: networkidle is aliased to load
|
page.goBack |
waitUntil |
Supported |
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
Thank you for your valuable feedback!