summaryrefslogtreecommitdiffhomepage
path: root/packages/tool-youtube-transcript/src/format.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/tool-youtube-transcript/src/format.test.ts')
-rw-r--r--packages/tool-youtube-transcript/src/format.test.ts121
1 files changed, 121 insertions, 0 deletions
diff --git a/packages/tool-youtube-transcript/src/format.test.ts b/packages/tool-youtube-transcript/src/format.test.ts
new file mode 100644
index 0000000..00b5d05
--- /dev/null
+++ b/packages/tool-youtube-transcript/src/format.test.ts
@@ -0,0 +1,121 @@
+import { describe, expect, it } from "vitest";
+import {
+ type CompletedResponse,
+ type FailedResponse,
+ formatCompleted,
+ formatFailed,
+ formatQueued,
+ formatTimestamp,
+ type QueuedResponse,
+ truncateOutput,
+} from "./format.js";
+
+describe("formatTimestamp", () => {
+ it("formats seconds as m:ss", () => {
+ expect(formatTimestamp(65)).toBe("1:05");
+ expect(formatTimestamp(723)).toBe("12:03");
+ });
+
+ it("handles zero", () => {
+ expect(formatTimestamp(0)).toBe("0:00");
+ });
+
+ it("handles minutes over 60", () => {
+ // 3700s = 61m40s; 4530s = 75m30s.
+ expect(formatTimestamp(3700)).toBe("61:40");
+ expect(formatTimestamp(4530)).toBe("75:30");
+ });
+});
+
+describe("formatCompleted", () => {
+ it("formats markdown with full text + segments", () => {
+ const data: CompletedResponse = {
+ status: "completed",
+ video_id: "vid123",
+ full_text: "Hello world.",
+ segments: [
+ { text: "Hello world.", start: 0, duration: 2.5 },
+ { text: "Second line.", start: 65, duration: 1.0 },
+ ],
+ };
+ const out = formatCompleted("https://youtu.be/vid123", data);
+ const expected = [
+ "## Transcript for https://youtu.be/vid123",
+ "**Video ID:** vid123",
+ "",
+ "### Full text",
+ "",
+ "Hello world.",
+ "",
+ "### Timestamped segments",
+ "",
+ "[0:00] Hello world.",
+ "[1:05] Second line.",
+ ].join("\n");
+ expect(out).toBe(expected);
+ });
+});
+
+describe("formatQueued", () => {
+ it("returns status + position + estimated time + pending file instruction", () => {
+ const data: QueuedResponse = {
+ status: "queued",
+ video_id: "vid456",
+ position: 3,
+ estimated_seconds: 120,
+ };
+ const now = () => 1_000_000_000_000;
+ const out = formatQueued("https://youtu.be/vid456", data, now);
+ const expectedTime = new Date(1_000_000_000_000 + 120_000).toISOString();
+ const expected =
+ `Transcript not yet available (status: queued, queue position: 3).\n` +
+ `Estimated available at: ${expectedTime} (in ~120s).\n` +
+ `You must append this video URL to .youtube_subtitles_pending in the current ` +
+ `working directory: https://youtu.be/vid456`;
+ expect(out).toBe(expected);
+ });
+
+ it("includes the processing status + pending-file instruction", () => {
+ const data: QueuedResponse = {
+ status: "processing",
+ video_id: "vid457",
+ position: 0,
+ estimated_seconds: 45.5,
+ };
+ const out = formatQueued("https://youtu.be/vid457", data, () => 0);
+ expect(out).toContain("status: processing");
+ expect(out).toContain("queue position: 0");
+ expect(out).toContain("(in ~46s)");
+ expect(out).toContain(".youtube_subtitles_pending");
+ expect(out).toContain("https://youtu.be/vid457");
+ });
+});
+
+describe("formatFailed", () => {
+ it("returns error type + details", () => {
+ const data: FailedResponse = {
+ status: "failed",
+ video_id: "vid789",
+ error: "Video unavailable",
+ error_type: "NotFoundError",
+ };
+ expect(formatFailed(data)).toBe(
+ "Transcript fetch failed. Error type: NotFoundError. Details: Video unavailable",
+ );
+ });
+});
+
+describe("truncateOutput", () => {
+ it("truncates with notice when over cap", () => {
+ const output = "a".repeat(100);
+ const result = truncateOutput(output, 50);
+ expect(result).toContain("a".repeat(50));
+ expect(result).toContain("[Output truncated: exceeded 50 characters]");
+ expect(result.length).toBeLessThan(output.length + 100);
+ });
+
+ it("returns as-is when under cap", () => {
+ expect(truncateOutput("short", 100)).toBe("short");
+ expect(truncateOutput("exact", 5)).toBe("exact");
+ });
+});