LogoLogo
🚀 Run Maestro tests in the cloud →
  • Home
  • Star us on GitHub
  • Getting Started
    • What is Maestro?
    • Installing Maestro
      • macOS
      • Windows
      • Linux
    • Build and Install your App
      • Android
      • iOS
    • Run a Sample Flow
    • Writing Your First Flow
    • Maestro Studio
    • Running Flows on CI
  • Cloud
    • Run Maestro tests in the cloud
    • Cloud Quickstart
    • CI Integration
      • GitHub Actions
        • Maestro GitHub Action for Android
        • Maestro GitHub Action for iOS
        • Maestro GitHub Action for Flutter
      • Bitrise
      • Bitbucket Pipelines
      • CircleCI
      • Integration with any CI platform
    • Pull Request Integration
    • Cloud Reference
      • Build your app for the cloud
      • Configuring OS Version
      • Configuring device locale
      • Device timezones
      • Email Notifications
      • Slack Notifications
      • Webhook Integration
      • Managing Secrets
      • Limits
      • Reusing App Binary
      • IP Allowlist
      • System Status
  • Platform Support
    • Supported Platforms
    • Android - Views
    • Android - Jetpack Compose
    • iOS - UIKit
    • iOS - SwiftUI
    • React Native
    • Flutter
    • Web Views
    • Web (Desktop Browser)
  • Examples
    • Android contacts flow automation
    • Facebook signup flow automation
    • Advanced: Wikipedia Android
    • Page Object Model
  • CLI
    • Cloud
    • Test Suites & Reports
    • Tags
    • Record Your Flow
    • Continuous Mode
    • View Hierarchy
    • Start Device
  • API Reference
    • Commands
      • addMedia
      • assertVisible
      • assertNotVisible
      • assertTrue
      • assertWithAI
      • assertNoDefectsWithAi
      • back
      • clearKeychain
      • clearState
      • copyTextFrom
      • evalScript
      • eraseText
      • extendedWaitUntil
      • extractTextWithAI
      • hideKeyboard
      • inputText
      • killApp
      • launchApp
      • openLink
      • pressKey
      • pasteText
      • repeat
      • retry
      • runFlow
      • runScript
      • scroll
      • scrollUntilVisible
      • setAirplaneMode
      • setLocation
      • startRecording
      • stopApp
      • stopRecording
      • swipe
      • takeScreenshot
      • toggleAirplaneMode
      • tapOn
      • doubleTapOn
      • longPressOn
      • travel
      • waitForAnimationToEnd
    • Common command arguments
    • Selectors
    • Configuration
      • Workspace configuration
      • Flow configuration
      • AI configuration
  • Advanced
    • Nested Flows
    • Wait
    • Loops
    • Conditions
    • Parameters & Constants
    • JavaScript
      • Run JavaScript
      • Outputs
      • Logging
      • Access element text
      • Make HTTP requests
      • GraalJS support
      • JavaScript announcement blog
    • Specify a Device
    • Configure Permissions
    • Detect Maestro in your app
    • Configure Maestro driver timeout
    • onFlowStart / onFlowComplete hooks
    • Test in different locales
    • Structuring your test suite
  • Troubleshooting
    • Known Issues
    • Frequently Asked Questions
    • Bug Report
    • Rollback Maestro
    • Debug Output
    • HOWTOs
      • Arrange your repository for Maestro tests
      • scrollUntilVisible for fragments
  • Community
    • Contributions
    • Articles & Tutorials
    • Case Studies
    • Resources
Powered by GitBook

Read to wire into CI or scale up your testing?

  • Run Maestro tests in the cloud →
On this page
  • Content
  • Introduction
  • Login Page example
  • login.js
  • Nested example
  • cards.js
  • How to structure and tips
  • Folder structure example
  • Ensuring all elements are loaded
  • Cross-platform example

Was this helpful?

Edit on GitHub
  1. Examples

Page Object Model

A guide to implementing Page Object Model within Maestro

PreviousAdvanced: Wikipedia AndroidNextCloud

Last updated 5 months ago

Was this helpful?

Content

Introduction

Implementating a Page Object Model has many benefits:

  • Improved readability, abstraction and grouping

  • Reducing unnecessary duplication

  • Improving test/flow maintenance

It allows you to update an element in one place which will then cascade throughout all of your tests/flows. This can save a lot of time when elements are modified and also assist in easier debugging of issues.

Login Page example

login.js

// login.js
output.login = {
    email: 'email_text',
    password: 'password_text',
    loginBtn: 'loginButton',
    registerBtn: 'registerButton'
}

You can then use these variables to reference element IDs, text or even other test data:

- runScript: login.js
- tapOn:
    id: ${output.login.email}
- inputText: "simon@maestro.com"
- tapOn:
    id: ${output.login.password}
- inputText: ${PASSWORD}
- tapOn:
    id: ${output.login.loginBtn}

Nested example

cards.js

// cards.js
output.cards = {
    cardName: 'card_title',
    cardImage: 'card',

    // All Cards Screen
    allCards: {
	createNewBtn: 'btnyam_create',
	cardImage: 'card_image',
	cardName: 'card_title'
    },

    // Virtual Cards
    virtualCards: {
	createNewBtn: 'btn_create',
	cardDetails: {
	    cardNumber: 'card_number',
   	    expiryDate: 'card_expiry'
	}
    }
}

You can create nested element structures to better separate/organise screens and flows. Using the example below, it's easy to define a separate structure for Virtual Cards within the overall Cards object. You could then use them in your flows as follows:

- runScript: cards.js
- tapOn:
    id: ${output.cards.virtualCards.createNewBtn}
- assertVisible:
    id: ${output.cards.virtualCards.cardDetails.cardNumber}

How to structure and tips

Folder structure example

Creating an elements folder is good practice as it allows you to keep all of your element files together.

android/
    cards/
    elements/
	cards.js
	help.js
	home.js
	loadElements.yaml
	login.js
	nav.js
    home/
    login/
iOS/
    cards/
    elements/
	cards.js
	help.js
	home.js
	loadElements.yaml
	login.js
	nav.js
    home/
    login/

Ensuring all elements are loaded

Once you begin creating numerous js files to cover all of your app screens and elements, it can become tricky to remember if you've included the right ones at the start of your test, especially if your flow is crossing multiple areas. A nice trick is to simply add your runScript command once to a single common flow, and then you can run that parent flow once at the start of all your other flows to ensure all of your screens and elements are loaded in correctly.

loadElements.yaml

# loadElements.yaml
appId: com.appid
---
- runScript: cards.js
- runScript: home.js
- runScript: login.js
- runScript: nav.js
- runScript: tabBar.js

Usage:

flow.yaml

appId: com.appID
---
- runFlow: elements/loadElements.yaml
- launchApp
// Test Steps

Cross-platform example

If you have the same app across both Android and iOS but the elements have different IDs, you can employ runFlow with a platform conditional to load in the correct elements.

- runFlow:
    when:
        platform: Android
    commands:
        - runScript:
            file: android_elements/login.js
- runFlow:
    when:
	platform: iOS
    commands:
	- runScript:
	    file: iOS_elements/login.js
Introduction
Login Page example
login.js
Nested example
cards.js
How to structure and tips
Folder structure example
Ensuring all elements are loaded
loadElements.yaml
flow.yaml
Cross-platform example