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, vi, afterEach } from 'vitest';
|
|
|
|
|
import {
|
|
|
|
|
isCompatibleVersion,
|
|
|
|
|
getVersionMismatchError,
|
|
|
|
|
KRAIKEN_LIB_VERSION,
|
|
|
|
|
COMPATIBLE_CONTRACT_VERSIONS,
|
|
|
|
|
} from 'kraiken-lib/version';
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// isCompatibleVersion (from kraiken-lib/version, aliased to source)
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
describe('isCompatibleVersion', () => {
|
|
|
|
|
it('returns true for each version in COMPATIBLE_CONTRACT_VERSIONS', () => {
|
|
|
|
|
for (const v of COMPATIBLE_CONTRACT_VERSIONS) {
|
|
|
|
|
expect(isCompatibleVersion(v)).toBe(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('returns false for version 0', () => {
|
|
|
|
|
expect(isCompatibleVersion(0)).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('returns false for a future version not yet listed', () => {
|
|
|
|
|
expect(isCompatibleVersion(9999)).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('returns false for negative version', () => {
|
|
|
|
|
expect(isCompatibleVersion(-1)).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// getVersionMismatchError (from kraiken-lib/version)
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
describe('getVersionMismatchError', () => {
|
|
|
|
|
it('includes the bad contract version in the output (ponder context)', () => {
|
|
|
|
|
const msg = getVersionMismatchError(99, 'ponder');
|
|
|
|
|
expect(msg).toContain('99');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('includes the library version in the output', () => {
|
|
|
|
|
const msg = getVersionMismatchError(99, 'ponder');
|
|
|
|
|
expect(msg).toContain(String(KRAIKEN_LIB_VERSION));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('includes ponder-specific remediation steps', () => {
|
|
|
|
|
const msg = getVersionMismatchError(99, 'ponder');
|
|
|
|
|
expect(msg).toContain('COMPATIBLE_CONTRACT_VERSIONS');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('includes frontend-specific remediation steps', () => {
|
|
|
|
|
const msg = getVersionMismatchError(99, 'frontend');
|
|
|
|
|
expect(msg).toContain('administrator');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('formats compatible versions list', () => {
|
|
|
|
|
const msg = getVersionMismatchError(99, 'ponder');
|
|
|
|
|
for (const v of COMPATIBLE_CONTRACT_VERSIONS) {
|
|
|
|
|
expect(msg).toContain(String(v));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('returns a multi-line string (box drawing)', () => {
|
|
|
|
|
const msg = getVersionMismatchError(99, 'ponder');
|
|
|
|
|
expect(msg.split('\n').length).toBeGreaterThan(3);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// validateContractVersion (helpers/version.ts) — mock the Ponder context
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
describe('validateContractVersion', () => {
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
vi.restoreAllMocks();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('logs success and upserts metadata on compatible version', async () => {
|
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
|
|
|
const { validateContractVersion } = await import('../src/helpers/version.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
|
|
|
|
|
|
|
|
const setFn = vi.fn().mockResolvedValue(undefined);
|
|
|
|
|
const ctx = {
|
|
|
|
|
client: {
|
|
|
|
|
readContract: vi.fn().mockResolvedValue(KRAIKEN_LIB_VERSION),
|
|
|
|
|
},
|
|
|
|
|
contracts: {
|
|
|
|
|
Kraiken: { abi: [], address: '0x0001' as `0x${string}` },
|
|
|
|
|
},
|
|
|
|
|
db: {
|
|
|
|
|
find: vi.fn().mockResolvedValue(null),
|
|
|
|
|
insert: vi.fn().mockReturnValue({ values: vi.fn().mockResolvedValue(undefined) }),
|
|
|
|
|
update: vi.fn().mockReturnValue({ set: setFn }),
|
|
|
|
|
},
|
|
|
|
|
logger: {
|
|
|
|
|
info: vi.fn(),
|
|
|
|
|
error: vi.fn(),
|
|
|
|
|
warn: vi.fn(),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as () => never);
|
|
|
|
|
|
|
|
|
|
await validateContractVersion(ctx as unknown as import('ponder:registry').Context);
|
|
|
|
|
|
|
|
|
|
expect(exitSpy).not.toHaveBeenCalled();
|
|
|
|
|
expect(ctx.logger.info).toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('calls process.exit on incompatible contract version', async () => {
|
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
|
|
|
const { validateContractVersion } = await import('../src/helpers/version.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
|
|
|
|
|
|
|
|
const ctx = {
|
|
|
|
|
client: {
|
|
|
|
|
readContract: vi.fn().mockResolvedValue(9999n),
|
|
|
|
|
},
|
|
|
|
|
contracts: {
|
|
|
|
|
Kraiken: { abi: [], address: '0x0001' as `0x${string}` },
|
|
|
|
|
},
|
|
|
|
|
db: {
|
|
|
|
|
find: vi.fn().mockResolvedValue(null),
|
|
|
|
|
insert: vi.fn().mockReturnValue({ values: vi.fn().mockResolvedValue(undefined) }),
|
|
|
|
|
update: vi.fn().mockReturnValue({ set: vi.fn().mockResolvedValue(undefined) }),
|
|
|
|
|
},
|
|
|
|
|
logger: {
|
|
|
|
|
info: vi.fn(),
|
|
|
|
|
error: vi.fn(),
|
|
|
|
|
warn: vi.fn(),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as () => never);
|
|
|
|
|
|
|
|
|
|
await validateContractVersion(ctx as unknown as import('ponder:registry').Context);
|
|
|
|
|
|
|
|
|
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('calls process.exit when readContract throws', async () => {
|
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
|
|
|
const { validateContractVersion } = await import('../src/helpers/version.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
|
|
|
|
|
|
|
|
const ctx = {
|
|
|
|
|
client: {
|
|
|
|
|
readContract: vi.fn().mockRejectedValue(new Error('network error')),
|
|
|
|
|
},
|
|
|
|
|
contracts: {
|
|
|
|
|
Kraiken: { abi: [], address: '0x0001' as `0x${string}` },
|
|
|
|
|
},
|
|
|
|
|
db: {
|
|
|
|
|
find: vi.fn().mockResolvedValue(null),
|
|
|
|
|
insert: vi.fn().mockReturnValue({ values: vi.fn().mockResolvedValue(undefined) }),
|
|
|
|
|
update: vi.fn().mockReturnValue({ set: vi.fn().mockResolvedValue(undefined) }),
|
|
|
|
|
},
|
|
|
|
|
logger: {
|
|
|
|
|
info: vi.fn(),
|
|
|
|
|
error: vi.fn(),
|
|
|
|
|
warn: vi.fn(),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as () => never);
|
|
|
|
|
|
|
|
|
|
await validateContractVersion(ctx as unknown as import('ponder:registry').Context);
|
|
|
|
|
|
|
|
|
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('updates existing metadata when a row already exists', async () => {
|
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
|
|
|
const { validateContractVersion } = await import('../src/helpers/version.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
|
|
|
|
|
|
|
|
const setFn = vi.fn().mockResolvedValue(undefined);
|
|
|
|
|
const existingMeta = { id: 'stack-meta', contractVersion: 1 };
|
|
|
|
|
const ctx = {
|
|
|
|
|
client: {
|
|
|
|
|
readContract: vi.fn().mockResolvedValue(KRAIKEN_LIB_VERSION),
|
|
|
|
|
},
|
|
|
|
|
contracts: {
|
|
|
|
|
Kraiken: { abi: [], address: '0x0001' as `0x${string}` },
|
|
|
|
|
},
|
|
|
|
|
db: {
|
|
|
|
|
find: vi.fn().mockResolvedValue(existingMeta),
|
|
|
|
|
insert: vi.fn().mockReturnValue({ values: vi.fn().mockResolvedValue(undefined) }),
|
|
|
|
|
update: vi.fn().mockReturnValue({ set: setFn }),
|
|
|
|
|
},
|
|
|
|
|
logger: {
|
|
|
|
|
info: vi.fn(),
|
|
|
|
|
error: vi.fn(),
|
|
|
|
|
warn: vi.fn(),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as () => never);
|
|
|
|
|
|
|
|
|
|
await validateContractVersion(ctx as unknown as import('ponder:registry').Context);
|
|
|
|
|
|
|
|
|
|
expect(exitSpy).not.toHaveBeenCalled();
|
|
|
|
|
expect(ctx.db.update).toHaveBeenCalled();
|
|
|
|
|
expect(ctx.db.insert).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
});
|