mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-24 17:03:55 +10:00
63 lines
2.5 KiB
TypeScript
63 lines
2.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { sampleResumeData } from "@reactive-resume/schema/resume/sample";
|
|
import { getResumeExportData } from "./export-sections";
|
|
import { buildMarkdown, htmlToMarkdown } from "./markdown";
|
|
|
|
describe("htmlToMarkdown", () => {
|
|
it("converts the constrained tiptap tag set", () => {
|
|
const html = "<p>Led <strong>teams</strong> of <em>engineers</em>.</p><ul><li>Shipped X</li><li>Owned Y</li></ul>";
|
|
expect(htmlToMarkdown(html)).toBe("Led **teams** of _engineers_.\n\n- Shipped X\n- Owned Y");
|
|
});
|
|
|
|
it("converts anchors to Markdown links and decodes entities", () => {
|
|
expect(htmlToMarkdown('<p>See <a href="https://x.com">Tom & Jerry</a></p>')).toBe(
|
|
"See [Tom & Jerry](https://x.com)",
|
|
);
|
|
});
|
|
|
|
it("returns an empty string for empty input", () => {
|
|
expect(htmlToMarkdown("")).toBe("");
|
|
});
|
|
});
|
|
|
|
describe("buildMarkdown", () => {
|
|
// Section titles are stored empty and resolved by the caller; mimic that with a simple resolver.
|
|
const resolveTitle = (sectionId: string) =>
|
|
({ summary: "Summary", experience: "Experience", education: "Education" })[sectionId];
|
|
const md = buildMarkdown(getResumeExportData(sampleResumeData, "resume"), resolveTitle);
|
|
|
|
it("emits the name as an H1 and headline as emphasis", () => {
|
|
expect(md.startsWith(`# ${sampleResumeData.basics.name}`)).toBe(true);
|
|
expect(md).toContain(`_${sampleResumeData.basics.headline}_`);
|
|
});
|
|
|
|
it("renders resolved section headings as H2", () => {
|
|
expect(md).toContain("## Experience");
|
|
});
|
|
|
|
it("falls back to the stored title when no resolver is given", () => {
|
|
const bare = buildMarkdown(getResumeExportData(sampleResumeData, "resume"));
|
|
expect(bare).not.toContain("## Experience");
|
|
});
|
|
|
|
it("ends with a single trailing newline and never contains raw HTML tags", () => {
|
|
expect(md.endsWith("\n")).toBe(true);
|
|
expect(md).not.toMatch(/<[a-z][^>]*>/i);
|
|
});
|
|
|
|
it("excludes the cover letter from the resume scope and includes it in the cover-letter scope", () => {
|
|
const cover = buildMarkdown(getResumeExportData(sampleResumeData, "cover-letter"));
|
|
expect(cover.length).toBeGreaterThan(0);
|
|
expect(cover).not.toBe(md);
|
|
});
|
|
|
|
it("renders the cover-letter scope without resume header or section heading", () => {
|
|
const cover = buildMarkdown(getResumeExportData(sampleResumeData, "cover-letter"));
|
|
|
|
expect(cover).toContain("Dear Hiring Manager");
|
|
expect(cover).not.toContain(`# ${sampleResumeData.basics.name}`);
|
|
expect(cover).not.toContain(`_${sampleResumeData.basics.headline}_`);
|
|
expect(cover).not.toContain("## Cover Letter");
|
|
});
|
|
});
|