import { http, HttpResponse } from "msw"; import { server } from "@server/test/msw"; import { checkEmbeddability, convertBareUrlsToEmbedMarkdown } from "./embeds"; const embedUrl = "https://www.example.com/embed"; const mockEmbedResponse = ( url: string, init: { status?: number; headers?: Record } = {} ) => { server.use( http.get( url, () => new HttpResponse(null, { status: init.status ?? 200, headers: init.headers ?? {}, }) ) ); }; describe("checkEmbeddability", () => { describe("when URL doesn't match any embed pattern", () => { it("should return embeddable: false with reason: no-match for non-http URLs", async () => { // The generic embed only matches http/https URLs const result = await checkEmbeddability("file:///local/path"); expect(result).toEqual({ embeddable: false, reason: "no-match" }); }); it("should return embeddable: false with reason: no-match for invalid URLs", async () => { const result = await checkEmbeddability("not-a-valid-url"); expect(result).toEqual({ embeddable: false, reason: "no-match" }); }); }); describe("when URL matches an embed pattern", () => { it("should return embeddable: true when no restrictive headers", async () => { mockEmbedResponse(embedUrl); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: true }); }); it("should return embeddable: false when X-Frame-Options: DENY", async () => { mockEmbedResponse(embedUrl, { headers: { "X-Frame-Options": "DENY" }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: false, reason: "x-frame-options" }); }); it("should return embeddable: false when X-Frame-Options: SAMEORIGIN", async () => { mockEmbedResponse(embedUrl, { headers: { "X-Frame-Options": "SAMEORIGIN" }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: false, reason: "x-frame-options" }); }); it("should return embeddable: false when X-Frame-Options: ALLOW-FROM", async () => { mockEmbedResponse(embedUrl, { headers: { "X-Frame-Options": "ALLOW-FROM https://example.com" }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: false, reason: "x-frame-options" }); }); it("should return embeddable: false when CSP frame-ancestors is 'none'", async () => { mockEmbedResponse(embedUrl, { headers: { "Content-Security-Policy": "default-src 'self'; frame-ancestors 'none'", }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: false, reason: "csp-frame-ancestors", }); }); it("should return embeddable: false when CSP frame-ancestors is 'self'", async () => { mockEmbedResponse(embedUrl, { headers: { "Content-Security-Policy": "frame-ancestors 'self'", }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: false, reason: "csp-frame-ancestors", }); }); it("should return embeddable: true when CSP frame-ancestors is *", async () => { mockEmbedResponse(embedUrl, { headers: { "Content-Security-Policy": "frame-ancestors *", }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: true }); }); it("should return embeddable: false when CSP frame-ancestors has specific origins", async () => { mockEmbedResponse(embedUrl, { headers: { "Content-Security-Policy": "frame-ancestors https://allowed-site.com", }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: false, reason: "csp-frame-ancestors", }); }); it("should return embeddable: false when COEP is require-corp", async () => { mockEmbedResponse(embedUrl, { headers: { "Cross-Origin-Embedder-Policy": "require-corp" }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: false, reason: "coep" }); }); it("should return embeddable: true when COEP is unsafe-none", async () => { mockEmbedResponse(embedUrl, { headers: { "Cross-Origin-Embedder-Policy": "unsafe-none" }, }); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: true }); }); it("should return embeddable: false when server returns 403", async () => { const url = "https://www.example.com/forbiddenpage"; mockEmbedResponse(url, { status: 403 }); const result = await checkEmbeddability(url); expect(result).toEqual({ embeddable: false, reason: "http-error" }); }); it("should return embeddable: false when server returns 404", async () => { const url = "https://www.example.com/nonexistentpage"; mockEmbedResponse(url, { status: 404 }); const result = await checkEmbeddability(url); expect(result).toEqual({ embeddable: false, reason: "http-error" }); }); it("should return embeddable: true on timeout (optimistic)", async () => { // Network errors and aborts both land in the catch branch and return // { embeddable: true, reason: "timeout" }. server.use(http.get(embedUrl, () => HttpResponse.error())); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: true, reason: "timeout" }); }); it("should return embeddable: true on network error (optimistic)", async () => { server.use(http.get(embedUrl, () => HttpResponse.error())); const result = await checkEmbeddability(embedUrl); expect(result).toEqual({ embeddable: true, reason: "timeout" }); }); }); describe("convertBareUrlsToEmbedMarkdown", () => { it("should convert bare YouTube URL to embed format", () => { const input = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"; const expected = "[https://www.youtube.com/watch?v=dQw4w9WgXcQ](https://www.youtube.com/watch?v=dQw4w9WgXcQ)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should convert bare Vimeo URL to embed format", () => { const input = "https://vimeo.com/123456789"; const expected = "[https://vimeo.com/123456789](https://vimeo.com/123456789)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should convert bare youtu.be URL to embed format", () => { const input = "https://youtu.be/dQw4w9WgXcQ"; const expected = "[https://youtu.be/dQw4w9WgXcQ](https://youtu.be/dQw4w9WgXcQ)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should not convert URLs that do not match embed patterns", () => { const input = "https://example.com/some-page"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(input); }); it("should not convert URLs that are already in markdown link format", () => { const input = "[https://www.example.com/embed](https://www.example.com/embed)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(input); }); it("should not convert URLs that have link text", () => { const input = "[Watch this video](https://www.example.com/embed)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(input); }); it("should not convert URLs that are part of other text on the same line", () => { const input = "Check out https://www.example.com/embed video"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(input); }); it("should handle multiple lines with mixed content", () => { const input = `Here is some text. https://www.youtube.com/watch?v=dQw4w9WgXcQ And some more text. https://example.com/not-an-embed https://vimeo.com/987654321`; const expected = `Here is some text. [https://www.youtube.com/watch?v=dQw4w9WgXcQ](https://www.youtube.com/watch?v=dQw4w9WgXcQ) And some more text. https://example.com/not-an-embed [https://vimeo.com/987654321](https://vimeo.com/987654321)`; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should preserve leading whitespace", () => { const input = " https://www.youtube.com/watch?v=dQw4w9WgXcQ"; const expected = " [https://www.youtube.com/watch?v=dQw4w9WgXcQ](https://www.youtube.com/watch?v=dQw4w9WgXcQ)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should handle empty string", () => { expect(convertBareUrlsToEmbedMarkdown("")).toBe(""); }); it("should handle text with no URLs", () => { const input = "This is just regular text with no URLs."; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(input); }); it("should convert Spotify URLs", () => { const input = "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT"; const expected = "[https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT](https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should convert Loom URLs", () => { const input = "https://www.loom.com/share/abc123def456"; const expected = "[https://www.loom.com/share/abc123def456](https://www.loom.com/share/abc123def456)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should convert Figma URLs", () => { // Figma regex requires 22-128 character file IDs const input = "https://www.figma.com/file/abcdefghij1234567890AB/Design-File"; const expected = "[https://www.figma.com/file/abcdefghij1234567890AB/Design-File](https://www.figma.com/file/abcdefghij1234567890AB/Design-File)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should handle trailing whitespace on lines", () => { const input = "https://www.youtube.com/watch?v=dQw4w9WgXcQ "; // Trailing whitespace is trimmed, so the URL still gets converted const expected = "[https://www.youtube.com/watch?v=dQw4w9WgXcQ](https://www.youtube.com/watch?v=dQw4w9WgXcQ)"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(expected); }); it("should not convert URLs with text before them", () => { const input = "Video: https://www.youtube.com/watch?v=dQw4w9WgXcQ"; expect(convertBareUrlsToEmbedMarkdown(input)).toBe(input); }); }); });