Skip to content

Add iOS Maestro E2E suite for the OneTrust example - #80

Merged
0x7f merged 4 commits into
mainfrom
e2e-android-onetrust-maestro
Oct 6, 2026
Merged

0x7f merged 4 commits into
mainfrom
e2e-android-onetrust-maestro

Conversation

@0x7f

@0x7f 0x7f commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Adds an iOS Maestro E2E suite for examples/onetrust, driving the built app against the real contentpass-staging backend and the OneTrust test tenant, with no mock server.
  • Fixes two bugs in the example that the suite ran into: a missing OAuth redirect scheme and a CMP-failure screen that was never reached.
  • Switches the shared CI setup action from restoring a cached node_modules to a fresh yarn install, which takes each macOS E2E job from 30–45 minutes down to about 15.

Android is not covered: neither GitHub-hosted runner type can accelerate its emulator (ubuntu-latest has no /dev/kvm, and the macOS runners have no HVF for a nested hypervisor). The iOS Simulator runs natively, so it doesn't have this problem.

Commits

  1. fix: configure the OAuth redirect scheme for the OneTrust example: the react-native-app-auth plugin entry in app.json had no redirectUrls, so a fresh expo prebuild registered no usable redirect scheme (Android got the literal string undefined).
  2. fix: show the CMP-failure screen instead of hanging on Loading: a failed startSDK() or adapter creation never sets cmpReady, so checking it first left the example on "Loading..." forever. cmpFailed is now checked first.
  3. test: add an iOS Maestro E2E suite for the OneTrust example: the workflow, the first three flows, the EXPO_PUBLIC_* overrides and test IDs in the example, and the setup-action change.
  4. test: cover cancelled login, Deny All and relaunches in the iOS E2E suite: three more flows, two more stages in happy-path, and a "Consent layer: shown/hidden" line in the example driven by the gate's onVisibilityChange.

What the suite checks

CI job Flow Checks
default-config happy-path Consent through the funnel. Then a subscriber logs in; the login survives a relaunch, the subscription alone keeps the layer away, and logging out brings the layer back
cancelled-login Cancelling iOS's sign-in prompt brings the layer back (guards #79; the flow fails with that fix reverted)
deny-all Withdrawing consent in the app brings the layer back
consent-survives-relaunch Stored consent alone satisfies the gate after a relaunch
onetrust-adapter-failure onetrust-adapter-failure An invalid OneTrust app id (EXPO_PUBLIC_ONETRUST_APP_ID) lands on the CMP-failure screen
cmp-timeout-fail-open cmp-timeout-fail-open Every gate timeout forced to 1 ms (EXPO_PUBLIC_GATE_TIMEOUT_MS) fails open into the app

There is one job per Metro configuration, not per flow, because a job is mostly setup and build. Each flow starts with clearKeychain and a clearState launch, since the flows in a job share a simulator and clearState leaves the login tokens in the keychain.

CI setup

  • macos-15 with Xcode 26.2, which idb-companion (Maestro's iOS driver) requires.
  • A Debug build, which loads its JS from a pre-warmed Metro. A Release bundle crashes on launch because Metro's minifier strips React Native's setUpGlobals polyfill. The scenario's EXPO_PUBLIC_* values therefore go on the Metro process rather than the build.
  • Built for arm64 only, which is all the simulator runs. This also avoids a Swift 6.2.3 compiler crash in the x86_64 slice of expo-modules-core.
  • No dependency cache. With nmHoistingLimits: workspaces, the cached node_modules is about 1 GB of small files. On the macOS runners, restoring it took 12–16 min and saving it 8–13 min; a fresh install takes 2–3.5 min. The Linux CI jobs go from a ~45 s cache hit to 1.5–2 min.
  • On failure, a job uploads Maestro's debug output (screenshots and screen layout) together with Metro's log. Metro's log is the app's JS console, including the SDK's debug lines, which the simulator log leaves out.
  • Needs the E2E_STAGING_EMAIL / E2E_STAGING_PASSWORD secrets for a staging account with an active subscription to the example's plan. Without one, login goes to the subscription checkout instead of back to the app. On fork PRs the job is skipped, since GitHub withholds secrets there.

0x7f added 2 commits October 5, 2026 10:44
The react-native-app-auth config plugin derives both platforms' redirect
scheme from its redirectUrls option, and the example's plugin entry carried
none. A fresh `expo prebuild` therefore registered no usable scheme: Android's
appAuthRedirectScheme came out as the literal string "undefined" instead of
de.contentpass.demo, breaking the OAuth redirect on any clean native build.
Neither a failed startSDK() nor a failed createOnetrustCmpAdapter() ever
sets cmpReady, so checking !cmpReady before cmpFailed left the OneTrust
example stuck on "Loading..." forever whenever the CMP could not load.
Check cmpFailed first, and give both screens a testID.
@0x7f
0x7f force-pushed the e2e-android-onetrust-maestro branch 2 times, most recently from a8efb26 to 034615d Compare October 5, 2026 09:22
@0x7f
0x7f marked this pull request as ready for review October 5, 2026 13:08
@0x7f
0x7f force-pushed the e2e-android-onetrust-maestro branch 2 times, most recently from eef91ff to 35e2c2f Compare October 6, 2026 06:37
@0x7f 0x7f changed the title Add Android Maestro E2E suite for the OneTrust example Add iOS Maestro E2E suite for the OneTrust example Oct 6, 2026
0x7f added 2 commits October 6, 2026 09:42
Three flows drive the built example against the real contentpass-staging
backend and the OneTrust test tenant, with no mock server:

- happy-path: consent through the hosted funnel, then a real login and
  logout with a subscribed staging fixture account (E2E_STAGING_EMAIL /
  E2E_STAGING_PASSWORD secrets)
- onetrust-adapter-failure: an invalid OneTrust app id lands on the
  CMP-failure screen
- cmp-timeout-fail-open: every gate timeout forced to 1ms fails open into
  the app

The example now reads EXPO_PUBLIC_ONETRUST_APP_ID and
EXPO_PUBLIC_GATE_TIMEOUT_MS, so each scenario is picked when Metro starts,
and its screens carry testIDs so selectors don't depend on copy.

The workflow runs on macos-15 with Xcode 26.2, which idb-companion
(Maestro's iOS driver) requires. Android is left out: neither GitHub-hosted
runner type can accelerate its emulator. The app is a Debug build that
loads its JS from a pre-warmed Metro, because Metro's minifier strips
React Native's setUpGlobals polyfill from a Release bundle. It is built for
arm64 only, all the simulator runs, which also avoids a Swift 6.2.3
compiler crash in the x86_64 slice of expo-modules-core.
…uite

Three new flows and two more stages in happy-path, each checking whether
the consent layer comes back or stays away:

- cancelled-login: cancelling iOS's sign-in prompt brings the layer back
  instead of failing open into the app
- deny-all: withdrawing consent in the app brings the layer back
- consent-survives-relaunch: stored consent alone satisfies the gate after
  a relaunch
- happy-path: a subscriber's login survives a relaunch, the subscription
  alone keeps the layer away, and logging out brings it back

The example now prints "Consent layer: shown/hidden" from the gate's
onVisibilityChange. Its screen also renders underneath the layer, so the
app's own text can't tell the two states apart.

Flows that run against the example's default config share one job, since
a job is mostly setup and build; only flows needing Metro started with
other EXPO_PUBLIC_* values get a job of their own. Since a job's flows
share a simulator, each starts with clearKeychain as well as a clearState
launch: clearState leaves the login tokens in the keychain alone.
@0x7f
0x7f force-pushed the e2e-android-onetrust-maestro branch from 35e2c2f to 273d063 Compare October 6, 2026 07:43
@0x7f
0x7f merged commit 77bdfbb into main Oct 6, 2026
6 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