Skip to content

test(Lazy): cover initial render, navigation loading, and reactive each#7

Merged
chiefcll merged 1 commit into
fix/lazy-correctnessfrom
test/lazy-coverage
May 13, 2026
Merged

test(Lazy): cover initial render, navigation loading, and reactive each#7
chiefcll merged 1 commit into
fix/lazy-correctnessfrom
test/lazy-coverage

Conversation

@chiefcll
Copy link
Copy Markdown
Contributor

@chiefcll chiefcll commented May 13, 2026

Stacked on top of #6.

Summary

Two changes:

  1. tests/Lazy.test.tsx — 14 cases focused on the TV-app use case of a Column containing many LazyRows.
  2. src/primitives/VirtualGrid.tsx — fixes a latent module-init bug that vitest exposed.

The VirtualGrid fix

VirtualGrid.tsx had this at module top level:

import * as lngp from '@solidtv/solid/primitives';
const columnScroll = lngp.withScrolling(false);

When the barrel is evaluated, exports populate in declaration order. VirtualGrid is exported before withScrolling in primitives/index.ts, so when VirtualGrid's module-init code runs, lngp.withScrolling is still undefined. Production bundlers reorder the deps and hide the cycle; vitest's vite-node SSR loader doesn't, so the barrel access returns undefined and throws on call.

Fix uses the pre-built scrollColumn constant already exported from ./utils/withScrolling.js — same direct-import pattern Row.tsx uses for scrollRow. As a bonus, deduplicates an identical withScrolling(false) call.

With this fix, the barrel loads cleanly under vitest, so Lazy.tsx does not need its own import workaround. The earlier draft of this PR refactored Lazy's imports; that's been reverted in favor of the real fix.

Test coverage

Initial render

  • sync=true mounts upCount items synchronously
  • !sync ramps up to upCount over time (verifies the 16ms setTimeout chain)
  • Caps at each.length when shorter than upCount
  • Renders nothing when each is null / false

Navigation-driven loading

  • ArrowRight at the buffer edge mounts the next item
  • Mounting stops at each.length
  • No mount fires while selection stays inside the buffer window

Column of LazyRows (the real TV shape)

  • Multiple LazyRows render their upCounts independently
  • Loading more items in one row leaves siblings untouched
  • ArrowDown / ArrowUp between rows preserves each row's loaded count

LazyColumn

  • ArrowDown drives vertical loading

Reactive each

  • Shrinking past selected keeps focus inside a valid index range
  • Growing each.length does not auto-mount beyond the current offset

Cleanup

  • Unmounting mid-preload-ramp produces no errors

Test plan

  • npm run tsc — clean
  • npm test — 134/134 (120 prior + 14 new)
  • Barrel import smoke test: import * as lngp from '@solidtv/solid/primitives' now succeeds under vitest

🤖 Generated with Claude Code

Adds tests/Lazy.test.tsx with 14 cases focused on the TV-app use case
of a Column of LazyRows:

- Initial render: sync mounts upCount synchronously; !sync ramps up
  via the 16ms setTimeout chain; each shorter than upCount caps the
  visible count; falsy each renders nothing.
- Navigation-driven loading: ArrowRight at the buffer edge mounts the
  next item; mounting stops at each.length; staying inside the buffer
  does not trigger a mount.
- Column of LazyRows (the real TV layout): multiple rows render their
  upCounts independently; loading items in one row leaves siblings
  untouched; moving up/down between rows preserves each row's loaded
  count.
- LazyColumn: ArrowDown drives vertical loading.
- Reactive each: shrinking past selected keeps focus inside a valid
  range; growing each.length does not auto-mount beyond offset.
- Cleanup: unmounting mid-preload-ramp produces no errors.

Tests pass against this branch and (with no further changes) against
main, validating that the prior correctness PR preserved behavior.

Also fixes a latent module-init bug in VirtualGrid that vitest
exposed: VirtualGrid.tsx had `const columnScroll = lngp.withScrolling(false)`
at module top level, reading from the `@solidtv/solid/primitives`
barrel that was still mid-construction (withScrolling is exported
later in the barrel's index). Production bundlers reorder the deps
and hide the cycle; vitest's vite-node SSR loader does not, so the
barrel access returned undefined and threw on call.

The fix uses the pre-built `scrollColumn` constant already exported
from `./utils/withScrolling.js` — same direct-import pattern Row.tsx
uses for `scrollRow`. Deduplicates an identical `withScrolling(false)`
call and removes the module-init-time barrel dependency.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@chiefcll chiefcll force-pushed the test/lazy-coverage branch from 556c8c1 to 226afba Compare May 13, 2026 12:24
@chiefcll chiefcll merged commit 523c2eb into fix/lazy-correctness May 13, 2026
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