Skip to content

test(e2e): Verify replay runtime controls drive native recording - #6704

Open
antonis wants to merge 6 commits into
feat/replay-runtime-controlsfrom
test/replay-runtime-controls-e2e
Open

test(e2e): Verify replay runtime controls drive native recording#6704
antonis wants to merge 6 commits into
feat/replay-runtime-controlsfrom
test/replay-runtime-controls-e2e

Conversation

@antonis

@antonis antonis commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Note

Stacked on top of #6703 (Session Replay runtime controls). Review/merge that first; this PR's base auto-retargets to main once it lands. The diff below is only the e2e delta.

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

Adds e2e Maestro flows that verify the Session Replay runtime controls (added in #6703) actually drive native recording end-to-end — not just that the JS forwards across the bridge (which the Jest/native unit tests already cover by mocking the bridge and stopping there). With buffer-mode replay off (replaysOnErrorSampleRate: 0) and no session sampling, a replay can only exist while a manually-started session is actively recording, so each assertion isolates what a control did.

  • src/EndToEndTests.tsx — add Start, Pause, Resume, Stop Replay buttons that call the matching Sentry.getReplay()?.* control.
  • maestro/manualReplay.yml — tap Start Replay, prime the view, capture an exception, then reuse assertReplay.yml to assert a real replay (replay_id, duration, segments, valid MP4) came back from the Sentry API. Proves start() drives recording.
  • maestro/replayStopResume.yml (new) — start()pause()resume() → capture → assertReplay (pause/resume don't crash and recording survives); then stop() → capture → assertNoReplay (recording actually halted).
  • maestro/utils/assertNoReplay.yml + a noReplay case in sentryApi.js — the inverse of assertReplay: asserts an event carries no replay association. Needed because the positive assertReplay throws when replay_id is absent, so it can't prove halting on its own.

flush() and startBuffering() are left for a follow-up — standalone they produce no error event to key the assertion off. The flows are auto-discovered by cli.mjs and run on both platforms, reusing the primeReplayBuffer.yml + assertReplay.yml utilities from #6683/#6684.

💡 Motivation and Context

Runtime controls (#6703) had no e2e coverage. Unit tests mock NATIVE, so a bridge-name mismatch, ABI/codegen drift, or a native no-op would pass them silently. This adds the missing through-the-bridge checks.

💚 How did you test it?

  • Local yarn build of the e2e package typechecks the new getReplay()?.start/pause/resume/stop() buttons.
  • Full run is on CI (Sauce Labs), gated behind the ready-to-merge label.

📝 Checklist

  • I added tests to verify changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing.
  • No breaking changes.

🔮 Next steps

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


  • test(e2e): Verify replay runtime controls drive native recording by antonis in #6704
  • feat(replay): Add Session Replay runtime controls by antonis in #6703
  • fix(tracing): background root spans overwrite native propagation context by alwx in #6720
  • ci(e2e): Fix broken idb-companion install on iOS e2e by antonis in #6719
  • chore(deps): Bump smol-toml to ^1.7.1 by antonis in #6713
  • chore(deps): Bump js-yaml to patched versions to resolve security alerts by antonis in #6710
  • chore(deps): Bump morgan to ^1.12.0 to resolve security alert by antonis in #6712
  • chore(deps): Bump joi to ^17.13.6 by antonis in #6714
  • chore(deps): Bump sharp to ^0.35.4 to resolve security alert by antonis in #6711
  • chore(deps): bump actions/setup-java from 6.0.0 to 6.0.1 by dependabot in #6716
  • chore(deps): bump getsentry/craft/.github/workflows/changelog-preview.yml from 2.30.1 to 2.31.0 by dependabot in #6718
  • chore(deps): bump getsentry/craft from 2.30.1 to 2.31.0 by dependabot in #6717
  • chore(deps): bump the codeql-action group with 3 updates by dependabot in #6715
  • fix(core): Fix process.exit typo in debugid script by friederbluemle in #6707
  • chore(ci): Only build production builds for visionOS and tvOS by antonis in #6700
  • chore(deps): update Sentry Android Gradle Plugin to v6.22.0 by github-actions in #6699

🤖 This preview updates automatically when you update the PR.

@antonis antonis added the ready-to-merge Triggers the full CI test suite label Sep 11, 2026
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Android (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 417.73 ms 435.08 ms 17.35 ms
Size 50.56 MiB 56.49 MiB 5.93 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
f3215d3+dirty 411.11 ms 454.38 ms 43.27 ms
af33f3b+dirty 434.90 ms 506.14 ms 71.24 ms
c2e182c+dirty 471.64 ms 553.59 ms 81.95 ms
5ca03f9+dirty 423.30 ms 467.00 ms 43.70 ms
a5d243c+dirty 424.52 ms 485.18 ms 60.66 ms
bc8f61e+dirty 442.98 ms 506.56 ms 63.58 ms
c823bb5+dirty 409.87 ms 478.57 ms 68.70 ms
d387874+dirty 438.69 ms 453.77 ms 15.08 ms
b0d3373+dirty 557.66 ms 579.42 ms 21.76 ms
0bd8916+dirty 412.77 ms 451.31 ms 38.54 ms

App size

Revision Plain With Sentry Diff
f3215d3+dirty 48.30 MiB 53.49 MiB 5.19 MiB
af33f3b+dirty 49.74 MiB 55.09 MiB 5.35 MiB
c2e182c+dirty 49.74 MiB 54.85 MiB 5.11 MiB
5ca03f9+dirty 49.74 MiB 55.26 MiB 5.52 MiB
a5d243c+dirty 48.30 MiB 53.54 MiB 5.23 MiB
bc8f61e+dirty 49.74 MiB 55.09 MiB 5.35 MiB
c823bb5+dirty 48.30 MiB 53.58 MiB 5.28 MiB
d387874+dirty 49.74 MiB 55.44 MiB 5.70 MiB
b0d3373+dirty 48.30 MiB 53.58 MiB 5.28 MiB
0bd8916+dirty 48.30 MiB 53.57 MiB 5.26 MiB

Previous results on branch: test/replay-runtime-controls-e2e

Startup times

Revision Plain With Sentry Diff
dca994f+dirty 426.52 ms 438.90 ms 12.37 ms
3e493d9+dirty 412.81 ms 476.24 ms 63.43 ms

App size

Revision Plain With Sentry Diff
dca994f+dirty 50.56 MiB 56.49 MiB 5.93 MiB
3e493d9+dirty 50.56 MiB 56.49 MiB 5.93 MiB

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3850.54 ms 1216.88 ms -2633.67 ms
Size 5.15 MiB 6.90 MiB 1.75 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
7a89652+dirty 3861.46 ms 1229.61 ms -2631.85 ms
0b1b5e3+dirty 3823.96 ms 1220.12 ms -2603.84 ms
eb55864+dirty 3869.04 ms 1241.75 ms -2627.29 ms
3e3142c+dirty 3867.38 ms 1232.48 ms -2634.90 ms
9210ae6+dirty 3815.93 ms 1214.14 ms -2601.79 ms
6177334+dirty 3834.85 ms 1217.58 ms -2617.28 ms
3a829f0+dirty 3839.76 ms 1214.69 ms -2625.06 ms
2cac31b+dirty 3886.27 ms 1230.85 ms -2655.42 ms
a5d243c+dirty 3842.35 ms 1214.29 ms -2628.06 ms
244f6e8+dirty 3833.36 ms 1212.96 ms -2620.41 ms

App size

Revision Plain With Sentry Diff
7a89652+dirty 5.15 MiB 6.70 MiB 1.55 MiB
0b1b5e3+dirty 5.15 MiB 6.70 MiB 1.54 MiB
eb55864+dirty 5.15 MiB 6.88 MiB 1.73 MiB
3e3142c+dirty 4.98 MiB 6.56 MiB 1.58 MiB
9210ae6+dirty 5.15 MiB 6.68 MiB 1.53 MiB
6177334+dirty 5.15 MiB 6.68 MiB 1.53 MiB
3a829f0+dirty 5.15 MiB 6.70 MiB 1.54 MiB
2cac31b+dirty 4.98 MiB 6.55 MiB 1.58 MiB
a5d243c+dirty 5.15 MiB 6.68 MiB 1.53 MiB
244f6e8+dirty 4.98 MiB 6.56 MiB 1.58 MiB

Previous results on branch: test/replay-runtime-controls-e2e

Startup times

Revision Plain With Sentry Diff
dca994f+dirty 3855.98 ms 1225.33 ms -2630.64 ms
3e493d9+dirty 3859.54 ms 1241.19 ms -2618.35 ms

App size

Revision Plain With Sentry Diff
dca994f+dirty 5.15 MiB 6.90 MiB 1.75 MiB
3e493d9+dirty 5.15 MiB 6.90 MiB 1.75 MiB

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3845.06 ms 1230.10 ms -2614.96 ms
Size 5.15 MiB 6.90 MiB 1.75 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
7a89652+dirty 3827.11 ms 1211.49 ms -2615.62 ms
0a147b2+dirty 3845.11 ms 1230.81 ms -2614.30 ms
5b7e8a7+dirty 3855.46 ms 1234.47 ms -2620.99 ms
5fe1c6c+dirty 1201.36 ms 1209.15 ms 7.78 ms
580fb5c+dirty 3835.45 ms 1218.61 ms -2616.84 ms
94af3bd+dirty 3847.84 ms 1230.33 ms -2617.51 ms
f3215d3+dirty 3846.08 ms 1231.85 ms -2614.23 ms
a636fa4+dirty 3846.16 ms 1210.10 ms -2636.05 ms
5a21b51+dirty 3837.87 ms 1223.47 ms -2614.40 ms
bbb8d67+dirty 3847.47 ms 1225.13 ms -2622.34 ms

App size

Revision Plain With Sentry Diff
7a89652+dirty 5.15 MiB 6.70 MiB 1.55 MiB
0a147b2+dirty 4.98 MiB 6.51 MiB 1.53 MiB
5b7e8a7+dirty 5.15 MiB 6.70 MiB 1.54 MiB
5fe1c6c+dirty 3.38 MiB 4.77 MiB 1.39 MiB
580fb5c+dirty 4.98 MiB 6.46 MiB 1.48 MiB
94af3bd+dirty 5.15 MiB 6.69 MiB 1.53 MiB
f3215d3+dirty 5.15 MiB 6.67 MiB 1.52 MiB
a636fa4+dirty 4.98 MiB 6.55 MiB 1.57 MiB
5a21b51+dirty 5.15 MiB 6.67 MiB 1.51 MiB
bbb8d67+dirty 4.98 MiB 6.55 MiB 1.57 MiB

Previous results on branch: test/replay-runtime-controls-e2e

Startup times

Revision Plain With Sentry Diff
dca994f+dirty 3851.82 ms 1233.59 ms -2618.23 ms
3e493d9+dirty 3871.14 ms 1234.98 ms -2636.17 ms

App size

Revision Plain With Sentry Diff
dca994f+dirty 5.15 MiB 6.90 MiB 1.75 MiB
3e493d9+dirty 5.15 MiB 6.90 MiB 1.75 MiB

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Android (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 413.08 ms 434.61 ms 21.53 ms
Size 50.56 MiB 56.49 MiB 5.93 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
6a3eb4c+dirty 525.65 ms 562.32 ms 36.67 ms
2cac31b+dirty 416.45 ms 449.45 ms 33.00 ms
9ad4522+dirty 432.43 ms 450.91 ms 18.49 ms
3ce5254+dirty 373.90 ms 427.84 ms 53.94 ms
b04af96+dirty 430.33 ms 485.98 ms 55.65 ms
68ae91b+dirty 515.04 ms 578.08 ms 63.04 ms
f3215d3+dirty 396.53 ms 436.66 ms 40.13 ms
a736b76+dirty 405.78 ms 458.74 ms 52.96 ms
2363c0f+dirty 419.48 ms 463.92 ms 44.44 ms
038a6d7+dirty 499.02 ms 527.68 ms 28.66 ms

App size

Revision Plain With Sentry Diff
6a3eb4c+dirty 49.74 MiB 55.44 MiB 5.70 MiB
2cac31b+dirty 49.74 MiB 55.37 MiB 5.63 MiB
9ad4522+dirty 49.74 MiB 55.38 MiB 5.63 MiB
3ce5254+dirty 43.94 MiB 48.98 MiB 5.04 MiB
b04af96+dirty 49.74 MiB 55.00 MiB 5.26 MiB
68ae91b+dirty 49.74 MiB 54.79 MiB 5.05 MiB
f3215d3+dirty 48.30 MiB 53.49 MiB 5.19 MiB
a736b76+dirty 48.30 MiB 53.48 MiB 5.18 MiB
2363c0f+dirty 49.74 MiB 54.84 MiB 5.10 MiB
038a6d7+dirty 48.30 MiB 53.60 MiB 5.30 MiB

Previous results on branch: test/replay-runtime-controls-e2e

Startup times

Revision Plain With Sentry Diff
dca994f+dirty 536.64 ms 578.88 ms 42.24 ms
3e493d9+dirty 521.27 ms 568.02 ms 46.75 ms

App size

Revision Plain With Sentry Diff
dca994f+dirty 50.56 MiB 56.49 MiB 5.93 MiB
3e493d9+dirty 50.56 MiB 56.49 MiB 5.93 MiB

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

⚠️ Auth token handling changes detected

This PR modifies code related to Sentry auth token handling. Please ensure no auth tokens are accidentally exposed or mishandled. See GHSA-68c2-4mpx-qh95 for context.

Files with auth token changes:

  • dev-packages/e2e-tests/maestro/utils/assertNoReplay.yml
  • dev-packages/e2e-tests/maestro/utils/assertReplayById.yml

Generated by 🚫 dangerJS against d7aab95

@antonis
antonis added this pull request to stack #6705 September 11, 2026 12:52
@antonis
antonis marked this pull request as ready for review September 14, 2026 09:49

@antonis antonis left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #6721 to follow up on the disabled iOS check c9c0789

@antonis antonis linked an issue Sep 14, 2026 that may be closed by this pull request
antonis and others added 4 commits September 14, 2026 13:12
Adds a manualReplay Maestro flow that exercises the Session Replay
runtime controls end-to-end. It launches with buffer-mode replay off
(replaysOnErrorSampleRate: 0) and no session sampling, taps a new
"Start Replay" button that calls Sentry.getReplay().start(), then
captures an exception and reuses assertReplay.yml to assert a real
replay (replay_id, duration, segments, valid MP4) came back from the
Sentry API.

With both sample rates off, the replay can only exist if start()
actually drove native recording across the bridge, so this closes the
gap the Jest and native unit tests can't — they mock the bridge and
stop there. The flow is auto-discovered by cli.mjs and runs on both
platforms, reusing the existing prime + assert utilities.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a replayStopResume Maestro flow that exercises the remaining
Session Replay runtime controls end-to-end, building on the start()
coverage in manualReplay:

- pause() + resume() must not crash and must leave recording active —
  after resuming, a captured error still carries a replay.
- stop() must halt recording — a subsequent error carries no replay,
  asserted via a new "noReplay" sentryApi case + assertNoReplay utility
  (the positive assertReplay throws when a replay_id is absent, so it
  can't prove halting on its own).

Buffer-mode replay is off and there is no session sampling, so a replay
can only exist while a manually-started session is actively recording,
which lets each assertion isolate what the control did. flush() and
startBuffering() are left for a follow-up (no error event to key the
assertion off standalone).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a no-error end-to-end path for the buffered-flush runtime controls:
startBuffering() records a buffer regardless of sample rate, and flush()
converts it to a session replay and uploads it immediately. The app surfaces
getReplay().getReplayId(), so the replay is asserted by querying it directly
(replayById), rather than discovering a replay_id on a captured error event.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The stop() "subsequent error carries no replay" assertion fails on iOS:
sentry-cocoa's stop() does not clear scope.replayId, so an error captured
after stop() still carries the stopped replay's id — unlike Android/sentry-java,
which reset it to EMPTY_ID. Gate the assertion to Android via when.platform
until the cocoa fix lands, then re-enable it cross-platform. pause()/resume()
coverage stays on both platforms.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@antonis
antonis force-pushed the test/replay-runtime-controls-e2e branch from c9c0789 to 6f97d4f Compare September 14, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Document and validate React Native Replay runtime controls

1 participant