2
0

embeddable.test.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { getEmbedLink } from "../src/embeddable";
  2. describe("YouTube timestamp parsing", () => {
  3. it("should parse YouTube URLs with timestamp in seconds", () => {
  4. const testCases = [
  5. {
  6. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=90",
  7. expectedStart: 90,
  8. },
  9. {
  10. url: "https://youtu.be/dQw4w9WgXcQ?t=120",
  11. expectedStart: 120,
  12. },
  13. {
  14. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&start=150",
  15. expectedStart: 150,
  16. },
  17. ];
  18. testCases.forEach(({ url, expectedStart }) => {
  19. const result = getEmbedLink(url);
  20. expect(result).toBeTruthy();
  21. expect(result?.type).toBe("video");
  22. if (result?.type === "video" || result?.type === "generic") {
  23. expect(result.link).toContain(`start=${expectedStart}`);
  24. }
  25. });
  26. });
  27. it("should parse YouTube URLs with timestamp in time format", () => {
  28. const testCases = [
  29. {
  30. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=1m30s",
  31. expectedStart: 90, // 1*60 + 30
  32. },
  33. {
  34. url: "https://youtu.be/dQw4w9WgXcQ?t=2m45s",
  35. expectedStart: 165, // 2*60 + 45
  36. },
  37. {
  38. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=1h2m3s",
  39. expectedStart: 3723, // 1*3600 + 2*60 + 3
  40. },
  41. {
  42. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=45s",
  43. expectedStart: 45,
  44. },
  45. {
  46. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=5m",
  47. expectedStart: 300, // 5*60
  48. },
  49. {
  50. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=2h",
  51. expectedStart: 7200, // 2*3600
  52. },
  53. ];
  54. testCases.forEach(({ url, expectedStart }) => {
  55. const result = getEmbedLink(url);
  56. expect(result).toBeTruthy();
  57. expect(result?.type).toBe("video");
  58. if (result?.type === "video" || result?.type === "generic") {
  59. expect(result.link).toContain(`start=${expectedStart}`);
  60. }
  61. });
  62. });
  63. it("should handle YouTube URLs without timestamps", () => {
  64. const testCases = [
  65. "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  66. "https://youtu.be/dQw4w9WgXcQ",
  67. "https://www.youtube.com/embed/dQw4w9WgXcQ",
  68. ];
  69. testCases.forEach((url) => {
  70. const result = getEmbedLink(url);
  71. expect(result).toBeTruthy();
  72. expect(result?.type).toBe("video");
  73. if (result?.type === "video" || result?.type === "generic") {
  74. expect(result.link).not.toContain("start=");
  75. }
  76. });
  77. });
  78. it("should handle YouTube shorts URLs with timestamps", () => {
  79. const url = "https://www.youtube.com/shorts/dQw4w9WgXcQ?t=30";
  80. const result = getEmbedLink(url);
  81. expect(result).toBeTruthy();
  82. expect(result?.type).toBe("video");
  83. if (result?.type === "video" || result?.type === "generic") {
  84. expect(result.link).toContain("start=30");
  85. }
  86. // Shorts should have portrait aspect ratio
  87. expect(result?.intrinsicSize).toEqual({ w: 315, h: 560 });
  88. });
  89. it("should handle playlist URLs with timestamps", () => {
  90. const url =
  91. "https://www.youtube.com/playlist?list=PLrAXtmRdnEQy1KbG5lbfgQ0-PKQY6FKYZ&t=60";
  92. const result = getEmbedLink(url);
  93. expect(result).toBeTruthy();
  94. expect(result?.type).toBe("video");
  95. if (result?.type === "video" || result?.type === "generic") {
  96. expect(result.link).toContain("start=60");
  97. expect(result.link).toContain("list=PLrAXtmRdnEQy1KbG5lbfgQ0-PKQY6FKYZ");
  98. }
  99. });
  100. it("should handle malformed or edge case timestamps", () => {
  101. const testCases = [
  102. {
  103. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=abc",
  104. expectedStart: 0, // Invalid timestamp should default to 0
  105. },
  106. {
  107. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=",
  108. expectedStart: 0, // Empty timestamp should default to 0
  109. },
  110. {
  111. url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=0",
  112. expectedStart: 0, // Zero timestamp should be handled
  113. },
  114. ];
  115. testCases.forEach(({ url, expectedStart }) => {
  116. const result = getEmbedLink(url);
  117. expect(result).toBeTruthy();
  118. expect(result?.type).toBe("video");
  119. if (result?.type === "video" || result?.type === "generic") {
  120. if (expectedStart === 0) {
  121. expect(result.link).not.toContain("start=");
  122. } else {
  123. expect(result.link).toContain(`start=${expectedStart}`);
  124. }
  125. }
  126. });
  127. });
  128. it("should preserve other URL parameters", () => {
  129. const url =
  130. "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=90&feature=youtu.be&list=PLtest";
  131. const result = getEmbedLink(url);
  132. expect(result).toBeTruthy();
  133. expect(result?.type).toBe("video");
  134. if (result?.type === "video" || result?.type === "generic") {
  135. expect(result.link).toContain("start=90");
  136. expect(result.link).toContain("enablejsapi=1");
  137. }
  138. });
  139. });