- 나무 화살표 · 줄 수와 항목 고르기의 흐린 글을 var(--color-text-secondary) 로 — 밝은 테마 대비 3.08 → 6.3 이상 - M01 왼쪽 목록 줄 수도 같은 공용 클래스(ui-tree__count)로 — 밝은 테마 2.64 → 5.41 - 항목 고르기: 잎 툴팁 = 층 이름 + 키 · 「새 분류N」 자리표는 이름 · 나무 이름에서 뺌 · 관리 화면 단추는 개인 항목만(확인) - ghost 단추는 두 테마 모두 6.85 이상이라 색 변경 없음 — 다크 1.06 은 ORCA 탭이 색 전환을 멈춰 생긴 측정값 - 자료 시험에 자리표 · 툴팁 추가 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7JS47SacjPxZ718QsZKyr
219 lines
7.4 KiB
TypeScript
219 lines
7.4 KiB
TypeScript
/**
|
|
* 항목 고르기 자료 쪽 검증 — 나무 · 찾기 · 돌려줄 summary_item · 폴더 줄(21-1 · 21-9 서버 모양).
|
|
* 실행: node --experimental-strip-types resources/tester/ui/item-picker-data.test.ts
|
|
*/
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
buildTree,
|
|
filterRows,
|
|
folderLines,
|
|
isCurrent,
|
|
itemName,
|
|
pathIds,
|
|
rowId,
|
|
rowTip,
|
|
shown,
|
|
toSummary,
|
|
type PickerRow,
|
|
type TreeLabels,
|
|
} from "../../../ui_template/ui_template_item_picker_data.ts";
|
|
|
|
const labels: TreeLabels = {
|
|
layers: { system: "마스터", company: "회사", personal: "개인" },
|
|
unclassified: "분류 없음",
|
|
};
|
|
|
|
/** 서버 줄 그대로 — `열` 은 집계표 열 id · 보이는 이름은 종류 + 분류 */
|
|
const row = (
|
|
key: string,
|
|
열: string,
|
|
종류: string,
|
|
분류: [string, string, string],
|
|
layer: PickerRow["layer"],
|
|
extra: Partial<PickerRow> = {},
|
|
): PickerRow => ({
|
|
key,
|
|
열,
|
|
종류,
|
|
분류1: 분류[0],
|
|
분류2: 분류[1],
|
|
분류3: 분류[2],
|
|
단위: "m",
|
|
일위대가: "UA000004",
|
|
자재조합: "UM000001",
|
|
도번: "SD01010100",
|
|
면적번: "SA01010100",
|
|
재료번: "SM01010100",
|
|
layer,
|
|
owner: layer === "company" ? "샘플회사" : layer === "personal" ? "샘플회사/사용자" : null,
|
|
...extra,
|
|
});
|
|
|
|
const rows: PickerRow[] = [
|
|
row("SS000001", "rv", "돌기슭막이", ["메쌓기", "1.2m", "기초유"], "system", {
|
|
names: {
|
|
일위대가: "돌기슭막이 메쌓기 일위대가",
|
|
자재조합: null,
|
|
도번: "돌기슭막이 도면",
|
|
면적번: "돌기슭막이 면적산출",
|
|
재료번: "돌기슭막이 재료산출",
|
|
},
|
|
}),
|
|
row("SS000002", "rv2", "돌기슭막이", ["메쌓기", "1.5m", "기초유"], "system"),
|
|
row("SS000003", "rv3", "돌기슭막이", ["찰쌓기", "1.2m", ""], "system"),
|
|
row("SS000004", "pv", "콘크리트포장", ["일반", "T=20cm", ""], "system"),
|
|
row("SS000005", "pg", "관보호공", ["콘크리트", "", ""], "system"),
|
|
row("SS000101", "c1", "돌기슭막이", ["메쌓기", "1.2m", "기초유"], "company"),
|
|
row("SS000102", "c2", "옹벽", ["", "H=2m", ""], "company"),
|
|
row("SS000201", "p1", "돌기슭막이", ["메쌓기", "1.2m", "기초유"], "personal"),
|
|
];
|
|
|
|
// 이름 = 종류 + 분류 이음 · 비면 열 id · 키
|
|
assert.equal(itemName(rows[0]), "돌기슭막이 메쌓기 1.2m 기초유");
|
|
assert.equal(itemName(rows[6]), "옹벽 H=2m");
|
|
assert.equal(itemName({ key: "SS000009", 열: "zz" }), "zz");
|
|
assert.equal(itemName({ key: "SS000009", 열: "" }), "SS000009");
|
|
|
|
// 「새 분류N」 자리표는 이름 · 나무 이름에서 뺌
|
|
assert.equal(shown("새 분류1"), "");
|
|
assert.equal(shown("새 분류 12"), "");
|
|
assert.equal(shown("새 분류"), "");
|
|
assert.equal(shown("새 분류표"), "새 분류표"); // 자리표가 아닌 진짜 이름은 그대로
|
|
assert.equal(shown(undefined), "");
|
|
const fresh = row("SS000300", "n1", "새 분류1", ["새 분류2", "", ""], "personal", {
|
|
분류3: "새 분류3",
|
|
});
|
|
assert.equal(itemName(fresh), "n1"); // 이름이 모두 자리표면 열 id
|
|
assert.equal(
|
|
itemName(row("SS000301", "n2", "옹벽", ["새 분류1", "H=2m", ""], "personal")),
|
|
"옹벽 H=2m",
|
|
);
|
|
const placeholderTree = buildTree([fresh], labels);
|
|
assert.equal(placeholderTree[2].children?.[0].label, "분류 없음"); // 종류
|
|
assert.equal(placeholderTree[2].children?.[0].children?.[0].label, "분류 없음"); // 분류1
|
|
assert.deepEqual(pathIds(fresh, labels), [
|
|
"personal",
|
|
"personal|분류 없음",
|
|
"personal|분류 없음|분류 없음",
|
|
]);
|
|
|
|
// 툴팁 = 층 이름 + 키
|
|
assert.equal(rowTip(rows[7], labels), "개인 · SS000201");
|
|
assert.equal(rowTip(rows[5], labels), "회사 · SS000101");
|
|
|
|
// 나무 — 그룹은 늘 마스터 · 회사 · 개인 차례 · 그룹 → 종류 → 분류1 → 잎
|
|
const tree = buildTree(rows, labels);
|
|
assert.deepEqual(
|
|
tree.map((g) => [g.label, g.count]),
|
|
[
|
|
["마스터", 5],
|
|
["회사", 2],
|
|
["개인", 1],
|
|
],
|
|
);
|
|
const system = tree[0];
|
|
assert.deepEqual(
|
|
system.children?.map((k) => [k.label, k.count]),
|
|
[
|
|
["돌기슭막이", 3],
|
|
["콘크리트포장", 1],
|
|
["관보호공", 1],
|
|
],
|
|
);
|
|
const cat = system.children?.[0].children?.[0];
|
|
assert.equal(cat?.label, "메쌓기");
|
|
assert.equal(cat?.count, 2);
|
|
const leaf = cat?.children?.[0];
|
|
assert.equal(leaf?.label, "돌기슭막이 메쌓기 1.2m 기초유");
|
|
assert.equal(leaf?.tip, "마스터 · SS000001"); // 툴팁 = 층 이름 + 키
|
|
assert.equal(leaf?.count, null);
|
|
assert.ok(leaf?.row);
|
|
|
|
// 분류가 빈 항목은 「분류 없음」 한 칸에 모임
|
|
assert.equal(tree[1].children?.[1].children?.[0].label, "분류 없음");
|
|
|
|
// 빈 그룹도 한 줄은 남음(회사 없는 사람의 회사 · 개인 그룹)
|
|
const onlySystem = buildTree(
|
|
rows.filter((r) => r.layer === "system"),
|
|
labels,
|
|
);
|
|
assert.deepEqual(
|
|
onlySystem.map((g) => [g.id, g.count, g.children?.length]),
|
|
[
|
|
["system", 5, 3],
|
|
["company", 0, 0],
|
|
["personal", 0, 0],
|
|
],
|
|
);
|
|
|
|
// 잎 id 는 층 · 주인 · 키 — 같은 키라도 층이 다르면 다른 줄
|
|
const twin = { ...rows[0], layer: "company" as const, owner: "샘플회사" };
|
|
assert.notEqual(rowId(rows[0]), rowId(twin));
|
|
|
|
// 찾기 — 이름 · 키 · 연결 이름 · 여러 낱말은 모두 들어 있어야 함 · 빈 글은 전부
|
|
assert.equal(filterRows(rows, "").length, rows.length);
|
|
assert.equal(filterRows(rows, " ").length, rows.length);
|
|
assert.deepEqual(
|
|
filterRows(rows, "옹벽").map((r) => r.key),
|
|
["SS000102"],
|
|
);
|
|
assert.deepEqual(
|
|
filterRows(rows, "ss000004").map((r) => r.key),
|
|
["SS000004"],
|
|
);
|
|
assert.deepEqual(
|
|
filterRows(rows, "돌기슭막이 1.5m").map((r) => r.key),
|
|
["SS000002"],
|
|
);
|
|
assert.deepEqual(
|
|
filterRows(rows, "돌기슭막이 도면").map((r) => r.key),
|
|
["SS000001"],
|
|
); // 서버가 준 이름(names)으로도 찾음
|
|
assert.equal(filterRows(rows, "없는이름").length, 0);
|
|
|
|
// 돌려줄 summary_item — 마스터는 owner null · 회사 · 개인은 주인 · 이름은 보이는 이름
|
|
assert.deepEqual(toSummary(rows[0]), {
|
|
layer: "system",
|
|
owner: null,
|
|
key: "SS000001",
|
|
name: "돌기슭막이 메쌓기 1.2m 기초유",
|
|
});
|
|
const mine = rows[7];
|
|
assert.deepEqual(toSummary(mine), {
|
|
layer: "personal",
|
|
owner: "샘플회사/사용자",
|
|
key: "SS000201",
|
|
name: "돌기슭막이 메쌓기 1.2m 기초유",
|
|
});
|
|
// layer 없는 줄(옛 서버)은 마스터로 봄
|
|
assert.equal(toSummary({ key: "SS000009", 열: "임시" }).layer, "system");
|
|
|
|
// 지금 지정된 항목인지
|
|
assert.ok(isCurrent(toSummary(mine), mine));
|
|
assert.ok(!isCurrent(toSummary(mine), rows[0]));
|
|
assert.ok(!isCurrent(null, rows[0]));
|
|
|
|
// 처음 펼칠 자리
|
|
assert.deepEqual(pathIds(rows[0], labels), [
|
|
"system",
|
|
"system|돌기슭막이",
|
|
"system|돌기슭막이|메쌓기",
|
|
]);
|
|
|
|
// 폴더 모양 — 다섯 줄 · 이름은 서버 names · 없으면 키만(작은 글) · 둘 다 없으면 빈 키
|
|
const lines = folderLines(rows[0]);
|
|
assert.deepEqual(
|
|
lines.map((l) => l.kind),
|
|
["drawing", "area", "material", "combo", "unitPrice"],
|
|
);
|
|
assert.deepEqual(lines[0], { kind: "drawing", name: "돌기슭막이 도면", key: "SD01010100" });
|
|
assert.deepEqual(lines[3], { kind: "combo", name: null, key: "UM000001" }); // names 에 없음
|
|
assert.deepEqual(folderLines(rows[1])[0], { kind: "drawing", name: null, key: "SD01010100" }); // names 자체가 없음
|
|
assert.deepEqual(folderLines({ key: "SS1", 열: "x" })[4], {
|
|
kind: "unitPrice",
|
|
name: null,
|
|
key: "",
|
|
});
|
|
|
|
console.log("항목 고르기 자료 시험 통과");
|