feat: remove stale gestures when diff#2297
Conversation
🦋 Changeset detectedLatest commit: b34a34e The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a PAPI binding Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
208e3fc to
05b9dc0
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/react/runtime/__test__/snapshot/gesture.test.jsx (1)
360-360: Consider extracting repeated text element lookup helper.The traversal
__root.__element_root.children[0].children[0]is repeated multiple times and is brittle to tree-shape changes; a local helper would improve maintainability.♻️ Optional refactor
+const getTextElement = () => __root.__element_root.children[0].children[0]; ... -const textElement = __root.__element_root.children[0].children[0]; +const textElement = getTextElement();Also applies to: 702-702, 848-848, 1119-1119
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/__test__/snapshot/gesture.test.jsx` at line 360, The test repeats the brittle traversal __root.__element_root.children[0].children[0]; extract a small helper (e.g., getTextElement or findTextElement) that returns that node so all occurrences call that function instead of duplicating the path; update usages at the locations referencing __root.__element_root.children[0].children[0] to call the helper, improving readability and making future tree-shape changes easier to handle.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/react/runtime/__test__/snapshot/gesture.test.jsx`:
- Line 360: The test repeats the brittle traversal
__root.__element_root.children[0].children[0]; extract a small helper (e.g.,
getTextElement or findTextElement) that returns that node so all occurrences
call that function instead of duplicating the path; update usages at the
locations referencing __root.__element_root.children[0].children[0] to call the
helper, improving readability and making future tree-shape changes easier to
handle.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.changeset/all-crabs-smell.md.changeset/fair-horses-worry.mdpackages/react/runtime/__test__/snapshot/gesture.test.jsxpackages/react/runtime/__test__/utils/nativeMethod.tspackages/react/runtime/src/alog/elementPAPICall.tspackages/react/runtime/src/gesture/processGesture.tspackages/react/runtime/types/types.d.tspackages/testing-library/testing-environment/etc/testing-environment.api.mdpackages/testing-library/testing-environment/src/lynx/ElementPAPI.ts
05b9dc0 to
5ba138f
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
packages/react/runtime/src/gesture/processGesture.ts (1)
190-207: Verify: Positional fallback for old gesture matching.The fallback
?? uniqOldBaseGestures[index]on line 197 uses positional matching when gesture IDs don't match. This is passed togetGestureInfowhich uses it foronWorkletCtxUpdatecallback diffing.This heuristic works well when gesture order is preserved but IDs regenerate. However, if gesture structure changes significantly (e.g., gestures reordered), incorrect
oldGesturereferences could lead to suboptimal worklet context updates.Consider whether this is the intended behavior or if passing
undefinedwhen ID lookup fails would be safer.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/src/gesture/processGesture.ts` around lines 190 - 207, The current positional fallback (uniqOldBaseGestures[index]) when oldBaseGesturesById.get(baseGesture.id) returns undefined can incorrectly pair gestures after reordering; update the matching logic so that if the ID lookup fails we pass undefined into getGestureInfo instead of using the positional fallback—i.e., replace the expression oldBaseGesturesById.get(baseGesture.id) ?? uniqOldBaseGestures[index] with just oldBaseGesturesById.get(baseGesture.id) (or explicit ?? undefined) so getGestureInfo (and its onWorkletCtxUpdate diffing) only compares by actual ID matches; keep the surrounding loop and subsequent __SetGestureDetector/removeGestureDetector calls unchanged.packages/react/runtime/__test__/gesture/processGesture.test.ts (1)
91-126: Make “remove before set” ordering explicit in assertions.These tests validate both calls happened, but not the sequence. Since the behavior contract is specifically stale-removal-first, please add an explicit order assertion so set-before-remove cannot pass.
Also applies to: 199-228
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/__test__/gesture/processGesture.test.ts` around lines 91 - 126, The test currently asserts both removeGestureDetector and setGestureDetector were called but not their sequence; update the test for processGesture to explicitly assert remove happens before set by checking the mock invocation order (compare removeGestureDetector.mock.invocationCallOrder[0] < setGestureDetector.mock.invocationCallOrder[0]) after the existing expectations; apply the same explicit ordering assertion to the other similar test block (the one around lines 199-228) to enforce the "remove-before-set" contract for processGesture.examples/gesture/src/App.tsx (1)
18-84: Consider extracting shared PanGesture wiring to reduce drift.
panGestureAandpanGestureBcurrently duplicate most lifecycle handler structure. A small helper/custom hook for shared begin/end handling and axis-specific update logic would make future edits safer.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/gesture/src/App.tsx` around lines 18 - 84, panGestureA and panGestureB duplicate lifecycle handlers; extract shared wiring into a helper (e.g., createPanHandlers or useSharedPanGesture) to centralize onBegin/onEnd logic and accept an axis-specific onUpdate callback. Move shared behavior that uses startPointMTRef and baseOffsetMTRef (setting startPoint, opacity changes, computing dx/dy updates to baseOffset, and logging) into that helper, and have panGestureA/panGestureB call useGesture(PanGesture).onBegin/onUpdate/onEnd with the shared handlers, passing a small axis-specific updater for panGestureB to only modify x. This keeps unique parts (axis constrain and transform string) configurable while reusing start/end behavior and refs.packages/react/runtime/__test__/snapshot/gesture.test.jsx (1)
850-872: Add explicit sequence checks for remove-then-set behavior.In update/diff paths, these assertions should also verify removal occurs before installation of the new detector to lock the stale-cleanup guarantee.
Also applies to: 1176-1180
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/__test__/snapshot/gesture.test.jsx` around lines 850 - 872, Add assertions that the removal spy is invoked before the set spy to enforce remove-then-set ordering: after the existing checks referencing spySetGesture, spyRemoveGesture and elementTree.__GetGestureDetectorIds, add an order assertion using Jest's mock.invocationCallOrder (e.g., expect(spyRemoveGesture.mock.invocationCallOrder[0]).toBeLessThan(spySetGesture.mock.invocationCallOrder[0])) so the test verifies removal happens before installation; apply the same change at the other location that mirrors these assertions (the block around lines 1176-1180) and reference the same spies (spyRemoveGesture, spySetGesture) when adding the order check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/testing-library/testing-environment/src/lynx/ElementPAPI.ts`:
- Around line 318-322: The condition in __RemoveGestureDetector incorrectly
checks e.gesture?.[id] (accessing a numeric property) so removal can fail;
update the check to compare the stored gesture object's id (e.g., e.gesture?.id
=== id) to match how __SetGestureDetector stores gesture as { id, type, config,
relationMap }, then delete e.gesture when the ids match; mirror the approach
used in __SetGestureDetector and the test reference where they use
props.gesture?.id.
---
Nitpick comments:
In `@examples/gesture/src/App.tsx`:
- Around line 18-84: panGestureA and panGestureB duplicate lifecycle handlers;
extract shared wiring into a helper (e.g., createPanHandlers or
useSharedPanGesture) to centralize onBegin/onEnd logic and accept an
axis-specific onUpdate callback. Move shared behavior that uses startPointMTRef
and baseOffsetMTRef (setting startPoint, opacity changes, computing dx/dy
updates to baseOffset, and logging) into that helper, and have
panGestureA/panGestureB call useGesture(PanGesture).onBegin/onUpdate/onEnd with
the shared handlers, passing a small axis-specific updater for panGestureB to
only modify x. This keeps unique parts (axis constrain and transform string)
configurable while reusing start/end behavior and refs.
In `@packages/react/runtime/__test__/gesture/processGesture.test.ts`:
- Around line 91-126: The test currently asserts both removeGestureDetector and
setGestureDetector were called but not their sequence; update the test for
processGesture to explicitly assert remove happens before set by checking the
mock invocation order (compare removeGestureDetector.mock.invocationCallOrder[0]
< setGestureDetector.mock.invocationCallOrder[0]) after the existing
expectations; apply the same explicit ordering assertion to the other similar
test block (the one around lines 199-228) to enforce the "remove-before-set"
contract for processGesture.
In `@packages/react/runtime/__test__/snapshot/gesture.test.jsx`:
- Around line 850-872: Add assertions that the removal spy is invoked before the
set spy to enforce remove-then-set ordering: after the existing checks
referencing spySetGesture, spyRemoveGesture and
elementTree.__GetGestureDetectorIds, add an order assertion using Jest's
mock.invocationCallOrder (e.g.,
expect(spyRemoveGesture.mock.invocationCallOrder[0]).toBeLessThan(spySetGesture.mock.invocationCallOrder[0]))
so the test verifies removal happens before installation; apply the same change
at the other location that mirrors these assertions (the block around lines
1176-1180) and reference the same spies (spyRemoveGesture, spySetGesture) when
adding the order check.
In `@packages/react/runtime/src/gesture/processGesture.ts`:
- Around line 190-207: The current positional fallback
(uniqOldBaseGestures[index]) when oldBaseGesturesById.get(baseGesture.id)
returns undefined can incorrectly pair gestures after reordering; update the
matching logic so that if the ID lookup fails we pass undefined into
getGestureInfo instead of using the positional fallback—i.e., replace the
expression oldBaseGesturesById.get(baseGesture.id) ?? uniqOldBaseGestures[index]
with just oldBaseGesturesById.get(baseGesture.id) (or explicit ?? undefined) so
getGestureInfo (and its onWorkletCtxUpdate diffing) only compares by actual ID
matches; keep the surrounding loop and subsequent
__SetGestureDetector/removeGestureDetector calls unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bc2c5867-861d-4996-b94b-1bcfb0cfed8c
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
.changeset/all-crabs-smell.md.changeset/fair-horses-worry.mdexamples/gesture/lynx.config.jsexamples/gesture/package.jsonexamples/gesture/src/App.cssexamples/gesture/src/App.tsxexamples/gesture/src/index.tsxexamples/gesture/src/rspeedy-env.d.tsexamples/gesture/tsconfig.jsonpackages/react/runtime/__test__/gesture/processGesture.test.tspackages/react/runtime/__test__/snapshot/gesture.test.jsxpackages/react/runtime/__test__/utils/nativeMethod.tspackages/react/runtime/src/alog/elementPAPICall.tspackages/react/runtime/src/gesture/processGesture.tspackages/react/runtime/types/types.d.tspackages/testing-library/testing-environment/etc/testing-environment.api.mdpackages/testing-library/testing-environment/src/lynx/ElementPAPI.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/react/runtime/src/alog/elementPAPICall.ts
- .changeset/fair-horses-worry.md
- packages/testing-library/testing-environment/etc/testing-environment.api.md
- .changeset/all-crabs-smell.md
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Merging this PR will not alter performance
Comparing Footnotes
|
Web Explorer#8804 Bundle Size — 748.66KiB (0%).b34a34e(current) vs fd0cc6e main#8801(baseline) Bundle metrics
Bundle size by type
|
| Current #8804 |
Baseline #8801 |
|
|---|---|---|
401.63KiB |
401.63KiB |
|
344.87KiB |
344.87KiB |
|
2.16KiB |
2.16KiB |
Bundle analysis report Branch f0rdream:gesture_stale_removal Project dashboard
Generated by RelativeCI Documentation Report issue
5ba138f to
b477f9b
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (2)
examples/gesture/src/App.tsx (2)
18-51: Consider wrapping gesture callback registration inuseMemooruseEffect.The gesture callback chain (
.onBegin().onUpdate().onEnd()) executes on every render, which may re-register callbacks unnecessarily. For a demo app this is fine, but in production code you'd want to memoize this setup.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/gesture/src/App.tsx` around lines 18 - 51, The chained gesture callbacks registered on panGestureA (returned by useGesture(PanGesture)) are currently re-attached on every render; move the .onBegin/.onUpdate/.onEnd registration into a useEffect (or create the gesture once with useMemo) so the handlers are only registered once or when dependencies change; reference startPointMTRef and baseOffsetMTRef in the effect dependency list (or use refs so deps can be stable), and if the gesture API exposes a teardown/unsubscribe, call it in the effect cleanup to avoid duplicate listeners.
53-84: Shared refs between gestures may cause coordinate drift when switching modes.Both
panGestureAandpanGestureBsharestartPointMTRefandbaseOffsetMTRef. When switching from A (X+Y) to B (X-only) and back, the Y offset resets to 0 (line 80), which could cause unexpected position jumps. For a demo this is acceptable, but consider separate refs if independent gesture state is needed.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/gesture/src/App.tsx` around lines 53 - 84, panGestureB and panGestureA share startPointMTRef and baseOffsetMTRef which causes Y to be reset to 0 in panGestureB.onEnd; either give panGestureB its own refs (e.g., startPointMTRefB, baseOffsetMTRefB) and use them in panGestureB handlers, or change panGestureB.onEnd to preserve the existing Y by reading baseOffsetMTRef.current.y and only updating X (set baseOffsetMTRef.current = { x: baseOffsetMTRef.current.x + dx, y: baseOffsetMTRef.current.y }); update corresponding onBegin/onUpdate to use the chosen refs consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@examples/gesture/src/App.tsx`:
- Around line 18-51: The chained gesture callbacks registered on panGestureA
(returned by useGesture(PanGesture)) are currently re-attached on every render;
move the .onBegin/.onUpdate/.onEnd registration into a useEffect (or create the
gesture once with useMemo) so the handlers are only registered once or when
dependencies change; reference startPointMTRef and baseOffsetMTRef in the effect
dependency list (or use refs so deps can be stable), and if the gesture API
exposes a teardown/unsubscribe, call it in the effect cleanup to avoid duplicate
listeners.
- Around line 53-84: panGestureB and panGestureA share startPointMTRef and
baseOffsetMTRef which causes Y to be reset to 0 in panGestureB.onEnd; either
give panGestureB its own refs (e.g., startPointMTRefB, baseOffsetMTRefB) and use
them in panGestureB handlers, or change panGestureB.onEnd to preserve the
existing Y by reading baseOffsetMTRef.current.y and only updating X (set
baseOffsetMTRef.current = { x: baseOffsetMTRef.current.x + dx, y:
baseOffsetMTRef.current.y }); update corresponding onBegin/onUpdate to use the
chosen refs consistently.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b66935e9-4876-4d70-b13f-ce4fb643ef3a
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
.changeset/all-crabs-smell.md.changeset/fair-horses-worry.mdexamples/gesture/lynx.config.jsexamples/gesture/package.jsonexamples/gesture/src/App.cssexamples/gesture/src/App.tsxexamples/gesture/src/index.tsxexamples/gesture/src/rspeedy-env.d.tsexamples/gesture/tsconfig.jsonpackages/react/runtime/__test__/gesture/processGesture.test.tspackages/react/runtime/__test__/snapshot/gesture.test.jsxpackages/react/runtime/__test__/utils/nativeMethod.tspackages/react/runtime/src/alog/elementPAPICall.tspackages/react/runtime/src/gesture/processGesture.tspackages/react/runtime/types/types.d.tspackages/testing-library/testing-environment/etc/testing-environment.api.mdpackages/testing-library/testing-environment/src/lynx/ElementPAPI.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/react/runtime/test/gesture/processGesture.test.ts
- .changeset/all-crabs-smell.md
- packages/testing-library/testing-environment/etc/testing-environment.api.md
- examples/gesture/lynx.config.js
- packages/testing-library/testing-environment/src/lynx/ElementPAPI.ts
- .changeset/fair-horses-worry.md
- packages/react/runtime/src/alog/elementPAPICall.ts
b477f9b to
c7d2583
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/react/runtime/__test__/gesture/processGesture.test.ts`:
- Around line 5-7: The test mock replaces onWorkletCtxUpdate with a no-op so
processGesture never triggers lynxWorkletImpl._hydrateCtx; update the mock in
the test to delegate to the real implementation instead of blocking it (e.g.,
use a spy or a wrapper that calls the original onWorkletCtxUpdate) so that
processGesture can exercise lynxWorkletImpl._hydrateCtx and the "consumes old
gestures..." assertion observes the hydrateCtx calls.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 57ffe947-a7d7-4578-acc7-4b1ab7bca41d
📒 Files selected for processing (15)
.changeset/all-crabs-smell.md.changeset/fair-horses-worry.mdexamples/gesture/lynx.config.jsexamples/gesture/package.jsonexamples/gesture/src/App.cssexamples/gesture/src/App.tsxexamples/gesture/src/index.tsxexamples/gesture/src/rspeedy-env.d.tsexamples/gesture/tsconfig.jsonpackages/react/runtime/__test__/gesture/processGesture.test.tspackages/react/runtime/__test__/snapshot/gesture.test.jsxpackages/react/runtime/__test__/utils/nativeMethod.tspackages/react/runtime/src/alog/elementPAPICall.tspackages/react/runtime/src/gesture/processGesture.tspackages/react/runtime/types/types.d.ts
✅ Files skipped from review due to trivial changes (7)
- .changeset/fair-horses-worry.md
- .changeset/all-crabs-smell.md
- examples/gesture/tsconfig.json
- packages/react/runtime/src/alog/elementPAPICall.ts
- examples/gesture/package.json
- examples/gesture/src/rspeedy-env.d.ts
- examples/gesture/lynx.config.js
🚧 Files skipped from review as they are similar to previous changes (2)
- examples/gesture/src/index.tsx
- packages/react/runtime/types/types.d.ts
c7d2583 to
83e401c
Compare
React External#348 Bundle Size — 591.76KiB (+0.28%).b34a34e(current) vs fd0cc6e main#345(baseline) Bundle metrics
Bundle size by type
Bundle analysis report Branch f0rdream:gesture_stale_removal Project dashboard Generated by RelativeCI Documentation Report issue |
React Example#7230 Bundle Size — 236.83KiB (0%).b34a34e(current) vs fd0cc6e main#7227(baseline) Bundle metrics
Bundle size by type
|
| Current #7230 |
Baseline #7227 |
|
|---|---|---|
145.76KiB |
145.76KiB |
|
91.07KiB |
91.07KiB |
Bundle analysis report Branch f0rdream:gesture_stale_removal Project dashboard
Generated by RelativeCI Documentation Report issue
React MTF Example#363 Bundle Size — 206.12KiB (0%).b34a34e(current) vs fd0cc6e main#360(baseline) Bundle metrics
Bundle size by type
|
| Current #363 |
Baseline #360 |
|
|---|---|---|
111.23KiB |
111.23KiB |
|
94.89KiB |
94.89KiB |
Bundle analysis report Branch f0rdream:gesture_stale_removal Project dashboard
Generated by RelativeCI Documentation Report issue
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/react/runtime/__test__/snapshot/gesture.test.jsx (2)
1117-1117: Minor: prefer idiomatic vitest assertion.Using
.not.toContain()is more readable than.includes().toBe(false).♻️ Suggested change
- expect(elementTree.__GetGestureDetectorIds(textElement).includes(1)).toBe(false); + expect(elementTree.__GetGestureDetectorIds(textElement)).not.toContain(1);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/__test__/snapshot/gesture.test.jsx` at line 1117, Replace the non-idiomatic assertion that checks absence via includes().toBe(false) with Vitest's clearer negated containment matcher: locate the assertion using elementTree.__GetGestureDetectorIds(textElement) and change the expectation to use expect(...).not.toContain(1) so the test reads more idiomatically and improves readability.
15-51: Consider extracting duplicatelynxWorkletImplmock setup.The identical
lynxWorkletImplobject is defined in bothbeforeAll(lines 15-30) andbeforeEach(lines 36-51). This duplication can lead to maintenance burden if the mock structure changes.♻️ Proposed refactor to extract shared mock
+const createLynxWorkletImplMock = () => ({ + _refImpl: { + clearFirstScreenWorkletRefMap: vi.fn(), + }, + _runOnBackgroundDelayImpl: { + runDelayedBackgroundFunctions: vi.fn(), + }, + _hydrateCtx: vi.fn(), + _jsFunctionLifecycleManager: { + addRef: vi.fn(), + }, + _eventDelayImpl: { + runDelayedWorklet: vi.fn(), + clearDelayedWorklets: vi.fn(), + }, +}); + beforeAll(() => { setupPage(__CreatePage('0', 0)); injectUpdateMainThread(); replaceCommitHook(); - globalThis.lynxWorkletImpl = { - _refImpl: { - clearFirstScreenWorkletRefMap: vi.fn(), - }, - ... - }; + globalThis.lynxWorkletImpl = createLynxWorkletImplMock(); }); beforeEach(() => { globalEnvManager.resetEnv(); SystemInfo.lynxSdkVersion = '999.999'; - globalThis.lynxWorkletImpl = { - _refImpl: { - clearFirstScreenWorkletRefMap: vi.fn(), - }, - ... - }; + globalThis.lynxWorkletImpl = createLynxWorkletImplMock(); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/react/runtime/__test__/snapshot/gesture.test.jsx` around lines 15 - 51, Duplicate mock initialization of globalThis.lynxWorkletImpl in the test file should be extracted into a single helper to avoid maintenance drift: create a function (e.g., setupLynxWorkletImplMock) that builds the mock object with the same nested fns (_refImpl.clearFirstScreenWorkletRefMap, _runOnBackgroundDelayImpl.runDelayedBackgroundFunctions, _hydrateCtx, _jsFunctionLifecycleManager.addRef, _eventDelayImpl.runDelayedWorklet/clearDelayedWorklets) and assign it to globalThis.lynxWorkletImpl, then call that helper from both beforeAll and beforeEach (keeping other lines like globalEnvManager.resetEnv() and SystemInfo.lynxSdkVersion assignment unchanged).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/react/runtime/__test__/snapshot/gesture.test.jsx`:
- Line 1117: Replace the non-idiomatic assertion that checks absence via
includes().toBe(false) with Vitest's clearer negated containment matcher: locate
the assertion using elementTree.__GetGestureDetectorIds(textElement) and change
the expectation to use expect(...).not.toContain(1) so the test reads more
idiomatically and improves readability.
- Around line 15-51: Duplicate mock initialization of globalThis.lynxWorkletImpl
in the test file should be extracted into a single helper to avoid maintenance
drift: create a function (e.g., setupLynxWorkletImplMock) that builds the mock
object with the same nested fns (_refImpl.clearFirstScreenWorkletRefMap,
_runOnBackgroundDelayImpl.runDelayedBackgroundFunctions, _hydrateCtx,
_jsFunctionLifecycleManager.addRef,
_eventDelayImpl.runDelayedWorklet/clearDelayedWorklets) and assign it to
globalThis.lynxWorkletImpl, then call that helper from both beforeAll and
beforeEach (keeping other lines like globalEnvManager.resetEnv() and
SystemInfo.lynxSdkVersion assignment unchanged).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ed8377b8-5885-4eb5-9c32-20e3aba6033c
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
.changeset/all-crabs-smell.md.changeset/fair-horses-worry.mdexamples/gesture/lynx.config.jsexamples/gesture/package.jsonexamples/gesture/src/App.cssexamples/gesture/src/App.tsxexamples/gesture/src/index.tsxexamples/gesture/src/rspeedy-env.d.tsexamples/gesture/tsconfig.jsonpackages/react/runtime/__test__/gesture/processGesture.test.tspackages/react/runtime/__test__/snapshot/gesture.test.jsxpackages/react/runtime/__test__/utils/nativeMethod.tspackages/react/runtime/src/alog/elementPAPICall.tspackages/react/runtime/src/gesture/processGesture.tspackages/react/runtime/types/types.d.tspackages/testing-library/testing-environment/etc/testing-environment.api.mdpackages/testing-library/testing-environment/src/lynx/ElementPAPI.ts
✅ Files skipped from review due to trivial changes (7)
- .changeset/fair-horses-worry.md
- .changeset/all-crabs-smell.md
- examples/gesture/src/rspeedy-env.d.ts
- examples/gesture/src/index.tsx
- examples/gesture/lynx.config.js
- examples/gesture/package.json
- packages/react/runtime/test/gesture/processGesture.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/testing-library/testing-environment/src/lynx/ElementPAPI.ts
- packages/react/runtime/types/types.d.ts
- examples/gesture/tsconfig.json
- packages/react/runtime/src/alog/elementPAPICall.ts
- packages/testing-library/testing-environment/etc/testing-environment.api.md
- packages/react/runtime/test/utils/nativeMethod.ts
- packages/react/runtime/src/gesture/processGesture.ts
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @lynx-js/react@0.119.0 ### Minor Changes - Simplify hooks for main-thread runtime, which only can run during the first screen. ([#2441](#2441)) ### Patch Changes - Remove stale gestures when gestures are removed ([#2297](#2297)) - Trace refactor ([#2466](#2466)) - Remove `ReactLynx::renderOpcodes` from the trace - Use `ReactLynx::transferRoot` to measure the time spent transferring the root to the background thread - refactor: set state of suspense to render fallback ([#2450](#2450)) - Support rstest for testing library, you can use rstest with RLTL now: ([#2328](#2328)) Create a config file `rstest.config.ts` with the following content: ```ts import { defineConfig } from "@rstest/core"; import { withLynxConfig } from "@lynx-js/react/testing-library/rstest-config"; export default defineConfig({ extends: withLynxConfig(), }); ``` `@lynx-js/react/testing-library/rstest-config` will automatically load your `lynx.config.ts` and apply the same configuration to rstest, so you can keep your test environment consistent with your development environment. And then use rstest as usual: ```bash $ rstest ``` For more usage detail, see <https://rstest.rs/> - Update preact version ([#2456](#2456)) - Add `nodeIndex` to generated FiberElement creation calls and expose React transform debug metadata as `uiSourceMapRecords`. ([#2402](#2402)) ## @lynx-js/react-rsbuild-plugin@0.16.0 ### Minor Changes - Simplify hooks for main-thread runtime, which only can run during the first screen. ([#2441](#2441)) ### Patch Changes - Support rstest for testing library using a dedicated testing loader. ([#2328](#2328)) - Fix `environments.lynx.performance.profile` so it overrides the default profile behavior for the current environment. ([#2468](#2468)) - Add `enableUiSourceMap` option to enable UI source map generation and debug-metadata asset emission. ([#2402](#2402)) - Updated dependencies \[[`a9f8d05`](a9f8d05), [`b1ad1b9`](b1ad1b9), [`f6184f3`](f6184f3), [`f6184f3`](f6184f3), [`a9f8d05`](a9f8d05), [`f542d9c`](f542d9c)]: - @lynx-js/template-webpack-plugin@0.10.9 - @lynx-js/react-webpack-plugin@0.9.1 - @lynx-js/react-alias-rsbuild-plugin@0.16.0 - @lynx-js/css-extract-webpack-plugin@0.7.0 - @lynx-js/react-refresh-webpack-plugin@0.3.5 - @lynx-js/use-sync-external-store@1.5.0 ## @lynx-js/react-alias-rsbuild-plugin@0.16.0 ### Minor Changes - Simplify hooks for main-thread runtime, which only can run during the first screen. ([#2441](#2441)) ### Patch Changes - fix(rstest): add global fallback aliases for `@lynx-js/react/jsx-runtime` and `@lynx-js/react/jsx-dev-runtime` ([#2464](#2464)) `pluginReactAlias` only aliased these entries inside layer-specific rules (`issuerLayer: BACKGROUND/MAIN_THREAD`). In rstest mode there are no layers, so JSX transformed by the testing loader—which emits `import { jsx } from '@lynx-js/react/jsx-runtime'`—could not be resolved, causing a `Cannot find module '@lynx-js/react/jsx-runtime'` error. Added global (non-layer-specific) fallback aliases pointing to the background jsx-runtime. ## @lynx-js/testing-environment@0.2.0 ### Minor Changes - **BREAKING CHANGE**: ([#2328](#2328)) Align the public test-environment API around `LynxEnv`. `LynxTestingEnv` now expects a `{ window }`-shaped environment instead of relying on a concrete `JSDOM` instance or `global.jsdom`. Callers that construct `LynxTestingEnv` manually or initialize the environment through globals should migrate to `new LynxTestingEnv({ window })` or set `global.lynxEnv`. This release also adds the `@lynx-js/testing-environment/env/rstest` entry for running the shared testing-environment suite under rstest. ### Patch Changes - Add `__RemoveGestureDetector` PAPI binding ([#2297](#2297)) ## @lynx-js/rspeedy@0.14.2 ### Patch Changes - Updated dependencies \[]: - @lynx-js/web-rsbuild-server-middleware@0.20.2 ## create-rspeedy@0.14.2 ### Patch Changes - Add Rstest ReactLynx Testing Library template. ([#2328](#2328)) ## @lynx-js/external-bundle-rsbuild-plugin@0.1.1 ### Patch Changes - Updated dependencies \[[`3262ca8`](3262ca8)]: - @lynx-js/externals-loading-webpack-plugin@0.1.1 ## @lynx-js/web-core@0.20.2 ### Patch Changes - fix: map clientX and clientY to x and y in touch event detail ([#2458](#2458)) - fix(web-platform): completely detach event listeners and forcefully free `MainThreadWasmContext` pointer alongside strict FIFO async component disposal to ensure total memory reclamation without use-after-free risks ([#2457](#2457)) - refactor: with WeakRef in element APIs and WASM bindings to improve memory management. ([#2439](#2439)) - fix: preserve CSS variable fallback values when encoding web-core stylesheets so declarations like `var(--token, rgba(...))` are emitted with their fallback intact. ([#2460](#2460)) - fix: avoid to do use-after-free for rust instance ([#2461](#2461)) - fix: Change uniqueId to uid in LynxCrossThreadEventTarget ([#2467](#2467)) - Updated dependencies \[]: - @lynx-js/web-worker-rpc@0.20.2 ## @lynx-js/externals-loading-webpack-plugin@0.1.1 ### Patch Changes - fix: deduplicate `loadScript` calls for externals sharing the same (bundle, section) pair ([#2465](#2465)) When multiple externals had different `libraryName` values but pointed to the same bundle URL and section path, `createLoadExternalSync`/`createLoadExternalAsync` was called once per external, causing `lynx.loadScript` to execute redundantly for the same section. Now only the first external in each `(url, sectionPath)` group triggers the load; subsequent externals in the group are assigned the already-loaded result directly. ## @lynx-js/react-webpack-plugin@0.9.1 ### Patch Changes - Support rstest for testing library using a dedicated testing loader. ([#2328](#2328)) - fix(rstest): normalize partial `compat` options in the testing loader ([#2464](#2464)) The testing loader forwards `compat` directly to `transformReactLynxSync` without normalization. When `compat` is supplied as a partial object, the required `target` field is absent and the WASM transform throws `Error: Missing field 'target'`. Added the same normalization already present in `getCommonOptions` for the background/main-thread loaders: fills in `target: 'MIXED'` and all other required fields with sensible defaults. - Add `enableUiSourceMap` option to enable UI source map generation and debug-metadata asset emission. ([#2402](#2402)) ## @lynx-js/template-webpack-plugin@0.10.9 ### Patch Changes - Introduce `LynxDebugMetadataPlugin` to emit debug-metadata assets. ([#2402](#2402)) - Updated dependencies \[[`24c4c69`](24c4c69), [`7332eb4`](7332eb4), [`fd0cc6e`](fd0cc6e), [`e5b0f66`](e5b0f66), [`5aa97d8`](5aa97d8), [`5c39654`](5c39654)]: - @lynx-js/web-core@0.20.2 ## @lynx-js/react-umd@0.119.0 ## upgrade-rspeedy@0.14.2 ## @lynx-js/web-rsbuild-server-middleware@0.20.2 ## @lynx-js/web-worker-rpc@0.20.2 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Style
Checklist