1
0
Fork 0
Code Issues Pull requests Projects Releases Packages Wiki Activity Actions Pages

add vitest and regression tests for arc 1

This commit is contained in:
super-jalawii 2026-06-27 10:31:09 -04:00
parent 0074f0e10c
commit 9f538b1543
9 changed files with 1561 additions and 4 deletions

1157
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,8 @@
"analyze:requests": "node scripts/request-analysis-worker.mjs",
"validate:content": "node scripts/validate-content-schemas.mjs",
"build": "tsc -b && vite build",
"test": "vitest run",
"test:watch": "vitest",
"lint": "eslint .",
"preview": "vite preview"
},
@ -23,6 +25,9 @@
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/node": "^24.12.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
@ -31,9 +36,10 @@
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0",
"jsdom": "^29.1.1",
"typescript": "~6.0.2",
"typescript-eslint": "^8.59.2",
"vite": "^8.0.12"
"vite": "^8.0.12",
"vitest": "^4.1.9"
}
}

View file

@ -0,0 +1,81 @@
import {
getMapBackgroundTileId,
parseHeightLayers,
parseRoomLayers,
} from "./worldshaperShared";
import type { JsonObject } from "../editorCore";
describe("worldshaperShared", () => {
it("prefers top-level background tile ids and falls back to the legacy nested shape", () => {
expect(getMapBackgroundTileId({ backgroundTileId: "grass" })).toBe("grass");
expect(getMapBackgroundTileId({ tiles: { backgroundTileId: "water" } as unknown as JsonObject })).toBe("water");
expect(getMapBackgroundTileId({})).toBe("");
});
it("synthesizes and resizes room layers from the current map payload", () => {
const result = parseRoomLayers({
rows: ["##", "#"],
roomLayers: [
{
layer: 2,
name: "Objects",
rows: ["A"],
instanceIds: ["npc_1", ""],
},
],
}, 3, 2);
expect(result).toEqual([
{
layer: 0,
name: undefined,
zIndex: 0,
rows: ["##.", "#.."],
instanceIds: [],
},
{
layer: 2,
name: "Objects",
zIndex: 0,
rows: ["A ", " "],
instanceIds: ["npc_1"],
},
]);
});
it("normalizes, trims, and bounds height patches while dropping duplicate ids", () => {
const result = parseHeightLayers({
heightLayers: [
{
id: "ridge",
z: 3,
x: -1,
y: -1,
rows: [
"...",
".9.",
"..8",
],
},
{
id: "ridge",
z: 9,
x: 0,
y: 0,
rows: ["1"],
},
],
}, 4, 4);
expect(result).toEqual([
{
id: "ridge",
name: undefined,
z: 3,
x: 0,
y: 0,
rows: ["9", " 8"],
},
]);
});
});

106
src/editorCore.test.ts Normal file
View file

@ -0,0 +1,106 @@
import {
getSpriteRows,
normalizeImageRecordForSave,
normalizeImagesPayloadForSave,
normalizeTileRecordForSave,
resolveUnifiedColorSymbol,
setUnifiedColorEntries,
} from "./editorCore";
import type { JsonObject, JsonValue } from "./editorCore";
describe("editorCore", () => {
it("normalizes tile records with padded rows and compatibility symbols", () => {
const result = normalizeTileRecordForSave({
id: "tile_grass",
rows: ["A", "BC", "DROP"],
width: 2,
height: 2,
});
expect(result).toEqual(expect.objectContaining({
id: "tile_grass",
symbol: "t",
rows: ["A.", "BC"],
width: 2,
height: 2,
}));
});
it("normalizes image records into frame-based storage while preserving tile compatibility", () => {
const result = normalizeImageRecordForSave({
id: "tile_tree",
roles: ["tile", "sprite", "other", "tile"],
rows: ["A", "BC"],
width: 2,
height: 2,
speed: -10,
playback: "invalid",
tileSymbol: "$",
});
expect(result.rows).toBeUndefined();
expect(result.symbol).toBeUndefined();
expect(result.graphicRole).toBeUndefined();
expect(result.roles).toEqual(["tile", "sprite"]);
expect(result.defaultFrame).toBe("frame_0");
expect(result.speed).toBe(0);
expect(result.playback).toBe("normal");
expect(result.tileSymbol).toBe("$");
expect(result.frames).toEqual([
expect.objectContaining({
id: "frame_0",
rows: ["A.", "BC"],
}),
]);
});
it("resolves sprite rows from the default enabled frame", () => {
const record: JsonObject = {
defaultFrame: "walk_1",
frames: [
{ id: "idle", rows: ["II"], enabled: true },
{ id: "walk_1", rows: ["WW"], enabled: true },
{ id: "disabled", rows: ["DD"], enabled: false },
],
};
expect(getSpriteRows(record)).toEqual(["WW"]);
});
it("normalizes image payload arrays without changing non-record entries", () => {
const payload: JsonValue = {
schemaVersion: 1,
images: [
{
id: "sprite_hero",
roles: ["sprite"],
rows: ["X"],
},
"leave-me-alone",
],
};
expect(normalizeImagesPayloadForSave(payload)).toEqual({
schemaVersion: 1,
images: [
expect.objectContaining({
id: "sprite_hero",
roles: ["sprite"],
defaultFrame: "frame_0",
}),
"leave-me-alone",
],
});
});
it("updates the unified color lookup from catalog entries", () => {
setUnifiedColorEntries([
{ key: "A", color: "#123456" },
{ key: "!", color: "#FFFFFF" },
]);
expect(resolveUnifiedColorSymbol("A")).toBe("#123456");
expect(resolveUnifiedColorSymbol(".")).toBe("#00000000");
expect(resolveUnifiedColorSymbol("Z", "#ABCDEF")).toBe("#ABCDEF");
});
});

1
src/test/setup.ts Normal file
View file

@ -0,0 +1 @@
import "@testing-library/jest-dom/vitest";

77
src/worldChunking.test.ts Normal file
View file

@ -0,0 +1,77 @@
import {
DEFAULT_WORLD_CHUNK_SIZE,
buildChunkFileName,
buildChunkKey,
createEmptyChunk,
localToWorldCoord,
normalizeChunkDimension,
resolveWorldChunkAddress,
worldToChunkCoord,
worldToLocalCoord,
} from "./worldChunking";
describe("worldChunking", () => {
it("normalizes chunk dimensions with flooring and fallback behavior", () => {
expect(normalizeChunkDimension(12.9)).toBe(12);
expect(normalizeChunkDimension(0, 24)).toBe(24);
expect(normalizeChunkDimension(-5, 24)).toBe(1);
expect(normalizeChunkDimension("bad", 18)).toBe(18);
});
it("converts world coordinates into chunk and local coordinates across the origin", () => {
expect(worldToChunkCoord(0, 32)).toBe(0);
expect(worldToChunkCoord(31, 32)).toBe(0);
expect(worldToChunkCoord(32, 32)).toBe(1);
expect(worldToChunkCoord(-1, 32)).toBe(-1);
expect(worldToChunkCoord(-33, 32)).toBe(-2);
expect(worldToLocalCoord(31, 32)).toBe(31);
expect(worldToLocalCoord(32, 32)).toBe(0);
expect(worldToLocalCoord(-1, 32)).toBe(31);
expect(worldToLocalCoord(-33, 32)).toBe(31);
expect(localToWorldCoord(-2, 31, 32)).toBe(-33);
});
it("resolves stable chunk addressing metadata", () => {
expect(buildChunkKey(-3, 4)).toBe("-3:4");
expect(buildChunkFileName(-3, 4)).toBe("-3_4.json");
expect(resolveWorldChunkAddress(-33, 64, 32, 16)).toEqual({
chunkX: -2,
chunkY: 4,
localX: 31,
localY: 0,
chunkKey: "-2:4",
fileName: "-2_4.json",
});
});
it("creates empty chunks with the current compatibility layer defaults", () => {
const chunk = createEmptyChunk("overworld", 2, -1, "grass", 4, 3);
expect(chunk).toEqual({
schemaVersion: 1,
worldId: "overworld",
chunkX: 2,
chunkY: -1,
width: 4,
height: 3,
backgroundTileId: "grass",
roomLayers: [
{
layer: 0,
rows: ["....", "....", "...."],
instanceIds: [],
},
{
layer: 1,
rows: [" ", " ", " "],
instanceIds: [],
},
],
heightLayers: [],
instances: [],
});
expect(createEmptyChunk("world", 0, 0).width).toBe(DEFAULT_WORLD_CHUNK_SIZE);
});
});

View file

@ -0,0 +1,121 @@
import {
buildImageRecordFromSpriteRecord,
buildImageRecordFromTileRecord,
buildTileRecordFromImageRecord,
getImageRecordFromPayload,
normalizeGraphicRoles,
normalizeImagesPayloadSnapshot,
} from "./graphicsDocumentHelpers";
import type { JsonObject } from "../editorCore";
describe("graphicsDocumentHelpers", () => {
it("keeps only supported graphic roles and de-duplicates them", () => {
expect(normalizeGraphicRoles(["tile", "sprite", "tile", "other", "", null])).toEqual(["tile", "sprite"]);
expect(normalizeGraphicRoles("tile")).toEqual([]);
});
it("builds tile-backed image records without inventing new storage rules", () => {
const existingRecord: JsonObject = {
id: "tile_grass",
roles: ["sprite"],
tileSymbol: "g",
tags: ["existing"],
};
const result = buildImageRecordFromTileRecord({
id: "tile_grass",
name: "Grass",
symbol: "#",
rows: ["AB", "C"],
width: 2,
height: 2,
pixelScale: 3,
opacity: 2,
tags: ["terrain", "terrain"],
}, existingRecord);
expect(result.roles).toEqual(["sprite", "tile"]);
expect(result.tileSymbol).toBe("#");
expect(result.rows).toBeUndefined();
expect(result.defaultFrame).toBe("frame_0");
expect(result.frames).toEqual([
expect.objectContaining({
id: "frame_0",
rows: ["AB", "C."],
width: 2,
height: 2,
pixelScale: 3,
opacity: 1,
}),
]);
expect(result.tags).toEqual(["terrain"]);
});
it("updates sprite roles while preserving compatibility fields from existing images", () => {
const existingRecord: JsonObject = {
id: "hero",
roles: ["tile", "sprite"],
tileSymbol: "@",
};
const result = buildImageRecordFromSpriteRecord({
id: "hero",
rows: ["X"],
width: 1,
height: 1,
}, "other", existingRecord);
expect(result.roles).toEqual(["tile"]);
expect(result.tileSymbol).toBe("@");
});
it("hydrates image rows from the resolved default frame", () => {
const payload: JsonObject = {
schemaVersion: 1,
images: [
{
id: "tile_grass",
roles: ["tile"],
tileSymbol: "G",
width: 2,
height: 2,
defaultFrame: "alt",
frames: [
{ id: "base", rows: ["AA", "AA"], enabled: true },
{ id: "alt", rows: ["BB", "BB"], enabled: true },
],
},
],
};
const snapshot = normalizeImagesPayloadSnapshot(payload);
const imageRecord = getImageRecordFromPayload(snapshot, "tile_grass");
expect(imageRecord).toEqual(expect.objectContaining({
id: "tile_grass",
rows: ["BB", "BB"],
}));
});
it("projects tile records from image records through the current compatibility adapter", () => {
const tileRecord = buildTileRecordFromImageRecord({
id: "tile_grass",
tileSymbol: "G",
name: "Grass",
description: "Ground",
width: 2,
height: 2,
frames: [
{ id: "frame_0", rows: ["AB", "CD"] },
],
});
expect(tileRecord).toEqual(expect.objectContaining({
id: "tile_grass",
symbol: "G",
rows: ["AB", "CD"],
width: 2,
height: 2,
}));
});
});

View file

@ -4,7 +4,7 @@
"target": "es2023",
"lib": ["ES2023", "DOM"],
"module": "esnext",
"types": ["vite/client"],
"types": ["vite/client", "vitest/globals"],
"skipLibCheck": true,
/* Bundler mode */

10
vitest.config.ts Normal file
View file

@ -0,0 +1,10 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "jsdom",
globals: true,
setupFiles: "./src/test/setup.ts",
include: ["src/**/*.test.ts", "src/**/*.test.tsx"],
},
});