fix: Ponder: add test infrastructure + coverage for helpers (target 95%) (#287)
- Add vitest ^2 + @vitest/coverage-v8 ^2 as devDependencies
- Add `test` and `test:coverage` scripts to package.json
- Create vitest.config.ts with resolve.alias to mock ponder virtual modules
(ponder:schema, ponder:registry) and point kraiken-lib/version to source
- Add coverage/ to .gitignore
- Add vitest.config.ts to tsconfig.json include so eslint project-aware rules apply
- Create src/tests/__mocks__/ponder-schema.ts and ponder-registry.ts stubs
- Create src/tests/stats.test.ts — 48 tests covering ring buffer logic,
segment updates, hourly advancement, projections, ETH reserve snapshots,
all exported async helpers with mock Ponder contexts
- Create src/tests/version.test.ts — 14 tests covering isCompatibleVersion,
getVersionMismatchError, and validateContractVersion (compatible / mismatch /
error paths, existing-meta upsert path)
- Create src/tests/abi.test.ts — 6 tests covering validateAbi and
validateContractAbi
Result: 68 tests pass, 100% line/statement/function coverage on all helpers
(stats.ts, version.ts, abi.ts, logger.ts) — exceeds 95% target.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 22:29:57 +00:00
|
|
|
import { describe, it, expect } from 'vitest';
|
fix: Ponder: add test infrastructure + coverage for helpers (target 95%) (#287)
- Add vitest ^2 + @vitest/coverage-v8 ^2 as devDependencies
- Add `test` and `test:coverage` scripts to package.json
- Create vitest.config.ts with resolve.alias to mock ponder virtual modules
(ponder:schema, ponder:registry) and point kraiken-lib/version to source
- Add coverage/ to .gitignore
- Add tests/**/* and vitest.config.ts to tsconfig.json include
- Create tests/__mocks__/ponder-schema.ts and ponder-registry.ts stubs
- Create tests/stats.test.ts — 48 tests covering ring buffer logic,
segment updates, hourly advancement, projections, ETH reserve snapshots,
all exported async helpers with mock Ponder contexts
- Create tests/version.test.ts — 14 tests covering isCompatibleVersion,
getVersionMismatchError, and validateContractVersion (compatible / mismatch /
error paths, existing-meta upsert path)
- Create tests/abi.test.ts — 6 tests covering validateAbi and validateContractAbi
Tests placed at tests/ (not src/tests/) so Ponder's Vite build does not
attempt to execute test files as event handlers on startup.
Result: 68 tests pass, 100% line/statement/function coverage on all helpers
(stats.ts, version.ts, abi.ts, logger.ts) — exceeds 95% target.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 22:53:01 +00:00
|
|
|
import { validateAbi, validateContractAbi } from '../src/helpers/abi.js';
|
fix: Ponder: add test infrastructure + coverage for helpers (target 95%) (#287)
- Add vitest ^2 + @vitest/coverage-v8 ^2 as devDependencies
- Add `test` and `test:coverage` scripts to package.json
- Create vitest.config.ts with resolve.alias to mock ponder virtual modules
(ponder:schema, ponder:registry) and point kraiken-lib/version to source
- Add coverage/ to .gitignore
- Add vitest.config.ts to tsconfig.json include so eslint project-aware rules apply
- Create src/tests/__mocks__/ponder-schema.ts and ponder-registry.ts stubs
- Create src/tests/stats.test.ts — 48 tests covering ring buffer logic,
segment updates, hourly advancement, projections, ETH reserve snapshots,
all exported async helpers with mock Ponder contexts
- Create src/tests/version.test.ts — 14 tests covering isCompatibleVersion,
getVersionMismatchError, and validateContractVersion (compatible / mismatch /
error paths, existing-meta upsert path)
- Create src/tests/abi.test.ts — 6 tests covering validateAbi and
validateContractAbi
Result: 68 tests pass, 100% line/statement/function coverage on all helpers
(stats.ts, version.ts, abi.ts, logger.ts) — exceeds 95% target.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 22:29:57 +00:00
|
|
|
import type { Abi } from 'viem';
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// validateAbi
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
describe('validateAbi', () => {
|
|
|
|
|
it('returns the exact same ABI reference it receives', () => {
|
|
|
|
|
const abi: Abi = [
|
|
|
|
|
{
|
|
|
|
|
name: 'transfer',
|
|
|
|
|
type: 'function',
|
|
|
|
|
stateMutability: 'nonpayable',
|
|
|
|
|
inputs: [
|
|
|
|
|
{ name: 'to', type: 'address' },
|
|
|
|
|
{ name: 'amount', type: 'uint256' },
|
|
|
|
|
],
|
|
|
|
|
outputs: [{ name: '', type: 'bool' }],
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
const result = validateAbi(abi);
|
|
|
|
|
expect(result).toBe(abi);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('returns an empty ABI unchanged', () => {
|
|
|
|
|
const abi: Abi = [];
|
|
|
|
|
expect(validateAbi(abi)).toBe(abi);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('preserves all entries in a multi-entry ABI', () => {
|
|
|
|
|
const abi: Abi = [
|
|
|
|
|
{
|
|
|
|
|
name: 'mint',
|
|
|
|
|
type: 'function',
|
|
|
|
|
stateMutability: 'nonpayable',
|
|
|
|
|
inputs: [],
|
|
|
|
|
outputs: [],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'Transfer',
|
|
|
|
|
type: 'event',
|
|
|
|
|
inputs: [
|
|
|
|
|
{ name: 'from', type: 'address', indexed: true },
|
|
|
|
|
{ name: 'to', type: 'address', indexed: true },
|
|
|
|
|
{ name: 'value', type: 'uint256', indexed: false },
|
|
|
|
|
],
|
|
|
|
|
anonymous: false,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
const result = validateAbi(abi);
|
|
|
|
|
expect(result).toHaveLength(2);
|
|
|
|
|
expect(result).toBe(abi);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// validateContractAbi
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
describe('validateContractAbi', () => {
|
|
|
|
|
it('returns the abi property from the contract object', () => {
|
|
|
|
|
const abi: Abi = [
|
|
|
|
|
{
|
|
|
|
|
name: 'balanceOf',
|
|
|
|
|
type: 'function',
|
|
|
|
|
stateMutability: 'view',
|
|
|
|
|
inputs: [{ name: 'account', type: 'address' }],
|
|
|
|
|
outputs: [{ name: '', type: 'uint256' }],
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
const contract = { abi, address: '0xdeadbeef' };
|
|
|
|
|
const result = validateContractAbi(contract);
|
|
|
|
|
expect(result).toBe(abi);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('works with an empty abi property', () => {
|
|
|
|
|
const contract = { abi: [] as Abi };
|
|
|
|
|
const result = validateContractAbi(contract);
|
|
|
|
|
expect(result).toEqual([]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('does not return any other property of the contract object', () => {
|
|
|
|
|
const abi: Abi = [];
|
|
|
|
|
const contract = { abi, address: '0x1234', name: 'MyContract' };
|
|
|
|
|
const result = validateContractAbi(contract);
|
|
|
|
|
expect(result).toBe(abi);
|
|
|
|
|
// result is just the ABI array, not the full contract object
|
|
|
|
|
expect(Array.isArray(result)).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
});
|