Skip to content

Advanced

Master scripting, HTTP requests, coordinate operations, and other advanced features.


JavaScript Scripting: evalScript / runScript / shell

Execute JavaScript code within your flow to implement complex logic.

evalScript: Execute Expressions Directly

yaml
# Increment counter by 1
- evalScript: "${counter = counter + 1}"

# Concatenate strings
- evalScript: "${fullName = firstName + ' ' + lastName}"

# Define an array
- evalScript: "${items = ['apple', 'banana', 'orange']}"

# Randomly select an array element
- evalScript: "${selected = items[Math.floor(Math.random() * items.length)]}"

# Complex calculations
- evalScript: "${score = Math.floor(Math.random() * 100) + 1}"

runScript: Script with Variable Injection

yaml
- runScript:
    script: "result = a + b"
    env:
      a: "10"
      b: "20"
# After execution, result = 30

shell: Shorthand for evalScript

shell is functionally identical to evalScript, just shorter to write (note: this is not an OS command line -- it executes JavaScript):

yaml
- shell: "counter = counter + 1"

Differences Between evalScript, runScript, and shell

evalScriptrunScriptshell
SyntaxevalScript: "${expression}"runScript: { script: "...", env: {...} }shell: "script"
Variable injectionNot supportedSupports env injectionNot supported
Use caseSimple one-line expressionsScripts needing external variable injectionShorthand for evalScript

Built-in Available Objects

Standard JavaScript objects available in scripts:

yaml
# Math functions
- evalScript: "${x = Math.floor(Math.random() * 100)}"
- evalScript: "${y = Math.max(10, 20)}"
- evalScript: "${z = Math.pow(2, 8)}"

# String operations
- evalScript: "${upper = 'hello'.toUpperCase()}"
- evalScript: "${part = 'hello world'.substring(0, 5)}"
- evalScript: "${arr = 'a,b,c'.split(',')}"

# JSON operations
- evalScript: "${obj = JSON.parse('{\"name\":\"test\"}')}"
- evalScript: "${str = JSON.stringify(obj)}"

# Type checking
- evalScript: "${type = typeof counter}"

assertTrue: Verify Script Conditions

yaml
- assertTrue: "${counter > 0}"
- assertTrue: "${status == 'success'}"

Clipboard Operations

Note: The clipboard here is the engine's built-in clipboard, not the Android system clipboard.

Copy Text from an Element: copyTextFrom

yaml
- copyTextFrom:
    text: "Username"             # Copy the text content of the element displaying "Username"

After copying, the text is stored in the copiedText variable and can be referenced via ${copiedText}.

Paste: pasteText

yaml
- pasteText                      # Input the previously copied text

Manually Set Clipboard: setClipboard

yaml
- setClipboard: "Custom content"

- pasteText                      # Inputs "Custom content"

Complete Example: Copy and Use

yaml
- copyTextFrom: { id: "verification_code" }
- tapOn: "Verification code input"
- pasteText

Random Input

Generate random data and input it -- useful for testing scenarios.

Random Text

yaml
- inputRandomText                # 8 random letters (default)

- inputRandomText:
    length: 16                   # 16 random letters

Random Number

yaml
- inputRandomNumber:
    length: 6                    # 6 random digits, e.g., "483729"

Random Email

yaml
- inputRandomEmail               # Generates an email like john.doe@example.com

Random Person Name

yaml
- inputRandomPersonName           # Generates a random person name

HTTP Requests: httpRequest

Make HTTP requests within your flow to fetch external data.

All Parameters

ParameterTypeRequiredDefaultDescription
urlStringRequired--Request URL
methodStringOptionalGETHTTP method (GET, POST, etc.)
headersObjectOptional--Request header key-value pairs
bodyObjectOptional--Request body
outputVariableStringOptional--Variable name to store the response
jsonPathStringOptional--Path to extract from JSON response
retry.timesNumberOptional1Maximum retry count
retry.intervalNumber or ArrayOptional3000Retry interval (ms), supports [min, max] for random

GET Request

yaml
- httpRequest:
    url: "https://api.example.com/sms?phone=${PHONE}"
    outputVariable: code          # Store the result in the code variable
    jsonPath: "data.code"         # Extract the data.code field from JSON

POST Request

yaml
- httpRequest:
    url: "https://api.example.com/login"
    method: POST
    headers:
      Content-Type: "application/json"
      Authorization: "Bearer ${TOKEN}"
    body:
      phone: "${PHONE}"
      password: "${PASSWORD}"
    outputVariable: result
    jsonPath: "data.token"

Request with Retry

Some APIs may not return results immediately (e.g., waiting for an SMS verification code); you can enable automatic retries:

yaml
- httpRequest:
    url: "https://api.example.com/sms/latest?phone=${PHONE}"
    outputVariable: smsCode
    jsonPath: "data.code"
    retry:
      times: 10                   # Retry up to 10 times (default: 1)
      interval: [3000, 5000]      # 3~5 second interval between retries (default: 3000 ms)

Retry trigger condition: retries automatically when the jsonPath extraction result is empty or null.

Complete Example: Auto-fetch Verification Code

yaml
# 1. Request to send a verification code
- httpRequest:
    url: "https://api.example.com/sms/send"
    method: POST
    body:
      phone: "${PHONE}"

# 2. Wait a few seconds then query for the code
- sleep: 3000

# 3. Fetch the verification code (with retry)
- httpRequest:
    url: "https://api.example.com/sms/latest?phone=${PHONE}"
    outputVariable: code
    jsonPath: "data.code"
    retry:
      times: 5
      interval: [2000, 4000]

# 4. Enter the verification code
- inputText: "${code}"

Coordinate Taps

When elements cannot be located by text or ID, you can tap directly using coordinates.

Absolute Coordinates (Pixels)

yaml
- tapOn:
    point: "360,800"             # Tap at x=360, y=800

Percentage Coordinates (Screen Ratio)

yaml
- tapOn:
    point: "50%,80%"             # Tap at 50% of screen width, 80% of screen height

The advantage of percentage coordinates: they are independent of screen resolution and behave consistently across different devices.

Relative Coordinates Within an Element

Tap at a specific position within the element's bounds:

yaml
# Tap the slider at 25% position (toward the left)
- tapOn:
    text: "Volume"
    point: "25%,50%"             # 25% of element width, 50% of element height

Coordinate Swipe

yaml
- swipe:
    start: "100,800"
    end: "100,200"               # Swipe from (100,800) to (100,200)
    duration: 300

# Percentage coordinates
- swipe:
    start: "50%,80%"
    end: "50%,20%"
    duration: 400

Scrolling Within a Container

Scroll to find elements within a specific container, with the swipe range confined to the container's boundaries.

yaml
- scrollUntilVisible:
    element:
      text: "Target Product"
    from:                        # Scroll within this container
      id: "product_list"
    direction: UP
    timeout: "20000"

Retry: retry

Automatically retry when a group of commands may occasionally fail.

yaml
- retry:
    maxRetries: "2"              # Retry up to 2 times after failure (3 attempts total)
    commands:
      - tapOn: "Submit"
      - assertVisible: "Submission successful"

If tapOn or assertVisible fails, execution restarts from tapOn, with up to 2 more retries.

When maxRetries is not specified, the default is 1 (1 retry after failure, 2 total attempts).

Limits: maxRetries has a maximum value of 3. file and commands cannot be used together.


Device Control

Set GPS Location

yaml
- setLocation:
    latitude: "39.9042"          # Latitude (Beijing)
    longitude: "116.4074"        # Longitude

Airplane Mode

yaml
- setAirplaneMode:
    enabled: true                # Enable airplane mode

- setAirplaneMode:
    enabled: false               # Disable airplane mode

# Short form
- setAirplaneMode: true          # Enable
- setAirplaneMode: false         # Disable

Screenshot: takeScreenshot

yaml
- takeScreenshot: /tmp/screen.png

Saves a screenshot of the current screen to the specified path.


Wait for Animation to End

Wait for on-screen animations or transition effects to complete.

yaml
- waitForAnimationToEnd          # Default max wait: 15 seconds

- waitForAnimationToEnd:
    timeout: 5000                # Custom timeout: 5 seconds

Open a web page via URL, or jump directly to a specific page within an App using a deep link.

yaml
# Open a web page
- openLink: "https://example.com"

# Open an App deep link (jump directly to a specific page within the App)
- openLink:
    link: "myapp://settings/profile"
    autoVerify: true
    browser: false               # Don't open in a browser

Permission Settings: setPermissions

Set App permissions in bulk.

yaml
- setPermissions:
    appId: com.example.app
    permissions:
      android.permission.CAMERA: allow
      android.permission.LOCATION: allow
      android.permission.MICROPHONE: deny

Can also be set during launchApp:

yaml
- launchApp:
    appId: com.example.app
    permissions:
      android.permission.CAMERA: allow

Auto-execute on Flow Start/Complete: onFlowStart / onFlowComplete

Configure commands to execute automatically before the flow starts and after it ends.

yaml
appId: com.example.app
onFlowStart:
  - launchApp                    # Automatically launch the App before the flow starts
onFlowComplete:
  - stopApp                     # Automatically stop the App after the flow ends (regardless of success or failure)
---
- tapOn: "Login"
- inputText: "${PASSWORD}"
ConfigExecution TimingNotes
onFlowStartBefore command section executesUsed for initialization
onFlowCompleteAfter command section executesExecutes regardless of success or failure, used for cleanup

Advanced Practice: Automated Testing — E-commerce App Browse & Order

yaml
appId: com.example.shop
name: E-commerce App Automated Testing

---
# Pre-define test search keywords
- evalScript: "keywords = ['phone case', 'USB cable', 'earbuds', 'power bank', 'keyboard']"

- launchApp
- assertVisible: "Home"

# ── Phase 1: Browse product list ──
- repeat:
    duration: "30000"
    commands:
      - swipe:
          direction: UP
          duration: [200, 500]
          waitToSettleTimeoutMs: 0
      - sleep: [2000, 4000]

# ── Phase 2: Search and view product details ──
- tapOn: "Search"
- inputText: "${keywords[Math.floor(Math.random() * keywords.length)]}"
- pressKey: Enter
- sleep: 2000

- repeat:
    times: "3"
    commands:
      - swipe:
          direction: UP
          duration: [200, 500]
          waitToSettleTimeoutMs: 0
      - sleep: [2000, 4000]

      # 50% chance of viewing details
      - tapOn:
          text: "View Details"
          optional: true
          chance: 0.5

      - sleep: [1000, 3000]

      # Go back to list
      - back

# ── Phase 3: Simulate order flow ──
- runFlow:
    commands:
      - tapOn:
          text: "Add to Cart"
          optional: true
      - tapOn:
          text: "Cart"
          optional: true
      - assertVisible:
          text: "Checkout"
          optional: true
      - takeScreenshot: /tmp/cart_result.png

- stopApp

Need a quick command lookup? → Command Cheat Sheet

Powered by VMOS Edge Team