Add auto-exit mode for test indexer and update testing docs - #1079
Conversation
When process() is called without simulate or endBlock, the test indexer now enters auto-exit mode: it fetches events via HyperSync, dynamically sets endBlock to the first block with events, and exits after processing only that block. batchSize is set to 1 to prevent over-processing. If no events are found before reaching chain head, exits with error. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
- Restructure testing SKILL.md to lead with auto-exit mode (no startBlock/endBlock needed) as the primary testing pattern - Demote manual block range discovery to advanced section - Use t.expect throughout all examples and template tests - Migrate all template test files from bare expect() to t.expect() https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
- Condense result.changes section to brief description - Add Entity State API section (set, get, getOrThrow, getAll) - Merge assertion patterns into compact examples - Trim HyperSync section: keep one curl example, remove multi-topic - Remove watch mode (doesn't work) https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
…odegen tests - GlobalState: update endBlock when a partition returns events at an earlier block than current endBlock (handles multi-partition races) - TestIndexer: set sourceBlockNumber to 0 when endBlock is missing - Contract import templates: add auto-exit snapshot test alongside simulate test for EVM chains (TS + ReScript) - Migrate codegen test imports to t.expect https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
- Rename auto-exit describe from "{contract} contract (integration)"
to "Indexer smoke test"
- ReScript codegen: use toMatchSnapshot() instead of inline snapshot
- Add toMatchSnapshot binding to Vitest.res
- Add integration smoke test to scenarios/e2e_test with auto-exit
(snapshot filled on first CI run)
- Add e2e_test to CI scenarios-test job in build_and_verify.yml
https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
|
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:
📝 WalkthroughWalkthroughMade chain Changes
Sequence DiagramsequenceDiagram
participant Harness as Test Harness
participant TI as TestIndexer
participant Main as Main
participant GS as GlobalState
participant Worker as Query Worker
participant Fetcher as Chain Fetcher
Harness->>TI: createTestIndexer(endBlock omitted)
TI->>TI: parseBlockRange -> None (auto-exit mode)
TI->>Main: start(..., exitAfterFirstEventBlock=true)
Main->>GS: GlobalState.make(exitAfterFirstEventBlock=true)
GS->>GS: initialize state with optional endBlock
Harness->>Worker: process({ chains: { 1: {} } })
Worker->>Fetcher: query events (batchSize=1)
Fetcher-->>Worker: return events from first block
Worker->>GS: submitPartitionQueryResponse (events found)
GS->>GS: set chain endBlock to first event block
GS->>Worker: signal updated endBlock / ExitWithSuccess decision
Worker-->>Harness: return result.changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 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 |
… test The inline snapshot can't be pre-populated without HyperSync access. Use expect.objectContaining/expect.any to validate the response shape and entity fields, which is more resilient to chain data changes anyway. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Template-generated tests can't pre-populate snapshots, so the empty inline snapshot causes vitest mismatch failures in CI. Use structural assertions (toBeGreaterThan, toBe) that validate the response shape without requiring exact data. Also add ~timeout parameter to Vitest.res Async.it binding for the 60s timeout needed by HyperSync auto-exit tests. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/cli/src/hbs_templating/contract_import_templates.rs (1)
387-387: Consider renaming_is_fuelparameter.The parameter
_is_fueluses an underscore prefix (conventionally indicating an unused variable in Rust), but it's actively used in conditionals on lines 492 and 612. Consider renaming tois_fuelfor clarity.Suggested rename
- pub fn generate_typescript_test_content(&self, _is_fuel: bool, chain_id: u64) -> String { + pub fn generate_typescript_test_content(&self, is_fuel: bool, chain_id: u64) -> String { ... - if !_is_fuel { + if !is_fuel {Apply similar changes to
generate_rescript_test_content.Also applies to: 517-517
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/hbs_templating/contract_import_templates.rs` at line 387, The parameter `_is_fuel` in generate_typescript_test_content (and similarly in generate_rescript_test_content) is misnamed with a leading underscore even though it is used; rename the parameter to is_fuel in each function signature and update all internal references/conditionals that check `_is_fuel` to use `is_fuel` so the variable name accurately reflects usage and removes the misleading unused-underscore convention.scenarios/e2e_test/src/indexer.test.ts (1)
1-1: Inconsistent assertion pattern with other test files.This file imports global
expectfrom vitest, while other test files in this PR (e.g.,erc20_template/src/indexer.test.ts) have migrated to using the per-test contextt.expect. Consider aligning with thet.expectpattern for consistency.Suggested change for consistency
-import { describe, it, expect } from "vitest"; +import { describe, it } from "vitest"; import { createTestIndexer } from "generated"; describe("Indexer smoke test", () => { it( "processes the first block with events on chain 1", - async () => { + async (t) => { const indexer = createTestIndexer(); const result = await indexer.process({ chains: { 1: {} } }); - expect(result.changes.length).toBeGreaterThan(0); + t.expect(result.changes.length).toBeGreaterThan(0); const change = result.changes[0]; - expect(change).toEqual({ + t.expect(change).toEqual({🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scenarios/e2e_test/src/indexer.test.ts` at line 1, The file currently imports the global expect from vitest which is inconsistent with other tests; remove expect from the import and convert all assertions to the per-test context form (t.expect). Specifically, update the import to only bring in describe and it, change each test callback to accept the test context parameter (commonly named t) and replace every use of expect(...) with t.expect(...), ensuring functions referenced such as describe and it remain unchanged while expect assertions are migrated to t.expect for consistency with the other tests (e.g., erc20_template/src/indexer.test.ts).
🤖 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/cli/src/hbs_templating/contract_import_templates.rs`:
- Line 387: The parameter `_is_fuel` in generate_typescript_test_content (and
similarly in generate_rescript_test_content) is misnamed with a leading
underscore even though it is used; rename the parameter to is_fuel in each
function signature and update all internal references/conditionals that check
`_is_fuel` to use `is_fuel` so the variable name accurately reflects usage and
removes the misleading unused-underscore convention.
In `@scenarios/e2e_test/src/indexer.test.ts`:
- Line 1: The file currently imports the global expect from vitest which is
inconsistent with other tests; remove expect from the import and convert all
assertions to the per-test context form (t.expect). Specifically, update the
import to only bring in describe and it, change each test callback to accept the
test context parameter (commonly named t) and replace every use of expect(...)
with t.expect(...), ensuring functions referenced such as describe and it remain
unchanged while expect assertions are migrated to t.expect for consistency with
the other tests (e.g., erc20_template/src/indexer.test.ts).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0cf29f79-4b6a-4cf7-970b-12b16d915ca9
⛔ Files ignored due to path filters (4)
packages/cli/src/hbs_templating/snapshots/envio__hbs_templating__contract_import_templates__test__rescript_test_file_for_evm.snapis excluded by!**/*.snappackages/cli/src/hbs_templating/snapshots/envio__hbs_templating__contract_import_templates__test__typescript_test_file_for_evm.snapis excluded by!**/*.snappackages/cli/src/hbs_templating/snapshots/envio__hbs_templating__contract_import_templates__test__typescript_test_file_for_fuel.snapis excluded by!**/*.snappnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (15)
.github/workflows/build_and_verify.ymlpackages/cli/src/hbs_templating/contract_import_templates.rspackages/cli/templates/static/erc20_template/typescript/src/indexer.test.tspackages/cli/templates/static/external_calls_template/typescript/src/indexer.test.tspackages/cli/templates/static/factory_template/typescript/src/indexer.test.tspackages/cli/templates/static/greeter_template/typescript/src/indexer.test.tspackages/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.tspackages/cli/templates/static/shared/.claude/skills/testing/SKILL.mdpackages/envio/src/GlobalState.respackages/envio/src/Main.respackages/envio/src/TestIndexer.respackages/envio/src/bindings/Vitest.resscenarios/e2e_test/package.jsonscenarios/e2e_test/src/indexer.test.tsscenarios/test_codegen/test/OptionalBlockParams_test.res
- Rename _is_fuel parameter to is_fuel in generate_typescript_test_content and generate_rescript_test_content since it's actively used - Switch e2e smoke test from global expect() to t.expect() for consistency with other test files (keep global import for asymmetric matchers) https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
The auto-exit smoke test hits real HyperSync which doesn't belong in the scenarios-test job (designed for offline/mock tests). Move it to the e2e-test job which already validates the e2e_test scenario with real infrastructure access. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
The auto-exit response doesn't include blockHash. Remove it from the toEqual assertion to match the actual response shape. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
The auto-exit smoke test requires live HyperSync access which is unreliable in the template-tests job. The smoke test is already covered by the e2e-test job via scenarios/e2e_test. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/e2e-tests/src/template-tests/templates.test.ts (1)
58-87: Make skip intent explicit withhasTests: falsefor disabled templates.Relying on
undefinedworks, but explicitfalseis easier to scan and safer if skip logic changes later.Suggested clarity-only diff
{ name: "evm-contract-import-ts", + hasTests: false, initArgs: [ "contract-import", "-c", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", @@ { name: "evm-contract-import-rescript", + hasTests: false, initArgs: [ "contract-import", "-c", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/e2e-tests/src/template-tests/templates.test.ts` around lines 58 - 87, The two template entries named "evm-contract-import-ts" and "evm-contract-import-rescript" currently omit an explicit skip flag; update their objects to include hasTests: false so the test harness sees the intent to skip tests explicitly (locate the template objects by their name fields "evm-contract-import-ts" and "evm-contract-import-rescript" in the templates array and add hasTests: false to each).
🤖 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/e2e-tests/src/template-tests/templates.test.ts`:
- Around line 58-87: The two template entries named "evm-contract-import-ts" and
"evm-contract-import-rescript" currently omit an explicit skip flag; update
their objects to include hasTests: false so the test harness sees the intent to
skip tests explicitly (locate the template objects by their name fields
"evm-contract-import-ts" and "evm-contract-import-rescript" in the templates
array and add hasTests: false to each).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b90f6e46-d74e-40b9-96f2-0d4944194925
📒 Files selected for processing (1)
packages/e2e-tests/src/template-tests/templates.test.ts
The ReScript contract-import init runs rescript build on src/ which compiles the test file and requires worker thread infrastructure. This consistently fails in the template-tests CI environment. The generated code is validated by cargo snapshot tests and the TypeScript variant covers the init flow. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Use record field syntax (\"chainId") with type annotation ({} : TestIndexer.evmChainConfig)
instead of dict syntax ("chainId": {}) which ReScript rejects as untyped empty record.
Re-enable evm-contract-import-rescript in template e2e tests.
https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
…ntract-import e2e - Replace individual assertions with toMatchInlineSnapshot() in TS smoke test - Remove incorrect is_fuel guard — Fuel has HyperSync support (HyperFuel) - Add --blockchain flag to Fuel LocalImportArgs for non-interactive init - Use CLI args (--blockchain, --contract-address) instead of prompting in Fuel flow - Add fuel-contract-import-ts and fuel-contract-import-rescript e2e test entries https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Regenerate CLI help docs after adding --blockchain to Fuel LocalImportArgs. Fix unused is_fuel parameter warning in generate_typescript_test_content. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Empty inline snapshots fail on first run in CI since vitest doesn't auto-populate in non-update mode. Use explicit assertions instead. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
These flags were only on the parent ContractImportArgs, so clap rejected them when placed after the `local` subcommand. Move them to LocalImportArgs (matching EVM pattern) and merge into parent before checking. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
The auto-exit smoke test scans from block 0 on Fuel testnet which can timeout in CI. Init + codegen + build are still verified. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Replace function-based initArgs with static path computed at module level. Avoids potential vitest describe.each serialization issues with functions. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Temporarily removing to verify whether Fuel entries are causing the template-tests failure. Fuel non-interactive CLI support is preserved in the codebase for future use. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
…ibes - Skip mock event test for Fuel in both TS and ReScript codegen: Fuel event params can't be extracted from the ABI yet, so the generated mock may produce invalid code (e.g. missing required `params` field). Only the smoke test is generated for Fuel contract-import. - Replace describe.each with individual describe blocks per template so vitest output shows which template failed (e.g. "Template: 'fuel-contract-import-rescript'"). - Re-add Fuel contract-import entries (hasTests: false). https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Replace manual toEqual with matchers with toMatchInlineSnapshot(). Snapshot is empty and will be populated by CI on first run. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Can't pre-populate toMatchInlineSnapshot without HyperSync access. Using toMatchObject with structural matchers instead — validates the full shape of the result including all Transfer entity fields. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Drop blockHash from EntityChange type and handleWriteBatch — it's internal metadata not useful for user-facing test assertions. https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Summary
This PR introduces auto-exit mode for the test indexer, eliminating the need to manually specify block ranges in most testing scenarios. The indexer now automatically detects the first block with events and processes it, then exits. This simplifies the testing workflow and updates all documentation and templates accordingly.
Key Changes
Core Testing Infrastructure
endBlockis omitted from chain config, the indexer enters auto-exit mode and automatically finds the first block with eventsendBlockfrom required tooption<int>in chain configurationbatchSize=1to process one block checkpoint at a time for efficient event detectionGlobalState & Main Loop
exitAfterFirstEventBlockflag toGlobalStateto track auto-exit modesubmitPartitionQueryResponseto setendBlockto the first event's block number when events arrive in auto-exit modeexitAfterFirstEventBlockparameter throughMain.startDocumentation
chains: { 1: {} })Test Templates & Generated Code
expect()tot.expect()(Vitest context parameter)expectfrom imports, keeping onlydescribeandittoMatchInlineSnapshotwith empty initial snapshotsTest Scenarios
OptionalBlockParams_test.res: Changed validation test to verify auto-exit mode doesn't raise "endBlock is required" errorCI/CD
Notable Implementation Details
https://claude.ai/code/session_01DEGFFfgA8of7gi6BHEngAm
Summary by CodeRabbit
New Features
Tests
Documentation