CircleCI β
How the new e2e suite (e2e/ β the wdio/Appium rebuild) runs on CircleCI. This page covers the pipeline parameters, the workflows they fire, and how the build, OTA, and Expo channel are resolved at run time.
Overview β
Every new-suite run on CircleCI is driven by five pipeline parameters. They compose orthogonally, so a small set of values covers the full matrix of "what suite, on what platform, against which backend, with or without an OTA, against which build".
| Parameter | Type | Default | Purpose |
|---|---|---|---|
suite | enum | regression | wdio suite to run (e.g. regression, login, push-notifications). |
platform | enum | '' | android, ios, or both. Empty = no e2e workflow fires (default build runs). |
environment | enum | QA | Backend selector: QA, UAT, PROD, REVIEW_APP. |
needs_ota | boolean | false | When true, an OTA is published before the e2e job(s) run. |
review_app | string | '' | Review-app subdomain, required when environment=REVIEW_APP. |
platform is the gate: leave it blank and CircleCI runs the default build workflow (lint + unit tests). Set it and the e2e workflow fires.
Usage patterns β
Pick a row, set the listed parameters in the CircleCI Trigger Pipeline dialog, leave the rest at their defaults. Tests always come from the branch CircleCI is checking out.
| # | I want to... | platform | suite | environment | needs_ota | review_app |
|---|---|---|---|---|---|---|
| 1 | Regression on qa β branch only has e2e changes (no app changes) | both | β | β | β | β |
| 2 | A suite against my branch's PR build (app changes, has PR) β no OTA needed | android / ios / both | e.g. login | β | β | β |
| 3 | Same as #2 but no PR yet β need an OTA | android / ios / both | e.g. login | β | true | β |
| 4 | Prod smoke against the latest production-e2e build | β | β | PROD | β | β |
| 5 | Nightly regression on develop against qa | automatic β fires on cron | ||||
| 6 | Any of #1β3 against staging (UAT backend) | as above | as above | UAT | as above | β |
| 7 | Any of #1β3 against a review app | as above | as above | REVIEW_APP | as above | pr-1234 |
β means leave the parameter at its default (empty / false / QA).
Workflow flow β
Five entry points off Read pipeline params:
platformempty βbuildworkflow (lint + unit tests)environment = PRODβ prod smoke- cron on
developβ nightly platformset,needs_ota = falseβ straight to the dropdown jobplatformset,needs_ota = trueβ OTA publish first, then the dropdown job
Build resolution β
CircleCI never builds the app itself for the new e2e suite β it always reuses an EAS build. The dropdown jobs find one via fingerprint match:
- Generate the branch's runtime fingerprint (
expo-updates fingerprint:generate). - Look for a
qa-profile build whose fingerprint matches. - If none, fall back to the
pr-native-changesprofile (built by GHA when a PR opens with native changes). - If neither has a match, the prepare step fails fast and prompts the developer to open a non-draft PR so GHA builds a
pr-native-changesbuild.
The prod path (environment=PROD) skips fingerprint matching and just grabs the latest production-e2e profile build β no OTA can apply to it.
OTA + Expo channel resolution β
The build always ships with channel: "qa" baked in. To run a branch's JS code against that build, the e2e bootstrap calls switchChannel(<branch>) at runtime β but only if there's actually something to switch to.
resolve-expo-channel runs as a CI step before the test runner starts:
This decouples needs_ota from the channel decision:
needs_ota=trueβ fresh OTA published to<branch>channel, channel-check finds it, build switches to<branch>.needs_ota=false, branch has prior OTAs β channel-check finds them, build switches to<branch>(re-uses the most recent OTA).needs_ota=false, fresh branch / no OTA history β channel-check finds nothing, no switch, build runs embedded qa code (= develop's code at build time). This is what makes pattern #1 work.
Job and command reference β
| Name | Type | Purpose |
|---|---|---|
e2e-new-tests-suite-android / -ios | job | Parameterised by suite. Used by both manual dropdowns and the nightly workflow. |
e2e-new-publish-ota | job | Runs resolve-build-and-ota (publishes OTA + resolves fingerprint-matched builds). Required by the e2e job when needs_ota=true. |
e2e-new-tests-prod-android-only / -ios-only | job | Prod smoke jobs. Hard-coded E2E_ENVIRONMENT=PROD, fetch the latest production-e2e build. |
set_env_e2e_new | command | Exports E2E_ENVIRONMENT (and REVIEW_APP when environment=REVIEW_APP) so e2e/constants/environments.ts resolves the right backend URLs. |
prepare-steps-e2e-new-regression-android-only / -ios-only | command | Installs eas-cli, fingerprint-matches the build, downloads it, uploads to BrowserStack. |
resolve-expo-channel | command | Decides whether to export EXPO_CHANNEL based on whether the branch's EAS channel has any updates. |
resolve-build-and-ota | command | Used by e2e-new-publish-ota: derives channel from branch, finds fingerprint-matched builds, bakes a codeword into OTA_VERSION, publishes OTA. |
Best practices β
- Default to the dropdowns. For ad-hoc runs, set
platformand (optionally)suite; leave the rest at defaults. - Only set
needs_ota=truewhen you have JS-only changes you need on the build. A branch with no app changes (#1) needs no OTA βresolve-expo-channelhandles that automatically. environment=PRODignoressuite,platform, andneeds_ota. It always runs the fixed prod smoke against the latestproduction-e2ebuild.- Don't set
review_appwithoutenvironment=REVIEW_APP. It'll be ignored, but it's a confusing signal. - Nightlies fire automatically on
developat 21:00 UTC MonβFri. No need to invoke them manually.