- TableEntity.fromJson: lineColor 비면 자동색 #fff · lineWidth 비면 1 · id 비면 새 id(면적산출 → 도면 표 변환 답에 세 칸이 없음 → 저장 JSON 선 색 빠지던 흠 E2) - 시험 aislo-table-bridge.test.ts 에 선 색 없는 표 놓기 · 저장 JSON 선 색 · 다시 읽기 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoSr2sqvYtBf1dtQdus88s
142 lines
5.1 KiB
TypeScript
142 lines
5.1 KiB
TypeScript
import { Point } from '@flatten-js/core';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { TableEntity } from '../entities/TableEntity.ts';
|
|
import { getEntities, isDrawingDirty, setEntities, setLayers } from '../state.ts';
|
|
import { getPendingTable, setPendingTable, tableAt } from '../tools/annotate/place-table-tool.ts';
|
|
import {
|
|
AISLO_PLACE_TABLE_MESSAGE,
|
|
AISLO_TABLE_UPDATED_MESSAGE,
|
|
AISLO_UPDATE_TABLE_MESSAGE,
|
|
handleTableMessage,
|
|
updateLinkedTables,
|
|
} from './aislo-table-bridge.ts';
|
|
|
|
const run = vi.hoisted(() => vi.fn());
|
|
vi.mock('../commands/run-command.ts', () => ({ runCommandInput: run }));
|
|
|
|
const layer = { id: 'layer-1', isLocked: false, isVisible: true, name: '작업' };
|
|
|
|
function table(link?: string): TableEntity {
|
|
return new TableEntity(
|
|
layer.id,
|
|
new Point(10, 20),
|
|
[30, 15],
|
|
[5, 5],
|
|
[
|
|
[{ text: '항목', colSpan: 2, key: 'S1!A1' }, null],
|
|
[
|
|
{ text: '면적', key: 'S1!A2' },
|
|
{ text: '12.5', align: 'right', key: 'S1!B2' },
|
|
],
|
|
],
|
|
{ fontSize: 2.5, ...(link ? { 연결: link } : {}) }
|
|
);
|
|
}
|
|
|
|
beforeEach(() => {
|
|
setLayers([layer]);
|
|
setEntities([]);
|
|
setPendingTable(null);
|
|
run.mockClear();
|
|
});
|
|
|
|
describe('표 놓기(PLACETABLE)', () => {
|
|
it('미리보기 · 놓을 표는 커서 자리(왼쪽 위)에 같은 칸 · 크기 · 연결로', () => {
|
|
const placed = tableAt(table('T1'), new Point(100, 200), layer.id);
|
|
expect([placed.getOrigin().x, placed.getOrigin().y]).toEqual([100, 200]);
|
|
expect(placed.getColumnWidths()).toEqual([30, 15]);
|
|
expect(placed.getCell(1, 1)?.text).toBe('12.5');
|
|
expect(placed.getStyle().연결).toBe('T1');
|
|
});
|
|
|
|
it('place-table 메시지 = 연결을 단 표를 맡기고 PLACETABLE 을 켬', async () => {
|
|
const notify = vi.fn();
|
|
const handled = await handleTableMessage(
|
|
{
|
|
type: AISLO_PLACE_TABLE_MESSAGE,
|
|
entity: { ...(await table().toJson()), lineColor: '#123456' },
|
|
link: 'T7',
|
|
},
|
|
notify
|
|
);
|
|
expect(handled).toBe(true);
|
|
expect(run).toHaveBeenCalledWith('PLACETABLE');
|
|
expect(getPendingTable()?.getStyle().연결).toBe('T7');
|
|
expect(getPendingTable()?.getCell(0, 0)?.colSpan).toBe(2);
|
|
expect(getPendingTable()?.lineColor).toBe('#123456');
|
|
expect(notify).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('옮기기 · 복사(clone) · JSON 왕복에도 style.연결이 남음', async () => {
|
|
const linked = table('T1');
|
|
expect(linked.clone().getStyle().연결).toBe('T1');
|
|
const json = await linked.toJson();
|
|
if (!json) throw new Error('표 JSON 없음');
|
|
const back = await TableEntity.fromJson(json);
|
|
expect(back.getStyle().연결).toBe('T1');
|
|
});
|
|
});
|
|
|
|
describe('선 색 없는 표(서버 표 변환 답 · 43-6)', () => {
|
|
it('id · 선 색 · 굵기가 없으면 기본값(자동색 #fff · 1 · 새 id)으로 채워 놓고 저장 JSON 에도 남음', async () => {
|
|
const json = await table('T8').toJson();
|
|
if (!json) throw new Error('표 JSON 없음');
|
|
const { id: _id, lineColor: _color, lineWidth: _width, layerId: _layer, ...bare } = json;
|
|
await handleTableMessage(
|
|
{ type: AISLO_PLACE_TABLE_MESSAGE, entity: bare as typeof json, link: 'T8' },
|
|
vi.fn()
|
|
);
|
|
const pending = getPendingTable();
|
|
expect(pending?.lineColor).toBe('#fff');
|
|
expect(pending?.lineWidth).toBe(1);
|
|
const placed = tableAt(pending as TableEntity, new Point(0, 0), layer.id);
|
|
placed.lineColor = pending?.lineColor ?? '';
|
|
const saved = await placed.toJson();
|
|
expect(saved?.lineColor).toBe('#fff');
|
|
const back = await TableEntity.fromJson(bare as typeof json);
|
|
expect(back.id).toBeTruthy();
|
|
expect(back.lineColor).toBe('#fff');
|
|
});
|
|
});
|
|
|
|
describe('표 칸 갈기(update-table)', () => {
|
|
it('연결이 같은 표의 칸만 갈고 자리 · 크기는 그대로 · 되돌리기 한 걸음', () => {
|
|
const linked = table('T1');
|
|
const other = table('T2');
|
|
setEntities([linked, other]);
|
|
const count = updateLinkedTables('T1', [
|
|
[{ text: '항목(새)', colSpan: 2 }, null],
|
|
[{ text: '면적' }, { text: '99.0', align: 'right' }],
|
|
]);
|
|
expect(count).toBe(1);
|
|
expect(linked.getCell(1, 1)?.text).toBe('99.0');
|
|
expect(linked.getCell(0, 1)).toBeNull(); // 병합 그대로
|
|
expect(other.getCell(1, 1)?.text).toBe('12.5');
|
|
expect([linked.getOrigin().x, linked.getColumnWidths()]).toEqual([10, [30, 15]]);
|
|
expect(isDrawingDirty()).toBe(true);
|
|
});
|
|
|
|
it('넘치는 칸은 버리고 모자란 칸은 빈 칸', () => {
|
|
const linked = table('T1');
|
|
setEntities([linked]);
|
|
updateLinkedTables('T1', [[{ text: 'a' }, { text: 'b' }, { text: '넘침' }]]);
|
|
expect(linked.getCells().map((row) => row.map((cell) => cell?.text ?? null))).toEqual([
|
|
['a', 'b'],
|
|
['', ''],
|
|
]);
|
|
});
|
|
|
|
it('update-table 메시지 = table-updated{link, count} · 없는 연결은 0 · 도면 그대로', async () => {
|
|
setEntities([table('T1')]);
|
|
const before = getEntities();
|
|
const notify = vi.fn();
|
|
await handleTableMessage({ type: AISLO_UPDATE_TABLE_MESSAGE, link: 'T9', cells: [] }, notify);
|
|
expect(notify).toHaveBeenCalledWith(AISLO_TABLE_UPDATED_MESSAGE, { link: 'T9', count: 0 });
|
|
expect(getEntities()).toBe(before);
|
|
});
|
|
|
|
it('표 메시지가 아니면 false', async () => {
|
|
expect(await handleTableMessage({ type: 'aislo:b08:save-request' }, vi.fn())).toBe(false);
|
|
});
|
|
});
|