|
@@ -0,0 +1,153 @@
|
|
|
+import { getEmbedLink } from "../src/embeddable";
|
|
|
+
|
|
|
+describe("YouTube timestamp parsing", () => {
|
|
|
+ it("should parse YouTube URLs with timestamp in seconds", () => {
|
|
|
+ const testCases = [
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=90",
|
|
|
+ expectedStart: 90,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://youtu.be/dQw4w9WgXcQ?t=120",
|
|
|
+ expectedStart: 120,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&start=150",
|
|
|
+ expectedStart: 150,
|
|
|
+ },
|
|
|
+ ];
|
|
|
+
|
|
|
+ testCases.forEach(({ url, expectedStart }) => {
|
|
|
+ const result = getEmbedLink(url);
|
|
|
+ expect(result).toBeTruthy();
|
|
|
+ expect(result?.type).toBe("video");
|
|
|
+ if (result?.type === "video" || result?.type === "generic") {
|
|
|
+ expect(result.link).toContain(`start=${expectedStart}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("should parse YouTube URLs with timestamp in time format", () => {
|
|
|
+ const testCases = [
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=1m30s",
|
|
|
+ expectedStart: 90, // 1*60 + 30
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://youtu.be/dQw4w9WgXcQ?t=2m45s",
|
|
|
+ expectedStart: 165, // 2*60 + 45
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=1h2m3s",
|
|
|
+ expectedStart: 3723, // 1*3600 + 2*60 + 3
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=45s",
|
|
|
+ expectedStart: 45,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=5m",
|
|
|
+ expectedStart: 300, // 5*60
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=2h",
|
|
|
+ expectedStart: 7200, // 2*3600
|
|
|
+ },
|
|
|
+ ];
|
|
|
+
|
|
|
+ testCases.forEach(({ url, expectedStart }) => {
|
|
|
+ const result = getEmbedLink(url);
|
|
|
+ expect(result).toBeTruthy();
|
|
|
+ expect(result?.type).toBe("video");
|
|
|
+ if (result?.type === "video" || result?.type === "generic") {
|
|
|
+ expect(result.link).toContain(`start=${expectedStart}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("should handle YouTube URLs without timestamps", () => {
|
|
|
+ const testCases = [
|
|
|
+ "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
|
|
+ "https://youtu.be/dQw4w9WgXcQ",
|
|
|
+ "https://www.youtube.com/embed/dQw4w9WgXcQ",
|
|
|
+ ];
|
|
|
+
|
|
|
+ testCases.forEach((url) => {
|
|
|
+ const result = getEmbedLink(url);
|
|
|
+ expect(result).toBeTruthy();
|
|
|
+ expect(result?.type).toBe("video");
|
|
|
+ if (result?.type === "video" || result?.type === "generic") {
|
|
|
+ expect(result.link).not.toContain("start=");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("should handle YouTube shorts URLs with timestamps", () => {
|
|
|
+ const url = "https://www.youtube.com/shorts/dQw4w9WgXcQ?t=30";
|
|
|
+ const result = getEmbedLink(url);
|
|
|
+
|
|
|
+ expect(result).toBeTruthy();
|
|
|
+ expect(result?.type).toBe("video");
|
|
|
+ if (result?.type === "video" || result?.type === "generic") {
|
|
|
+ expect(result.link).toContain("start=30");
|
|
|
+ }
|
|
|
+ // Shorts should have portrait aspect ratio
|
|
|
+ expect(result?.intrinsicSize).toEqual({ w: 315, h: 560 });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("should handle playlist URLs with timestamps", () => {
|
|
|
+ const url =
|
|
|
+ "https://www.youtube.com/playlist?list=PLrAXtmRdnEQy1KbG5lbfgQ0-PKQY6FKYZ&t=60";
|
|
|
+ const result = getEmbedLink(url);
|
|
|
+
|
|
|
+ expect(result).toBeTruthy();
|
|
|
+ expect(result?.type).toBe("video");
|
|
|
+ if (result?.type === "video" || result?.type === "generic") {
|
|
|
+ expect(result.link).toContain("start=60");
|
|
|
+ expect(result.link).toContain("list=PLrAXtmRdnEQy1KbG5lbfgQ0-PKQY6FKYZ");
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it("should handle malformed or edge case timestamps", () => {
|
|
|
+ const testCases = [
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=abc",
|
|
|
+ expectedStart: 0, // Invalid timestamp should default to 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=",
|
|
|
+ expectedStart: 0, // Empty timestamp should default to 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=0",
|
|
|
+ expectedStart: 0, // Zero timestamp should be handled
|
|
|
+ },
|
|
|
+ ];
|
|
|
+
|
|
|
+ testCases.forEach(({ url, expectedStart }) => {
|
|
|
+ const result = getEmbedLink(url);
|
|
|
+ expect(result).toBeTruthy();
|
|
|
+ expect(result?.type).toBe("video");
|
|
|
+ if (result?.type === "video" || result?.type === "generic") {
|
|
|
+ if (expectedStart === 0) {
|
|
|
+ expect(result.link).not.toContain("start=");
|
|
|
+ } else {
|
|
|
+ expect(result.link).toContain(`start=${expectedStart}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("should preserve other URL parameters", () => {
|
|
|
+ const url =
|
|
|
+ "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=90&feature=youtu.be&list=PLtest";
|
|
|
+ const result = getEmbedLink(url);
|
|
|
+
|
|
|
+ expect(result).toBeTruthy();
|
|
|
+ expect(result?.type).toBe("video");
|
|
|
+ if (result?.type === "video" || result?.type === "generic") {
|
|
|
+ expect(result.link).toContain("start=90");
|
|
|
+ expect(result.link).toContain("enablejsapi=1");
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|