| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- /**
- * Unit tests for multi-collection filter logic (PR #191).
- *
- * Tests the filterByCollections post-filter and the resolveCollectionFilter
- * behavior for single-collection vs multi-collection search.
- */
- import { describe, test, expect } from "vitest";
- // Reproduce the filterByCollections logic from qmd.ts for testing
- // (the function is private in qmd.ts)
- function filterByCollections<T extends { filepath?: string; file?: string }>(
- results: T[],
- collectionNames: string[],
- ): T[] {
- if (collectionNames.length <= 1) return results;
- const prefixes = collectionNames.map((n) => `qmd://${n}/`);
- return results.filter((r) => {
- const path = r.filepath || r.file || "";
- return prefixes.some((p) => path.startsWith(p));
- });
- }
- describe("filterByCollections", () => {
- const results = [
- { filepath: "qmd://docs/readme.md", file: "qmd://docs/readme.md" },
- { filepath: "qmd://notes/todo.md", file: "qmd://notes/todo.md" },
- { filepath: "qmd://journals/2024/jan.md", file: "qmd://journals/2024/jan.md" },
- { filepath: "qmd://docs/api.md", file: "qmd://docs/api.md" },
- ];
- test("returns all results when no collections specified", () => {
- expect(filterByCollections(results, [])).toEqual(results);
- });
- test("returns all results for single collection (no-op, handled by SQL filter)", () => {
- expect(filterByCollections(results, ["docs"])).toEqual(results);
- });
- test("filters to matching collections when multiple specified", () => {
- const filtered = filterByCollections(results, ["docs", "journals"]);
- expect(filtered).toHaveLength(3);
- expect(filtered.map((r) => r.filepath)).toEqual([
- "qmd://docs/readme.md",
- "qmd://journals/2024/jan.md",
- "qmd://docs/api.md",
- ]);
- });
- test("filters correctly with two collections", () => {
- const filtered = filterByCollections(results, ["notes", "journals"]);
- expect(filtered).toHaveLength(2);
- expect(filtered.map((r) => r.filepath)).toEqual([
- "qmd://notes/todo.md",
- "qmd://journals/2024/jan.md",
- ]);
- });
- test("returns empty when no results match collections", () => {
- const filtered = filterByCollections(results, ["archive", "trash"]);
- expect(filtered).toHaveLength(0);
- });
- test("uses file field when filepath is missing", () => {
- const fileOnlyResults = [
- { file: "qmd://docs/readme.md" },
- { file: "qmd://notes/todo.md" },
- ];
- const filtered = filterByCollections(fileOnlyResults, ["docs", "notes"]);
- expect(filtered).toHaveLength(2);
- });
- test("uses filepath over file when both present", () => {
- const mixedResults = [
- { filepath: "qmd://docs/readme.md", file: "qmd://notes/todo.md" },
- ];
- const filtered = filterByCollections(mixedResults, ["docs", "notes"]);
- expect(filtered).toHaveLength(1);
- // Should match via filepath (docs), not file (notes)
- expect(filtered[0].filepath).toBe("qmd://docs/readme.md");
- });
- });
- describe("resolveCollectionFilter input normalization", () => {
- // Test the array normalization logic without the DB dependency
- function normalizeCollectionInput(raw: string | string[] | undefined): string[] {
- if (!raw) return [];
- return Array.isArray(raw) ? raw : [raw];
- }
- test("undefined returns empty array", () => {
- expect(normalizeCollectionInput(undefined)).toEqual([]);
- });
- test("single string returns single-element array", () => {
- expect(normalizeCollectionInput("docs")).toEqual(["docs"]);
- });
- test("array passes through", () => {
- expect(normalizeCollectionInput(["docs", "notes"])).toEqual(["docs", "notes"]);
- });
- test("empty string returns single-element array", () => {
- expect(normalizeCollectionInput("")).toEqual([]);
- });
- });
- describe("collection option type from parseArgs", () => {
- // Verify that parseArgs with `multiple: true` produces string[]
- test("parseArgs multiple:true produces array for repeated flags", () => {
- const { parseArgs } = require("node:util");
- const { values } = parseArgs({
- args: ["-c", "docs", "-c", "notes"],
- options: {
- collection: { type: "string", short: "c", multiple: true },
- },
- strict: true,
- });
- expect(values.collection).toEqual(["docs", "notes"]);
- });
- test("parseArgs multiple:true produces array for single flag", () => {
- const { parseArgs } = require("node:util");
- const { values } = parseArgs({
- args: ["-c", "docs"],
- options: {
- collection: { type: "string", short: "c", multiple: true },
- },
- strict: true,
- });
- expect(values.collection).toEqual(["docs"]);
- });
- test("parseArgs multiple:true produces undefined when flag absent", () => {
- const { parseArgs } = require("node:util");
- const { values } = parseArgs({
- args: [],
- options: {
- collection: { type: "string", short: "c", multiple: true },
- },
- strict: true,
- });
- expect(values.collection).toBeUndefined();
- });
- });
|