Skip to content

fix: counter double-0 + always-latest scaffold; RTL-style @creact-labs/testing; decouple key from identity; drop h - #17

Merged
drn1996 merged 7 commits into
developfrom
fix/counter-double-zero-and-h
Jul 22, 2026
Merged

fix: counter double-0 + always-latest scaffold; RTL-style @creact-labs/testing; decouple key from identity; drop h#17
drn1996 merged 7 commits into
developfrom
fix/counter-double-zero-and-h

Conversation

@drn1996

@drn1996 drn1996 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

One PR covering the counter bug, the always-latest scaffold, a real testing library, and the key/h cleanup you asked for.

1. The double-0 bug

The counter logged Count: 0 twice at startup — the effect ran once on the undefined initial output (shown as 0 via ?? 0) and again when the handler set 0. Now it waits for the first real value → a single 0, then 1, 2, …

2. Scaffold always uses the latest

Generated package.json pins @creact-labs/creact and @creact-labs/testing to latest, so a fresh app never gets an aging runtime.

3. @creact-labs/testing — a real library (RTL for creact)

Redesigned around React-Testing-Library's philosophy: you observe deployed nodes, outputs, and testId/key/type, not DOM.

  • render(ui) → a view with getBy/queryBy/findBy by testId, key, and type (get throws on 0/>1, query returns null, find waits), nodes(), waitFor, and node handles with output()/outputs().
  • Removed the nonsensical h export (and the low-level findNode/readOutput/renderTest surface) — app authors write real JSX.
  • testId is now a universal JSX attribute (<Comp testId="…" />), captured by the runtime and queryable via getByTestId.

4. key no longer does double duty (creact)

useAsyncOutput used to force a key on every component and stamp the root with the stack name — conflating React's key with the durable-state address. Now:

  • A lone component addresses by name (name-name); a key is required only to disambiguate colliding siblings.
  • key is just the React key again; node.key/node.type/node.testId are exposed for tooling.
  • JSX.Element/CReactNode widened (Solid-style) so components can return fragments/arrays/text.

5. h gone everywhere, no masking

All 462 h() calls across 9 creact test files converted to real JSX (object literals only for raw string/Symbol element types). The old h wrongly kept key in props; tests relying on that were corrected to real deps — documented, not silenced. creact stays at 100% coverage, 656 tests.

6. Scaffold showcase

index.test.tsx now teaches the API: render() + getByTestId + output().

7. Removed personal name/email from the codebase (author fields + LICENSE).

Bumps

creact 0.5.0, @creact-labs/testing 0.2.0 (peer ^0.5.0), create-creact-app 0.1.1.

Verified

  • creact 656 tests / 100% coverage / typecheck; testing 21 tests; create-creact-app 26 tests.
  • All fallow gates + the shared publish gate (isolated build + publint + attw) green.
  • End-to-end: scaffold → install packed 0.5.0/0.2.0 → npm test passes (getByTestId showcase) → app runs with a single Count: 0.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a render() test utility with RTL-style queries (by type, key, and testId), output inspection, and lifecycle controls.
    • JSX now supports primitive returns (string/number/boolean) and adds a universal testId attribute.
    • Runtime support improved: components using async output no longer require an explicit key.
    • Introduced polling-based waitFor with timeout/interval (plus delay).
  • Breaking Changes

    • Testing APIs were reorganized: removed h, renderTest, and prior query helpers; waitFor now uses a callback-based signature.
  • Chores

    • Version and author/notice updates across packages.

drn1996 and others added 6 commits July 21, 2026 03:54
… creact/testing

The counter logged "Count: 0" twice at startup: the effect ran once on the
undefined initial output (shown as 0 via ?? 0) and again when the async handler
set count to 0. Wait for the first real value before logging, so it prints 0
once, then 1, 2, ...

Also pin the scaffolded deps to "latest" so a fresh app always gets the newest
@creact-labs/creact and @creact-labs/testing instead of an aging caret range.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the author fields and the LICENSE copyright line with the project org
(CReact Labs) so no personal name or email address remains in the codebase.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…testId

Previously `useAsyncOutput` forced a `key` on every component (and the root's
key was overwritten with the stack name), conflating React's reconciliation key
with the durable-state address. Now:

- A lone component addresses by its name (name-name); a `key` is required only to
  disambiguate colliding siblings (the existing collision check enforces that).
- `key` is once again just the React key; the root is no longer stamped with the
  stack name (injectRootKey removed).
- InstanceNode carries `key`, `type`, and `testId` (read off the element props),
  so tools can query nodes by any of them. `testId` is a universal JSX attribute.
- Widen JSX.Element / CReactNode to what the runtime actually accepts (arrays,
  text, booleans, accessors) — Solid-style — so components may return fragments.

BREAKING: node ids for previously-keyed roots change; components no longer need a
key when unambiguous. Bumped to 0.5.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rework @creact-labs/testing around RTL's philosophy — you observe deployed
nodes, their outputs, and testId/key/type instead of DOM:

- `render(ui, options?)` returns a view with getBy/queryBy/findBy queries by
  testId, key, and type (get throws on 0 or >1, query returns null, find waits),
  plus `nodes()`, `waitFor`, and ergonomic node handles with `output()`/`outputs()`.
- `waitFor(callback)` retries a callback until it returns truthy (RTL-style).
- Remove the nonsensical public `h` element factory and the low-level
  findNode/queryNodes/readOutput/renderTest surface; app authors write real JSX.
- peerDependency and tests track creact ^0.5.0.

BREAKING API change. Bumped to 0.2.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With `h` gone from @creact-labs/testing, the runtime's own tests use real JSX
(component elements) and plain object literals (raw string/Symbol element types
the pipeline tests build by hand). Components that read `props.key` as a
useAsyncOutput dependency — an artifact of the old h (which wrongly left key in
props) — now use real deps; identity comes from the element key. Coverage stays
at 100%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generated index.test.tsx now teaches @creact-labs/testing's real API:
render() + getByTestId (with getByType/getByKey noted) + output(), no h. The app
renders a lone <Counter /> (no key needed) with a testId for querying.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 196921a7-8377-48ff-a5d4-cb222b850983

📥 Commits

Reviewing files that changed from the base of the PR and between cdfc4ea and f307ac8.

📒 Files selected for processing (5)
  • packages/create-creact-app/src/templates.ts
  • packages/testing/src/__tests__/render.test.tsx
  • packages/testing/src/__tests__/wait-for.test.ts
  • packages/testing/src/render.ts
  • packages/testing/src/wait-for.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/testing/src/tests/wait-for.test.ts
  • packages/testing/src/tests/render.test.tsx
  • packages/testing/src/wait-for.ts
  • packages/create-creact-app/src/templates.ts
  • packages/testing/src/render.ts

📝 Walkthrough

Walkthrough

The PR introduces a query-based testing render API, replaces legacy hyperscript helpers, updates JSX and runtime identity contracts, migrates tests to JSX syntax, and refreshes generated app templates, package metadata, and versions.

Changes

Testing and runtime transition

Layer / File(s) Summary
Testing render and polling API
packages/testing/src/render.ts, packages/testing/src/wait-for.ts, packages/testing/src/index.ts, packages/testing/src/__tests__/*
Adds render views, node queries, output accessors, memory tests, and callback-based polling while removing legacy query and render helpers.
Runtime identity and JSX contracts
packages/creact/src/jsx/jsx-runtime.ts, packages/creact/src/runtime/instance.ts, packages/creact/src/runtime/run.ts, packages/creact/tsconfig.test.json
Expands JSX node types, stores key/type/testId metadata, changes unkeyed instance addressing, and removes root key injection.
JSX-based runtime and flow validation
packages/creact/src/flow/__tests__/*, packages/creact/src/runtime/__tests__/*, packages/creact/src/store/__tests__/*
Migrates hyperscript-based test construction to JSX or plain node descriptors and updates identity-related expectations.
Scaffolding and release metadata
packages/create-creact-app/*, packages/creact/package.json, packages/testing/package.json, package.json, LICENSE
Updates package versions and authorship metadata, generated tests, dependency templates, README instructions, and JSX test-file generation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: counter fix, latest scaffold versions, RTL-style testing, key/identity decoupling, and removing h.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/counter-double-zero-and-h

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🤖 Grok fallow review — proceed

Clean gate: zero dead code, duplication, health threshold, and audit findings on the change. Proceed.

  • Hotspot activity (non-gating): packages/create-creact-app/src/index.ts leading at 72.0 churn, accelerating
  • Hotspot activity (non-gating): accelerating files include reactive/tracking.ts, testing/wait-for.ts, reactive/owner.ts, reactive/signal.ts, reactive/array.ts, reactive/selector.ts, primitives/context.ts, create-creact-app/templates.ts, jsx/jsx-runtime.ts, runtime/fiber.ts

Reviews the full fallow report — dead code, duplication, health, and audit. Re-runs edit this comment.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/create-creact-app/src/__tests__/templates.test.ts (1)

45-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert executable template code, not comments.

toContain("render(") and toContain("getByTestId") also match the template’s explanatory comments. Assert the concrete statements or compile/run the generated test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/create-creact-app/src/__tests__/templates.test.ts` around lines 45 -
49, Update the template assertions for files["index.test.tsx"] in the templates
test to match executable testing statements rather than generic substrings that
explanatory comments can satisfy. Assert concrete render and getByTestId usage,
while preserving the existing renderTest exclusion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/create-creact-app/src/templates.ts`:
- Line 277: Update the comment generated by indexTsx() to reference
index.test.tsx instead of index.test.ts, matching the filename emitted by
projectFiles().
- Around line 257-259: Update the template documentation around index.test.tsx
to remove the claim that it uses “no real timers.” Describe instead that the
test renders and queries the counter in isolation without requiring a running
app or timer-based waiting, while preserving the existing query-method details.

In `@packages/testing/src/__tests__/render.test.tsx`:
- Around line 122-129: The test “defaults to a no-op backend that saves nothing”
currently asserts against an unused NoopMemory instance instead of render’s
actual backend. Update the test to verify the view’s persistence behavior
through the render path, such as asserting that no saveState operation occurs,
or remove the unused memory and assert only behavior observable from the
returned view.

In `@packages/testing/src/wait-for.ts`:
- Around line 20-38: Update the exported waitFor function to await callback()
before evaluating its truthiness, while preserving the existing retry, timeout,
and error-capture behavior for falsy results and rejected callbacks. Add
coverage in wait-for.test.ts for an async predicate that resolves falsy before
eventually resolving truthy.

---

Nitpick comments:
In `@packages/create-creact-app/src/__tests__/templates.test.ts`:
- Around line 45-49: Update the template assertions for files["index.test.tsx"]
in the templates test to match executable testing statements rather than generic
substrings that explanatory comments can satisfy. Assert concrete render and
getByTestId usage, while preserving the existing renderTest exclusion.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7cd9e3e8-fced-4cf0-b879-c286a956343c

📥 Commits

Reviewing files that changed from the base of the PR and between 745aed6 and cdfc4ea.

📒 Files selected for processing (31)
  • LICENSE
  • package.json
  • packages/creact/package.json
  • packages/creact/src/flow/__tests__/error-boundary.test.tsx
  • packages/creact/src/flow/__tests__/for.test.tsx
  • packages/creact/src/flow/__tests__/show.test.tsx
  • packages/creact/src/flow/__tests__/switch.test.tsx
  • packages/creact/src/jsx/jsx-runtime.ts
  • packages/creact/src/runtime/__tests__/create-runtime.test.tsx
  • packages/creact/src/runtime/__tests__/instance.test.tsx
  • packages/creact/src/runtime/__tests__/render.test.tsx
  • packages/creact/src/runtime/__tests__/run.test.tsx
  • packages/creact/src/runtime/instance.ts
  • packages/creact/src/runtime/run.ts
  • packages/creact/src/store/__tests__/store.test.tsx
  • packages/creact/tsconfig.test.json
  • packages/create-creact-app/package.json
  • packages/create-creact-app/src/__tests__/templates.test.ts
  • packages/create-creact-app/src/templates.ts
  • packages/testing/package.json
  • packages/testing/src/__tests__/memory.test.ts
  • packages/testing/src/__tests__/query.test.ts
  • packages/testing/src/__tests__/render-test.test.ts
  • packages/testing/src/__tests__/render.test.tsx
  • packages/testing/src/__tests__/wait-for.test.ts
  • packages/testing/src/index.ts
  • packages/testing/src/jsx.ts
  • packages/testing/src/query.ts
  • packages/testing/src/render-test.ts
  • packages/testing/src/render.ts
  • packages/testing/src/wait-for.ts
💤 Files with no reviewable changes (6)
  • packages/testing/src/jsx.ts
  • packages/testing/src/tests/render-test.test.ts
  • packages/testing/src/tests/query.test.ts
  • packages/testing/src/render-test.ts
  • packages/testing/src/query.ts
  • packages/creact/src/runtime/run.ts

Comment thread packages/create-creact-app/src/templates.ts Outdated
Comment thread packages/create-creact-app/src/templates.ts
Comment thread packages/testing/src/__tests__/render.test.tsx Outdated
Comment thread packages/testing/src/wait-for.ts
- waitFor now awaits its callback, so an async predicate retries on its resolved
  value instead of returning immediately on the always-truthy pending promise;
  covered with an async test. TestView.waitFor accepts async callbacks too.
- the default-backend test spies NoopMemory.saveState to actually verify render's
  default (was tautological — the local memory was never passed to render).
- scaffold: fix the index.test.tsx comment and reword the README (the counter
  does start a real timer; the test just doesn't wait on it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@drn1996
drn1996 merged commit 8a21348 into develop Jul 22, 2026
16 checks passed
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