Files
STCourses/packages/feature-studio/test/convert-ui.test.tsx
T
Lucas WintherandClaude Opus 5.5 20246b442f feat(studio): "Make editable in the studio" panel for imported courses
Owner sees what conversion does, starts it, follows progress and lands in the
workbench; other authors are told only the owner can. Existing tokens only.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 20:33:55 +01:00

39 lines
2.2 KiB
TypeScript

import { expect, test } from "bun:test";
import { renderToString } from "react-dom/server";
import { ConvertPanelView, ReadOnlyView } from "../src/ui/ConvertPanel";
const noop = () => {};
test("the owner sees the action and what it does", () => {
const html = renderToString(<ConvertPanelView phase={{ kind: "idle" }} onConvert={noop} />);
expect(html).toContain("Make editable in the studio");
expect(html).toContain("same id");
expect(html).toContain("progress and notes");
expect(html).toContain("outside git");
expect(html).toContain("<button");
});
test("progress and failure states", () => {
const running = renderToString(<ConvertPanelView phase={{ kind: "running", progress: 0.4, message: "Checksumming media/a.mp4" }} onConvert={noop} />);
expect(running).toContain('role="progressbar"');
expect(running).toContain('aria-valuenow="40"');
expect(running).toContain("Checksumming media/a.mp4");
expect(running).toContain("disabled");
const failed = renderToString(<ConvertPanelView phase={{ kind: "failed", error: "the imported manifest is invalid" }} onConvert={noop} />);
expect(failed).toContain('role="alert"');
expect(failed).toContain("the imported manifest is invalid");
expect(failed).toContain("Try again");
});
test("read-only view: imported for the owner offers the action; for others explains who can", () => {
const owner = renderToString(<ReadOnlyView courseId="imp" info={{ title: "Imp", message: "Imported course", root: "/d/courses/imp", imported: true, convertible: true }} onConverted={noop} />);
expect(owner).toContain("Make editable in the studio");
expect(owner).not.toContain("/d/courses/imp");
const author = renderToString(<ReadOnlyView courseId="imp" info={{ title: "Imp", message: "Imported course", root: "/d/courses/imp", imported: true, convertible: false }} onConverted={noop} />);
expect(author).not.toContain("<button");
expect(author).toContain("Only the owner");
const outside = renderToString(<ReadOnlyView courseId="o" info={{ title: "O", message: "This course is managed outside STCourses", root: "/repos/o", imported: false, convertible: false }} onConverted={noop} />);
expect(outside).toContain("/repos/o");
expect(outside).not.toContain("<button");
});