Skip to content

v0.7: exact per-test reporting, element screenshots, iOS goBack, faster polling - #11

Merged
jochen-testingbot merged 4 commits into
mainfrom
feat/v0.7-competitor-parity
Nov 10, 2026
Merged

jochen-testingbot merged 4 commits into
mainfrom
feat/v0.7-competitor-parity

Conversation

@jochen-testingbot

Copy link
Copy Markdown
Contributor

Brings the driver to parity with (and past) the Sauce Labs and TestMu.Ai mobilewright drivers. Every change was verified on TestingBot production using the new e2e/live.config.ts suite.

Changes

  • Exact per-test reporting. connect()/disconnect() run inside the test, so the driver reads Playwright's test.info() there instead of matching tests to sessions by timestamps afterwards.
    • sessionPerTest: each session is named describe › title (retry N) when it starts, and its verdict is reported when the test ends.
    • Pooled sessions fail if any test on them failed.
    • Each test in the Playwright report links to its TestingBot session.
    • Rotated sessions correct the fixture's device.model/device.osVersion annotations.
    • The timing-based matching remains as the fallback.
  • Element screenshots. locator.screenshot() is cropped to the element and screenshot({ scale }) downscales, using a dependency-free PNG crop/scale (src/png.ts).
  • screen.goBack() on iOS performs the system left-edge back swipe instead of throwing.
  • snapshotTuning (on by default) sets waitForIdleTimeout: 0, plus animationCoolOffTimeout: 0 on iOS, once per session.
  • visibility: 'bounds' option: elements count as visible based on their frame size, like local mobilecli.
  • allocationRetryDelay: "no device available" is retried with backoff while the run holds no session. mobilewright's pool only retries when one of its own slots is released.
  • Fix: iOS fill()/clearText() clear the focused field through GET /element/active + element clear. Previously fill('7') on a field holding 0 gave 70.

Verified on production

Check Result
Reporting (sessionPerTest, forced failure, retry) Sessions named per test (including (retry 1)); correct verdicts with Playwright's error messages
Reporting (pooled) 1 of 2 tests failed. reporting › fails on purpose: ExpectError …
Element screenshot Android 240×150 (exactly the element's bounds); iOS 250×124 for an 81×40pt element at 3.07×
iOS goBack() General → back in the Settings app
Fill + assert timing Android emulator 7.3s → 3.5s; iOS simulator 3.4s → 2.95s
Full live suite Real Android device (Mi 10, Galaxy S23/S25) in both visibility modes; Android emulator; iOS simulator in both modes

Unit/integration tests: 158 passing against protocol 0.0.53 and 0.0.68.

Known upstream (mobilewright 0.0.68) limitations, documented in the README

  • Mixed-platform hang: the pool never evicts an idle slot of the other platform, so mixed Android + iOS runs with 1 worker hang. The README advises running each platform as its own --project invocation.
  • iOS getText(): returns text ?? label ?? value, so a labelled iOS text field reports its label. Use toHaveValue.

CHANGELOG has the 0.7.0 entry (unreleased).

…iOS fill fix

- screenshot({ clip, scale }): crop to the element (points -> pixels via the
  screen scale) and downscale, with a dependency-free PNG transform. Falls
  back to the full screen for PNG formats Appium does not produce.
- pressButton('BACK') on iOS: left-edge swipe instead of throwing.
- snapshotTuning option: waitForIdleTimeout 0 (+ animationCoolOffTimeout 0 on
  iOS) via /appium/settings once per session. Measured on production:
  fill+assert 7.3s -> 3.5s on an Android emulator, 3.4s -> 2.95s on an iOS
  simulator.
- visibility: 'bounds' option for mobilecli-like isVisible.
- iOS clearText/fill: clear through GET /element/active + element clear.
  XCUITest's source has no focused attribute and RN fields put the caret at
  the start, so the backspace path never cleared anything.
connect()/disconnect() run inside the test (the device fixture is
test-scoped), so the driver reads Playwright's test.info() from the user's own
@playwright/test copy instead of reconstructing test<->session links from
wall-clock intervals afterwards.

- connect(): add a TestingBot session link annotation to the Playwright
  report; in sessionPerTest mode name the session after the test
  ("describe › title (retry N)") and correct the fixture's device.model /
  device.osVersion annotations for rotated sessions.
- disconnect(): record the attempt's outcome in the run log; in
  sessionPerTest mode push the verdict while the session is still alive.
- observer: sessions whose every span carries an outcome get an exact name
  and verdict (pooled sessions fail if any attempt on them failed); the
  timing heuristic remains the fallback when test.info() is unavailable.

Verified on production: per-test sessions named and judged correctly
including retries, pooled session reports "1 of 2 tests failed".
mobilewright's pool re-queues a NoDeviceAvailableError and only retries when
one of its own slots is released, so with an empty pool a fast hub rejection
(capacity, pinned device busy, plan limit) idled the test until its
allocation timeout. allocate() now retries with exponential backoff
(allocationRetryDelay, default 5s, capped at 30s) until the pool's signal
aborts; with a session held it still hands the error back to the pool.
e2e/live.config.ts runs against TestingBot's public sample app (no local
builds): hierarchy timing, fill + sum, element screenshots, iOS goBack in
Settings, and per-test reporting, with env toggles for sessionPerTest,
forced failures, retries, visibility and snapshot tuning.

README: exact reporting, new options, iOS BACK and element screenshots, and
the mixed-platform pool caveat. CHANGELOG: 0.7.0 (unreleased).
@jochen-testingbot
jochen-testingbot merged commit ae41907 into main Nov 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant