CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/chart-render-tests

Chart-render regression testing across the three chart-library families - Canvas (Chart.js: locator screenshot snapshot + `canvas.toDataURL()` diff with animations disabled), SVG (D3: `outerHTML` structural snapshot with generated-ID normalization + per-element data-binding tests), and declarative specs (Vega / Vega-Lite: JSON Schema validation + Vega-Lite → Vega compile test). Detects the family from package.json imports (chart.js / d3 / vega-lite), then applies the matching recipe; full per-library depth with citations in references/chartjs.md, references/d3.md, references/vega.md. Use when a dashboard or data product renders charts and their output needs regression coverage - before a chart-library major upgrade, after a theming change, or when runtime-generated Vega specs must be proven valid before render.

74

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

vega-advanced-spec-tests.mdreferences/

Vega/Vega-Lite advanced spec tests

Deep reference for the Vega side of chart-render-tests (vega.md). Consult after the core schema + structure + compilation gates pass, when adding render-time, composition, transform, interaction, or spec-snapshot coverage.

Render-to-SVG test

import { Vega } from 'react-vega';
import { create } from 'jsdom';

test('renders SVG with expected mark count', async () => {
  const dom = create('<div id="vis"></div>');
  global.document = dom.window.document;

  const view = new vega.View(vega.parse(vegaSpec))
    .renderer('svg')
    .initialize(dom.window.document.querySelector('#vis'))
    .run();

  const svg = await view.toSVG();
  // Use a parser to count <path>/<rect> elements
  const rectCount = (svg.match(/<rect/g) || []).length;
  expect(rectCount).toBe(4);  // 4 quarters
});

Multi-view composition test

Per the Vega-Lite docs, Vega-Lite supports faceting, layering, concatenation, repeating. Test each composition:

test('layered spec has 2 layers', () => {
  const spec = {
    layer: [
      { mark: 'line', encoding: {...} },
      { mark: 'point', encoding: {...} },
    ],
  };

  expect(validate(spec)).toBe(true);
  expect(spec.layer).toHaveLength(2);
});

test('faceted spec creates one view per category', async () => {
  const spec = {
    facet: { field: 'category', type: 'nominal' },
    spec: { mark: 'bar', encoding: {...} },
  };

  const compiled = vl.compile(spec).spec;
  const view = new vega.View(vega.parse(compiled)).renderer('svg').initialize(...).run();
  // Inspect view's data tables to verify N facets emerged
});

Data transform test

Per the Vega-Lite docs, transforms include "Aggregate, filter, bin, calculate, fold, pivot." Test transform output:

test('aggregate transform produces correct sum', () => {
  const spec = {
    data: { values: [
      { region: 'NA', revenue: 100 },
      { region: 'NA', revenue: 200 },
      { region: 'EU', revenue: 150 },
    ]},
    transform: [
      { aggregate: [{ op: 'sum', field: 'revenue', as: 'total' }],
        groupby: ['region'] },
    ],
    mark: 'bar',
    encoding: { x: { field: 'region' }, y: { field: 'total', type: 'quantitative' } },
  };

  const view = new vega.View(vega.parse(vl.compile(spec).spec));
  await view.runAsync();
  const data = view.data('source_0');
  expect(data.find(d => d.region === 'NA').total).toBe(300);
  expect(data.find(d => d.region === 'EU').total).toBe(150);
});

Interaction (parameters / selections)

Per the Vega-Lite docs, "Interactive parameters - Selections and value bindings" enable interaction. Test parameters resolve:

test('selection parameter filters data', async () => {
  const spec = {
    params: [{ name: 'brush', select: 'interval' }],
    data: {...},
    mark: 'point',
    encoding: {...},
    transform: [{ filter: { param: 'brush' } }],
  };

  // Compile, render, inject brush event, verify filtered data
  ...
});

Spec-snapshot regression

For complex spec-generation logic, snapshot the spec output:

test('quarterly-revenue spec snapshot stable', () => {
  const spec = generateBarSpec({
    x: 'quarter',
    y: 'revenue',
    title: 'Quarterly Revenue',
  });

  expect(spec).toMatchSnapshot('quarterly-revenue.spec.json');
});

When intentionally changing spec generation, regenerate snapshots: UPDATE_SNAPSHOTS=1 npm test.

SKILL.md

tile.json