template.test.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { mkdtemp, readFile, stat } from "node:fs/promises";
  2. import { tmpdir } from "node:os";
  3. import { join } from "node:path";
  4. import { describe, expect, it } from "vitest";
  5. import { createEngine } from "@nengine/core";
  6. import { newProject, sanitizeId } from "../src/template.js";
  7. async function tmpDir(): Promise<string> {
  8. return mkdtemp(join(tmpdir(), "editor-template-"));
  9. }
  10. describe("sanitizeId", () => {
  11. it("slugs names and falls back for empty input", () => {
  12. expect(sanitizeId("My Farm!")).toBe("my-farm");
  13. expect(sanitizeId(" 山谷 农场")).toBe("farm");
  14. expect(sanitizeId("")).toBe("farm");
  15. expect(sanitizeId("Turnip_Vale")).toBe("turnipvale");
  16. });
  17. });
  18. describe("newProject", () => {
  19. it("generates the full template tree", async () => {
  20. const dir = await tmpDir();
  21. try {
  22. const project = await newProject("Test Farm", dir);
  23. expect(project.hasContent).toBe(true);
  24. expect(project.hasMods).toBe(true);
  25. const expected = [
  26. "content/time.yaml",
  27. "content/weather.yaml",
  28. "content/interact.yaml",
  29. "content/maps/test-farm.yaml",
  30. "content/items/hoe.yaml",
  31. "content/items/test-farm-seed.yaml",
  32. "content/items/test-farm.yaml",
  33. "content/crops/test-farm.yaml",
  34. "content/scenes/test-farm.yaml",
  35. ];
  36. for (const rel of expected) {
  37. await expect(stat(join(dir, rel))).resolves.toBeDefined();
  38. }
  39. await expect(stat(join(dir, "mods"))).resolves.toBeDefined();
  40. } finally {
  41. await rmRecursive(dir);
  42. }
  43. });
  44. it("boots the generated project through createEngine", async () => {
  45. const dir = await tmpDir();
  46. try {
  47. const project = await newProject("Boot Farm", dir);
  48. const engine = createEngine({ contentDir: join(project.root, "content") });
  49. await engine.start();
  50. try {
  51. expect(engine.world.get("player")).toMatchObject({ id: "player", type: "player", x: 8, y: 8 });
  52. const mapEntity = engine.world.query({ type: "map" })[0];
  53. expect(mapEntity?.id).toBe("boot-farm");
  54. const scenes = engine.registry.list("scene");
  55. expect(scenes).toHaveLength(1);
  56. expect(scenes[0]?.id).toBe("boot-farm");
  57. const crops = engine.registry.list("crop");
  58. expect(crops[0]?.seedItem).toBe("boot-farm-seed");
  59. expect(engine.registry.list("time")).toHaveLength(1);
  60. expect(engine.registry.list("weather")).toHaveLength(1);
  61. } finally {
  62. await engine.stop();
  63. }
  64. } finally {
  65. await rmRecursive(dir);
  66. }
  67. });
  68. it("interpolates the sanitized name into file ids", async () => {
  69. const dir = await tmpDir();
  70. try {
  71. await newProject("Valley View", dir);
  72. const crop = await readFile(join(dir, "content/crops/valley-view.yaml"), "utf8");
  73. expect(crop).toContain("id: valley-view");
  74. expect(crop).toContain("seedItem: valley-view-seed");
  75. const scene = await readFile(join(dir, "content/scenes/valley-view.yaml"), "utf8");
  76. expect(scene).toContain("entities: []");
  77. } finally {
  78. await rmRecursive(dir);
  79. }
  80. });
  81. });
  82. async function rmRecursive(dir: string): Promise<void> {
  83. const { rm } = await import("node:fs/promises");
  84. await rm(dir, { recursive: true, force: true });
  85. }
  86. describe("template map layout", () => {
  87. it("lays out grass, water, and tilled tiles correctly", async () => {
  88. const dir = await tmpDir();
  89. try {
  90. await newProject("Layout", dir);
  91. const { parse } = await import("yaml");
  92. const map = parse(await readFile(join(dir, "content/maps/layout.yaml"), "utf8")) as {
  93. width: number;
  94. height: number;
  95. spawn: { x: number; y: number };
  96. layers: { data: string[][] }[];
  97. };
  98. expect(map.width).toBe(12);
  99. expect(map.height).toBe(12);
  100. const data = map.layers[0]?.data ?? [];
  101. expect(data[0]?.[0]).toBe("water");
  102. expect(data[2]?.[2]).toBe("water");
  103. expect(data[4]?.[4]).toBe("tilled");
  104. expect(data[5]?.[7]).toBe("tilled");
  105. expect(data[11]?.[11]).toBe("grass");
  106. expect(data[map.spawn.y]?.[map.spawn.x]).toBe("grass");
  107. } finally {
  108. await rmRecursive(dir);
  109. }
  110. });
  111. });