From d79381b7e8c3a601bf75ab0333424045f49e9f94 Mon Sep 17 00:00:00 2001 From: Maximilian Haupt Date: Mon, 5 Oct 2026 10:44:35 +0200 Subject: [PATCH 1/4] fix: configure the OAuth redirect scheme for the OneTrust example 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. --- examples/onetrust/app.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/onetrust/app.json b/examples/onetrust/app.json index 4a3b933..ec5f693 100644 --- a/examples/onetrust/app.json +++ b/examples/onetrust/app.json @@ -26,7 +26,12 @@ "favicon": "./assets/favicon.png" }, "plugins": [ - "react-native-app-auth" + [ + "react-native-app-auth", + { + "redirectUrls": ["de.contentpass.demo://oauth"] + } + ] ] } } From 6892a3b64a7f486b6ff07d9c1d955c90cea2579d Mon Sep 17 00:00:00 2001 From: Maximilian Haupt Date: Mon, 5 Oct 2026 10:44:58 +0200 Subject: [PATCH 2/4] fix: show the CMP-failure screen instead of hanging on Loading 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. --- examples/onetrust/src/App.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/onetrust/src/App.tsx b/examples/onetrust/src/App.tsx index 6396db6..f3a7ebc 100644 --- a/examples/onetrust/src/App.tsx +++ b/examples/onetrust/src/App.tsx @@ -56,18 +56,22 @@ export default function App() { }); }, []); - if (!cmpReady) { + // Checked before !cmpReady: neither startSDK() nor + // createOnetrustCmpAdapter() failing ever sets cmpReady, so checking + // !cmpReady first would leave the app stuck on "Loading..." forever + // instead of ever reaching this screen. + if (cmpFailed) { return ( - Loading... + Failed to load CMP ); } - if (cmpFailed || !cmpAdapter) { + if (!cmpReady || !cmpAdapter) { return ( - Failed to load CMP + Loading... ); } From 87a4b01ac8a1b68efceb4e7c1b259f896436acf8 Mon Sep 17 00:00:00 2001 From: Maximilian Haupt Date: Mon, 5 Oct 2026 10:45:17 +0200 Subject: [PATCH 3/4] test: add an iOS Maestro E2E suite for the OneTrust example 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. --- .github/actions/setup/action.yml | 18 +- .github/workflows/e2e-ios.yml | 159 ++++++++++++++++++ examples/onetrust/e2e/README.md | 73 ++++++++ .../e2e/flows/cmp-timeout-fail-open.yaml | 21 +++ examples/onetrust/e2e/flows/happy-path.yaml | 68 ++++++++ .../e2e/flows/onetrust-adapter-failure.yaml | 16 ++ examples/onetrust/src/App.tsx | 2 + examples/onetrust/src/Config.ts | 26 ++- examples/onetrust/src/Content.tsx | 10 +- 9 files changed, 377 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/e2e-ios.yml create mode 100644 examples/onetrust/e2e/README.md create mode 100644 examples/onetrust/e2e/flows/cmp-timeout-fail-open.yaml create mode 100644 examples/onetrust/e2e/flows/happy-path.yaml create mode 100644 examples/onetrust/e2e/flows/onetrust-adapter-failure.yaml diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 60df308..f45e97c 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -9,19 +9,11 @@ runs: with: node-version-file: .nvmrc - - name: Cache dependencies - id: yarn-cache - uses: actions/cache@v4 - with: - path: | - **/node_modules - .yarn/install-state.gz - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}-${{ hashFiles('**/package.json', '!node_modules/**') }} - restore-keys: | - ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - ${{ runner.os }}-yarn- - + # Installs from the registry on every run rather than restoring a cached + # node_modules: with nmHoistingLimits: workspaces that cache is ~1 GB of + # small files, which took 12-16 minutes to unpack on the macOS runners + # (and 8-13 to pack whenever its key changed), against about a minute to + # fetch every package. - name: Install dependencies - if: steps.yarn-cache.outputs.cache-hit != 'true' run: yarn install --immutable shell: bash diff --git a/.github/workflows/e2e-ios.yml b/.github/workflows/e2e-ios.yml new file mode 100644 index 0000000..2d6614b --- /dev/null +++ b/.github/workflows/e2e-ios.yml @@ -0,0 +1,159 @@ +name: E2E iOS + +on: + pull_request: + push: + branches: + - main + +jobs: + e2e-ios: + # GitHub already withholds secrets from fork-originated pull_request + # runs, so this only decides whether the job shows as skipped (clean) + # rather than failed on missing credentials for those runs. + if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request' + # The iOS Simulator is a native macOS process, not a nested VM, so it + # doesn't need hardware virtualization support the way the Android + # emulator does — unlike both ubuntu-latest (no /dev/kvm) and macos-14 + # itself (no HVF for a *nested* hypervisor), this just works. + # macos-15, not macos-14: idb-companion (Maestro's iOS driver) requires + # macOS Sequoia+ and a full Xcode 26 install, neither available on 14. + runs-on: macos-15 + strategy: + fail-fast: false + matrix: + include: + - flow: happy-path + onetrust_app_id: '' + gate_timeout_ms: '' + - flow: onetrust-adapter-failure + onetrust_app_id: 'e2e-invalid-app-id' + gate_timeout_ms: '' + - flow: cmp-timeout-fail-open + onetrust_app_id: '' + gate_timeout_ms: '1' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup + uses: ./.github/actions/setup + + - name: Install JDK + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + + # macos-15 defaults xcode-select to 16.4; idb-companion needs a full + # Xcode 26 install (CLT alone isn't enough), which is present on the + # image but not selected by default. + - name: Select Xcode 26 + run: sudo xcode-select -s /Applications/Xcode_26.2.app + + - name: Install Maestro and idb-companion + run: | + curl -Ls "https://get.maestro.mobile.dev" | bash + echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" + brew tap facebook/fb + brew install facebook/fb/idb-companion + + - name: Prebuild iOS project + working-directory: examples/onetrust + # ios/ is gitignored (generated by expo prebuild), so a clean + # checkout needs this before any CocoaPods/Xcode step is available. + run: npx expo prebuild --platform ios --no-install + + - name: Pod install + working-directory: examples/onetrust/ios + run: pod install + + # Debug, not Release: a Release build's JS bundle goes through Metro's + # minifier, which — confirmed by inspecting the bundled output — was + # silently stripping the body of a core React Native polyfill module + # (setUpGlobals), crashing the app on launch before it ever reaches + # the UI ("TypeError: undefined is not a function" during module + # init). A Debug build skips bundling/minification at build time + # entirely and fetches its JS from Metro at runtime instead, which + # sidesteps the bug; see the Metro step below for why the per-flow + # env vars move there instead of the build step as a result. + # + # ARCHS=arm64: a generic simulator destination otherwise builds an + # x86_64 slice too, which the Apple Silicon runner's simulator never + # runs. Besides doubling the compile, that slice is where Swift 6.2.3 + # (Xcode 26.2) intermittently crashes in its SendNonSendable pass on + # expo-modules-core's SharedObject.emit(event:arguments:). + - name: Build app (Debug) + working-directory: examples/onetrust/ios + run: | + xcodebuild \ + -workspace ContentpassOnetrustExample.xcworkspace \ + -scheme ContentpassOnetrustExample \ + -configuration Debug \ + -sdk iphonesimulator \ + -derivedDataPath build \ + -destination 'generic/platform=iOS Simulator' \ + ARCHS=arm64 \ + build + + - name: Start Metro (${{ matrix.flow }}) + working-directory: examples/onetrust + env: + EXPO_PUBLIC_ONETRUST_APP_ID: ${{ matrix.onetrust_app_id }} + EXPO_PUBLIC_GATE_TIMEOUT_MS: ${{ matrix.gate_timeout_ms }} + # A Debug build fetches its JS bundle from Metro at app-launch time, + # so the env vars that pick the per-flow scenario have to be set on + # the Metro process, not on the (now scenario-independent) build + # step above. + run: | + npx expo start --port 8081 > /tmp/metro.log 2>&1 & + for i in $(seq 1 30); do + curl -s http://localhost:8081/status | grep -q "packager-status:running" && break + sleep 2 + done + if ! curl -s http://localhost:8081/status | grep -q "packager-status:running"; then + echo "Metro did not become ready in time" + cat /tmp/metro.log + exit 1 + fi + # Metro's first bundle of this app takes well over a minute to + # transform from a cold cache (confirmed via a CI run that still + # showed "Bundling 88%..." past Maestro's 60s wait) — pre-warm it + # here, where there's no assertion timer running, rather than + # leave the app to request it cold at launch. + echo "Pre-warming Metro's bundle cache..." + time curl -s -o /dev/null "http://localhost:8081/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true" + + - name: Run ${{ matrix.flow }} on simulator + working-directory: examples/onetrust + env: + # Maestro's own XCTest-runner driver bootstrap ("iOS driver not + # ready in time") can take longer than its default on a + # GitHub-hosted runner than on a local machine. + MAESTRO_DRIVER_STARTUP_TIMEOUT: '240000' + run: | + DEVICE_UDID=$(xcrun simctl list devices available -j | jq -r '[.devices[] | .[] | select(.name | test("iPhone"))][0].udid') + xcrun simctl boot "$DEVICE_UDID" + xcrun simctl bootstatus "$DEVICE_UDID" -b + xcrun simctl install "$DEVICE_UDID" ios/build/Build/Products/Debug-iphonesimulator/ContentpassOnetrustExample.app + maestro test e2e/flows/${{ matrix.flow }}.yaml \ + -e E2E_STAGING_EMAIL="${{ secrets.E2E_STAGING_EMAIL }}" \ + -e E2E_STAGING_PASSWORD="${{ secrets.E2E_STAGING_PASSWORD }}" + + # Metro's output is the app's JS console, including the SDK's + # console.debug lines (every message from the layer's WebView, the + # gate's and the CMP adapter's progress), none of which reach the + # simulator log that Maestro collects. + - name: Add Metro log to debug output + if: failure() + run: | + mkdir -p ~/.maestro/tests + cp /tmp/metro.log ~/.maestro/tests/ 2>/dev/null || true + + - name: Upload Maestro debug output + if: failure() + uses: actions/upload-artifact@v4 + with: + name: maestro-debug-${{ matrix.flow }} + path: ~/.maestro/tests/ + retention-days: 7 diff --git a/examples/onetrust/e2e/README.md b/examples/onetrust/e2e/README.md new file mode 100644 index 0000000..b65e826 --- /dev/null +++ b/examples/onetrust/e2e/README.md @@ -0,0 +1,73 @@ +# OneTrust example E2E (iOS, Maestro) + +Maestro flows driving the built `examples/onetrust` app against the real +`contentpass-staging` backend and the real OneTrust test tenant — no mock +server. See `flows/` for what each one covers. + +iOS only for now: the Android emulator needs hardware virtualization that +neither GitHub-hosted runner type currently provides (`ubuntu-latest` has no +`/dev/kvm`; `macos-14` has no HVF for a _nested_ hypervisor). The iOS +Simulator is a native macOS process, not a VM, so it doesn't hit this at +all — see `.github/workflows/e2e-ios.yml`. Revisit Android once there's a +runner (GitHub larger Linux runner, or self-hosted) that actually exposes +nested virtualization. + +## Debug + Metro, not a Release build + +The app runs as a **Debug** build with a live Metro server, not a +self-contained Release build. A Release build's JS bundle goes through +Metro's minifier, which — confirmed by inspecting the bundled output byte +for byte — silently strips the body of a core React Native polyfill module +(`setUpGlobals`), crashing the app on launch before it ever reaches the UI +(`TypeError: undefined is not a function` during module init). This is a +toolchain bug worth fixing on its own, but it isn't an E2E-infra concern, so +Debug (which skips bundling/minification at build time and fetches JS from +Metro at runtime) sidesteps it entirely. One consequence: the +`EXPO_PUBLIC_ONETRUST_APP_ID` / `EXPO_PUBLIC_GATE_TIMEOUT_MS` env vars that +pick a scenario have to be set on the **Metro process**, not on the build — +a Debug build itself is identical across all three flows. + +## Prerequisites + +- [Maestro CLI](https://maestro.mobile.dev) installed (`curl -Ls "https://get.maestro.mobile.dev" | bash`). +- [idb-companion](https://github.com/facebook/idb), which Maestro needs to drive the iOS Simulator (`brew tap facebook/fb && brew install facebook/fb/idb-companion`). +- A Metro server running with the right env vars for the scenario you want + (see below), and a booted iOS Simulator with the app installed against it + (`yarn ios` from `examples/onetrust` does both for local dev). +- For `flows/happy-path.yaml` only: a dedicated contentpass-staging test + account's credentials, exported as `E2E_STAGING_EMAIL` / + `E2E_STAGING_PASSWORD`. This is a stable fixture account, and it needs an + active subscription to the example's plan: without one, the login hands + the account on to the subscription checkout instead of redirecting back to + the app, so the flow never sees `AUTHENTICATED`. Never commit these + values; locally, export them in your shell, don't put them in a tracked + `.env`. + +## Running a flow + +```sh +maestro test flows/happy-path.yaml -e E2E_STAGING_EMAIL="$E2E_STAGING_EMAIL" -e E2E_STAGING_PASSWORD="$E2E_STAGING_PASSWORD" +maestro test flows/onetrust-adapter-failure.yaml +maestro test flows/cmp-timeout-fail-open.yaml +``` + +The latter two need Metro itself started with the matching env var before +`yarn ios`: + +```sh +EXPO_PUBLIC_ONETRUST_APP_ID=garbage-app-id npx expo start # onetrust-adapter-failure.yaml +EXPO_PUBLIC_GATE_TIMEOUT_MS=1 npx expo start # cmp-timeout-fail-open.yaml +``` + +## What `happy-path.yaml` has to step through + +- The funnel's real labels are "Einwilligen & weiter" and "Login mit + Contentpass". This app never shows a separate native OneTrust banner; the + hosted Contentpass funnel is the only consent/login UI. +- iOS's native `ASWebAuthenticationSession` permission dialog ("Wants to Use + ... to Sign In") appears before the OIDC login page and needs its own + `tapOn: "Continue"`. +- After the login form is submitted, iOS may put a "Save Password?" system + alert over the page. While it is up, it is the only thing in the UI + hierarchy Maestro sees, so the flow dismisses it ("Not Now") before + waiting for the app. diff --git a/examples/onetrust/e2e/flows/cmp-timeout-fail-open.yaml b/examples/onetrust/e2e/flows/cmp-timeout-fail-open.yaml new file mode 100644 index 0000000..574488f --- /dev/null +++ b/examples/onetrust/e2e/flows/cmp-timeout-fail-open.yaml @@ -0,0 +1,21 @@ +appId: com.contentpassOnetrustExample.onetrustExample +--- +# Built with EXPO_PUBLIC_GATE_TIMEOUT_MS set to an unrealistically small +# value (e.g. "1"), so every one of ContentpassConsentGate's own timeouts +# fires before the real OneTrust SDK or Contentpass backend can respond. +# The gate is designed to fail open in that case: render the app's content +# directly rather than block it behind a CMP/backend that never answered in +# time. Neither the OneTrust banner nor the Contentpass funnel should ever +# appear. +# +# 90s wait: a first CI run (fresh simulator, no cached DNS/TLS state) still +# needs real network round trips for OneTrust adapter creation in App.tsx, +# which has its own timeout (`createOnetrustCmpAdapter` is not covered by +# the forced gate timeouts) — more than Maestro's ~17s implicit default. +- launchApp +- extendedWaitUntil: + visible: + id: 'content-full-consent' + timeout: 90000 +- assertVisible: + id: 'content-authenticated' diff --git a/examples/onetrust/e2e/flows/happy-path.yaml b/examples/onetrust/e2e/flows/happy-path.yaml new file mode 100644 index 0000000..5867413 --- /dev/null +++ b/examples/onetrust/e2e/flows/happy-path.yaml @@ -0,0 +1,68 @@ +appId: com.contentpassOnetrustExample.onetrustExample +--- +# Full happy path against the real contentpass-staging backend and the real +# OneTrust test tenant: accept consent, then separately verify login/logout +# with a static staging test account (${E2E_STAGING_EMAIL} / +# ${E2E_STAGING_PASSWORD}, injected at `maestro test` invocation time — see +# e2e/README.md). +# +# The funnel shown here is real, hosted Contentpass content (not native +# OneTrust banner UI — this app never calls into OneTrust's own banner, only +# its consent-status/adapter APIs), so its labels are verified against a +# live run rather than guessed: "Einwilligen & weiter" (not "Accept All") +# and "Login mit Contentpass" (not "Log in"). +# +# Every wait below is generous (90s) because a first CI run — fresh +# simulator, no cached DNS/TLS state, first real network round trip from a +# GitHub-hosted runner to the real OneTrust CDN and Contentpass backend — +# measured meaningfully slower than local iterative testing; Maestro's +# ~17s implicit default was not enough. +- launchApp +- extendedWaitUntil: + visible: 'Login mit Contentpass' + timeout: 90000 +- tapOn: 'Einwilligen & weiter' +- extendedWaitUntil: + visible: + id: 'content-full-consent' + timeout: 90000 +- assertVisible: 'Has full consent: Yes' + +# Relaunch to a clean funnel, then verify the auth path independently of +# consent. iOS shows its own native ASWebAuthenticationSession permission +# dialog ("Wants to Use... to Sign In") before the real OIDC login page +# loads — there's no Android equivalent of this step. +- launchApp: + clearState: true +- extendedWaitUntil: + visible: 'Login mit Contentpass' + timeout: 90000 +- tapOn: 'Login mit Contentpass' +- tapOn: 'Continue' +- extendedWaitUntil: + visible: 'Email' + timeout: 90000 +- tapOn: 'Email' +- inputText: ${E2E_STAGING_EMAIL} +- tapOn: 'Please log in' +- tapOn: 'PASSWORD' +- inputText: ${E2E_STAGING_PASSWORD} +# Anchored exact match: the page's own "Please log in" heading contains +# "Log in" as a substring too, and an unanchored match landed on that +# non-interactive heading instead of the submit button. +- tapOn: '^Log in$' +# iOS may offer to save the just-submitted password in a system alert that +# hides everything else from Maestro until it's dismissed. +- tapOn: + text: 'Not Now' + optional: true + +# Back in the app after the OAuth redirect. +- extendedWaitUntil: + visible: + id: 'content-authenticated' + timeout: 90000 +- assertVisible: 'Is authenticated: Yes' +- tapOn: + id: 'content-logout-button' +- assertVisible: 'Is authenticated: No' diff --git a/examples/onetrust/e2e/flows/onetrust-adapter-failure.yaml b/examples/onetrust/e2e/flows/onetrust-adapter-failure.yaml new file mode 100644 index 0000000..482053a --- /dev/null +++ b/examples/onetrust/e2e/flows/onetrust-adapter-failure.yaml @@ -0,0 +1,16 @@ +appId: com.contentpassOnetrustExample.onetrustExample +--- +# Built with EXPO_PUBLIC_ONETRUST_APP_ID set to a garbage value, so +# createOnetrustCmpAdapter() rejects during startup. App.tsx catches that and +# shows its own "Failed to load CMP" screen instead of ever reaching +# ContentpassSdkProvider / ContentpassConsentGate. +# +# 90s wait: a first CI run (fresh simulator, no cached DNS/TLS state) needs +# more than Maestro's ~17s implicit default to even get the rejection back +# from OneTrust's real CDN. +- launchApp +- extendedWaitUntil: + visible: + id: 'app-cmp-failed' + timeout: 90000 +- assertVisible: 'Failed to load CMP' diff --git a/examples/onetrust/src/App.tsx b/examples/onetrust/src/App.tsx index f3a7ebc..81bb103 100644 --- a/examples/onetrust/src/App.tsx +++ b/examples/onetrust/src/App.tsx @@ -7,6 +7,7 @@ import type { CmpAdapter } from '@contentpass/react-native-contentpass'; import { createOnetrustCmpAdapter } from '@contentpass/react-native-contentpass-cmp-onetrust'; import { CONTENTPASS_CONFIG, + GATE_TIMEOUTS, ONETRUST_CDN_LOCATION, ONETRUST_APP_ID, ONETRUST_LANGUAGE_CODE, @@ -82,6 +83,7 @@ export default function App() { cmpAdapter={cmpAdapter!} contentpassConfig={CONTENTPASS_CONFIG} hideAppWhenVisible={false} + timeouts={GATE_TIMEOUTS} > diff --git a/examples/onetrust/src/Config.ts b/examples/onetrust/src/Config.ts index 388535d..d46975c 100644 --- a/examples/onetrust/src/Config.ts +++ b/examples/onetrust/src/Config.ts @@ -1,4 +1,5 @@ import type { ContentpassConfig } from '@contentpass/react-native-contentpass'; +import type { ContentpassGateTimeouts } from '@contentpass/react-native-contentpass-ui'; export const CONTENTPASS_CONFIG: ContentpassConfig = { // Testing app @@ -12,5 +13,28 @@ export const CONTENTPASS_CONFIG: ContentpassConfig = { }; export const ONETRUST_CDN_LOCATION = 'cdn.cookielaw.org'; -export const ONETRUST_APP_ID = '019beb25-2008-72e0-8788-da1eec1f18dc-test'; +export const ONETRUST_APP_ID = + process.env.EXPO_PUBLIC_ONETRUST_APP_ID || + '019beb25-2008-72e0-8788-da1eec1f18dc-test'; export const ONETRUST_LANGUAGE_CODE = 'en'; + +// Lets an E2E build force every ContentpassConsentGate timeout down to the +// same tiny value, to deterministically exercise its fail-open path without +// needing the CMP or backend to actually misbehave. +const forcedTimeoutMs = process.env.EXPO_PUBLIC_GATE_TIMEOUT_MS + ? Number(process.env.EXPO_PUBLIC_GATE_TIMEOUT_MS) + : undefined; + +export const GATE_TIMEOUTS: ContentpassGateTimeouts | undefined = + forcedTimeoutMs + ? { + cmpInitTimeoutMs: forcedTimeoutMs, + cmpMetadataTimeoutMs: forcedTimeoutMs, + cmpConsentStatusTimeoutMs: forcedTimeoutMs, + authenticateTimeoutMs: forcedTimeoutMs, + secondLayerTimeoutMs: forcedTimeoutMs, + contentpassInitTimeoutMs: forcedTimeoutMs, + layerPageLoadTimeoutMs: forcedTimeoutMs, + layerReadyTimeoutMs: forcedTimeoutMs, + } + : undefined; diff --git a/examples/onetrust/src/Content.tsx b/examples/onetrust/src/Content.tsx index fc59ece..f2d012d 100644 --- a/examples/onetrust/src/Content.tsx +++ b/examples/onetrust/src/Content.tsx @@ -35,19 +35,25 @@ export default function Content({ cmpAdapter }: { cmpAdapter: CmpAdapter }) { return ( Hello World! - Has full consent: {hasFullConsent ? 'Yes' : 'No'} + + Has full consent: {hasFullConsent ? 'Yes' : 'No'} +