Q22 of 26 · Mobile QA

How do you design and implement a screen object model for a mobile Appium framework?

Mobile QASeniormobilescreen-objectpage-objectframework-designappiumarchitecture

Short answer

Short answer: Mirror the Page Object Model — each app screen is a class encapsulating its locators and user-facing actions. Action methods return screen objects (fluent interface) to enable chaining. A base class holds the driver reference and shared wait utilities.

Detail

The screen object model for mobile has the same benefits as POM for web — locators are centralised, tests read like user journeys, and locator changes require one edit. The mobile-specific considerations:

Base class responsibilities: driver reference, platform getter (iOS | Android), waitForScreen() which waits for the unique element that identifies this screen, shared scroll/swipe helpers.

Screen class structure:

class ProductScreen extends BaseScreen {
  private get addToCartBtn() {
    return this.platform === 'iOS'
      ? $('~Add to cart')
      : $('~add-to-cart-button');
  }

  async addToCart(): Promise<CartScreen> {
    await this.addToCartBtn.waitForDisplayed();
    await this.addToCartBtn.click();
    return new CartScreen(this.driver);
  }
}

Factory for session setup: a session factory reads the platform from environment config and creates the correct driver with the correct capabilities. Tests import from the factory, never create drivers directly.

Shared components: navigation bars, tab bars, and modal sheets appear across screens. Model them as separate component objects imported by the screens that use them — avoids duplicating locators for the bottom tab bar across every screen class.

What NOT to put in screen objects: assertions. Screen objects expose the state; tests do the asserting. Mixing them couples test intent with implementation — if the assertion belongs in the test, the test should own it.

// EXAMPLE

LoginScreen.ts

import { BaseScreen } from './BaseScreen';
import { HomeScreen } from './HomeScreen';

export class LoginScreen extends BaseScreen {
  private get emailField() { return $('~email-input'); }
  private get passwordField() { return $('~password-input'); }
  private get signInButton() { return $('~sign-in-button'); }

  async signIn(email: string, password: string): Promise<HomeScreen> {
    await this.emailField.setValue(email);
    await this.passwordField.setValue(password);
    await this.signInButton.click();
    return new HomeScreen(this.driver);
  }
}

// WHAT INTERVIEWERS LOOK FOR

Fluent return types, locator encapsulation, platform switch in the screen object not in the test, and separation of assertions from screen object methods.