Files
gh-enviodev-envio-plugins-p…/skills/hyperindex-development/references/testing.md
2025-11-29 18:26:05 +08:00

5.6 KiB

Testing HyperIndex Indexers

Unit test handlers with MockDb and simulated events.

Setup

  1. Install test framework:
pnpm i mocha @types/mocha
  1. Create test folder and file: test/test.ts

  2. Add to package.json:

"test": "mocha"
  1. Generate test helpers:
pnpm codegen

Basic Test Structure

import assert from "assert";
import { TestHelpers, UserEntity } from "generated";

const { MockDb, Greeter, Addresses } = TestHelpers;

describe("Greeter Indexer", () => {
  it("NewGreeting creates User entity", async () => {
    // 1. Create mock database
    const mockDb = MockDb.createMockDb();

    // 2. Create mock event
    const mockEvent = Greeter.NewGreeting.createMockEvent({
      greeting: "Hello",
      user: Addresses.defaultAddress,
    });

    // 3. Process event
    const updatedDb = await mockDb.processEvents([mockEvent]);

    // 4. Assert result
    const user = updatedDb.entities.User.get(Addresses.defaultAddress);
    assert.equal(user?.latestGreeting, "Hello");
  });
});

MockDb API

Create Empty Database

const mockDb = MockDb.createMockDb();

Add Entities

const mockDb = MockDb.createMockDb();
const dbWithEntity = mockDb.entities.User.set({
  id: "user-1",
  balance: BigInt(1000),
  name: "Alice",
});

Get Entities

const user = updatedDb.entities.User.get("user-1");

Process Events

const updatedDb = await mockDb.processEvents([event1, event2, event3]);

Creating Mock Events

Basic Event

const mockEvent = MyContract.Transfer.createMockEvent({
  from: "0x123...",
  to: "0x456...",
  value: BigInt(1000),
});

With Custom Metadata

const mockEvent = MyContract.Transfer.createMockEvent(
  {
    from: "0x123...",
    to: "0x456...",
    value: BigInt(1000),
  },
  {
    chainId: 1,
    srcAddress: "0xContractAddress",
    logIndex: 0,
    block: {
      number: 12345678,
      timestamp: 1699000000,
      hash: "0xblockhash...",
    },
    transaction: {
      hash: "0xtxhash...",
    },
  }
);

Test Patterns

Entity Creation

it("creates entity on event", async () => {
  const mockDb = MockDb.createMockDb();

  const event = MyContract.Created.createMockEvent({
    id: "token-1",
    name: "Token",
  });

  const updatedDb = await mockDb.processEvents([event]);

  const token = updatedDb.entities.Token.get("token-1");
  assert.ok(token, "Token should exist");
  assert.equal(token.name, "Token");
});

Entity Updates

it("updates entity on subsequent events", async () => {
  const mockDb = MockDb.createMockDb();
  const userAddress = Addresses.defaultAddress;

  // First event
  const event1 = Greeter.NewGreeting.createMockEvent({
    greeting: "Hello",
    user: userAddress,
  });

  // Second event
  const event2 = Greeter.NewGreeting.createMockEvent({
    greeting: "Hi again",
    user: userAddress,
  });

  const updatedDb = await mockDb.processEvents([event1, event2]);

  const user = updatedDb.entities.User.get(userAddress);
  assert.equal(user?.numberOfGreetings, 2);
  assert.equal(user?.latestGreeting, "Hi again");
});

Pre-existing Entities

it("updates existing entity", async () => {
  // Start with entity in database
  const mockDb = MockDb.createMockDb()
    .entities.Token.set({
      id: "token-1",
      totalSupply: BigInt(1000),
    });

  const event = MyContract.Mint.createMockEvent({
    tokenId: "token-1",
    amount: BigInt(500),
  });

  const updatedDb = await mockDb.processEvents([event]);

  const token = updatedDb.entities.Token.get("token-1");
  assert.equal(token?.totalSupply, BigInt(1500));
});

Multiple Event Types

it("handles multiple event types", async () => {
  const mockDb = MockDb.createMockDb();

  const mintEvent = MyContract.Mint.createMockEvent({ ... });
  const transferEvent = MyContract.Transfer.createMockEvent({ ... });
  const burnEvent = MyContract.Burn.createMockEvent({ ... });

  const updatedDb = await mockDb.processEvents([
    mintEvent,
    transferEvent,
    burnEvent,
  ]);

  // Assert final state
});

Debugging Tests

Log Entity State

const user = updatedDb.entities.User.get(userId);
console.log(JSON.stringify(user, null, 2));

Check Entity Exists

assert.ok(
  updatedDb.entities.User.get(userId),
  `User ${userId} should exist`
);

Common Issues

"Cannot read properties of undefined"

  • Entity doesn't exist - check IDs match
  • Entity wasn't created - verify handler logic

Type Mismatch

  • Match schema types (BigInt vs number)
  • Use BigInt() for BigInt fields

Missing Imports

import { TestHelpers, EntityType } from "generated";
const { MockDb, ContractName, Addresses } = TestHelpers;

Running Tests

# Run all tests
pnpm test

# Run specific test file
pnpm mocha test/transfers.test.ts

# Watch mode (with nodemon)
pnpm mocha --watch test/

Test Template

import assert from "assert";
import { TestHelpers, TokenEntity } from "generated";

const { MockDb, MyContract, Addresses } = TestHelpers;

describe("MyContract Indexer", () => {
  describe("Transfer events", () => {
    it("creates Transfer entity", async () => {
      const mockDb = MockDb.createMockDb();

      const event = MyContract.Transfer.createMockEvent({
        from: Addresses.defaultAddress,
        to: "0x456...",
        value: BigInt(1000),
      });

      const updatedDb = await mockDb.processEvents([event]);

      // Add assertions
    });
  });
});