@things-factory/board-service 10.1.5 → 10.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,16 +14,30 @@ describe('board-version-diff (pure)', () => {
14
14
  ]
15
15
  };
16
16
  const flat = (0, board_version_diff_1.flattenBoardComponents)(model);
17
- expect(flat.map(f => f.refid)).toEqual([1, 2, 3]);
17
+ /*
18
+ * 맨 앞은 **씬 자체**(`__root__`)다. 배경색·조명·scale 만 바뀐 릴리즈가 「차이 없음」으로
19
+ * 나오던 버그를 고치면서 들어갔고(§`flattenBoardComponents`), 이 시험이 안 따라와 있었다
20
+ * (2026-09-10 에 맞췄다). 루트를 빼면 그 버그가 조용히 돌아온다.
21
+ */
22
+ expect(flat[0].key).toBe('__root__');
23
+ expect(flat.map(f => f.refid)).toEqual([null, 1, 2, 3]);
18
24
  });
19
25
  it('parses a JSON string model', () => {
20
26
  const model = JSON.stringify({ components: [{ refid: 1, type: 'rect' }] });
21
- expect((0, board_version_diff_1.flattenBoardComponents)(model).map(f => f.refid)).toEqual([1]);
27
+ expect((0, board_version_diff_1.flattenBoardComponents)(model).map(f => f.refid)).toEqual([null, 1]);
22
28
  });
23
29
  it('returns [] for null/invalid model', () => {
24
30
  expect((0, board_version_diff_1.flattenBoardComponents)(null)).toEqual([]);
25
31
  expect((0, board_version_diff_1.flattenBoardComponents)('not-json')).toEqual([]);
26
- expect((0, board_version_diff_1.flattenBoardComponents)({})).toEqual([]);
32
+ });
33
+ it('an empty object is an empty scene, not an invalid model', () => {
34
+ /*
35
+ * `{}` 가 위 묶음에 함께 있었다. 무효한 입력이 아니라 **컴포넌트가 없는 씬**이고, 그것이
36
+ * 갈려야 배경색만 바뀐 릴리즈가 차이로 잡힌다 — `__root__` 항목이 있는 이유가 그것이다.
37
+ * 여기서 `[]` 를 기대하면 그 버그가 시험으로 고정된다.
38
+ */
39
+ const flat = (0, board_version_diff_1.flattenBoardComponents)({});
40
+ expect(flat.map(f => f.key)).toEqual(['__root__']);
27
41
  });
28
42
  });
29
43
  describe('diffBoardModels', () => {
@@ -1 +1 @@
1
- {"version":3,"file":"board-version-diff.test.js","sourceRoot":"","sources":["../../../server/service/board/board-version-diff.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * board-version-diff — 보드 model(things-scene 컴포넌트 트리) diff 순수 로직 단위 검증.\n */\nimport { diffBoardModels, flattenBoardComponents } from './board-version-diff'\n\ndescribe('board-version-diff (pure)', () => {\n describe('flattenBoardComponents', () => {\n it('flattens nested components recursively', () => {\n const model = {\n components: [\n { refid: 1, type: 'rect' },\n { refid: 2, type: 'group', components: [{ refid: 3, type: 'text' }] }\n ]\n }\n const flat = flattenBoardComponents(model)\n expect(flat.map(f => f.refid)).toEqual([1, 2, 3])\n })\n\n it('parses a JSON string model', () => {\n const model = JSON.stringify({ components: [{ refid: 1, type: 'rect' }] })\n expect(flattenBoardComponents(model).map(f => f.refid)).toEqual([1])\n })\n\n it('returns [] for null/invalid model', () => {\n expect(flattenBoardComponents(null)).toEqual([])\n expect(flattenBoardComponents('not-json')).toEqual([])\n expect(flattenBoardComponents({})).toEqual([])\n })\n })\n\n describe('diffBoardModels', () => {\n it('detects added, removed, and modified components by refid', () => {\n const base = {\n components: [\n { refid: 1, type: 'rect', left: 0 },\n { refid: 2, type: 'text', text: 'hello' }\n ]\n }\n const target = {\n components: [\n { refid: 1, type: 'rect', left: 50 }, // modified (left)\n { refid: 3, type: 'circle' } // added\n // refid 2 removed\n ]\n }\n const diffs = diffBoardModels(base, target)\n const byType = (t: string) => diffs.filter(d => d.changeType === t).map(d => d.refid).sort()\n\n expect(byType('added')).toEqual([3])\n expect(byType('removed')).toEqual([2])\n expect(byType('modified')).toEqual([1])\n\n const modified = diffs.find(d => d.refid === 1)\n expect(modified?.changedProps).toContain('left')\n })\n\n it('reports no diffs for identical models', () => {\n const model = { components: [{ refid: 1, type: 'rect', left: 10 }] }\n expect(diffBoardModels(model, JSON.parse(JSON.stringify(model)))).toEqual([])\n })\n\n it('ignores children array when diffing a container component props', () => {\n const base = { components: [{ refid: 1, type: 'group', components: [{ refid: 2, type: 'text' }] }] }\n // 자식만 바뀌고 컨테이너 자체 속성은 동일 → 컨테이너는 modified 아님, 자식만 removed\n const target = { components: [{ refid: 1, type: 'group', components: [] }] }\n const diffs = diffBoardModels(base, target)\n expect(diffs.find(d => d.refid === 1)).toBeUndefined()\n expect(diffs.find(d => d.refid === 2)?.changeType).toBe('removed')\n })\n\n it('falls back to positional key when refid is missing', () => {\n const base = { components: [{ type: 'rect', left: 0 }] }\n const target = { components: [{ type: 'rect', left: 99 }] }\n const diffs = diffBoardModels(base, target)\n expect(diffs).toHaveLength(1)\n expect(diffs[0].changeType).toBe('modified')\n expect(diffs[0].changedProps).toContain('left')\n })\n })\n})\n"]}
1
+ {"version":3,"file":"board-version-diff.test.js","sourceRoot":"","sources":["../../../server/service/board/board-version-diff.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * board-version-diff — 보드 model(things-scene 컴포넌트 트리) diff 순수 로직 단위 검증.\n */\nimport { diffBoardModels, flattenBoardComponents } from './board-version-diff'\n\ndescribe('board-version-diff (pure)', () => {\n describe('flattenBoardComponents', () => {\n it('flattens nested components recursively', () => {\n const model = {\n components: [\n { refid: 1, type: 'rect' },\n { refid: 2, type: 'group', components: [{ refid: 3, type: 'text' }] }\n ]\n }\n const flat = flattenBoardComponents(model)\n /*\n * 맨 앞은 **씬 자체**(`__root__`)다. 배경색·조명·scale 만 바뀐 릴리즈가 「차이 없음」으로\n * 나오던 버그를 고치면서 들어갔고(§`flattenBoardComponents`), 이 시험이 안 따라와 있었다\n * (2026-09-10 에 맞췄다). 루트를 빼면 그 버그가 조용히 돌아온다.\n */\n expect(flat[0].key).toBe('__root__')\n expect(flat.map(f => f.refid)).toEqual([null, 1, 2, 3])\n })\n\n it('parses a JSON string model', () => {\n const model = JSON.stringify({ components: [{ refid: 1, type: 'rect' }] })\n expect(flattenBoardComponents(model).map(f => f.refid)).toEqual([null, 1])\n })\n\n it('returns [] for null/invalid model', () => {\n expect(flattenBoardComponents(null)).toEqual([])\n expect(flattenBoardComponents('not-json')).toEqual([])\n })\n\n it('an empty object is an empty scene, not an invalid model', () => {\n /*\n * `{}` 가 위 묶음에 함께 있었다. 무효한 입력이 아니라 **컴포넌트가 없는 씬**이고, 그것이\n * 갈려야 배경색만 바뀐 릴리즈가 차이로 잡힌다 — `__root__` 항목이 있는 이유가 그것이다.\n * 여기서 `[]` 를 기대하면 그 버그가 시험으로 고정된다.\n */\n const flat = flattenBoardComponents({})\n expect(flat.map(f => f.key)).toEqual(['__root__'])\n })\n })\n\n describe('diffBoardModels', () => {\n it('detects added, removed, and modified components by refid', () => {\n const base = {\n components: [\n { refid: 1, type: 'rect', left: 0 },\n { refid: 2, type: 'text', text: 'hello' }\n ]\n }\n const target = {\n components: [\n { refid: 1, type: 'rect', left: 50 }, // modified (left)\n { refid: 3, type: 'circle' } // added\n // refid 2 removed\n ]\n }\n const diffs = diffBoardModels(base, target)\n const byType = (t: string) => diffs.filter(d => d.changeType === t).map(d => d.refid).sort()\n\n expect(byType('added')).toEqual([3])\n expect(byType('removed')).toEqual([2])\n expect(byType('modified')).toEqual([1])\n\n const modified = diffs.find(d => d.refid === 1)\n expect(modified?.changedProps).toContain('left')\n })\n\n it('reports no diffs for identical models', () => {\n const model = { components: [{ refid: 1, type: 'rect', left: 10 }] }\n expect(diffBoardModels(model, JSON.parse(JSON.stringify(model)))).toEqual([])\n })\n\n it('ignores children array when diffing a container component props', () => {\n const base = { components: [{ refid: 1, type: 'group', components: [{ refid: 2, type: 'text' }] }] }\n // 자식만 바뀌고 컨테이너 자체 속성은 동일 → 컨테이너는 modified 아님, 자식만 removed\n const target = { components: [{ refid: 1, type: 'group', components: [] }] }\n const diffs = diffBoardModels(base, target)\n expect(diffs.find(d => d.refid === 1)).toBeUndefined()\n expect(diffs.find(d => d.refid === 2)?.changeType).toBe('removed')\n })\n\n it('falls back to positional key when refid is missing', () => {\n const base = { components: [{ type: 'rect', left: 0 }] }\n const target = { components: [{ type: 'rect', left: 99 }] }\n const diffs = diffBoardModels(base, target)\n expect(diffs).toHaveLength(1)\n expect(diffs[0].changeType).toBe('modified')\n expect(diffs[0].changedProps).toContain('left')\n })\n })\n})\n"]}