Files
Find-Word/tests/release.test.ts
2026-10-14 06:19:24 +00:00

78 lines
3.4 KiB
TypeScript

// @vitest-environment node
import { readFileSync, readdirSync } from "node:fs";
import { describe, expect, it } from "vitest";
// 사용자 지정 문자열은 편집자가 회사 이름을 추측해 정규화하지 못하도록
// 화면 테스트와 문서 계약에서 원문 그대로 고정한다.
describe("릴리스 문서 계약", () => {
it("Node 최소 버전은 잠긴 의존성이 요구하는 22.22.2와 일치한다", () => {
const metadata = JSON.parse(readFileSync("package.json", "utf8"));
const lock = JSON.parse(readFileSync("package-lock.json", "utf8"));
expect.soft(metadata.engines.node).toBe(">=22.22.2");
expect.soft(lock.packages[""].engines.node).toBe(">=22.22.2");
expect(lock.packages["node_modules/jsdom"].engines.node).toContain(
"^22.22.2",
);
for (const path of ["README.md", "docs/DEPLOYMENT.md"]) {
const document = readFileSync(path, "utf8");
expect.soft(document, path).toContain("22.22.2");
expect.soft(document, path).not.toContain("22.12");
}
});
it("프로젝트는 비공개 권리 유보이며 저장소 주소를 명시한다", () => {
const metadata = JSON.parse(readFileSync("package.json", "utf8"));
const lock = JSON.parse(readFileSync("package-lock.json", "utf8"));
expect.soft(metadata.private).toBe(true);
expect.soft(metadata.license).toBe("UNLICENSED");
expect.soft(lock.packages[""].license).toBe("UNLICENSED");
expect.soft(metadata.repository).toEqual({
type: "git",
url: "https://source.ibit.kr/OZ-Group/Find-Word.git",
});
expect
.soft(metadata.homepage)
.toBe("https://source.ibit.kr/OZ-Group/Find-Word");
const license = readFileSync("LICENSE", "utf8");
expect(license).toMatch(/private/i);
expect(license).toContain("All rights reserved.");
expect(readFileSync("README.md", "utf8")).toContain(metadata.homepage);
});
it("잠금 파일의 모든 런타임 의존성 notice 전문을 배포용 사본에 보존한다", () => {
const lock = JSON.parse(readFileSync("package-lock.json", "utf8")) as {
packages: Record<string, { dev?: boolean; version: string }>;
};
const notice = readFileSync("THIRD_PARTY_NOTICES.md", "utf8");
expect(readFileSync("public/THIRD_PARTY_NOTICES.md", "utf8")).toBe(notice);
for (const [path, pkg] of Object.entries(lock.packages)) {
if (!path || pkg.dev) continue;
const name = path.split("node_modules/").at(-1)!;
const license = readFileSync(`${path}/LICENSE`, "utf8").trim();
expect(notice).toContain(`## ${name} ${pkg.version}\n\n${license}`);
}
});
it("브랜드 문구를 사용자 원문 그대로 문서에도 보존한다", () => {
const credit = "Designed by OZ at Heat-T Medical Inc.";
for (const path of [
"README.md",
".agent/TASK.md",
".agent/ACCEPTANCE.md",
".agent/CONTEXT.md",
]) {
expect.soft(readFileSync(path, "utf8"), path).toContain(credit);
}
for (const path of [
"README.md",
...["docs", ".agent"].flatMap((dir) =>
readdirSync(dir)
.filter((file) => file.endsWith(".md"))
.map((file) => `${dir}/${file}`),
),
]) {
// 잘못된 표기를 다시 권장하는 문서가 남아 있으면 다음 편집 때 회귀한다.
expect
.soft(readFileSync(path, "utf8"), path)
.not.toContain(["HearT", "M"].join("-"));
}
});
});