Files
outline/server/utils/embeds.test.ts
T
Tom Moor 091346dfe8 chore: Migrate to vitest (#12272)
* wip

* Remove obsolete snapshots

* simplify

* chore(test): Convert mocks to TypeScript and tighten fetch mock types

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Remove unneccessary patches

* Migrate to msw instead of custom fetch mock

* Address PR review comments

- Split chained vi.useFakeTimers().setSystemTime() into separate calls.
- Switch test setup to dynamic imports so EventEmitter.defaultMaxListeners
  assignment runs before module init (static imports were hoisted above it).
- Drop redundant NODE_ENV guard in monkeyPatchSequelizeErrorsForJest; its
  sole caller already gates on env.isTest.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 21:10:51 -04:00

297 lines
11 KiB
TypeScript

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<string, string> } = {}
) => {
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);
});
});
});