Skip to content

Commit e7d6f1f

Browse files
Merge pull request #302 from dojoengine/fix/recs
fix: tests, improvements
2 parents 820346a + 9353306 commit e7d6f1f

File tree

6 files changed

+371
-77
lines changed

6 files changed

+371
-77
lines changed

examples/example-vite-react-app-recs/src/dojo/setup.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DojoConfig, DojoProvider } from "@dojoengine/core";
22
import { BurnerManager } from "@dojoengine/create-burner";
3-
import { getSyncEvents } from "@dojoengine/state";
3+
import { getSyncEntities, getSyncEvents } from "@dojoengine/state";
44
import * as torii from "@dojoengine/torii-client";
55
import { Account, ArraySignatureType } from "starknet";
66

@@ -24,6 +24,15 @@ export async function setup({ ...config }: DojoConfig) {
2424
// Define contract components based on the world configuration
2525
const contractComponents = defineContractComponents(world);
2626

27+
const getSync = await getSyncEntities(
28+
toriiClient,
29+
contractComponents as any,
30+
undefined,
31+
[],
32+
3000,
33+
true
34+
);
35+
2736
// Create client-side components that mirror the contract components
2837
const clientComponents = createClientComponents({ contractComponents });
2938

@@ -79,5 +88,6 @@ export async function setup({ ...config }: DojoConfig) {
7988
burnerManager,
8089
toriiClient,
8190
eventSync,
91+
getSync,
8292
};
8393
}

packages/state/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
},
2626
"dependencies": {
2727
"@dojoengine/recs": "2.0.13",
28-
"@dojoengine/torii-client": "workspace:*",
28+
"@dojoengine/torii-client": "1.0.0-alpha.20",
2929
"vitest": "^1.6.0"
3030
}
3131
}

packages/state/src/__tests__/utils.test.ts

+235-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Type as RecsType } from "@dojoengine/recs";
2-
import { describe, expect, it } from "vitest";
1+
import { Type as RecsType, Schema } from "@dojoengine/recs";
2+
import { describe, expect, it, vi } from "vitest";
33

44
import { convertValues } from "../utils";
55

@@ -108,4 +108,237 @@ describe("convertValues", () => {
108108
expect(result.nested).toEqual({ innerField: { value: "42" } });
109109
});
110110
});
111+
112+
it("should handle null and undefined values", () => {
113+
const schema: Schema = {
114+
name: RecsType.String,
115+
age: RecsType.Number,
116+
};
117+
const values = {
118+
name: { value: "Alice", type: "string" },
119+
age: undefined,
120+
};
121+
const expected = {
122+
name: "Alice",
123+
age: undefined,
124+
};
125+
expect(convertValues(schema, values)).toEqual(expected);
126+
});
127+
128+
it("should convert enum types correctly", () => {
129+
const schema: Schema = {
130+
status: RecsType.String,
131+
};
132+
const values = {
133+
status: { value: { option: "ACTIVE" }, type: "enum" },
134+
};
135+
const expected = {
136+
status: "ACTIVE",
137+
};
138+
expect(convertValues(schema, values)).toEqual(expected);
139+
});
140+
141+
it("should handle RecsType.StringArray with empty array", () => {
142+
const schema: Schema = {
143+
tags: RecsType.StringArray,
144+
};
145+
const values = {
146+
tags: { value: [], type: "array" },
147+
};
148+
const expected = {
149+
tags: [],
150+
};
151+
expect(convertValues(schema, values)).toEqual(expected);
152+
});
153+
154+
it("should handle RecsType.StringArray with enum items", () => {
155+
const schema: Schema = {
156+
tags: RecsType.StringArray,
157+
};
158+
const values = {
159+
tags: {
160+
value: [
161+
{ value: { option: "TAG1" }, type: "enum" },
162+
{ value: { option: "TAG2" }, type: "enum" },
163+
],
164+
type: "array",
165+
},
166+
};
167+
const expected = {
168+
tags: ["TAG1", "TAG2"],
169+
};
170+
expect(convertValues(schema, values)).toEqual(expected);
171+
});
172+
173+
it("should handle RecsType.StringArray with BigInt conversion", () => {
174+
const schema: Schema = {
175+
ids: RecsType.StringArray,
176+
};
177+
const values = {
178+
ids: {
179+
value: [
180+
{ value: "12345678901234567890", type: "string" },
181+
{ value: "98765432109876543210", type: "string" },
182+
],
183+
type: "array",
184+
},
185+
};
186+
const expected = {
187+
ids: [
188+
BigInt("12345678901234567890"),
189+
BigInt("98765432109876543210"),
190+
],
191+
};
192+
expect(convertValues(schema, values)).toEqual(expected);
193+
});
194+
195+
it("should fallback to string if BigInt conversion fails", () => {
196+
vi.spyOn(console, "warn").mockImplementation(() => {});
197+
198+
const schema: Schema = {
199+
ids: RecsType.StringArray,
200+
};
201+
const values = {
202+
ids: {
203+
value: [{ value: "invalid_bigint", type: "string" }],
204+
type: "array",
205+
},
206+
};
207+
const expected = {
208+
ids: ["invalid_bigint"],
209+
};
210+
expect(convertValues(schema, values)).toEqual(expected);
211+
expect(console.warn).toHaveBeenCalledWith(
212+
"Failed to convert invalid_bigint to BigInt. Using string value instead."
213+
);
214+
});
215+
216+
it("should handle RecsType.String", () => {
217+
const schema: Schema = {
218+
name: RecsType.String,
219+
};
220+
const values = {
221+
name: { value: "Bob", type: "string" },
222+
};
223+
const expected = {
224+
name: "Bob",
225+
};
226+
expect(convertValues(schema, values)).toEqual(expected);
227+
});
228+
229+
it("should handle RecsType.BigInt with valid BigInt", () => {
230+
const schema: Schema = {
231+
balance: RecsType.BigInt,
232+
};
233+
const values = {
234+
balance: { value: "1000000000000000000", type: "string" },
235+
};
236+
const expected = {
237+
balance: BigInt("1000000000000000000"),
238+
};
239+
expect(convertValues(schema, values)).toEqual(expected);
240+
});
241+
242+
it("should handle RecsType.Boolean", () => {
243+
const schema: Schema = {
244+
isActive: RecsType.Boolean,
245+
};
246+
const values = {
247+
isActive: { value: true, type: "boolean" },
248+
};
249+
const expected = {
250+
isActive: true,
251+
};
252+
expect(convertValues(schema, values)).toEqual(expected);
253+
});
254+
255+
it("should handle RecsType.Number", () => {
256+
const schema: Schema = {
257+
score: RecsType.Number,
258+
};
259+
const values = {
260+
score: { value: "42", type: "string" },
261+
};
262+
const expected = {
263+
score: 42,
264+
};
265+
expect(convertValues(schema, values)).toEqual(expected);
266+
});
267+
268+
it("should handle nested structs", () => {
269+
const nestedSchema: Schema = {
270+
street: RecsType.String,
271+
zip: RecsType.Number,
272+
};
273+
const schema: Schema = {
274+
name: RecsType.String,
275+
address: nestedSchema,
276+
};
277+
const values = {
278+
name: { value: "Charlie", type: "string" },
279+
address: {
280+
value: {
281+
street: { value: "123 Main St", type: "string" },
282+
zip: { value: "12345", type: "string" },
283+
},
284+
type: "struct",
285+
},
286+
};
287+
const expected = {
288+
name: "Charlie",
289+
address: {
290+
street: "123 Main St",
291+
zip: 12345,
292+
},
293+
};
294+
expect(convertValues(schema, values)).toEqual(expected);
295+
});
296+
297+
it("should handle map structures", () => {
298+
const nestedSchema: Schema = {
299+
key1: RecsType.String,
300+
key2: RecsType.Number,
301+
};
302+
const schema: Schema = {
303+
config: nestedSchema,
304+
};
305+
const values = {
306+
config: {
307+
value: new Map([
308+
["key1", { value: "value1", type: "string" }],
309+
["key2", { value: "100", type: "string" }],
310+
]),
311+
type: "struct",
312+
},
313+
};
314+
const expected = {
315+
config: {
316+
key1: "value1",
317+
key2: 100,
318+
},
319+
};
320+
expect(convertValues(schema, values)).toEqual(expected);
321+
});
322+
323+
it("should handle primitive fallback in default case", () => {
324+
const schema: Schema = {
325+
miscellaneous: RecsType.String,
326+
};
327+
const values = {
328+
miscellaneous: { value: "some value", type: "unknown" },
329+
};
330+
const expected = {
331+
miscellaneous: "some value",
332+
};
333+
expect(convertValues(schema, values)).toEqual(expected);
334+
});
335+
336+
it("should handle empty schema", () => {
337+
const schema: Schema = {};
338+
const values = {
339+
anyKey: { value: "any value", type: "string" },
340+
};
341+
const expected = {};
342+
expect(convertValues(schema, values)).toEqual(expected);
343+
});
111344
});

packages/state/src/recs/index.ts

+34-11
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const getSyncEntities = async <S extends Schema>(
4949
clause: Clause | undefined,
5050
entityKeyClause: EntityKeysClause[],
5151
limit: number = 100,
52-
logging: boolean = true
52+
logging: boolean = false
5353
) => {
5454
if (logging) console.log("Starting getSyncEntities");
5555
await getEntities(client, clause, components, limit, logging);
@@ -199,7 +199,7 @@ export const getEntitiesQuery = async <S extends Schema>(
199199
entityKeyClause: EntityKeysClause,
200200
patternMatching: PatternMatching = "FixedLen",
201201
limit: number = 1000,
202-
logging: boolean = true
202+
logging: boolean = false
203203
) => {
204204
if (logging) console.log("Starting getEntitiesQuery");
205205
let cursor = 0;
@@ -310,7 +310,8 @@ export const setEntities = async <S extends Schema>(
310310
components: Component<S, Metadata, undefined>[],
311311
logging: boolean = false
312312
) => {
313-
if (logging) console.log(entities);
313+
if (logging) console.log("Entities to set:", entities);
314+
314315
for (let key in entities) {
315316
if (!Object.hasOwn(entities, key)) {
316317
continue;
@@ -330,14 +331,32 @@ export const setEntities = async <S extends Schema>(
330331

331332
if (recsComponent) {
332333
try {
333-
setComponent(
334-
recsComponent,
335-
key as Entity,
336-
convertValues(
337-
recsComponent.schema,
338-
entities[key][componentName]
339-
) as ComponentValue
340-
);
334+
const rawValue = entities[key][componentName];
335+
if (logging)
336+
console.log(
337+
`Raw value for ${componentName} on ${key}:`,
338+
rawValue
339+
);
340+
341+
const convertedValue = convertValues(
342+
recsComponent.schema,
343+
rawValue
344+
) as ComponentValue;
345+
346+
if (logging)
347+
console.log(
348+
`Converted value for ${componentName} on ${key}:`,
349+
convertedValue
350+
);
351+
352+
if (!convertedValue) {
353+
console.error(
354+
`convertValues returned undefined or invalid for ${componentName} on ${key}`
355+
);
356+
}
357+
358+
setComponent(recsComponent, key as Entity, convertedValue);
359+
341360
if (logging)
342361
console.log(
343362
`Set component ${recsComponent.metadata?.name} on ${key}`
@@ -348,6 +367,10 @@ export const setEntities = async <S extends Schema>(
348367
error
349368
);
350369
}
370+
} else {
371+
console.warn(
372+
`Component ${componentName} not found in provided components.`
373+
);
351374
}
352375
}
353376
}

0 commit comments

Comments
 (0)