← Files DataARCHIVED FILE

templates/data-app/base/tests/chart-export.test.mjs

5.41 KB · Sep 30, 2026 · 23:19 UTC

↓ Download file

import assert from "node:assert/strict";
import test from "node:test";
import { chartExportAppearance, chartExportControls, chartExportFilename, chartExportMetadata, chartExportPresets, chartExportProvenance, chartExportSize, chartExportSpec } from "../src/chart-export.js";

test("export dimensions are finite and bounded, and presets retain their advertised ratios", () => {
  assert.deepEqual(chartExportSize(NaN, Infinity), { width: 1000, height: 600 });
  assert.deepEqual(chartExportSize(-1, 9000), { width: 320, height: 2400 });
  for (const preset of chartExportPresets.filter(item => item.width)) {
    assert.deepEqual(chartExportSize(preset.width, preset.height), { width: preset.width, height: preset.height });
  }
  assert.equal(chartExportFilename("Revenue / Q3?"), "Revenue-Q3.png");
});

test("destination presets retain useful image sizes without mock contexts", () => {
  assert.deepEqual(chartExportPresets.map(({ id }) => id), ["original", "slide", "document", "slack", "custom"]);
  assert.deepEqual(chartExportPresets.filter(item => item.width).map(({ id, width, height }) => [id, width, height]),
    [["slide", 920, 480], ["document", 720, 400], ["slack", 640, 400]]);
  assert.ok(chartExportPresets.find(item => item.id === "document").adaptiveHeight);
  assert.ok(chartExportPresets.find(item => item.id === "slack").adaptiveHeight);
});

test("export options preserve the reviewed spec, filters, annotations and values", () => {
  const chart = Object.freeze({ type: "line", x: "date", y: "value", startAtZero: false,
    annotations: [{ id: "launch", kind: "event", at: "2026-08-01", field: "launch", label: "Launch" }],
    showValues: false, showXAxisLabel: false });
  const next = chartExportSpec(chart, { axes: true, values: true });
  assert.equal(chart.showValues, false);
  assert.equal(next.showValues, true);
  assert.equal(next.showXAxisLabel, false, "export never invents an axis title that was intentionally omitted");
  assert.equal(next.annotations, chart.annotations);
  assert.equal(next.startAtZero, false);
  assert.equal(chartExportControls({ type: "funnel" }).axes, false);
  assert.equal(chartExportControls({ type: "bar", presentation: {} }).values, false);
});

test("provenance uses recorded source metadata without SQL, private file paths, or invented dates", () => {
  const text = chartExportProvenance({ source: { label: "Reviewed workbook", files: ["/private/input/workbook.xlsx"],
    sql: "SELECT confidential FROM internal", executedAt: "invalid", url: "https://example.com/source?token=secret" } },
    [{ label: "Plan", value: "Team" }]);
  assert.match(text, /Reviewed workbook/u);
  assert.match(text, /workbook.xlsx/u);
  assert.match(text, /Plan: Team/u);
  assert.doesNotMatch(text, /private|confidential|internal|secret|Captured/u);
  assert.equal(chartExportProvenance({}), "");
});


test("export appearance is scoped, preserves the current theme, and provides light and dark palettes", () => {
  assert.deepEqual(chartExportAppearance("original", "auto"), { "--surface": "#fff" });
  assert.deepEqual(chartExportAppearance("original", "auto", "dark"), {});
  const light = chartExportAppearance("codex-classic", "light");
  const dark = chartExportAppearance("codex-classic", "dark");
  assert.equal(light.colorScheme, "light");
  assert.equal(light["--surface"], "#fff");
  assert.equal(dark.colorScheme, "dark");
  assert.equal(light["--text"], "#1a1c1f");
  assert.equal(dark["--text"], "#fff");
  assert.notEqual(light["--surface"], dark["--surface"]);
  assert.deepEqual(chartExportAppearance("original", "dark"), dark);
  assert.deepEqual(chartExportAppearance("dark-pixel", "light"), light);
  assert.equal(chartExportAppearance("dark-pixel", "dark")["--surface"], "#181c18");
  assert.equal(chartExportAppearance("scientific-blue", "dark")["--surface"], "#172131");
});


test("source and filters are separate export fields without changing source semantics", () => {
  const metadata = chartExportMetadata({ source: { label: "Reviewed workbook", executedAt: "2026-08-01T00:00:00Z" } },
    [{ label: "Plan", value: "Team" }, { label: "Region", value: "all" }]);
  assert.deepEqual(metadata, { source: "Source: Reviewed workbook · Captured Aug 1, 2026", filters: "Plan: Team" });
  assert.deepEqual(chartExportMetadata({}), { source: "", filters: "" });
});

test("export dates use human-readable labels without changing days, ranges or selections", () => {
  const filters = Object.freeze([
    Object.freeze({ label: "Week of", value: "2026-08-17" }),
    Object.freeze({ label: "Date range", value: "2026-08-17..2026-08-23" }),
    Object.freeze({ label: "Selected days", value: Object.freeze(["2026-08-17", "2026-08-23"]) }),
    Object.freeze({ label: "Plan", value: "Team" }),
  ]);
  const metadata = chartExportMetadata({}, filters);
  assert.match(metadata.filters, /Week of: Aug 17, 2026/u);
  assert.match(metadata.filters, /Date range: Aug 17\s*–\s*23, 2026/u);
  assert.match(metadata.filters, /Selected days: Aug 17, 2026, Aug 23, 2026/u);
  assert.match(metadata.filters, /Plan: Team/u);
  assert.equal(filters[0].value, "2026-08-17");
  assert.match(chartExportMetadata({}, [{ label: "Period", value: "2025-12-29..2026-01-04" }]).filters,
    /Dec 29, 2025\s*–\s*Jan 4, 2026/u);
  assert.equal(chartExportMetadata({}, [{ label: "Date", value: "2026-02-30" }]).filters, "Date: 2026-02-30");
  assert.equal(chartExportMetadata({}, [{ label: "Period", value: "2026-08-23..2026-08-17" }]).filters,
    "Period: 2026-08-23..2026-08-17");
});

SHA-256: 75058d0597492267d1e967f6d135da03f9d586c5bf3ac0503a8b5984e09208ce