From d3144b3649e292d4d7df546e660c35821bb2f7fd Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 17 Jul 2026 10:12:38 +0000 Subject: [PATCH 1/7] Unify config-YAML testing with MockIndexer and start envio test package - Add packages/envio/test as a ReScript source dir with its own vitest setup; npm artifact excludes it (build-artifact strips the test source entry from the published rescript.json and never copies the dir). - Move MockIndexerConfig and scenario-unrelated tests (ConfigYaml, ColumnNameFormat, Utils, ReorgDetection, HyperSync, etc.) from scenarios/test_codegen to packages/envio/test. - MockIndexer.Indexer.make accepts ~config parsed through the real user YAML pipeline; handler-file autoload is skipped for supplied configs and the mock source registration derives its contract from the config instead of hardcoding Gravatar. The module-level pg client is now lazy. - Add YamlConfigIndexer_test: YAML + schema strings drive a full mock indexer run into Postgres. - CI runs the envio package tests (NODE_PATH points require() at the prebuilt NAPI addon artifact). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb6Yyif9GZG1DWAiCER4Gh --- .github/workflows/build_and_verify.yml | 9 ++ package.json | 2 +- packages/build-envio/src/build-artifact.ts | 19 ++++ packages/envio/package.json | 3 +- packages/envio/rescript.json | 4 + .../envio}/test/AddressLowercase_test.res | 0 .../envio}/test/BlockStore_test.res | 0 .../envio}/test/ClientAddressFilter_test.res | 0 .../envio}/test/ConfigYaml_test.res | 0 .../envio}/test/Config_test.res | 0 .../envio}/test/Encoders_schema_test.res | 0 .../envio}/test/EntityFilter_test.res | 0 .../envio}/test/EventRouter_svm_test.res | 0 .../envio}/test/HyperSyncClient_test.res | 0 .../envio}/test/HyperSync_test.res | 0 .../envio}/test/OnBlockSchema_test.res | 0 .../envio}/test/RateLimit_test.res | 0 .../envio}/test/ReorgDetection_test.res | 0 .../envio}/test/SvmHyperSyncClient_test.res | 0 .../envio}/test/SvmHyperSyncSource_test.res | 0 .../envio}/test/TransactionStore_test.res | 0 .../envio}/test/Utils_test.res | 0 .../envio}/test/helpers/MockIndexerConfig.res | 0 .../lib_tests/ChainState_materialize_test.res | 0 .../test/lib_tests/ColumnNameFormat_test.res | 0 .../test/lib_tests/ConfigEnvioInfo_test.res | 0 .../test/lib_tests/EffectCache_test.res | 0 .../envio}/test/lib_tests/Metrics_test.res | 0 .../test/lib_tests/PackageJson_test.res | 0 .../envio}/test/lib_tests/Rpc_Test.res | 0 .../envio}/test/lib_tests/Throttler_test.res | 0 packages/envio/test/setup.ts | 3 + packages/envio/vitest.config.ts | 26 +++++ .../test_codegen/test/IndexerState_test.res | 4 +- .../test/YamlConfigIndexer_test.res | 71 ++++++++++++++ .../test_codegen/test/helpers/MockIndexer.res | 95 +++++++++++++------ .../test/lib_tests/IndexerLoop_test.res | 2 +- 37 files changed, 205 insertions(+), 33 deletions(-) rename {scenarios/test_codegen => packages/envio}/test/AddressLowercase_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/BlockStore_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/ClientAddressFilter_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/ConfigYaml_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/Config_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/Encoders_schema_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/EntityFilter_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/EventRouter_svm_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/HyperSyncClient_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/HyperSync_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/OnBlockSchema_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/RateLimit_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/ReorgDetection_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/SvmHyperSyncClient_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/SvmHyperSyncSource_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/TransactionStore_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/Utils_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/helpers/MockIndexerConfig.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/ChainState_materialize_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/ColumnNameFormat_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/ConfigEnvioInfo_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/EffectCache_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/Metrics_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/PackageJson_test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/Rpc_Test.res (100%) rename {scenarios/test_codegen => packages/envio}/test/lib_tests/Throttler_test.res (100%) create mode 100644 packages/envio/test/setup.ts create mode 100644 packages/envio/vitest.config.ts create mode 100644 scenarios/test_codegen/test/YamlConfigIndexer_test.res diff --git a/.github/workflows/build_and_verify.yml b/.github/workflows/build_and_verify.yml index e1065f52ec..2d9158b97b 100644 --- a/.github/workflows/build_and_verify.yml +++ b/.github/workflows/build_and_verify.yml @@ -223,6 +223,15 @@ jobs: echo "Hasura is up"; exit 0; fi; sleep 1; done echo "Hasura did not become ready"; exit 1 + - name: envio package tests + working-directory: packages/envio + env: + # The workspace envio package has no envio-linux-x64 dependency and + # this job has no Rust toolchain for the cargo dev fallback, so let + # require() find the prebuilt NAPI addon artifact via NODE_PATH. + NODE_PATH: ${{ github.workspace }}/.envio-artifacts + run: pnpm test + - name: test_codegen working-directory: scenarios/test_codegen run: | diff --git a/package.json b/package.json index dd4a44b6d0..5c1494e8e7 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "test:templates": "pnpm --filter e2e-tests test:templates", "test:e2e": "pnpm --filter e2e-tests test:e2e", - "test": "for d in test_codegen fuel_test svm_test e2e_test; do echo \"=== scenarios/$d ===\" && (cd \"scenarios/$d\" && pnpm exec envio codegen && pnpm test) || exit 1; done" + "test": "(cd packages/envio && pnpm test) && for d in test_codegen fuel_test svm_test e2e_test; do echo \"=== scenarios/$d ===\" && (cd \"scenarios/$d\" && pnpm exec envio codegen && pnpm test) || exit 1; done" }, "devDependencies": {}, "pnpm": { diff --git a/packages/build-envio/src/build-artifact.ts b/packages/build-envio/src/build-artifact.ts index e5f0899787..2a6a1e116a 100644 --- a/packages/build-envio/src/build-artifact.ts +++ b/packages/build-envio/src/build-artifact.ts @@ -157,6 +157,25 @@ export function copyPublishFiles(envioDir: string, outDir: string): void { } copyRecursive(src, dest); } + stripTestSources(path.join(outDir, "rescript.json")); +} + +/** + * The test dir isn't shipped (it can't be a ReScript "dev" source because + * those never emit in-source JS), so the published rescript.json must not + * reference it. + */ +export function stripTestSources(rescriptJsonPath: string): void { + const config = JSON.parse(fs.readFileSync(rescriptJsonPath, "utf-8")); + if (Array.isArray(config.sources)) { + config.sources = config.sources.filter( + (source: { dir?: string }) => source?.dir !== "test" + ); + } + fs.writeFileSync( + rescriptJsonPath, + JSON.stringify(config, null, 2) + "\n" + ); } /** diff --git a/packages/envio/package.json b/packages/envio/package.json index c55a0a0acf..7b370e76cd 100644 --- a/packages/envio/package.json +++ b/packages/envio/package.json @@ -13,7 +13,8 @@ }, "scripts": { "build": "rescript", - "watch": "rescript watch" + "watch": "rescript watch", + "test": "rescript && vitest run" }, "author": "envio contributors ", "license": "SEE LICENSE IN licenses/README.md", diff --git a/packages/envio/rescript.json b/packages/envio/rescript.json index 3a34de2bb1..133976506c 100644 --- a/packages/envio/rescript.json +++ b/packages/envio/rescript.json @@ -5,6 +5,10 @@ { "dir": "src", "subdirs": true + }, + { + "dir": "test", + "subdirs": true } ], "suffix": ".res.mjs", diff --git a/scenarios/test_codegen/test/AddressLowercase_test.res b/packages/envio/test/AddressLowercase_test.res similarity index 100% rename from scenarios/test_codegen/test/AddressLowercase_test.res rename to packages/envio/test/AddressLowercase_test.res diff --git a/scenarios/test_codegen/test/BlockStore_test.res b/packages/envio/test/BlockStore_test.res similarity index 100% rename from scenarios/test_codegen/test/BlockStore_test.res rename to packages/envio/test/BlockStore_test.res diff --git a/scenarios/test_codegen/test/ClientAddressFilter_test.res b/packages/envio/test/ClientAddressFilter_test.res similarity index 100% rename from scenarios/test_codegen/test/ClientAddressFilter_test.res rename to packages/envio/test/ClientAddressFilter_test.res diff --git a/scenarios/test_codegen/test/ConfigYaml_test.res b/packages/envio/test/ConfigYaml_test.res similarity index 100% rename from scenarios/test_codegen/test/ConfigYaml_test.res rename to packages/envio/test/ConfigYaml_test.res diff --git a/scenarios/test_codegen/test/Config_test.res b/packages/envio/test/Config_test.res similarity index 100% rename from scenarios/test_codegen/test/Config_test.res rename to packages/envio/test/Config_test.res diff --git a/scenarios/test_codegen/test/Encoders_schema_test.res b/packages/envio/test/Encoders_schema_test.res similarity index 100% rename from scenarios/test_codegen/test/Encoders_schema_test.res rename to packages/envio/test/Encoders_schema_test.res diff --git a/scenarios/test_codegen/test/EntityFilter_test.res b/packages/envio/test/EntityFilter_test.res similarity index 100% rename from scenarios/test_codegen/test/EntityFilter_test.res rename to packages/envio/test/EntityFilter_test.res diff --git a/scenarios/test_codegen/test/EventRouter_svm_test.res b/packages/envio/test/EventRouter_svm_test.res similarity index 100% rename from scenarios/test_codegen/test/EventRouter_svm_test.res rename to packages/envio/test/EventRouter_svm_test.res diff --git a/scenarios/test_codegen/test/HyperSyncClient_test.res b/packages/envio/test/HyperSyncClient_test.res similarity index 100% rename from scenarios/test_codegen/test/HyperSyncClient_test.res rename to packages/envio/test/HyperSyncClient_test.res diff --git a/scenarios/test_codegen/test/HyperSync_test.res b/packages/envio/test/HyperSync_test.res similarity index 100% rename from scenarios/test_codegen/test/HyperSync_test.res rename to packages/envio/test/HyperSync_test.res diff --git a/scenarios/test_codegen/test/OnBlockSchema_test.res b/packages/envio/test/OnBlockSchema_test.res similarity index 100% rename from scenarios/test_codegen/test/OnBlockSchema_test.res rename to packages/envio/test/OnBlockSchema_test.res diff --git a/scenarios/test_codegen/test/RateLimit_test.res b/packages/envio/test/RateLimit_test.res similarity index 100% rename from scenarios/test_codegen/test/RateLimit_test.res rename to packages/envio/test/RateLimit_test.res diff --git a/scenarios/test_codegen/test/ReorgDetection_test.res b/packages/envio/test/ReorgDetection_test.res similarity index 100% rename from scenarios/test_codegen/test/ReorgDetection_test.res rename to packages/envio/test/ReorgDetection_test.res diff --git a/scenarios/test_codegen/test/SvmHyperSyncClient_test.res b/packages/envio/test/SvmHyperSyncClient_test.res similarity index 100% rename from scenarios/test_codegen/test/SvmHyperSyncClient_test.res rename to packages/envio/test/SvmHyperSyncClient_test.res diff --git a/scenarios/test_codegen/test/SvmHyperSyncSource_test.res b/packages/envio/test/SvmHyperSyncSource_test.res similarity index 100% rename from scenarios/test_codegen/test/SvmHyperSyncSource_test.res rename to packages/envio/test/SvmHyperSyncSource_test.res diff --git a/scenarios/test_codegen/test/TransactionStore_test.res b/packages/envio/test/TransactionStore_test.res similarity index 100% rename from scenarios/test_codegen/test/TransactionStore_test.res rename to packages/envio/test/TransactionStore_test.res diff --git a/scenarios/test_codegen/test/Utils_test.res b/packages/envio/test/Utils_test.res similarity index 100% rename from scenarios/test_codegen/test/Utils_test.res rename to packages/envio/test/Utils_test.res diff --git a/scenarios/test_codegen/test/helpers/MockIndexerConfig.res b/packages/envio/test/helpers/MockIndexerConfig.res similarity index 100% rename from scenarios/test_codegen/test/helpers/MockIndexerConfig.res rename to packages/envio/test/helpers/MockIndexerConfig.res diff --git a/scenarios/test_codegen/test/lib_tests/ChainState_materialize_test.res b/packages/envio/test/lib_tests/ChainState_materialize_test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/ChainState_materialize_test.res rename to packages/envio/test/lib_tests/ChainState_materialize_test.res diff --git a/scenarios/test_codegen/test/lib_tests/ColumnNameFormat_test.res b/packages/envio/test/lib_tests/ColumnNameFormat_test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/ColumnNameFormat_test.res rename to packages/envio/test/lib_tests/ColumnNameFormat_test.res diff --git a/scenarios/test_codegen/test/lib_tests/ConfigEnvioInfo_test.res b/packages/envio/test/lib_tests/ConfigEnvioInfo_test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/ConfigEnvioInfo_test.res rename to packages/envio/test/lib_tests/ConfigEnvioInfo_test.res diff --git a/scenarios/test_codegen/test/lib_tests/EffectCache_test.res b/packages/envio/test/lib_tests/EffectCache_test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/EffectCache_test.res rename to packages/envio/test/lib_tests/EffectCache_test.res diff --git a/scenarios/test_codegen/test/lib_tests/Metrics_test.res b/packages/envio/test/lib_tests/Metrics_test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/Metrics_test.res rename to packages/envio/test/lib_tests/Metrics_test.res diff --git a/scenarios/test_codegen/test/lib_tests/PackageJson_test.res b/packages/envio/test/lib_tests/PackageJson_test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/PackageJson_test.res rename to packages/envio/test/lib_tests/PackageJson_test.res diff --git a/scenarios/test_codegen/test/lib_tests/Rpc_Test.res b/packages/envio/test/lib_tests/Rpc_Test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/Rpc_Test.res rename to packages/envio/test/lib_tests/Rpc_Test.res diff --git a/scenarios/test_codegen/test/lib_tests/Throttler_test.res b/packages/envio/test/lib_tests/Throttler_test.res similarity index 100% rename from scenarios/test_codegen/test/lib_tests/Throttler_test.res rename to packages/envio/test/lib_tests/Throttler_test.res diff --git a/packages/envio/test/setup.ts b/packages/envio/test/setup.ts new file mode 100644 index 0000000000..1f438c0a2b --- /dev/null +++ b/packages/envio/test/setup.ts @@ -0,0 +1,3 @@ +// Importing Env triggers Logging.setLogger as a side effect, +// ensuring the logger is available for all tests. +import "../src/Env.res.mjs"; diff --git a/packages/envio/vitest.config.ts b/packages/envio/vitest.config.ts new file mode 100644 index 0000000000..e2603c012d --- /dev/null +++ b/packages/envio/vitest.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["test/**/*_test.res.mjs", "test/**/*.test.ts"], + exclude: ["test/helpers/**"], + // Run tests sequentially - both file-wide and test-wide + fileParallelism: false, + sequence: { + concurrent: false, + }, + pool: "forks", + maxWorkers: 1, + testTimeout: 30_000, + hookTimeout: 30_000, + setupFiles: ["test/setup.ts"], + passWithNoTests: true, + server: { + deps: { + // Externalize non-test files so they load via native Node.js ESM, + // preventing dual module cache between vite and native import() + external: [/^(?!.*\.(test|spec)\.)(?!.*_test\.)(?!.*\/test\/).*$/i], + }, + }, + }, +}); diff --git a/scenarios/test_codegen/test/IndexerState_test.res b/scenarios/test_codegen/test/IndexerState_test.res index 1a44a67aa3..95b80947a3 100644 --- a/scenarios/test_codegen/test/IndexerState_test.res +++ b/scenarios/test_codegen/test/IndexerState_test.res @@ -147,7 +147,7 @@ let populateChainQueuesWithRandomEvents = (~runTime=1000, ~maxBlockTime=15, ()) let state = IndexerState.make( ~config, - ~persistence=MockIndexer.defaultPersistence, + ~persistence=MockIndexer.defaultPersistence(), ~chainStates, ~isInReorgThreshold=false, ~isRealtime=false, @@ -338,7 +338,7 @@ describe("IndexerState", () => { ) IndexerState.make( ~config, - ~persistence=MockIndexer.defaultPersistence, + ~persistence=MockIndexer.defaultPersistence(), ~chainStates, ~isInReorgThreshold=false, ~isRealtime=false, diff --git a/scenarios/test_codegen/test/YamlConfigIndexer_test.res b/scenarios/test_codegen/test/YamlConfigIndexer_test.res new file mode 100644 index 0000000000..2ae539617d --- /dev/null +++ b/scenarios/test_codegen/test/YamlConfigIndexer_test.res @@ -0,0 +1,71 @@ +open Vitest + +// The user-facing entity shape declared in the schema string below — +// intentionally absent from the generated project schema. +type yamlToken = { + id: string, + owner: string, +} + +type yamlTokenOps = {set: yamlToken => unit} +type yamlHandlerContext = {@as("YamlToken") yamlToken: yamlTokenOps} + +describe("YAML-driven MockIndexer", () => { + Async.it( + "runs the indexer loop with a config parsed from user YAML instead of the generated one", + async t => { + let parsed = MockIndexerConfig.parseYaml( + ~schema=` +type YamlToken { + id: ID! + owner: String! +} +`, + ` +name: yaml-driven +chains: + - id: 1337 + rpc: + url: https://rpc.example.test + for: sync + start_block: 1 + contracts: + - name: Token + address: "0x0000000000000000000000000000000000000001" + events: + - event: Transfer() +`, + ) + + let source = MockIndexer.Source.make([#getHeightOrThrow, #getItemsOrThrow], ~chain=#1337) + let indexerMock = await MockIndexer.Indexer.make( + ~config=parsed.config, + ~chains=[{chain: #1337, sourceConfig: Config.CustomSources([source.source])}], + ~shouldRollbackOnReorg=false, + ) + await Utils.delay(0) + + source.resolveGetHeightOrThrow(300) + await Utils.delay(0) + await Utils.delay(0) + + source.resolveGetItemsOrThrow([ + { + blockNumber: 5, + logIndex: 0, + handler: async args => { + let context = + args.context->(Utils.magic: MockIndexer.handlerContext => yamlHandlerContext) + context.yamlToken.set({id: "token-1", owner: "0xabc"}) + }, + }, + ], ~latestFetchedBlockNumber=300) + await indexerMock.getBatchWritePromise() + + let tokens: array = await indexerMock.queryRaw( + parsed.config.userEntitiesByName->Dict.getUnsafe("YamlToken"), + ) + t.expect(tokens).toEqual([{id: "token-1", owner: "0xabc"}]) + }, + ) +}) diff --git a/scenarios/test_codegen/test/helpers/MockIndexer.res b/scenarios/test_codegen/test/helpers/MockIndexer.res index 04e6088c6a..16c5694093 100644 --- a/scenarios/test_codegen/test/helpers/MockIndexer.res +++ b/scenarios/test_codegen/test/helpers/MockIndexer.res @@ -1,22 +1,34 @@ type chainId = Indexer.chainId +// The generated project config. Cheap: Config.load() memoizes the pure parse. let config = Config.load() +let entityConfigByName = (config: Config.t, name): Internal.entityConfig => + config.userEntitiesByName->Dict.get(name)->Option.getOrThrow + let entityConfig = (name: Indexer.Entities.name<_>): Internal.entityConfig => - config.userEntitiesByName - ->Dict.get(name->(Utils.magic: Indexer.Entities.name<_> => string)) - ->Option.getOrThrow + config->entityConfigByName(name->(Utils.magic: Indexer.Entities.name<_> => string)) // The store requires a persistence/config even when the cycle never runs; reuse one. -let defaultPersistence = PgStorage.makePersistenceFromConfig( - ~config, - ~storage=PgStorage.makeStorageFromEnv( - ~config, - ~sql=PgStorage.makeClient(), - ~pgSchema=Env.Db.publicSchema, - ~isHasuraEnabled=false, - ), -) +// Lazy so importing the helper doesn't open a pg client for tests that never use it. +let defaultPersistenceRef = ref(None) +let defaultPersistence = () => + switch defaultPersistenceRef.contents { + | Some(persistence) => persistence + | None => + let config = Config.load() + let persistence = PgStorage.makePersistenceFromConfig( + ~config, + ~storage=PgStorage.makeStorageFromEnv( + ~config, + ~sql=PgStorage.makeClient(), + ~pgSchema=Env.Db.publicSchema, + ~isHasuraEnabled=false, + ), + ) + defaultPersistenceRef := Some(persistence) + persistence + } module InMemoryStore = { let setEntity = (indexerState, ~entityConfig: Internal.entityConfig, entity) => { @@ -32,10 +44,14 @@ module InMemoryStore = { ) } - let make = (~entities=[]) => { + let make = (~config=?, ~entities=[]) => { + let config = switch config { + | Some(config) => config + | None => Config.load() + } let indexerState = IndexerState.make( ~config, - ~persistence=defaultPersistence, + ~persistence=defaultPersistence(), // A trivial chain state map for store-only tests that never run the loop. ~chainStates=Dict.make(), ~isInReorgThreshold=false, @@ -204,12 +220,13 @@ module Storage = { } } - let toPersistence = (storageMock: t) => { + let toPersistence = (storageMock: t, ~config=?) => { + let config = switch config { + | Some(config) => config + | None => Config.load() + } { - ...PgStorage.makePersistenceFromConfig( - ~config=Config.load(), - ~storage=storageMock.storage, - ), + ...PgStorage.makePersistenceFromConfig(~config, ~storage=storageMock.storage), storageStatus: Ready({ cleanRun: false, cache: Dict.make(), @@ -246,7 +263,7 @@ type mockSourceEvent = { // MockSource items choose their callback at response time, after ChainState has // already been created. Install one stable registration up front and dispatch // through callback metadata carried only by the test payload. -let makeMockSourceRegistration = (~index): Internal.onEventRegistration => { +let makeMockSourceRegistration = (~index, ~contractName): Internal.onEventRegistration => { let handler: Internal.handler = args => { let args = args->( Utils.magic: Internal.handlerArgs => Internal.genericHandlerArgs< @@ -282,9 +299,9 @@ let makeMockSourceRegistration = (~index): Internal.onEventRegistration => { eventConfig: ({ id: "MockEvent", // Keep the synthetic registration in the same address-dependent fetch - // partition as the generated test registrations. MockSource ignores the + // partition as the config's registrations. MockSource ignores the // query selection, while ChainState still owns and resolves this slot. - contractName: "Gravatar", + contractName, name: "MockEvent", paramsRawEventSchema: EventConfigBuilder.buildParamsSchema([]), simulateParamsSchema: EventConfigBuilder.buildSimulateParamsSchema([]), @@ -341,6 +358,12 @@ let installMockSourceRegistrations = ( } let mockRegistration = makeMockSourceRegistration( ~index=registrations.onEventRegistrations->Array.length, + // Any contract from the chain keeps the synthetic registration in the + // address-dependent partition of a real contract. + ~contractName=switch chainConfig.contracts->Array.get(0) { + | Some(contract) => contract.name + | None => "MockContract" + }, ) registrations.onEventRegistrations->Array.push(mockRegistration)->ignore sourceStates->Array.forEach(state => @@ -380,6 +403,9 @@ module Indexer = { let rec make = async ( ~chains: array, + // A config parsed through the user-facing pipeline (MockIndexerConfig.parseYaml). + // Defaults to the generated project config. + ~config as customConfig: option=?, ~saveFullHistory=false, // Reinit storage without Hasura // makes tests ~1.9 seconds faster @@ -411,7 +437,10 @@ module Indexer = { // from the config it's given, so registration must see the resolved // config rather than the raw generated one. let config = { - let config = Config.load() + let config = switch customConfig { + | Some(config) => config + | None => Config.load() + } let chainMap = chains @@ -440,7 +469,14 @@ module Indexer = { } } - let registrationsByChainId = await HandlerLoader.registerAllHandlers(~config) + let registrationsByChainId = switch customConfig { + | None => await HandlerLoader.registerAllHandlers(~config) + | Some(_) => + // A supplied config has no handler files on disk; register inline + // handlers (if any) through the same public registry lifecycle. + HandlerRegister.startRegistration(~config) + HandlerRegister.finishRegistration(~config) + } installMockSourceRegistrations(~config, ~registrationsByChainId) let sql = PgStorage.makeClient() @@ -540,7 +576,8 @@ module Indexer = { }) }, query: (type entity, name: Indexer.Entities.name) => { - let ec = entityConfig(name) + let ec = + config->entityConfigByName(name->(Utils.magic: Indexer.Entities.name => string)) sql ->Postgres.unsafe(PgStorage.makeLoadAllQuery(~pgSchema, ~tableName=ec.table.tableName)) ->Promise.thenResolve(items => { @@ -549,7 +586,8 @@ module Indexer = { ->(Utils.magic: promise> => promise>) }, queryHistory: (type entity, name: Indexer.Entities.name) => { - let ec = entityConfig(name) + let ec = + config->entityConfigByName(name->(Utils.magic: Indexer.Entities.name => string)) sql ->Postgres.unsafe( PgStorage.makeLoadAllQuery( @@ -648,6 +686,7 @@ module Indexer = { } await make( ~chains, + ~config=?customConfig, ~enableHasura, ~enableRawEvents, ~saveFullHistory, @@ -933,8 +972,8 @@ module Source = { ~message="MockSource on-event registration was not installed before resolving items", ) let payload: Evm.payload = { - contractName: "Gravatar", - eventName: "MockEvent", + contractName: onEventRegistration.eventConfig.contractName, + eventName: onEventRegistration.eventConfig.name, params: %raw(`{}`), chainId: chain->ChainMap.Chain.toChainId, srcAddress: "0x0000000000000000000000000000000000000000"->Address.unsafeFromString, diff --git a/scenarios/test_codegen/test/lib_tests/IndexerLoop_test.res b/scenarios/test_codegen/test/lib_tests/IndexerLoop_test.res index 8e77d10215..096897adec 100644 --- a/scenarios/test_codegen/test/lib_tests/IndexerLoop_test.res +++ b/scenarios/test_codegen/test/lib_tests/IndexerLoop_test.res @@ -50,7 +50,7 @@ let makeState = (~onError=errHandler => errHandler->ErrorHandling.raiseExn, ()) IndexerState.make( ~config, - ~persistence=MockIndexer.defaultPersistence, + ~persistence=MockIndexer.defaultPersistence(), ~chainStates, // isInReorgThreshold avoids triggering a fetch on the mock source (which // implements no methods) when the processing loop runs to its empty exit. From 4edf6edc44455cc954dadecf551d84ded1e8a410 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 17 Jul 2026 14:00:55 +0000 Subject: [PATCH 2/7] Parallelize envio package tests and drop unused spec-file pattern Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb6Yyif9GZG1DWAiCER4Gh --- packages/envio/vitest.config.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/envio/vitest.config.ts b/packages/envio/vitest.config.ts index e2603c012d..e4d7038514 100644 --- a/packages/envio/vitest.config.ts +++ b/packages/envio/vitest.config.ts @@ -4,13 +4,9 @@ export default defineConfig({ test: { include: ["test/**/*_test.res.mjs", "test/**/*.test.ts"], exclude: ["test/helpers/**"], - // Run tests sequentially - both file-wide and test-wide - fileParallelism: false, - sequence: { - concurrent: false, - }, + // No shared database or other cross-file state, so files can run in + // parallel (each fork gets its own process-level globals). pool: "forks", - maxWorkers: 1, testTimeout: 30_000, hookTimeout: 30_000, setupFiles: ["test/setup.ts"], @@ -19,7 +15,7 @@ export default defineConfig({ deps: { // Externalize non-test files so they load via native Node.js ESM, // preventing dual module cache between vite and native import() - external: [/^(?!.*\.(test|spec)\.)(?!.*_test\.)(?!.*\/test\/).*$/i], + external: [/^(?!.*\.test\.)(?!.*_test\.)(?!.*\/test\/).*$/i], }, }, }, From 637ab55fe13e9e7bcf247ba0d4825a472feda2d5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 08:10:35 +0000 Subject: [PATCH 3/7] Fix test_codegen compile against published envio artifact YamlConfigIndexer_test referenced MockIndexerConfig, which now lives only in envio's test dir and is excluded from the published npm artifact that scenarios build against in CI. Inline the parse via the public Core.parseConfigYaml + Config.fromPublic instead. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb6Yyif9GZG1DWAiCER4Gh --- .../test/YamlConfigIndexer_test.res | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/scenarios/test_codegen/test/YamlConfigIndexer_test.res b/scenarios/test_codegen/test/YamlConfigIndexer_test.res index 2ae539617d..7afc85c6fa 100644 --- a/scenarios/test_codegen/test/YamlConfigIndexer_test.res +++ b/scenarios/test_codegen/test/YamlConfigIndexer_test.res @@ -14,14 +14,17 @@ describe("YAML-driven MockIndexer", () => { Async.it( "runs the indexer loop with a config parsed from user YAML instead of the generated one", async t => { - let parsed = MockIndexerConfig.parseYaml( - ~schema=` + // Parse through the real user-facing pipeline (Rust napi → public JSON → + // Config.fromPublic), the same path MockIndexerConfig.parseYaml uses. + let config = + Core.parseConfigYaml( + ~schema=` type YamlToken { id: ID! owner: String! } `, - ` + ` name: yaml-driven chains: - id: 1337 @@ -35,11 +38,13 @@ chains: events: - event: Transfer() `, - ) + ) + ->JSON.parseOrThrow + ->Config.fromPublic let source = MockIndexer.Source.make([#getHeightOrThrow, #getItemsOrThrow], ~chain=#1337) let indexerMock = await MockIndexer.Indexer.make( - ~config=parsed.config, + ~config, ~chains=[{chain: #1337, sourceConfig: Config.CustomSources([source.source])}], ~shouldRollbackOnReorg=false, ) @@ -63,7 +68,7 @@ chains: await indexerMock.getBatchWritePromise() let tokens: array = await indexerMock.queryRaw( - parsed.config.userEntitiesByName->Dict.getUnsafe("YamlToken"), + config.userEntitiesByName->Dict.getUnsafe("YamlToken"), ) t.expect(tokens).toEqual([{id: "token-1", owner: "0xabc"}]) }, From 89f4be462eef469160234e613cc399575833a80f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 08:25:33 +0000 Subject: [PATCH 4/7] Share config-parse helper via shippable testing/ dir instead of duplicating test_codegen's acceptance test needs the YAML parse helper that lives in the envio package. It compiled locally (workspace symlink exposes envio's lib/ocaml) but broke in CI, where scenarios build against the published artifact that excludes the test dir. Move MockIndexerConfig into a new packages/envio/testing dir: vitest-free ReScript helpers that ship in the artifact and stay in the published rescript.json sources, so dependent suites compile against them in CI. The test dir (vitest suites) stays stripped. The helper is not part of the user-facing JS API (index.js), keeping it internal. Kept the module name to avoid colliding with test_codegen's own MockConfig. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb6Yyif9GZG1DWAiCER4Gh --- packages/build-envio/src/build-artifact.ts | 9 ++++++--- packages/envio/rescript.json | 4 ++++ .../{test/helpers => testing}/MockIndexerConfig.res | 0 .../test_codegen/test/YamlConfigIndexer_test.res | 13 ++++--------- 4 files changed, 14 insertions(+), 12 deletions(-) rename packages/envio/{test/helpers => testing}/MockIndexerConfig.res (100%) diff --git a/packages/build-envio/src/build-artifact.ts b/packages/build-envio/src/build-artifact.ts index 2a6a1e116a..4489176f43 100644 --- a/packages/build-envio/src/build-artifact.ts +++ b/packages/build-envio/src/build-artifact.ts @@ -58,6 +58,9 @@ const PUBLISH_FILES = [ "index.d.ts", "index.js", "src", + // Internal ReScript test helpers (vitest-free) that dependent test suites + // compile against. Not part of the user-facing JS API (index.js). + "testing", ]; // ── Core logic ────────────────────────────────────────────────────── @@ -161,9 +164,9 @@ export function copyPublishFiles(envioDir: string, outDir: string): void { } /** - * The test dir isn't shipped (it can't be a ReScript "dev" source because - * those never emit in-source JS), so the published rescript.json must not - * reference it. + * The `test` dir (vitest suites) isn't shipped, so the published + * rescript.json must not reference it. The `testing` dir (vitest-free + * shared helpers) IS shipped and stays in sources. */ export function stripTestSources(rescriptJsonPath: string): void { const config = JSON.parse(fs.readFileSync(rescriptJsonPath, "utf-8")); diff --git a/packages/envio/rescript.json b/packages/envio/rescript.json index 133976506c..8f0ce83d2f 100644 --- a/packages/envio/rescript.json +++ b/packages/envio/rescript.json @@ -6,6 +6,10 @@ "dir": "src", "subdirs": true }, + { + "dir": "testing", + "subdirs": true + }, { "dir": "test", "subdirs": true diff --git a/packages/envio/test/helpers/MockIndexerConfig.res b/packages/envio/testing/MockIndexerConfig.res similarity index 100% rename from packages/envio/test/helpers/MockIndexerConfig.res rename to packages/envio/testing/MockIndexerConfig.res diff --git a/scenarios/test_codegen/test/YamlConfigIndexer_test.res b/scenarios/test_codegen/test/YamlConfigIndexer_test.res index 7afc85c6fa..979ec92cb6 100644 --- a/scenarios/test_codegen/test/YamlConfigIndexer_test.res +++ b/scenarios/test_codegen/test/YamlConfigIndexer_test.res @@ -14,17 +14,14 @@ describe("YAML-driven MockIndexer", () => { Async.it( "runs the indexer loop with a config parsed from user YAML instead of the generated one", async t => { - // Parse through the real user-facing pipeline (Rust napi → public JSON → - // Config.fromPublic), the same path MockIndexerConfig.parseYaml uses. - let config = - Core.parseConfigYaml( - ~schema=` + let {config} = MockIndexerConfig.parseYaml( + ~schema=` type YamlToken { id: ID! owner: String! } `, - ` + ` name: yaml-driven chains: - id: 1337 @@ -38,9 +35,7 @@ chains: events: - event: Transfer() `, - ) - ->JSON.parseOrThrow - ->Config.fromPublic + ) let source = MockIndexer.Source.make([#getHeightOrThrow, #getItemsOrThrow], ~chain=#1337) let indexerMock = await MockIndexer.Indexer.make( From a02fa99d3312a131a9f7f99a212c5f17b3b29024 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 10:27:10 +0000 Subject: [PATCH 5/7] Move envio tests + helpers into dedicated envio-tests package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the test/testing split inside the envio package with a separate private workspace package, envio-tests, that depends on envio. It holds all the (non-generated-code) test suites and the MockIndexerConfig helper. - envio ships pure runtime: no test/testing dirs, no vitest devDep. build-artifact.ts drops stripTestSources and the testing PUBLISH entry. - envio-tests runs its vitest suite against the envio artifact in CI (via the pnpmfile redirect), so it loads the NAPI addon through the artifact's platform dependency like scenarios do — no NODE_PATH hack. - test_codegen depends on envio-tests to reuse MockIndexerConfig in its YAML-driven acceptance test, instead of duplicating the parse helper. - CI 'envio package tests' step becomes 'envio-tests'; root test script and workspace wiring updated. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb6Yyif9GZG1DWAiCER4Gh --- .github/workflows/build_and_verify.yml | 9 ++----- package.json | 2 +- packages/build-envio/src/build-artifact.ts | 22 ---------------- packages/envio-tests/.gitignore | 6 +++++ packages/envio-tests/package.json | 25 +++++++++++++++++++ packages/envio-tests/rescript.json | 23 +++++++++++++++++ .../test/AddressLowercase_test.res | 0 .../test/BlockStore_test.res | 0 .../test/ClientAddressFilter_test.res | 0 .../test/ConfigYaml_test.res | 0 .../test/Config_test.res | 0 .../test/Encoders_schema_test.res | 0 .../test/EntityFilter_test.res | 0 .../test/EventRouter_svm_test.res | 0 .../test/HyperSyncClient_test.res | 0 .../test/HyperSync_test.res | 0 .../test/OnBlockSchema_test.res | 0 .../test/RateLimit_test.res | 0 .../test/ReorgDetection_test.res | 0 .../test/SvmHyperSyncClient_test.res | 0 .../test/SvmHyperSyncSource_test.res | 0 .../test/TransactionStore_test.res | 0 .../test/Utils_test.res | 0 .../test/helpers}/MockIndexerConfig.res | 0 .../lib_tests/ChainState_materialize_test.res | 0 .../test/lib_tests/ColumnNameFormat_test.res | 0 .../test/lib_tests/ConfigEnvioInfo_test.res | 0 .../test/lib_tests/EffectCache_test.res | 0 .../test/lib_tests/Metrics_test.res | 0 .../test/lib_tests/PackageJson_test.res | 0 .../test/lib_tests/Rpc_Test.res | 0 .../test/lib_tests/Throttler_test.res | 0 packages/{envio => envio-tests}/test/setup.ts | 2 +- .../{envio => envio-tests}/vitest.config.ts | 0 packages/envio/package.json | 6 ++--- packages/envio/rescript.json | 8 ------ pnpm-lock.yaml | 25 +++++++++++++++++++ scenarios/test_codegen/package.json | 3 ++- scenarios/test_codegen/rescript.json | 3 ++- 39 files changed, 89 insertions(+), 45 deletions(-) create mode 100644 packages/envio-tests/.gitignore create mode 100644 packages/envio-tests/package.json create mode 100644 packages/envio-tests/rescript.json rename packages/{envio => envio-tests}/test/AddressLowercase_test.res (100%) rename packages/{envio => envio-tests}/test/BlockStore_test.res (100%) rename packages/{envio => envio-tests}/test/ClientAddressFilter_test.res (100%) rename packages/{envio => envio-tests}/test/ConfigYaml_test.res (100%) rename packages/{envio => envio-tests}/test/Config_test.res (100%) rename packages/{envio => envio-tests}/test/Encoders_schema_test.res (100%) rename packages/{envio => envio-tests}/test/EntityFilter_test.res (100%) rename packages/{envio => envio-tests}/test/EventRouter_svm_test.res (100%) rename packages/{envio => envio-tests}/test/HyperSyncClient_test.res (100%) rename packages/{envio => envio-tests}/test/HyperSync_test.res (100%) rename packages/{envio => envio-tests}/test/OnBlockSchema_test.res (100%) rename packages/{envio => envio-tests}/test/RateLimit_test.res (100%) rename packages/{envio => envio-tests}/test/ReorgDetection_test.res (100%) rename packages/{envio => envio-tests}/test/SvmHyperSyncClient_test.res (100%) rename packages/{envio => envio-tests}/test/SvmHyperSyncSource_test.res (100%) rename packages/{envio => envio-tests}/test/TransactionStore_test.res (100%) rename packages/{envio => envio-tests}/test/Utils_test.res (100%) rename packages/{envio/testing => envio-tests/test/helpers}/MockIndexerConfig.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/ChainState_materialize_test.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/ColumnNameFormat_test.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/ConfigEnvioInfo_test.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/EffectCache_test.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/Metrics_test.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/PackageJson_test.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/Rpc_Test.res (100%) rename packages/{envio => envio-tests}/test/lib_tests/Throttler_test.res (100%) rename packages/{envio => envio-tests}/test/setup.ts (77%) rename packages/{envio => envio-tests}/vitest.config.ts (100%) diff --git a/.github/workflows/build_and_verify.yml b/.github/workflows/build_and_verify.yml index 2d9158b97b..a4fbad0a99 100644 --- a/.github/workflows/build_and_verify.yml +++ b/.github/workflows/build_and_verify.yml @@ -223,13 +223,8 @@ jobs: echo "Hasura is up"; exit 0; fi; sleep 1; done echo "Hasura did not become ready"; exit 1 - - name: envio package tests - working-directory: packages/envio - env: - # The workspace envio package has no envio-linux-x64 dependency and - # this job has no Rust toolchain for the cargo dev fallback, so let - # require() find the prebuilt NAPI addon artifact via NODE_PATH. - NODE_PATH: ${{ github.workspace }}/.envio-artifacts + - name: envio-tests + working-directory: packages/envio-tests run: pnpm test - name: test_codegen diff --git a/package.json b/package.json index 5c1494e8e7..fcfd9415ac 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "test:templates": "pnpm --filter e2e-tests test:templates", "test:e2e": "pnpm --filter e2e-tests test:e2e", - "test": "(cd packages/envio && pnpm test) && for d in test_codegen fuel_test svm_test e2e_test; do echo \"=== scenarios/$d ===\" && (cd \"scenarios/$d\" && pnpm exec envio codegen && pnpm test) || exit 1; done" + "test": "(cd packages/envio-tests && pnpm test) && for d in test_codegen fuel_test svm_test e2e_test; do echo \"=== scenarios/$d ===\" && (cd \"scenarios/$d\" && pnpm exec envio codegen && pnpm test) || exit 1; done" }, "devDependencies": {}, "pnpm": { diff --git a/packages/build-envio/src/build-artifact.ts b/packages/build-envio/src/build-artifact.ts index 4489176f43..e5f0899787 100644 --- a/packages/build-envio/src/build-artifact.ts +++ b/packages/build-envio/src/build-artifact.ts @@ -58,9 +58,6 @@ const PUBLISH_FILES = [ "index.d.ts", "index.js", "src", - // Internal ReScript test helpers (vitest-free) that dependent test suites - // compile against. Not part of the user-facing JS API (index.js). - "testing", ]; // ── Core logic ────────────────────────────────────────────────────── @@ -160,25 +157,6 @@ export function copyPublishFiles(envioDir: string, outDir: string): void { } copyRecursive(src, dest); } - stripTestSources(path.join(outDir, "rescript.json")); -} - -/** - * The `test` dir (vitest suites) isn't shipped, so the published - * rescript.json must not reference it. The `testing` dir (vitest-free - * shared helpers) IS shipped and stays in sources. - */ -export function stripTestSources(rescriptJsonPath: string): void { - const config = JSON.parse(fs.readFileSync(rescriptJsonPath, "utf-8")); - if (Array.isArray(config.sources)) { - config.sources = config.sources.filter( - (source: { dir?: string }) => source?.dir !== "test" - ); - } - fs.writeFileSync( - rescriptJsonPath, - JSON.stringify(config, null, 2) + "\n" - ); } /** diff --git a/packages/envio-tests/.gitignore b/packages/envio-tests/.gitignore new file mode 100644 index 0000000000..c523baac77 --- /dev/null +++ b/packages/envio-tests/.gitignore @@ -0,0 +1,6 @@ +node_modules/ + +# ReScript artifacts +lib +*.res.js +*.res.mjs diff --git a/packages/envio-tests/package.json b/packages/envio-tests/package.json new file mode 100644 index 0000000000..23f622d75b --- /dev/null +++ b/packages/envio-tests/package.json @@ -0,0 +1,25 @@ +{ + "name": "envio-tests", + "version": "0.0.1-dev", + "private": true, + "type": "module", + "scripts": { + "build": "rescript", + "watch": "rescript watch", + "test": "rescript && vitest run" + }, + "devDependencies": { + "@rescript/runtime": "12.2.0", + "rescript": "12.2.0", + "rescript-schema": "9.5.1", + "vitest": "4.1.0" + }, + "dependencies": { + "bignumber.js": "9.3.1", + "prom-client": "15.1.3", + "envio": "file:../envio" + }, + "engines": { + "node": ">=22.0.0" + } +} diff --git a/packages/envio-tests/rescript.json b/packages/envio-tests/rescript.json new file mode 100644 index 0000000000..cea7a0e521 --- /dev/null +++ b/packages/envio-tests/rescript.json @@ -0,0 +1,23 @@ +{ + "name": "envio-tests", + "namespace": false, + "sources": [ + { + "dir": "test", + "subdirs": true + } + ], + "suffix": ".res.mjs", + "package-specs": { + "module": "esmodule", + "in-source": true + }, + "jsx": { + "version": 4 + }, + "dependencies": ["rescript-schema", "envio"], + "compiler-flags": ["-open RescriptSchema"], + "warnings": { + "error": "+a" + } +} diff --git a/packages/envio/test/AddressLowercase_test.res b/packages/envio-tests/test/AddressLowercase_test.res similarity index 100% rename from packages/envio/test/AddressLowercase_test.res rename to packages/envio-tests/test/AddressLowercase_test.res diff --git a/packages/envio/test/BlockStore_test.res b/packages/envio-tests/test/BlockStore_test.res similarity index 100% rename from packages/envio/test/BlockStore_test.res rename to packages/envio-tests/test/BlockStore_test.res diff --git a/packages/envio/test/ClientAddressFilter_test.res b/packages/envio-tests/test/ClientAddressFilter_test.res similarity index 100% rename from packages/envio/test/ClientAddressFilter_test.res rename to packages/envio-tests/test/ClientAddressFilter_test.res diff --git a/packages/envio/test/ConfigYaml_test.res b/packages/envio-tests/test/ConfigYaml_test.res similarity index 100% rename from packages/envio/test/ConfigYaml_test.res rename to packages/envio-tests/test/ConfigYaml_test.res diff --git a/packages/envio/test/Config_test.res b/packages/envio-tests/test/Config_test.res similarity index 100% rename from packages/envio/test/Config_test.res rename to packages/envio-tests/test/Config_test.res diff --git a/packages/envio/test/Encoders_schema_test.res b/packages/envio-tests/test/Encoders_schema_test.res similarity index 100% rename from packages/envio/test/Encoders_schema_test.res rename to packages/envio-tests/test/Encoders_schema_test.res diff --git a/packages/envio/test/EntityFilter_test.res b/packages/envio-tests/test/EntityFilter_test.res similarity index 100% rename from packages/envio/test/EntityFilter_test.res rename to packages/envio-tests/test/EntityFilter_test.res diff --git a/packages/envio/test/EventRouter_svm_test.res b/packages/envio-tests/test/EventRouter_svm_test.res similarity index 100% rename from packages/envio/test/EventRouter_svm_test.res rename to packages/envio-tests/test/EventRouter_svm_test.res diff --git a/packages/envio/test/HyperSyncClient_test.res b/packages/envio-tests/test/HyperSyncClient_test.res similarity index 100% rename from packages/envio/test/HyperSyncClient_test.res rename to packages/envio-tests/test/HyperSyncClient_test.res diff --git a/packages/envio/test/HyperSync_test.res b/packages/envio-tests/test/HyperSync_test.res similarity index 100% rename from packages/envio/test/HyperSync_test.res rename to packages/envio-tests/test/HyperSync_test.res diff --git a/packages/envio/test/OnBlockSchema_test.res b/packages/envio-tests/test/OnBlockSchema_test.res similarity index 100% rename from packages/envio/test/OnBlockSchema_test.res rename to packages/envio-tests/test/OnBlockSchema_test.res diff --git a/packages/envio/test/RateLimit_test.res b/packages/envio-tests/test/RateLimit_test.res similarity index 100% rename from packages/envio/test/RateLimit_test.res rename to packages/envio-tests/test/RateLimit_test.res diff --git a/packages/envio/test/ReorgDetection_test.res b/packages/envio-tests/test/ReorgDetection_test.res similarity index 100% rename from packages/envio/test/ReorgDetection_test.res rename to packages/envio-tests/test/ReorgDetection_test.res diff --git a/packages/envio/test/SvmHyperSyncClient_test.res b/packages/envio-tests/test/SvmHyperSyncClient_test.res similarity index 100% rename from packages/envio/test/SvmHyperSyncClient_test.res rename to packages/envio-tests/test/SvmHyperSyncClient_test.res diff --git a/packages/envio/test/SvmHyperSyncSource_test.res b/packages/envio-tests/test/SvmHyperSyncSource_test.res similarity index 100% rename from packages/envio/test/SvmHyperSyncSource_test.res rename to packages/envio-tests/test/SvmHyperSyncSource_test.res diff --git a/packages/envio/test/TransactionStore_test.res b/packages/envio-tests/test/TransactionStore_test.res similarity index 100% rename from packages/envio/test/TransactionStore_test.res rename to packages/envio-tests/test/TransactionStore_test.res diff --git a/packages/envio/test/Utils_test.res b/packages/envio-tests/test/Utils_test.res similarity index 100% rename from packages/envio/test/Utils_test.res rename to packages/envio-tests/test/Utils_test.res diff --git a/packages/envio/testing/MockIndexerConfig.res b/packages/envio-tests/test/helpers/MockIndexerConfig.res similarity index 100% rename from packages/envio/testing/MockIndexerConfig.res rename to packages/envio-tests/test/helpers/MockIndexerConfig.res diff --git a/packages/envio/test/lib_tests/ChainState_materialize_test.res b/packages/envio-tests/test/lib_tests/ChainState_materialize_test.res similarity index 100% rename from packages/envio/test/lib_tests/ChainState_materialize_test.res rename to packages/envio-tests/test/lib_tests/ChainState_materialize_test.res diff --git a/packages/envio/test/lib_tests/ColumnNameFormat_test.res b/packages/envio-tests/test/lib_tests/ColumnNameFormat_test.res similarity index 100% rename from packages/envio/test/lib_tests/ColumnNameFormat_test.res rename to packages/envio-tests/test/lib_tests/ColumnNameFormat_test.res diff --git a/packages/envio/test/lib_tests/ConfigEnvioInfo_test.res b/packages/envio-tests/test/lib_tests/ConfigEnvioInfo_test.res similarity index 100% rename from packages/envio/test/lib_tests/ConfigEnvioInfo_test.res rename to packages/envio-tests/test/lib_tests/ConfigEnvioInfo_test.res diff --git a/packages/envio/test/lib_tests/EffectCache_test.res b/packages/envio-tests/test/lib_tests/EffectCache_test.res similarity index 100% rename from packages/envio/test/lib_tests/EffectCache_test.res rename to packages/envio-tests/test/lib_tests/EffectCache_test.res diff --git a/packages/envio/test/lib_tests/Metrics_test.res b/packages/envio-tests/test/lib_tests/Metrics_test.res similarity index 100% rename from packages/envio/test/lib_tests/Metrics_test.res rename to packages/envio-tests/test/lib_tests/Metrics_test.res diff --git a/packages/envio/test/lib_tests/PackageJson_test.res b/packages/envio-tests/test/lib_tests/PackageJson_test.res similarity index 100% rename from packages/envio/test/lib_tests/PackageJson_test.res rename to packages/envio-tests/test/lib_tests/PackageJson_test.res diff --git a/packages/envio/test/lib_tests/Rpc_Test.res b/packages/envio-tests/test/lib_tests/Rpc_Test.res similarity index 100% rename from packages/envio/test/lib_tests/Rpc_Test.res rename to packages/envio-tests/test/lib_tests/Rpc_Test.res diff --git a/packages/envio/test/lib_tests/Throttler_test.res b/packages/envio-tests/test/lib_tests/Throttler_test.res similarity index 100% rename from packages/envio/test/lib_tests/Throttler_test.res rename to packages/envio-tests/test/lib_tests/Throttler_test.res diff --git a/packages/envio/test/setup.ts b/packages/envio-tests/test/setup.ts similarity index 77% rename from packages/envio/test/setup.ts rename to packages/envio-tests/test/setup.ts index 1f438c0a2b..2a48c4f5c9 100644 --- a/packages/envio/test/setup.ts +++ b/packages/envio-tests/test/setup.ts @@ -1,3 +1,3 @@ // Importing Env triggers Logging.setLogger as a side effect, // ensuring the logger is available for all tests. -import "../src/Env.res.mjs"; +import "envio/src/Env.res.mjs"; diff --git a/packages/envio/vitest.config.ts b/packages/envio-tests/vitest.config.ts similarity index 100% rename from packages/envio/vitest.config.ts rename to packages/envio-tests/vitest.config.ts diff --git a/packages/envio/package.json b/packages/envio/package.json index 7b370e76cd..b52cc9c9da 100644 --- a/packages/envio/package.json +++ b/packages/envio/package.json @@ -13,8 +13,7 @@ }, "scripts": { "build": "rescript", - "watch": "rescript watch", - "test": "rescript && vitest run" + "watch": "rescript watch" }, "author": "envio contributors ", "license": "SEE LICENSE IN licenses/README.md", @@ -76,7 +75,6 @@ "tsx": "4.21.0" }, "devDependencies": { - "rescript": "12.2.0", - "vitest": "4.1.0" + "rescript": "12.2.0" } } diff --git a/packages/envio/rescript.json b/packages/envio/rescript.json index 8f0ce83d2f..3a34de2bb1 100644 --- a/packages/envio/rescript.json +++ b/packages/envio/rescript.json @@ -5,14 +5,6 @@ { "dir": "src", "subdirs": true - }, - { - "dir": "testing", - "subdirs": true - }, - { - "dir": "test", - "subdirs": true } ], "suffix": ".res.mjs", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8bdd15710..6d033fbaa0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -127,6 +127,28 @@ importers: rescript: specifier: 12.2.0 version: 12.2.0 + + packages/envio-tests: + dependencies: + bignumber.js: + specifier: 9.3.1 + version: 9.3.1 + envio: + specifier: file:../envio + version: link:../envio + prom-client: + specifier: 15.1.3 + version: 15.1.3 + devDependencies: + '@rescript/runtime': + specifier: 12.2.0 + version: 12.2.0 + rescript: + specifier: 12.2.0 + version: 12.2.0 + rescript-schema: + specifier: 9.5.1 + version: 9.5.1(rescript@12.2.0) vitest: specifier: 4.1.0 version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(jsdom@16.7.0)(vite@7.3.1(@types/node@24.12.2)(tsx@4.21.0)) @@ -231,6 +253,9 @@ importers: envio: specifier: file:../../packages/envio version: link:../../packages/envio + envio-tests: + specifier: file:../../packages/envio-tests + version: link:../../packages/envio-tests ts-expect: specifier: 1.3.0 version: 1.3.0 diff --git a/scenarios/test_codegen/package.json b/scenarios/test_codegen/package.json index 874a2750e9..6ecbc12f1b 100644 --- a/scenarios/test_codegen/package.json +++ b/scenarios/test_codegen/package.json @@ -32,7 +32,8 @@ "typescript": "6.0.3", "ts-expect": "1.3.0", "viem": "2.54.0", - "envio": "file:../../packages/envio" + "envio": "file:../../packages/envio", + "envio-tests": "file:../../packages/envio-tests" }, "engines": { "node": ">=22.0.0" diff --git a/scenarios/test_codegen/rescript.json b/scenarios/test_codegen/rescript.json index e31d181f4f..1559cf514b 100644 --- a/scenarios/test_codegen/rescript.json +++ b/scenarios/test_codegen/rescript.json @@ -20,7 +20,8 @@ }, "dependencies": [ "rescript-schema", - "envio" + "envio", + "envio-tests" ], "compiler-flags": ["-open RescriptSchema"], "warnings": { From 5c6b825237f27e263aa797b9ef5077c341d0f86c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 11:29:01 +0000 Subject: [PATCH 6/7] Update lockfile for envio-tests prom-client dependency Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb6Yyif9GZG1DWAiCER4Gh --- pnpm-lock.yaml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b6320a309..1052424d5a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1167,6 +1167,9 @@ packages: bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + bintrees@1.0.2: + resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + bn.js@5.2.3: resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} @@ -2266,6 +2269,10 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + prom-client@15.1.3: + resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} + engines: {node: ^16 || ^18 || >=20} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -2578,6 +2585,9 @@ packages: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} + tdigest@0.1.2: + resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} + terminal-link@2.1.1: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} @@ -3434,8 +3444,7 @@ snapshots: '@noble/hashes@1.8.0': {} - '@opentelemetry/api@1.9.0': - optional: true + '@opentelemetry/api@1.9.0': {} '@pinojs/redact@0.4.0': {} @@ -3802,6 +3811,8 @@ snapshots: bignumber.js@9.3.1: {} + bintrees@1.0.2: {} + bn.js@5.2.3: {} body-parser@1.20.2: @@ -5119,6 +5130,11 @@ snapshots: process-warning@5.0.0: {} + prom-client@15.1.3: + dependencies: + '@opentelemetry/api': 1.9.0 + tdigest: 0.1.2 + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -5444,6 +5460,10 @@ snapshots: tagged-tag@1.0.0: {} + tdigest@0.1.2: + dependencies: + bintrees: 1.0.2 + terminal-link@2.1.1: dependencies: ansi-escapes: 4.3.2 From ced9451453e85df76ea7c5fd75e088083da5dd6a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Jul 2026 11:54:03 +0000 Subject: [PATCH 7/7] Drop prom-client from envio-tests Main replaced the prom-client-based metrics with a custom Metrics module, so nothing imports prom-client at runtime anymore. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fb6Yyif9GZG1DWAiCER4Gh --- packages/envio-tests/package.json | 1 - pnpm-lock.yaml | 27 ++------------------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/packages/envio-tests/package.json b/packages/envio-tests/package.json index 23f622d75b..932233d878 100644 --- a/packages/envio-tests/package.json +++ b/packages/envio-tests/package.json @@ -16,7 +16,6 @@ }, "dependencies": { "bignumber.js": "9.3.1", - "prom-client": "15.1.3", "envio": "file:../envio" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1052424d5a..82f61f2319 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -133,9 +133,6 @@ importers: envio: specifier: file:../envio version: link:../envio - prom-client: - specifier: 15.1.3 - version: 15.1.3 devDependencies: '@rescript/runtime': specifier: 12.2.0 @@ -1167,9 +1164,6 @@ packages: bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - bintrees@1.0.2: - resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} - bn.js@5.2.3: resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} @@ -2269,10 +2263,6 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} - prom-client@15.1.3: - resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} - engines: {node: ^16 || ^18 || >=20} - prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -2585,9 +2575,6 @@ packages: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} - tdigest@0.1.2: - resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} - terminal-link@2.1.1: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} @@ -3444,7 +3431,8 @@ snapshots: '@noble/hashes@1.8.0': {} - '@opentelemetry/api@1.9.0': {} + '@opentelemetry/api@1.9.0': + optional: true '@pinojs/redact@0.4.0': {} @@ -3811,8 +3799,6 @@ snapshots: bignumber.js@9.3.1: {} - bintrees@1.0.2: {} - bn.js@5.2.3: {} body-parser@1.20.2: @@ -5130,11 +5116,6 @@ snapshots: process-warning@5.0.0: {} - prom-client@15.1.3: - dependencies: - '@opentelemetry/api': 1.9.0 - tdigest: 0.1.2 - prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -5460,10 +5441,6 @@ snapshots: tagged-tag@1.0.0: {} - tdigest@0.1.2: - dependencies: - bintrees: 1.0.2 - terminal-link@2.1.1: dependencies: ansi-escapes: 4.3.2