feat!: replace Karma and Jasmine with Vitest (v1.0.0) - #34
Conversation
|
Two things this touches that are already open here:
🤖 Generated with Claude Code |
etimberg
left a comment
There was a problem hiding this comment.
Happy to go this direction. I generally use vitest professionally these days but haven't thought about switching chart.js to use it. Maybe claude can help there too
Karma was deprecated in 2023, and most of what this package did existed to
work around it: scanning `__karma__.files` to find fixtures, reading every
fixture config back over `XMLHttpRequest`, and registering matchers through
`jasmine.addMatchers`. None of it has a counterpart in a bundler-driven
runner, so v1 drops the Karma and Jasmine peers instead of keeping a second
entry point alive beside them. Consumers still on Karma stay on 0.5.x.
What the rendering rules do is unchanged, and so are the reference images
captured with them: the sprite sheet, the wrapper CSS, `devicePixelRatio = 1`
and the pixelmatch comparison all behave as before. pixelmatch moves 5 -> 7,
where `checkerboard` blending became the default in 7.2.0; that is a different
measurement rather than a stricter one, so the matcher keeps blending against
white and a fixture opts into the checkerboard per comparison.
Notable changes:
- `setup({Chart})` takes the Chart.js constructor instead of reading a global.
Karma loaded the UMD bundle into `window`, a bundler does not.
- `createFixtures({configs, images})` takes the resolved file maps, because
`import.meta.glob` resolves against the file the literal pattern is written
in. The glob has to stay in the consumer; only the map can move here.
- `pending()` becomes `ctx.skip()`, so `useShadowDOM` and `useOffscreenCanvas`
need the test context passed to `acquireChart`.
- Fixture images are rewritten by a `saveFixtureImage` browser command
(`chartjs-test-utils/node`), registered only when updating. The suite detects
the mode from the command's presence rather than a `define` flag, which
Vitest re-encodes: `JSON.stringify(false)` arrives as the truthy string
"false" and every fixture quietly rewrites itself while reporting a pass.
- The package publishes its sources instead of a rollup bundle, so pixelmatch
resolves as a normal dependency rather than being inlined.
- The package now tests itself: node specs for the option matcher and the mock
context, and a browser suite that renders two fixtures in Chromium and
Firefox. CI installs both browsers and runs lint, typecheck and both suites.
Verified against a real suite: chartjs-chart-treemap's browser tests (63 pixel
fixtures plus the controller specs, 142 tests across both browsers) pass with
its `test/utils` replaced by this package and no reference image regenerated.
That run is what caught the sprite sheet being decoded lazily, which silently
dropped text from the first fixture that drew any.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
BREAKING CHANGE: Karma and Jasmine are no longer supported. The package
requires Vitest, `setup({Chart})` must be called from a setup file, and
`specsFromFixtures` is now built by `createFixtures`.
It very likely can 😄 |
Rebased on master now that chartjs#33 has landed. The mechanical part of the rebase kept this branch's files; this commit is the part that is not mechanical. - eslint and eslint-config-chartjs are gone from `devDependencies`, `lint` and `format` are Biome, and the `eslint-disable` pragmas in the new sources are gone: two for `callback-return`, a rule Biome does not have, and two for `no-console`, now `biome-ignore lint/suspicious/noConsole` with the reason on the same line -- a reason wrapped onto the next line suppresses nothing and reports itself as an unused suppression. - `biome.jsonc` lints `.ts` and `.mjs` too, so the Vitest configs and the fixture script are covered. - The rule exceptions chartjs#33 needed for the ES5-era sources are lifted: `useArrowFunction`, `noArguments`, `useOptionalChain`, `useTemplate` and `noInnerDeclarations` are back on Biome's recommended settings, because the rewrite has no `var`-in-block, `arguments` or string concatenation left. `src/spriting.js` keeps `useOptionalChain` off in an `overrides` block: it is a port of the 0.5.0 sprite sheet, and rewriting `text && text.charCodeAt` as `text?.charCodeAt` is equivalent only because the loops iterate over `text.length`. - With those rules on, Biome found four real things in the new code, all fixed rather than silenced: three `forEach` callbacks whose concise arrow bodies returned a value (now `for...of`), the `chart.$test || {}` guards (now optional chaining), a `var me = this` left useless once the mock context's method wrappers became arrows, and nine string concatenations in the matcher messages -- which the unit specs assert verbatim, so they are covered. - `recommended: true` is deprecated in Biome 2.5; it is now `preset: "recommended"`. `biome check` is clean with no warnings. The suites still pass: 7 node specs, 24 browser specs plus the 2 deliberate skips, and chartjs-chart-treemap's browser suite -- 142 tests across Chromium and Firefox -- still passes against this package with no reference image regenerated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Rebased onto
Re-verified after the rebase, not assumed: If you would rather review the delta than the whole thing again, the second commit ( 🤖 Generated with Claude Code |
@etimberg — this is a proposal, and the question underneath it is yours to answer before the code matters: is Chart.js heading to Vitest? If the answer is no, this PR should be closed rather than merged; a major nobody adopts is worse than a dormant
0.5.0. If the answer is yes, or maybe, here is a worked path with the traps already paid for.Why a major rather than a Vitest entry beside the Karma one
Karma was deprecated in 2023. Most of what this package does exists to work around it: scanning
__karma__.filesto discover fixtures, reading every fixture config back over a synchronousXMLHttpRequest, registering matchers throughjasmine.addMatchers, and calling Jasmine's globalpending()from inside a helper. None of that has a counterpart in a bundler-driven runner.My first draft kept the Karma entry and added Vitest as a subpath. That optimizes for a case that does not exist: a major breaks nobody precisely because it is a major. The seven repos that depend on this package (Chart.js, annotation, datalabels, zoom, and the date-fns, luxon and moment adapters) pin
^0.5.0and will not see1.0.0until they choose to. Two entries in one package would instead keep the Karma core alive forever with nobody benefiting.So:
1.0.0is Vitest-only, and0.5.xstays available for Karma consumers.What does not change
The rules that make chart pixels comparable across browsers and platforms are untouched, and so are the reference images captured with them: the text sprite sheet, the wrapper CSS,
devicePixelRatio = 1, and the pixelmatch comparison.pixelmatchmoves^5→^7, where 7.2.0 madecheckerboardblending the default — that is a different measurement rather than a stricter one (each goes blind where the ink colour meets the background it is blended against), so the matcher keeps blending against white and a fixture can opt into the checkerboard once its reference image has been re-validated against it.What changes for a consumer
Chartis injected because Karma loaded the UMD bundle intowindowand a bundler does not.import.meta.glob(likerequire.context) resolves against the file the literal pattern is written in, so fixture discovery cannot move into the package — only the resolved maps can be passed in. This shapes the whole API and is the one constraint worth knowing before reading the diff.Jasmine's
pending()has no global equivalent, so options that not every browser supports take the test context:Traps this already accounts for
launchorlaunchOptionson abrowser.instances[]entry and silently ignores both. Verified by pointingexecutablePathat a file that does not exist and watching the run pass anyway.defineflag is re-encoded by Vitest:JSON.stringify(false)arrives in the browser as the string"false", which is truthy — every fixture then rewrites itself while reporting a pass. SosaveFixtureImage(chartjs-test-utils/node) is registered only when updating, and its presence is the switch.rootDir: srckeeps the Vitest configs out of the existing projects, so a typo'd or ignored key goes unnoticed.tsconfig.tooling.jsonis in the typecheck chain, and it is what caught thelaunchtrap above.istanbul. Vitest refuses v8 as soon as a non-Chromium instance is configured, because v8 coverage comes over the Chrome DevTools Protocol.Evidence
A green check and "not measured" look the same from outside, so:
ctx.skip()path exercised deliberately.test/utilsreplaced by this package, with no reference image regenerated.Imagethat has not finished decoding draws nothing, so text vanished from the first fixture that drew any — and the reference captured under the same flaw compared clean. The sheet decodes at import again, guarded so a node import does not touchImage.npm pack+ install into a scratch project: the entry andchartjs-test-utils/nodeboth resolve through the package name, deep imports are blocked by theexportsmap, andpublintis clean.Packaging note
The package publishes its sources instead of a rollup bundle, so
pixelmatchresolves as a normal dependency rather than being inlined, and theexportsmap can keep the node-only fixture writer (node:fs) out of the browser entry. CI runs lint, typecheck and both suites on Node 24 with Chromium and Firefox installed.ESLint stays at 8 here because
eslint-config-chartjsis eslintrc-only; #33 proposes Biome instead, which removes that constraint. The two PRs are independent and will conflict textually insrc/andpackage.json— whichever lands first, I will rebase the other.Not in this PR
Migrating the Chart.js suite itself. It is an order of magnitude larger than any plugin repo I have migrated, and that migration needs a Chart.js maintainer driving it. This offers a path, not a commitment to walk it for you.
🤖 Generated with Claude Code