Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:26:05 +08:00
commit 8bcde7080b
26 changed files with 5957 additions and 0 deletions

View File

@@ -0,0 +1,284 @@
# Testing HyperIndex Indexers
Unit test handlers with MockDb and simulated events.
## Setup
1. Install test framework:
```bash
pnpm i mocha @types/mocha
```
2. Create test folder and file: `test/test.ts`
3. Add to `package.json`:
```json
"test": "mocha"
```
4. Generate test helpers:
```bash
pnpm codegen
```
## Basic Test Structure
```typescript
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
```typescript
const mockDb = MockDb.createMockDb();
```
### Add Entities
```typescript
const mockDb = MockDb.createMockDb();
const dbWithEntity = mockDb.entities.User.set({
id: "user-1",
balance: BigInt(1000),
name: "Alice",
});
```
### Get Entities
```typescript
const user = updatedDb.entities.User.get("user-1");
```
### Process Events
```typescript
const updatedDb = await mockDb.processEvents([event1, event2, event3]);
```
## Creating Mock Events
### Basic Event
```typescript
const mockEvent = MyContract.Transfer.createMockEvent({
from: "0x123...",
to: "0x456...",
value: BigInt(1000),
});
```
### With Custom Metadata
```typescript
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
```typescript
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
```typescript
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
```typescript
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
```typescript
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
```typescript
const user = updatedDb.entities.User.get(userId);
console.log(JSON.stringify(user, null, 2));
```
### Check Entity Exists
```typescript
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
```typescript
import { TestHelpers, EntityType } from "generated";
const { MockDb, ContractName, Addresses } = TestHelpers;
```
## Running Tests
```bash
# 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
```typescript
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
});
});
});
```