import { describe, it } from "@std/testing/bdd"; import { expect } from "@std/expect"; import { CTMarkdown } from "./ct-markdown.ts"; describe("ct-markdown", () => { it("should be defined", () => { expect(CTMarkdown).toBeDefined(); }); it("should create element instance", () => { const element = new CTMarkdown(); expect(element).toBeInstanceOf(CTMarkdown); }); it("should have default empty content", () => { const element = new CTMarkdown(); expect(element.content).toBe(""); }); it("should have default variant", () => { const element = new CTMarkdown(); expect(element.variant).toBe("default"); }); it("should have streaming disabled by default", () => { const element = new CTMarkdown(); expect(element.streaming).toBe(false); }); it("should render basic markdown", () => { const el = new CTMarkdown(); const markdown = "Hello **world**"; const rendered = (el as any)._renderMarkdown(markdown); expect(rendered).toContain("world"); }); it("should replace LLM-friendly links with ct-cell-link", () => { const el = new CTMarkdown(); const link = "/of:bafyabc123/path"; const markdown = `Check this [Link](${link})`; const rendered = (el as any)._renderMarkdown(markdown); expect(rendered).toContain( ``, ); }); it("should wrap code blocks with copy buttons", () => { const el = new CTMarkdown(); const markdown = "```js\nconsole.log('hello');\n```"; const rendered = (el as any)._renderMarkdown(markdown); expect(rendered).toContain("code-block-container"); expect(rendered).toContain("ct-copy-button"); }); it("should get content value from string", () => { const el = new CTMarkdown(); el.content = "test content"; const value = (el as any)._getContentValue(); expect(value).toBe("test content"); }); it("should handle null/undefined content gracefully", () => { const el = new CTMarkdown(); el.content = null as any; const value = (el as any)._getContentValue(); expect(value).toBe(""); }); describe("Cell integration", () => { // Note: Full Cell integration testing requires real CellImpl instances // which are complex to mock. These tests verify the component's // subscription management logic with manual _unsubscribe manipulation. it("should have null _unsubscribe by default", () => { const el = new CTMarkdown(); expect((el as any)._unsubscribe).toBeNull(); }); it("should cleanup subscription on disconnect", () => { const el = new CTMarkdown(); // Simulate having a subscription let cleaned = false; (el as any)._unsubscribe = () => { cleaned = true; }; // Trigger disconnect el.disconnectedCallback(); expect(cleaned).toBe(true); expect((el as any)._unsubscribe).toBeNull(); }); it("should cleanup old subscription when willUpdate is called with changed content", () => { const el = new CTMarkdown(); // Simulate having an old subscription let oldCleaned = false; (el as any)._unsubscribe = () => { oldCleaned = true; }; // Trigger willUpdate with content change (string content, not Cell) el.content = "new content"; (el as any).willUpdate(new Map([["content", "old content"]])); // Old subscription should have been cleaned up expect(oldCleaned).toBe(true); // No new subscription for string content expect((el as any)._unsubscribe).toBeNull(); }); }); describe("variant", () => { it("should accept inverse variant", () => { const el = new CTMarkdown(); el.variant = "inverse"; expect(el.variant).toBe("inverse"); }); }); describe("streaming", () => { it("should accept streaming prop", () => { const el = new CTMarkdown(); el.streaming = true; expect(el.streaming).toBe(true); }); }); describe("entity decoding", () => { it("should decode basic HTML entities", () => { const el = new CTMarkdown(); const decoded = (el as any)._decodeHtmlEntities("<div>&""); expect(decoded).toBe('
&"'); }); it("should decode numeric entities in fallback mode", () => { const el = new CTMarkdown(); // Force fallback mode (test environment has no document) const decoded = (el as any)._decodeHtmlEntities("<>"); expect(decoded).toBe("<>"); }); it("should decode hex entities in fallback mode", () => { const el = new CTMarkdown(); const decoded = (el as any)._decodeHtmlEntities("<>"); expect(decoded).toBe("<>"); }); }); });