Skip to content

Latest commit

 

History

History

Folders and files

README.md

@foundryprotocol/0gkit-testing

Test toolkit for 0gkit. Mock providers, fixture factories, a deterministic testWallet, a setupLocalDevnet() vitest helper, and four vitest matchers that understand 0G semantics.

npm i -D @foundryprotocol/0gkit-testing

Mocks — sub-millisecond primitives

import {
  mockStorageClient,
  mockComputeClient,
  mockDAClient,
} from "@foundryprotocol/0gkit-testing";

const storage = mockStorageClient();
const { root, tx } = await storage.upload(new TextEncoder().encode("gm"));
const bytes = await storage.download(root); // round-trips deterministically
const est = await storage.estimate(new Uint8Array(300_000));
//=> { kind: "storage", gas, fee, breakdown: { sizeBytes: 300_000, segments: 2 } }
const dr = await storage.upload(bytes, { dryRun: true });
//=> { dryRun: true, estimate, result: { root, tx: { latencyMs: 0 }, raw } }

const compute = mockComputeClient(); // default echo responder
const reply = await compute.inference({
  messages: [{ role: "user", content: "ping" }],
});
//=> { output: "echo: ping", receipt, raw }
const ce = await compute.estimate({
  messages: [{ role: "user", content: "ping" }],
});
//=> { kind: "compute", gas: 0n, fee, breakdown: { inputTokens, outputTokensMax, model } }

const da = mockDAClient();
const { digest } = await da.publish(bytes);
const ok = await da.verify(digest, bytes); // true; tamper bytes → false

Same upload / download / inference / estimate / publish shape as the real packages — including the SP6 inference() API on Compute and the SP7 { dryRun: true } overloads on Storage and Compute (returning the DryRunResult<T> envelope from @foundryprotocol/0gkit-core). Roots and digests are sha256 of the input bytes — deterministic, so tests assert on stable values without snapshots.

Fixtures

import {
  fixtureReceipt,
  fixtureAttestation,
  FIXTURE_ATTESTATION_SIGNER,
} from "@foundryprotocol/0gkit-testing";

const tx = fixtureReceipt({ blockNumber: 17n });
// { txHash: "0xab...ab", blockNumber: 17n, latencyMs: 5 }

const signed = await fixtureAttestation({ scores: [0.9, 0.85] });
// signed.envelope, signed.digest, signed.signature — verifies with
// @foundryprotocol/0gkit-attestation.verifyEnvelope(signed, FIXTURE_ATTESTATION_SIGNER)

testWallet — deterministic Signer

import { testWallet } from "@foundryprotocol/0gkit-testing";

const signer = testWallet({ index: 0 });
// Matches anvil's pre-funded dev account 0:
// address = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266

Uses the same mnemonic as 0gkit-devnet's pre-funded accounts, so any test hitting setupLocalDevnet() with testWallet({ index: 0 }) has gas immediately — no faucet round-trip.

setupLocalDevnet({ autoStart })

// vitest.config.ts
import { setupLocalDevnet } from "@foundryprotocol/0gkit-testing";
export default {
  test: {
    globalSetup: ["./vitest.setup.ts"],
  },
};

// vitest.setup.ts
import { setupLocalDevnet } from "@foundryprotocol/0gkit-testing";
export default async function () {
  const devnet = await setupLocalDevnet({ autoStart: true });
  return () => devnet.stop();
}

Per-suite is equally easy:

import { beforeAll, afterAll } from "vitest";
import { setupLocalDevnet } from "@foundryprotocol/0gkit-testing";

const devnet = await setupLocalDevnet();
beforeAll(() => devnet.start());
afterAll(() => devnet.stop());

Lazily imports @foundryprotocol/0gkit-devnet so this package stays light when devnet isn't needed.

Vitest matchers

// vitest.setup.ts
import "@foundryprotocol/0gkit-testing/matchers";
expect(receipt).toBeConfirmedOn0G();
expect(root).toHaveRootMatching(/^0xab/);
await expect(signed).toBeValidAttestation(FIXTURE_ATTESTATION_SIGNER);
expect(err).toBeZeroGError("CONFIG");

Failure messages name what was expected, what was received, and (when possible) a one-line hint pointing at the likely cause.

Matcher Asserts
toBeConfirmedOn0G() Receipt has hex txHash, positive bigint blockNumber, non-negative latencyMs.
toHaveRootMatching(regex) Value is a 32-byte hex root that matches the regex.
toBeValidAttestation(expectedSigner?) Digest is intact and the signature recovers (optionally to the expected signer).
toBeZeroGError(code) Error is a ZeroGError with the named code (CONFIG / NETWORK / CHAIN / ATTESTATION).

Tree-shaking sub-paths

Cherry-pick what you need to keep the test bundle small:

import { mockStorageClient } from "@foundryprotocol/0gkit-testing/mocks";
import { fixtureReceipt } from "@foundryprotocol/0gkit-testing/fixtures";

Notes

  • 0gkit-attestation is an optional runtime dep — fixtureAttestation and toBeValidAttestation lazily import it. Install it alongside if you use those features.
  • setupLocalDevnet requires @foundryprotocol/0gkit-devnet (declared as a devDep here; install it where you use it).

License

MIT