import { createCollection, createLiveQueryCollection, localOnlyCollectionOptions, } from "@tanstack/db" import type { FileEntry } from "./api" import { describe, expect, it } from "vitest" import { file } from "../test/fixtures" import { selectedEntries, validName, fileQuery, type Sort } from "./files" async function visibleFiles(files: FileEntry[], search: string, sort: Sort, descending: boolean) { const source = createCollection( localOnlyCollectionOptions({ getKey: (entry: FileEntry) => entry.id, initialData: files }), ) const query = createLiveQueryCollection({ query: (q) => fileQuery(q, source, search, sort, descending), }) try { await query.preload() return query.toArray.map((entry) => files.find((original) => original.id === entry.id)) } finally { await query.cleanup() await source.cleanup() } } describe("file presentation", () => { const first = file({ id: "a", name: "File 2.txt", size: 20 }) const second = file({ id: "b", name: "File 10.txt", size: 10, kind: "directory", createdAt: "2026-09-03T00:00:00.000Z", updatedAt: "2026-09-04T00:00:00.000Z", }) it("filters without modifying the source and sorts names numerically", async () => { const files = [second, first] expect(await visibleFiles(files, " FILE ", "Name", false)).toEqual([first, second]) expect(files).toEqual([second, first]) expect(await visibleFiles(files, "missing", "Name", false)).toEqual([]) }) it.each([ ["Size", [second, first]], ["Kind", [second, first]], ["Created", [first, second]], ["Modified", [first, second]], ] as const)("implements %s sorting", async (sort, expected) => { expect(await visibleFiles([first, second], "", sort, false)).toEqual(expected) expect(await visibleFiles([first, second], "", sort, true)).toEqual([...expected].reverse()) }) it.each([ ["Created", "createdAt"], ["Modified", "updatedAt"], ] as const)("sorts %s chronologically across time-zone offsets", async (sort, field) => { const earliest = file({ id: "a", [field]: "2026-09-05T12:30:00+02:00" }) const middle = file({ id: "b", [field]: "2026-09-05T11:00:00Z" }) const latest = file({ id: "c", [field]: "2026-09-05T07:30:00-04:00" }) const files = [middle, latest, earliest] expect(await visibleFiles(files, "", sort, false)).toEqual([earliest, middle, latest]) expect(await visibleFiles(files, "", sort, true)).toEqual([latest, middle, earliest]) expect(files).toEqual([middle, latest, earliest]) }) it.each([ ["Created", "createdAt"], ["Modified", "updatedAt"], ] as const)("breaks equivalent %s instants by numeric name then ID", async (sort, field) => { const first = file({ id: "a", name: "File 2.txt", [field]: "2026-09-05T12:00:00+02:00" }) const second = file({ id: "b", name: "File 2.txt", [field]: "2026-09-05T10:00:00Z" }) const third = file({ id: "c", name: "File 10.txt", [field]: "2026-09-05T06:00:00-04:00" }) const files = [third, second, first] expect(await visibleFiles(files, "", sort, false)).toEqual([first, second, third]) expect(await visibleFiles(files, "", sort, true)).toEqual([third, second, first]) }) it("selects stable record IDs, not names or revisions", () => { const renamed = file({ id: "a", name: "Renamed", revision: "revision-two" }) expect(selectedEntries([renamed, file({ id: "b", name: "Renamed" })], ["a"])).toEqual([renamed]) }) }) describe("file names", () => { it.each(["", " ", ".", "..", "a/b", "a\\b", "a\0b", "a\nb"])("rejects %j", (name) => { expect(validName(name)).toBe(false) }) it.each(["report.txt", "Résumé 2026.pdf", ".hidden", "emoji 📦"])("allows %j", (name) => { expect(validName(name)).toBe(true) }) }) it("selects directories from one account collection and excludes deleted records", async () => { const root = file() const child = file({ id: "child", parentId: "folder" }) const deleted = file({ id: "deleted", trashedAt: "2026-09-07T00:00:00Z" }) const source = createCollection( localOnlyCollectionOptions({ getKey: (entry: FileEntry) => entry.id, initialData: [root, child, deleted], }), ) const rootQuery = createLiveQueryCollection({ query: (q) => fileQuery(q, source, "", "Name", false), }) const childQuery = createLiveQueryCollection({ query: (q) => fileQuery(q, source, "", "Name", false, "folder"), }) try { await Promise.all([rootQuery.preload(), childQuery.preload()]) expect(rootQuery.toArray.map((entry) => entry.id)).toEqual([root.id]) expect(childQuery.toArray.map((entry) => entry.id)).toEqual([child.id]) source.update(child.id, (entry) => { entry.name = "Changed" }) expect(childQuery.toArray[0]?.name).toBe("Changed") } finally { await rootQuery.cleanup() await childQuery.cleanup() await source.cleanup() } })