or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assertions.mdconfiguration.mddevice-management.mdelement-interaction.mdelement-selection.mdindex.mdsynchronization.mdweb-view-testing.md
tile.json

web-view-testing.mddocs/

Web View Testing

Complete testing capabilities for hybrid applications with web view content, supporting both regular and secured web elements with DOM-based interactions and assertions.

Capabilities

Web View Selection

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'));

Web Element Interactions

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);

JavaScript Execution

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);

Web Element Selection

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');

Secured Web Elements (iOS Only)

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);

Web Element Assertions

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();

Multi-Element Selection

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();

Common Web View Patterns

Typical usage patterns for hybrid app testing.

Form Interactions

// 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();
}

Dynamic Content

// 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);
}

Single Page Application Navigation

// 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');
}

Error Handling

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);
}

Types

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;
}