/** * Chart-renderer contract regression: the `range` scheme config form. * * The Theme Builder's Color panel writes a named scheme into `config.range.*`. * A bare scheme-name *string* passes vega-lite compile but Vega rejects it at * run ("Unrecognized scale range value"), silently blanking the chart — so the * panel must write the object form `{ scheme: name }`. This drives a real * vega-lite compile → vega parse → view run (renderer 'none', no DOM) over an * actual gallery spec to lock that in. (renderSpec itself is integration-heavy — * vega-embed + a live DOM — and is mocked in component tests; this covers the * config contract underneath it.) */ import { describe, expect, it } from 'vitest'; import { compile } from 'vega-lite'; import * as vega from 'vega'; import type { TopLevelSpec } from 'vega-lite'; import type { Config } from 'vega-lite'; import { THEME_PREVIEW_SPECS } from '@core/theme-preview-specs'; const nominalColorSpec = THEME_PREVIEW_SPECS.find((c) => c.id === 'line')! .spec as unknown as TopLevelSpec; async function run(config: Config): Promise { const view = new vega.View(vega.parse(compile(nominalColorSpec, { config }).spec), { renderer: 'none', }); await view.runAsync(); view.finalize(); } describe('range scheme config form', () => { it('renders with the { scheme } object form (what the Color panel writes)', async () => { await expect(run({ range: { category: { scheme: 'category20b' } } })).resolves.toBeUndefined(); }); it('renders with an explicit color array', async () => { await expect( run({ range: { category: ['#111111', '#222222', '#333333'] } }), ).resolves.toBeUndefined(); }); it('rejects a bare scheme-name string (the bug this guards against)', async () => { await expect( run({ range: { category: 'category20b' } as unknown as Config['range'] }), ).rejects.toThrow(/Unrecognized scale range value/); }); });