* Add npm release track invariant and beta dist-tag procedure * Revert "Keep older chat history and image previews stable (#2490)" The timeline optimistic/pagination rework needs more work than main releases can wait for. Reverted together with #2484; both are reapplied on integration/timeline-optimistic-rework. * Revert "Stop completed turns from appearing stuck (#2484)" See the #2490 revert. #2490 built on this submission-authority change, so the two revert and reapply as a pair.
90 lines
2.9 KiB
TypeScript
90 lines
2.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
createImageSourceCacheKey,
|
|
fileUriToPath,
|
|
localFileSourceToPath,
|
|
parseDataUrl,
|
|
parseImageDataUrl,
|
|
pathToFileUri,
|
|
} from "./utils";
|
|
|
|
describe("pathToFileUri", () => {
|
|
it("converts POSIX absolute paths to file URIs", () => {
|
|
expect(pathToFileUri("/home/user/file.txt")).toBe("file:///home/user/file.txt");
|
|
});
|
|
|
|
it("converts Windows drive-letter paths to file URIs", () => {
|
|
expect(pathToFileUri("C:\\Users\\file.txt")).toBe("file:///C:/Users/file.txt");
|
|
});
|
|
|
|
it("converts UNC paths to host-based file URIs", () => {
|
|
expect(pathToFileUri("\\\\server\\share\\dir")).toBe("file://server/share/dir");
|
|
});
|
|
|
|
it("passes through file URIs unchanged", () => {
|
|
expect(pathToFileUri("file:///already/uri")).toBe("file:///already/uri");
|
|
});
|
|
|
|
it("passes through relative paths unchanged", () => {
|
|
expect(pathToFileUri("relative/path")).toBe("relative/path");
|
|
});
|
|
});
|
|
|
|
describe("fileUriToPath", () => {
|
|
it("converts Windows drive-letter file URIs back to paths", () => {
|
|
expect(fileUriToPath("file:///C:/Users/file.txt")).toBe("C:/Users/file.txt");
|
|
});
|
|
|
|
it("converts host-based file URIs back to UNC paths", () => {
|
|
expect(fileUriToPath("file://server/share/shot%231.png")).toBe("\\\\server\\share\\shot#1.png");
|
|
});
|
|
});
|
|
|
|
describe("localFileSourceToPath", () => {
|
|
it("decodes markdown-encoded Windows drive-letter paths", () => {
|
|
expect(localFileSourceToPath("C:%5CUsers%5Cfile.txt")).toBe("C:/Users/file.txt");
|
|
});
|
|
|
|
it("preserves literal percent sequences in plain local paths", () => {
|
|
expect(localFileSourceToPath("/tmp/image%20with%20literal%20percent.png")).toBe(
|
|
"/tmp/image%20with%20literal%20percent.png",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("parseDataUrl", () => {
|
|
it("accepts base64 data URLs with media-type parameters", () => {
|
|
expect(parseDataUrl("data:image/png;charset=utf-8;name=preview;base64,AAECAw==")).toEqual({
|
|
mimeType: "image/png",
|
|
base64: "AAECAw==",
|
|
});
|
|
});
|
|
|
|
it("rejects non-base64 data URLs", () => {
|
|
expect(() => parseDataUrl("data:image/png,not-base64")).toThrow(
|
|
"Attachment data URL is not base64 encoded.",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("parseImageDataUrl", () => {
|
|
it("returns a compact cache key for image data URLs", () => {
|
|
const dataUrl = `data:image/png;base64,${"a".repeat(512)}`;
|
|
|
|
expect(parseImageDataUrl(dataUrl)).toMatchObject({
|
|
mimeType: "image/png",
|
|
base64: "a".repeat(512),
|
|
});
|
|
expect(createImageSourceCacheKey(dataUrl)).toMatch(/^data-image:image\/png:512:/);
|
|
expect(createImageSourceCacheKey(dataUrl)).not.toContain("a".repeat(128));
|
|
});
|
|
|
|
it("ignores non-image data URLs", () => {
|
|
expect(parseImageDataUrl("data:text/plain;base64,SGVsbG8=")).toBeNull();
|
|
});
|
|
|
|
it("ignores SVG data URLs", () => {
|
|
expect(parseImageDataUrl("data:image/svg+xml;base64,PHN2ZyAvPg==")).toBeNull();
|
|
});
|
|
});
|