Build1 distinct publisher3 min readPublished
Stability on the app's end-to-end suite went from 50% to 98%. The reusable part is the guardrail rather than the computer vision. The wrapper hides Appium. A test cannot pause and hope. Every bypass is named UNSAFE_.
The Engineer · Build desk

build
Most flaky mobile tests are locator debt, and the fix sits upstream of the suite1 distinct publisher
build
Browser-native OCR swaps a five-week DPA queue for a 586 MB first load1 distinct publisher
build
Agent-written PRs move the bottleneck to whoever still has to read them1 distinct publisher
build
Deltix's iOS agent only pays off if the successful run survives as a regression test1 distinct publisher
Compiled by The EngineerSomething wrong?How this is made
The guardrail lives in the call signature. In the new builder a step cannot exist without an assertion attached: no tap, wait, or type without declaring what the screen should show afterward, so a run fails at the step where reality diverged instead of four actions later when something downstream breaks [11]. Waiting is no longer a separate action an author decides to perform. Under the old API it was, and `pause(1000)` was the cheapest way to perform it, seeming to work locally and usually passing in CI [6].
Bypasses still exist. Custom timeouts and script injection are reachable, prefixed `UNSAFE_`, and Shopify treats `UNSAFE_timeoutInSeconds` in a test as a signal for review [13]. The bad path stays available but gets renamed into something a reviewer has to defend, and that renaming is the entire enforcement model. Shopify's account describes no retry policy in either direction [21]; what it documents is the removal of an affordance.
One layer down, the assertion changed meaning. Old tests often checked that a node existed in the component tree rather than that a merchant could see or use it [7]. New ones screenshot each step and locate the target visually, with PaddleOCR reading text and OpenCV matching against SVGs from Shopify's Polaris design system [15]. The second half of that stack is the part that does not travel. Icon matching needs a first-party design system whose assets are the same SVGs the app renders; text matching needs screen copy stable enough to recognise. Shopify has both.
The headline pair reads harder as failures than as successes. Half stability means one run in two fails; 98% means one in 50, so the per-run failure rate went from 50 to 2, a factor of 25 [18]. That factor sits on an undefined denominator. The post does not say over what window, across how many runs, or whether stability is counted per test or per suite run [19]. The 50% baseline is also a property of one test corpus written against one old API on Shopify's largest app [3], not a measurement of Appium.
What got cheaper is unambiguous. Adding a step used to mean opening an inspector, drilling into the component tree to find or add a `testID`, then wiring it up; now it is `touch({ text: 'Save' })` against what is visible in the simulator [17]. Shopify also argues the small surface area and predictable grammar make humans and AI tools produce correct tests on the first try more often [14], which is a claim about authoring, not about stability.
The mechanism that couples every action to its assertion works without OCR and without a design system; it simply needs an API that offers no way to skip the wait [11].
Ranked by verification strength, evidence, and original report placement.
Shopify's account of the fix describes replacing the API surface and hiding Appium behind a wrapper, and does not mention a retry policy.
Shopify's mobile apps rely on a small layer of end-to-end tests at the top of the test pyramid, driving the real app the way a merchant would, running as blocking CI on every pull request.
The Shopify mobile app, its largest, reached the point where the E2E suite was blocking more good pull requests than bad ones, with tests going flaky because screens might take an extra second to load, and the suite was pulled from PR checks entirely.
Shopify reports hitting 98% test stability, up from 50% using the old API.
Since 2023 the Shopify app's E2E tests have run on Appium through WebdriverIO, using React Native Test IDs to find elements.
Appium gave Shopify low-level control but nothing enforced good testing patterns: after tapping one element, tests could immediately try to tap the next before the new screen had rendered, causing element not found failures.
Distinct publishers with included, body-backed reporting in this cluster.
1 article · September 4, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Detailed, first-party, unchecked
Every fact here traces to Shopify's own engineering blog, including both stability numbers. The technical specifics are concrete enough to argue with, since the post names PaddleOCR, OpenCV, the Polaris SVGs and the UNSAFE_ convention, but no one outside the team has run the suite, and the headline improvement is reported without run counts or a baseline methodology.
One app, inside one company
Use is real but narrow: the wrapper gates pull requests on the Shopify app and nothing else. Other Shopify apps are described as exploration, and the framework is not published or offered to anyone outside the company, so there is no third-party experience to weigh against the vendor's account.
The number leads, the cost is absent
A 50-to-98 improvement is a strong headline and it is honestly defined, but the post declines to price the design it advocates: a screenshot and a visual match on every step, with no run time and no CI bill reported. It also bundles two changes, the guardrails and the vision layer, so a reader cannot tell how much of the gain came simply from making pause(1000) unwritable.
Subject and publisher are the same team
This is Shopify's engineering brand writing about Shopify's engineering, the genre where an internal tool gets its most flattering account and the closing note is about expanding it. The candour about having to pull the suite from PR checks is real, and it also does useful work: an admission that specific buys credibility for the number that follows it.
Plausible mechanism, unaudited arithmetic
The causal story is easy to accept because it names the exact failure it removes, and forbidding fixed sleeps in a builder API is the kind of change whose effect a reader can reason about. Confidence stops short of high because the quantified part rests on two round percentages from one team's dashboard, with the run volume behind them undisclosed.