/
indexerSync.test.ts
151 lines (128 loc) · 5.13 KB
/
indexerSync.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { ViteDevServer } from "vite";
import { Browser, Page } from "@playwright/test";
import { createAsyncErrorHandler } from "./asyncErrors";
import {
deployContracts,
startViteServer,
startBrowserAndPage,
startIndexer,
openClientWithRootAccount,
} from "./setup";
import { range } from "@latticexyz/utils";
import path from "node:path";
import { rpcHttpUrl } from "./setup/constants";
import { z } from "zod";
import { callPageFunction } from "./data/callPageFunction";
import { expectClientData } from "./data/expectClientData";
import { mergeTestData } from "./data/mergeTestData";
import { push, pushRange, pop } from "./data/numberListSystem";
import { setContractData } from "./data/setContractData";
import { testData1, testData2 } from "./data/testData";
import { waitForInitialSync } from "./data/waitForInitialSync";
const env = z
.object({
DATABASE_URL: z.string().default("postgres://127.0.0.1/postgres"),
})
.parse(process.env, {
errorMap: (issue) => ({
message: `Missing or invalid environment variable: ${issue.path.join(".")}`,
}),
});
describe("Sync from indexer", async () => {
const asyncErrorHandler = createAsyncErrorHandler();
let webserver: ViteDevServer;
let browser: Browser;
let page: Page;
beforeEach(async () => {
await deployContracts(rpcHttpUrl);
// Start client and browser
webserver = await startViteServer();
const browserAndPage = await startBrowserAndPage(asyncErrorHandler.reportError);
browser = browserAndPage.browser;
page = browserAndPage.page;
});
afterEach(async () => {
await browser.close();
await webserver.close();
asyncErrorHandler.resetErrors();
});
it("should log error if indexer is offline", async () => {
await openClientWithRootAccount(page, { indexerUrl: `http://127.0.0.1:9999/trpc` });
await waitForInitialSync(page);
expect(asyncErrorHandler.getErrors()).toHaveLength(1);
expect(asyncErrorHandler.getErrors()[0]).toContain("error getting snapshot");
});
describe.each([["sqlite"], ["postgres"]] as const)("%s indexer", (indexerType) => {
let indexerIteration = 1;
let indexer: ReturnType<typeof startIndexer>;
beforeEach(async () => {
// Start indexer
const port = 3000 + indexerIteration++;
indexer = startIndexer({
port,
rpcHttpUrl,
reportError: asyncErrorHandler.reportError,
...(indexerType === "postgres"
? { indexer: "postgres", databaseUrl: env.DATABASE_URL }
: { indexer: "sqlite", sqliteFilename: path.join(__dirname, `anvil-${port}.db`) }),
});
await indexer.doneSyncing;
});
afterEach(async () => {
await indexer.kill();
});
it("should sync test data", async () => {
await openClientWithRootAccount(page, { indexerUrl: indexer.url });
await waitForInitialSync(page);
// Write data to the contracts, expect the client to be synced
await setContractData(page, testData1);
await expectClientData(page, testData1);
// Write more data to the contracts, expect client to update
await setContractData(page, testData2);
await expectClientData(page, mergeTestData(testData1, testData2));
// Reload the page, expect all data to still be set
await page.reload();
await waitForInitialSync(page);
await expectClientData(page, mergeTestData(testData1, testData2));
asyncErrorHandler.expectNoAsyncErrors();
});
it("should sync number list modified via system", async () => {
await openClientWithRootAccount(page, { indexerUrl: indexer.url });
await waitForInitialSync(page);
// Push one element to the array
await push(page, 42);
await expectClientData(page, { NumberList: [{ key: {}, value: { value: [42] } }] });
// Push 5000 elements to the array
await pushRange(page, 0, 5000);
await expectClientData(page, { NumberList: [{ key: {}, value: { value: [42, ...range(5000, 1, 0)] } }] });
// Pop one element from the array
await pop(page);
await expectClientData(page, { NumberList: [{ key: {}, value: { value: [42, ...range(4999, 1, 0)] } }] });
// Should not have thrown errors
asyncErrorHandler.expectNoAsyncErrors();
});
it("should only have filtered position data", async () => {
await openClientWithRootAccount(page, { indexerUrl: indexer.url });
await waitForInitialSync(page);
const entities = await callPageFunction(page, "getKeys", ["Position"]);
expect(entities).toEqual(
// TODO: figure out how to make this consistently return the same order? may require https://github.com/latticexyz/mud/issues/1979
expect.arrayContaining([
{
x: 1,
y: 1,
zone: "0x6d61703100000000000000000000000000000000000000000000000000000000",
},
{
x: 2,
y: -2,
zone: "0x6d61703100000000000000000000000000000000000000000000000000000000",
},
])
);
// Should not have thrown errors
asyncErrorHandler.expectNoAsyncErrors();
});
});
});