Batch 2-4 of the test-strategy rollout. Test-only except one minimal, behaviour-preserving extraction in file.utils.ts. All suites green: server 82 suites/836+1todo, editor-ext 86, mcp 270, client (new files) 86. integrations (server): - file.utils.ts: extract pure `isEntryPathSafe(entryName, targetDir)` from extractZipInternal so the zip-slip/path-traversal guard is unit-testable; call site rerouted, behaviour identical (only a warn-message string merged). - file.utils.zip-safety.spec.ts: traversal/strip/__MACOSX/prefix-confusion cases (mutation-resistant: fails if containment loses the path.sep). - import-formatter / import.utils / table-utils / export utils / import.service extractTitleAndRemoveHeading: pure import/export transforms, Notion/XWiki formatting, table colspan widths (idempotent), slug/link rewriting. client: - safeRedirectPath: open-redirect guard, every reject branch independently. - buildChatMarkdown (fence anti-breakout), label-colors, normalize-label, share tree build, page URL builders, notification time-grouping (fake clock). packages: - editor-ext: deriveFootnoteId golden table, parseHtmlEmbedHeight crafted values, orphan footnote extraction. - mcp: deriveFootnoteId parity (drift guard vs editor-ext), applyTextEdits idempotency + cross-block replaceAll, diffDocs/summarizeChange on reorder. Reviewed (APPROVE): extraction behaviour-preserving, assertions mutation-resistant. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { normalizeLabelName } from "@/features/label/utils/normalize-label.ts";
|
|
|
|
/**
|
|
* `normalizeLabelName` = trim + collapse ALL whitespace runs to a single hyphen
|
|
* + lowercase. Used to canonicalize label names so "Bug Fix" and " bug fix "
|
|
* map to the same key.
|
|
*/
|
|
describe("normalizeLabelName", () => {
|
|
it("trims leading and trailing whitespace", () => {
|
|
expect(normalizeLabelName(" bug ")).toBe("bug");
|
|
});
|
|
|
|
it("lowercases", () => {
|
|
expect(normalizeLabelName("BUG")).toBe("bug");
|
|
expect(normalizeLabelName("MixedCase")).toBe("mixedcase");
|
|
});
|
|
|
|
it("collapses internal whitespace runs to a single hyphen", () => {
|
|
expect(normalizeLabelName("bug fix")).toBe("bug-fix");
|
|
expect(normalizeLabelName("a b c")).toBe("a-b-c");
|
|
});
|
|
|
|
it("combines trim + collapse + lowercase", () => {
|
|
expect(normalizeLabelName(" Bug Fix ")).toBe("bug-fix");
|
|
});
|
|
|
|
it("treats tab and newline as whitespace", () => {
|
|
expect(normalizeLabelName("bug\tfix")).toBe("bug-fix");
|
|
expect(normalizeLabelName("bug\nfix")).toBe("bug-fix");
|
|
expect(normalizeLabelName("bug\r\nfix")).toBe("bug-fix");
|
|
});
|
|
|
|
it("treats unicode whitespace (no-break space) as a separator", () => {
|
|
// U+00A0 NO-BREAK SPACE is matched by the \s class.
|
|
expect(normalizeLabelName("bug fix")).toBe("bug-fix");
|
|
});
|
|
|
|
it("leaves an already-normalized name unchanged", () => {
|
|
expect(normalizeLabelName("bug-fix")).toBe("bug-fix");
|
|
});
|
|
|
|
it("returns empty string for whitespace-only input", () => {
|
|
expect(normalizeLabelName(" ")).toBe("");
|
|
expect(normalizeLabelName("")).toBe("");
|
|
});
|
|
});
|