test(example): de-flake use-rive-trigger #230 (deterministic re-renders)#303
Merged
Conversation
f092cf5 to
1f39e95
Compare
There was a problem hiding this comment.
Pull request overview
This PR aims to de-flake the useRiveTrigger harness regression test from #230 by removing wall-clock–driven re-render scheduling and replacing it with deterministic, test-driven re-renders, while also pinning iOS CI runners to stabilize simulator availability.
Changes:
- Add an explicit
context.rerender()hook to deterministically churn callback identity in the unstable-callback harness test. - Keep a mount-time JS-thread blocking reproduction in the test as a permanent regression guard.
- Pin iOS GitHub Actions jobs (
build-ios,test-harness-ios) tomacos-15to avoid simulator roulette onmacos-latest.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| example/tests/use-rive-trigger.harness.tsx | Replaces interval-based re-rendering with a deterministic context.rerender() driver and retains a mount-time JS-block regression guard. |
| .github/workflows/ci.yml | Pins iOS jobs to macos-15 to avoid intermittent simulator boot failures tied to macos-latest runner image changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This was referenced Jul 1, 2026
HayesGordon
approved these changes
Jul 1, 2026
The #230 test drove re-renders with setInterval(50ms)/300ms and asserted renderCount >= 3 within a 2000ms waitFor. waitFor resolves the instant renderCount hits 3, so it needs exactly 2 interval ticks — zero margin. When the JS thread is busy at mount (RiveView + dataBind init) the ticks are starved and only 1 lands, so renderCount stays at 2 and the test fails (the intermittent 'expected 2 to be greater than or equal to 3'). Drive the re-renders deterministically via an exposed context.rerender() instead of racing a wall-clock setInterval, removing the timing dependence. Keep the failure condition as a permanent regression guard: a 500ms JS-thread block at mount that starves any re-render driver. The old setInterval version fails 8/8 under it; the deterministic version passes 8/8 — so every run now verifies the fix against the reproduction.
macos-latest is mid-migration to macOS 26. Jobs randomly land on macos-15-arm64 or macos-26-arm64, and only the macOS 15 image has a pre-created iPhone 16 Pro on an iOS >=26 runtime. When a job lands on macos-26 the simulator-action boot step fails with 'No devices found', which is why the same commit passes on one run and fails on another. Pin build-ios and test-harness-ios to macos-15 for deterministic runs.
ea6b23b to
2e2b975
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
#230test drove re-renders withsetInterval(50ms)for 300ms and assertedrenderCount >= 3within a 2000mswaitFor.waitForresolves the instant renderCount hits 3 — i.e. it needs exactly 2 interval ticks, zero margin. When the JS thread is busy at mount (RiveView + dataBind init) the ticks are starved and only 1 lands, so renderCount stays at 2 and the test fails (the intermittentexpected 2 to be greater than or equal to 3).Fix
Drive the re-renders deterministically via an exposed
context.rerender()(the patternissue297.hooksalready uses) instead of racing a wall-clocksetInterval. The callback-identity churn is preserved; the timing dependence is gone.Reproduction kept in the test
The PR keeps the failure condition as a permanent regression guard — a 500ms JS-thread block at mount that starves any re-render driver (what RiveView init does on a slow runner). This is the concrete reproduction:
setIntervalapproach + this block → 8/8 fail (renderCountstuck at 2)So every CI run now verifies the fix against the reproduction, rather than relying on the ~1% natural flake. (Locally I also confirmed the natural flake at ~1%, and that
renderCountlands at exactly 3 — zero margin — on every passing run.)CI changes
This PR is not purely a JS test change — it also touches
.github/workflows/ci.yml:build-ios,test-harness-ios) tomacos-15(Xcode26.3, simulatoriPhone 16 Proon iOS>=26.0).macos-latestis mid-migration to macOS 26, whose simulator set has no matching iPhone 16 Pro / iOS >=26 runtime, which breaks the harness boot ("No devices found"). This overlaps with ci(ios): pin iOS jobs to macos-15 to stabilize simulator boot #300, which pins the same runners; if ci(ios): pin iOS jobs to macos-15 to stabilize simulator boot #300 lands first, this part should be rebased away.test-harness-iosretry loop. The harness can hang indefinitely if the app launches but never connects to the bridge; without a cap a single stuck attempt eats the whole 15-min step budget and the retry loop never advances. macOS has notimeout, so a background watchdog kills the stuck attempt andnuke_harnessreaps the rest before the retry.