sbuffkin_hexmaker/tests/integration/e2e-singleNote.integration.ts
isaprettycoolguy@protonmail.com 6aa885b5b2 feat: export module — PDF/Markdown for notes, hexes, maps, tables, workflows (1.2.0)
Adds a unified export pipeline under src/export/ with exporters for single notes,
structured hexes, maps (with reference table), random tables, and workflows
(with rolled samples). PDF rendering reuses Obsidian's MarkdownRenderer + theme
CSS; map PNG/PDF goes through a dedicated canvas renderer.

UI surface:
- "Export" tab in MapModal (PNG/PDF with overlay + size options)
- "Export" link in HexEditorModal + HexExportModal
- "Export PDF/Markdown" links in RandomTableView header
- "Export…" button in WorkflowEditorModal + WorkflowExportModal
- Commands: export current note (PDF/MD), current hex, current workflow
- File-menu items on any .md file: Export to PDF / Markdown

Other:
- New `exportFolder` setting (defaults to {worldFolder}/exports)
- hexGeometry: add hexSize / hexCenter / hexPolygonPoints / gridBoundingBox
- HexTableView + HexEditorModal: first-wins on duplicate palette names
  (matches HexMapView's .find() behaviour)
- Tests: unit + integration suites for all exporters; sim-vault fixture

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-05 20:46:41 -04:00

65 lines
2.1 KiB
TypeScript

/**
* End-to-end integration test for the single-note exporter (1.2).
* Drives the real `exportSingleNoteAsMarkdown` against the simulated vault.
*/
import { describe, it, before, after } from "node:test";
import expect from "expect";
import fs from "node:fs/promises";
import path from "node:path";
import os from "node:os";
import { MockHexmakerPlugin, MockTFile } from "../helpers/simVault";
import { exportSingleNoteAsMarkdown } from "../../src/export/exporters/singleNote";
let tmpDir: string;
let plugin: MockHexmakerPlugin;
before(async () => {
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "duckmage-e2e-sn-"));
plugin = new MockHexmakerPlugin(tmpDir);
});
after(async () => {
await fs.rm(tmpDir, { recursive: true, force: true });
});
describe("e2e: single-note exporter against sim-vault", () => {
it("exports a town note with frontmatter stripped and title prepended", async () => {
const file = plugin.app.vault.getAbstractFileByPath(
"towns/Saltwatch.md",
);
expect(file).toBeTruthy();
await exportSingleNoteAsMarkdown(plugin as never, file as MockTFile as never);
const out = await fs.readFile(
path.join(tmpDir, "exports/Saltwatch.md"),
"utf8",
);
// Title prepended since the source had no leading H1
expect(out.startsWith("# Saltwatch\n")).toBe(true);
// Frontmatter stripped
expect(out).not.toMatch(/population:/);
// Content preserved
expect(out).toMatch(/A small fishing town/);
expect(out).toMatch(/Maren Kell/);
});
it("does not double up the title when the note already has an H1", async () => {
const file = plugin.app.vault.getAbstractFileByPath(
"tables/treasure/gold pile.md",
);
expect(file).toBeTruthy();
await exportSingleNoteAsMarkdown(plugin as never, file as MockTFile as never);
const out = await fs.readFile(
path.join(tmpDir, "exports/gold pile.md"),
"utf8",
);
// gold pile.md has no H1 → title is prepended
expect(out.startsWith("# gold pile\n")).toBe(true);
// Single h1 only
const h1Count = (out.match(/^# /gm) ?? []).length;
expect(h1Count).toBe(1);
});
});