Skip to content

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".

ParameterTypeDefaultPurpose
suiteenumregressionwdio suite to run (e.g. regression, login, push-notifications).
platformenum''android, ios, or both. Empty = no e2e workflow fires (default build runs).
environmentenumQABackend selector: QA, UAT, PROD, REVIEW_APP.
needs_otabooleanfalseWhen true, an OTA is published before the e2e job(s) run.
review_appstring''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...platformsuiteenvironmentneeds_otareview_app
1Regression on qa β€” branch only has e2e changes (no app changes)bothβ€”β€”β€”β€”
2A suite against my branch's PR build (app changes, has PR) β€” no OTA neededandroid / ios / bothe.g. loginβ€”β€”β€”
3Same as #2 but no PR yet β€” need an OTAandroid / ios / bothe.g. loginβ€”trueβ€”
4Prod smoke against the latest production-e2e buildβ€”β€”PRODβ€”β€”
5Nightly regression on develop against qaautomatic β€” fires on cron
6Any of #1–3 against staging (UAT backend)as aboveas aboveUATas aboveβ€”
7Any of #1–3 against a review appas aboveas aboveREVIEW_APPas abovepr-1234

β€” means leave the parameter at its default (empty / false / QA).

Workflow flow ​

Five entry points off Read pipeline params:

  • platform empty β†’ build workflow (lint + unit tests)
  • environment = PROD β†’ prod smoke
  • cron on develop β†’ nightly
  • platform set, needs_ota = false β†’ straight to the dropdown job
  • platform set, 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:

  1. Generate the branch's runtime fingerprint (expo-updates fingerprint:generate).
  2. Look for a qa-profile build whose fingerprint matches.
  3. If none, fall back to the pr-native-changes profile (built by GHA when a PR opens with native changes).
  4. 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-changes build.

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 ​

NameTypePurpose
e2e-new-tests-suite-android / -iosjobParameterised by suite. Used by both manual dropdowns and the nightly workflow.
e2e-new-publish-otajobRuns 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-onlyjobProd smoke jobs. Hard-coded E2E_ENVIRONMENT=PROD, fetch the latest production-e2e build.
set_env_e2e_newcommandExports 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-onlycommandInstalls eas-cli, fingerprint-matches the build, downloads it, uploads to BrowserStack.
resolve-expo-channelcommandDecides whether to export EXPO_CHANNEL based on whether the branch's EAS channel has any updates.
resolve-build-and-otacommandUsed by e2e-new-publish-ota: derives channel from branch, finds fingerprint-matched builds, bakes a codeword into OTA_VERSION, publishes OTA.

Best practices ​

  1. Default to the dropdowns. For ad-hoc runs, set platform and (optionally) suite; leave the rest at defaults.
  2. Only set needs_ota=true when you have JS-only changes you need on the build. A branch with no app changes (#1) needs no OTA β€” resolve-expo-channel handles that automatically.
  3. environment=PROD ignores suite, platform, and needs_ota. It always runs the fixed prod smoke against the latest production-e2e build.
  4. Don't set review_app without environment=REVIEW_APP. It'll be ignored, but it's a confusing signal.
  5. Nightlies fire automatically on develop at 21:00 UTC Mon–Fri. No need to invoke them manually.