Complete testing capabilities for hybrid applications with web view content, supporting both regular and secured web elements with DOM-based interactions and assertions.
Target and interact with web views within mobile applications using native element matchers.
/**
* Access web view for DOM-based element interactions
* @param matcher - Optional native matcher for specific web view (required for multiple web views)
* @returns Web view interface for element selection
*/
function web(matcher?: NativeMatcher): WebViewElement;
interface WebViewElement {
/**
* Select web element within the web view using DOM selectors
* @param webMatcher - DOM-based selector for web element
* @returns Web element interface with interaction methods
*/
element<T extends WebMatcher>(webMatcher: T): MaybeSecuredWebElement<T>;
/**
* Select specific web view by index when multiple exist (iOS only)
* @param index - Zero-based index of web view
* @returns Web view element at specified index
*/
atIndex(index: number): WebViewElement;
}Usage Examples:
// Single web view (most common case)
const webElement = web().element(by.web.id('submit_button'));
// Specific web view in multi-web-view scenario
const specificWebView = web(by.id('main_webview'));
const webElement = specificWebView.element(by.web.className('action-button'));
// Select web view by index (iOS only)
const secondWebView = web().atIndex(1);
const webElement = secondWebView.element(by.web.tag('input'));Standard DOM element interactions adapted for mobile web view testing.
interface WebElement {
/**
* Tap web element
*/
tap(): Promise<void>;
/**
* Type text into web input element
* @param text - Text to type
* @param isContentEditable - Whether element is content-editable (ignored on iOS)
*/
typeText(text: string, isContentEditable?: boolean): Promise<void>;
/**
* Replace all text in web input element
* @param text - Replacement text
*/
replaceText(text: string): Promise<void>;
/**
* Clear text from web input element
*/
clearText(): Promise<void>;
/**
* Scroll web element into view
*/
scrollToView(): Promise<void>;
/**
* Get text content from web element
* @returns Current text content
*/
getText(): Promise<string>;
/**
* Set focus on web element
*/
focus(): Promise<void>;
/**
* Select all text in web input element (Android: content-editable only)
*/
selectAllText(): Promise<void>;
/**
* Move cursor to end of text in web input element (Android: content-editable only)
*/
moveCursorToEnd(): Promise<void>;
}Usage Examples:
// Basic web element interactions
await web().element(by.web.id('username')).typeText('john.doe@example.com');
await web().element(by.web.id('password')).typeText('secretpassword');
await web().element(by.web.className('submit-btn')).tap();
// Text manipulation
await web().element(by.web.name('email')).replaceText('new.email@example.com');
await web().element(by.web.id('search_input')).clearText();
// Advanced text operations
await web().element(by.web.id('editor')).focus();
await web().element(by.web.id('editor')).selectAllText();
await web().element(by.web.id('editor')).moveCursorToEnd();
// Scroll element into view
await web().element(by.web.id('footer_button')).scrollToView();
// Get element content
const currentText = await web().element(by.web.id('status_message')).getText();
console.log('Current status:', currentText);Execute custom JavaScript within web view context for advanced interactions and data retrieval.
/**
* Execute JavaScript function within web view context
* @param script - JavaScript function as string or function reference
* @param args - Optional arguments to pass to the script
* @returns Result of JavaScript execution
*/
function runScript(script: string, args?: unknown[]): Promise<any>;
function runScript<F>(script: (...args: any[]) => F, args?: unknown[]): Promise<F>;
/**
* Get current page URL from web view
* @returns Current page URL
*/
function getCurrentUrl(): Promise<string>;
/**
* Get current page title from web view
* @returns Current page title
*/
function getTitle(): Promise<string>;Usage Examples:
// Execute custom JavaScript
await web().element(by.web.id('custom_element')).runScript('element => element.click()');
// Execute with parameters
await web().element(by.web.id('input_field')).runScript(
'function setValue(element, value) { element.value = value; }',
['New Value']
);
// Execute with function reference
await web().element(by.web.id('canvas')).runScript(
function drawCircle(canvas, x, y, radius) {
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.stroke();
},
[100, 100, 50]
);
// Get page information
const currentUrl = await web().element(by.web.tag('body')).getCurrentUrl();
const pageTitle = await web().element(by.web.tag('body')).getTitle();
console.log('Page:', pageTitle, 'at', currentUrl);DOM-based element selection methods providing comprehensive targeting options.
/**
* Web element matchers for DOM-based selection
*/
interface ByWebFacade {
/** Select by DOM element ID */
id(id: string): WebMatcher;
/** Select by CSS class name */
className(className: string): WebMatcher;
/** Select by CSS selector */
cssSelector(cssSelector: string): WebMatcher;
/** Select by name attribute */
name(name: string): WebMatcher;
/** Select by XPath expression */
xpath(xpath: string): WebMatcher;
/** Select link by href attribute */
href(linkText: string): WebMatcher;
/** Select link by partial href match */
hrefContains(linkTextFragment: string): WebMatcher;
/** Select by HTML tag name */
tag(tagName: string): WebMatcher;
/** Select by element value (iOS only) */
value(value: string): WebMatcher;
/** Select by accessibility label (iOS only) */
label(text: string): MaybeSecuredWebMatcher;
/** Select secured element by type (iOS only) */
type(type: string): SecuredWebMatcher;
}Usage Examples:
// DOM ID selection
await web().element(by.web.id('login_form')).tap();
// CSS class selection
await web().element(by.web.className('primary-button')).tap();
// CSS selector selection
await web().element(by.web.cssSelector('input[type="email"]')).typeText('user@example.com');
await web().element(by.web.cssSelector('.modal .close-button')).tap();
// Name attribute selection
await web().element(by.web.name('username')).typeText('johndoe');
// XPath selection
await web().element(by.web.xpath('//button[@type="submit"]')).tap();
await web().element(by.web.xpath('//div[contains(@class, "error")]')).getText();
// Link selection
await web().element(by.web.href('https://example.com/terms')).tap();
await web().element(by.web.hrefContains('privacy')).tap();
// Tag selection
await web().element(by.web.tag('h1')).getText();
await web().element(by.web.tag('input')).typeText('search query');Enhanced security context for sensitive web interactions on iOS platform.
interface SecuredWebElement {
/**
* Tap secured web element (iOS only)
*/
tap(): Promise<void>;
/**
* Type text into secured web element (iOS only)
* @param text - Text to type
* @param isContentEditable - Whether element is content-editable
*/
typeText(text: string, isContentEditable: boolean): Promise<void>;
/**
* Replace text in secured web element (iOS only)
* @param text - Replacement text
*/
replaceText(text: string): Promise<void>;
/**
* Clear text from secured web element (iOS only)
*/
clearText(): Promise<void>;
}
interface MaybeSecuredWebMatcher {
/**
* Convert to secured web element (iOS only)
* @returns Secured web element interface
*/
asSecured(): IndexableSecuredWebElement;
}Usage Examples:
// iOS secured web elements
await web().element(by.web.label('Secure Login')).asSecured().tap();
await web().element(by.web.type('textField')).asSecured().typeText('password', false);
await web().element(by.web.type('secureTextField')).asSecured().replaceText('newpassword');
await web().element(by.web.type('textField')).asSecured().clearText();
// Multiple secured elements with index
await web().element(by.web.type('textField')).asSecured().atIndex(1).typeText('value', true);Validate web element states and content within web view context.
/**
* Web element assertion interface
*/
interface WebExpect {
/**
* Assert web element has specific text content
* @param text - Expected text content
*/
toHaveText(text: string): Promise<void>;
/**
* Assert web element exists in DOM tree
*/
toExist(): Promise<void>;
/**
* Negate web element assertion
*/
not: WebExpect;
}
/**
* Secured web element assertion interface (iOS only)
*/
interface SecuredWebExpect {
/**
* Assert secured web element exists in DOM tree (iOS only)
*/
toExist(): Promise<void>;
/**
* Negate secured web element assertion (iOS only)
*/
not: SecuredWebExpect;
}Usage Examples:
// Web element assertions
await expect(web().element(by.web.id('welcome_message'))).toHaveText('Welcome to our app!');
await expect(web().element(by.web.className('error-banner'))).toExist();
await expect(web().element(by.web.id('loading_spinner'))).not.toExist();
// Secured web element assertions (iOS only)
await expect(web().element(by.web.label('Secure Field')).asSecured()).toExist();
await expect(web().element(by.web.type('hiddenField')).asSecured()).not.toExist();Handle multiple matching web elements with indexing and iteration.
interface IndexableWebElement extends WebElement {
/**
* Select specific web element by index when multiple matches exist
* @param index - Zero-based index of element
* @returns Specific web element instance
*/
atIndex(index: number): WebElement;
}Usage Examples:
// Select specific element from multiple matches
await web().element(by.web.tag('button')).atIndex(0).tap(); // First button
await web().element(by.web.tag('button')).atIndex(2).tap(); // Third button
// Work with form inputs
await web().element(by.web.tag('input')).atIndex(0).typeText('username');
await web().element(by.web.tag('input')).atIndex(1).typeText('password');
// Select from list items
const itemText = await web().element(by.web.className('list-item')).atIndex(5).getText();Typical usage patterns for hybrid app testing.
// Complete form submission flow
async function fillAndSubmitForm() {
// Fill form fields
await web().element(by.web.name('email')).typeText('user@example.com');
await web().element(by.web.name('password')).typeText('securepassword');
await web().element(by.web.name('confirmPassword')).typeText('securepassword');
// Select dropdown option
await web().element(by.web.id('country_select')).tap();
await web().element(by.web.cssSelector('option[value="US"]')).tap();
// Check checkbox
await web().element(by.web.id('terms_checkbox')).tap();
// Submit form
await web().element(by.web.cssSelector('button[type="submit"]')).tap();
// Verify success
await expect(web().element(by.web.className('success-message'))).toExist();
}// Handle dynamic content loading
async function waitForDynamicContent() {
// Wait for initial load
await waitFor(web().element(by.web.id('content_container')))
.toExist()
.withTimeout(10000);
// Trigger more content
await web().element(by.web.id('load_more_button')).tap();
// Wait for new content
await waitFor(web().element(by.web.className('new-content')))
.toExist()
.withTimeout(15000);
}// Navigate SPA routes
async function navigateSPA() {
// Click navigation link
await web().element(by.web.href('/products')).tap();
// Wait for route change
await waitFor(web().element(by.web.id('products_page')))
.toExist()
.withTimeout(5000);
// Verify URL changed
const currentUrl = await web().element(by.web.tag('body')).getCurrentUrl();
expect(currentUrl).toContain('/products');
}Common error scenarios and resolution strategies for web view testing.
// Web view not ready
try {
await web().element(by.web.id('element')).tap();
} catch (error) {
// Wait for web view to load
await waitFor(element(by.type('WebView')))
.toBeVisible()
.withTimeout(10000);
// Retry interaction
await web().element(by.web.id('element')).tap();
}
// Element not found in DOM
try {
await web().element(by.web.id('missing_element')).tap();
} catch (error) {
// Check if element exists with different selector
const exists = await web().runScript('() => !!document.getElementById("missing_element")');
if (!exists) {
console.log('Element not found in DOM');
}
}
// JavaScript execution errors
try {
await web().element(by.web.id('element')).runScript('element => element.nonexistentMethod()');
} catch (error) {
console.log('JavaScript execution failed:', error.message);
}interface WebViewElement {
element<T extends WebMatcher>(webMatcher: T): MaybeSecuredWebElement<T>;
atIndex(index: number): WebViewElement;
}
interface WebElement {
tap(): Promise<void>;
typeText(text: string, isContentEditable?: boolean): Promise<void>;
replaceText(text: string): Promise<void>;
clearText(): Promise<void>;
scrollToView(): Promise<void>;
getText(): Promise<string>;
focus(): Promise<void>;
selectAllText(): Promise<void>;
moveCursorToEnd(): Promise<void>;
runScript(script: string | Function, args?: unknown[]): Promise<any>;
getCurrentUrl(): Promise<string>;
getTitle(): Promise<string>;
}
interface SecuredWebElement {
tap(): Promise<void>;
typeText(text: string, isContentEditable: boolean): Promise<void>;
replaceText(text: string): Promise<void>;
clearText(): Promise<void>;
}
interface WebMatcher {
__web__: any; // Internal marker
}
interface SecuredWebMatcher {
__web__: any; // Internal marker
}
interface MaybeSecuredWebMatcher {
__web__: any; // Internal marker
asSecured(): IndexableSecuredWebElement;
}