Skip to content

Migrate chai and sinon to vitest - #220

Open
Michiel-VandeVelde wants to merge 33 commits into
LinkedDataFragments:masterfrom
Michiel-VandeVelde:improve-test-coverage-vitest-js
Open

Migrate chai and sinon to vitest#220
Michiel-VandeVelde wants to merge 33 commits into
LinkedDataFragments:masterfrom
Michiel-VandeVelde:improve-test-coverage-vitest-js

Conversation

@Michiel-VandeVelde

Copy link
Copy Markdown
Contributor

No description provided.

Splits the Mocha->Vitest and JS->TS conversions into two steps so each
diff stays small and reviewable. This is step 1: syntax only, no types.
…PatternFragmentsHtmlView

feature-webid/controllers: 16% -> 80%, including a second pre-existing bug
found along the way (not fixed): _verifyWebID's predicate switch compares
an N3 term object to string literals with ===, so it never matches.
feature-summary/views/summary: 18% -> 100%.
QuadPatternFragmentsHtmlView.ts: 54% -> ~100%.
Util.ts: 87% -> 100% statements.
UrlData.ts: found a third pre-existing bug along the way (not fixed):
options.assetsPath is always ignored, since baseURLPath + 'assets/' is
never an empty string and short-circuits the || fallback.
EmptyDatasource/IndexDatasource: 50%/26% -> ~100%.
View.ts/ViewCollection.ts: cover the view-extension rendering paths.
Error/Forbidden/NotFound HtmlView: cover their template-selection logic.
HtmlView.ts: 35% -> 79%. The remaining gap is qejs's actual render call,
which can't be exercised here: qejs resolves template paths via
require.main.filename, which Vitest's module runner never sets, so every
real qejs.renderFile call fails structurally under this test setup. Only
the resulting error-handling path is covered; the success path isn't
reachable in tests.
… feature-webid

Datasource.ts: 96% -> 98.5% (graph-side blank-node translation, forced
default graph without quad support).
SparqlDatasource.ts: 92% -> 100% (_encodeObject/_convertLiteral edge cases).
QuadPatternFragmentsController.ts: 88% -> 96.5% (extension chain, including
the error-logging path, and close()).
WebIDControllerExtension.ts: 80% -> 90% (the full HTTPS + TLS _handleRequest
flow). The remaining gap is the predicate switch in _verifyWebID, already
established as unreachable dead code.
CliRunner.ts: 90.47% -> 98.41% (SIGHUP abort-before-listening and
already-in-progress paths). The one remaining line is a defensive
"workers.pop() returned nothing" fallback inside the respawn loop that
appears structurally unreachable given the surrounding control flow.
LinkedDataFragmentsServer.ts: covered the default no-op _log fallback.
Constructor validation, controller ordering, datasource error handling,
logging setup, and run()'s full lifecycle (listen-when-ready, port
override, SIGINT stop, forced second-SIGINT exit) — all driven through
stubbed process.once/on, matching the pattern CliRunner-test.js already
uses for process/signal handling, so nothing is ever registered on the
real process listeners.

Found a fourth pre-existing bug along the way (not fixed): access-log's
own implementation treats a `null` third argument as an options object,
since `typeof null === 'object'` — so the accesslogger this file builds
throws every time it's actually invoked. Access logging is completely
broken; the test documents that rather than working around it.
feature-memento, feature-qpf, and feature-summary

Controller.ts is now at 100% branches. Small, previously-untested
branches closed: pre-built ViewCollection reuse, an already-set
parsedUrl/Vary header, a Forwarded header without proto, a
double-invoked next()/done(), View's error-to-response-emit path,
N3/RdfaDatasource's file-option fallback, DatasourceRouter's
missing-parsedUrl fallback, SummaryController with no configured
summaries directory, MementoHtmlViewExtension with no timegates
configured, and QuadPatternFragmentsRdfView's no-pageUrl short-circuit.
…ller

Datasource.ts: subject/object blank-node translation on both the query
and result side, plus select() without an onError callback. (Several
other flagged branches on this file turned out to be a coverage-tool
sourcemap artifact, not real gaps — confirmed by checking raw lcov
statement hit counts, which showed those exact lines executing
thousands of times across the existing HDT/SPARQL integration tests.)

QuadPatternFragmentsController.ts is now at 100% branches:
_createPatternString's full term/graph matrix, the error-without-stack
log path, and the previousPageUrl branch on page >= 2.
Closes the last real branch gap in Util.ts: no existing test
constructed an error without a message, so the `message || ''`
fallback was never exercised.
…r tests

qejs's template resolver reads require.main.filename when resolving a
template referenced via inherits(...). Vitest's workers have no classic
CommonJS entry script, so require.main is undefined there and that access
throws. The throw happens inside an unterminated Q promise chain, so Q
silently swallows it instead of surfacing it, and response.emit('error', ...)
throwing for the same reason (no listener attached) skips the response.end()
call right after it, leaving the response hanging forever.

Fix: a Vitest setupFiles script sets process.mainModule if unset, so
require.main resolves the way qejs assumes. Un-skip the 3 describe blocks
this was blocking, and stop forcing NotFoundHtmlView/NotFoundRdfView's
require() onto the compiled .js output, matching how the rest of the suite
requires views (extensionless, resolving through Vite to .ts source).
…r), Controller, HtmlView, SparqlDatasource, and N3ParserExtended; ignore coverage/
…iewExtension regressions from upstream refinement
@Michiel-VandeVelde

Copy link
Copy Markdown
Contributor Author

@jitsedesmet ready for review :)

@jitsedesmet
jitsedesmet self-requested a review August 21, 2026 12:21

@jitsedesmet jitsedesmet left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sampled some files, and I found two things. By no means is this a complete review, but since I expect I'll have less to say beyond this, I would request these changes already.

(I also expect the line diff for these changes might be great and would unpin all my file-views)

Comment thread test/DummyServer.js Outdated
Comment thread packages/datasource-sparql/test/datasources/SparqlDatasource-test.js Outdated
sinon's stub/spy API predates vitest and duplicates functionality vitest
already provides natively; dropping it removes a devDependency and lets
every test file use one consistent mocking API.
Leftover node >=10.0 pin from before the modernization work; the root
package.json's devDependencies (e.g. @types/node ^22) already reflect
the actual supported Node version.
Enables avoid-new, prefer-await-to-then, and prefer-await-to-callbacks
on *-test.js files, matching the modern-async-only style Comunica's own
eslint config pushes for the same reason: vitest/supertest are already
promise-based, so wrapping them back in new Promise((done) => ...) or
driving them through .then()/callbacks is no longer necessary.
Lets callers (including its own tests) await the actual build/instantiate
completion signal instead of guessing how many event-loop ticks the
internal promise chain takes to settle. runCli discards the returned
promise explicitly with void, following this codebase's existing
convention for intentionally-unhandled promises (see HtmlView.ts).
Replaces new Promise((done) => ...) test-body wrappers, supertest
.end(callback) chains, and .then() chains with async/await throughout.
Event/callback-based APIs (EventEmitter, datasource.close(cb), etc.) are
bridged via Node's built-in events.once()/util.promisify() instead of
hand-rolled new Promise(); genuine one-off deferred promises use
Promise.withResolvers() instead. A few test doubles that must themselves
mimic a callback-based API keep callbacks with a targeted eslint-disable
explaining why.

Converting HtmlView-test.js surfaced 3 tests that were silently ignoring
the render callback's error argument, masking a template-rendering gap
in the test fixtures (missing the title/header/assetsPath/baseURL
defaults View.render() normally merges in) — fixed by spreading
view._defaults into those tests' options to match the real calling
convention.
Promise.withResolvers() is Node 22+ (ES2024), but CI tests against
Node 20.x/22.x/24.x — the 20.x job failed with "Promise.withResolvers
is not a function" since that was only verified locally on Node 22.
Added a plain-Promise-based withResolvers() to test/test-helpers.js
(outside the promise/avoid-new rule's *-test.js glob) and switched all
call sites to import it instead of using the native version.
It was in yarn.lock (and my local node_modules from an earlier yarn add)
but never actually landed in package.json, so a real clean install --
like CI's -- had nothing to install it from, breaking the lint job with
"ESLint couldn't find the plugin \"eslint-plugin-promise\"". Verified by
deleting node_modules/eslint-plugin-promise and reinstalling from
scratch.

@jitsedesmet jitsedesmet left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already a first part. The changes are nice improvements, but some of the tests that are added break the TS API we added previously, and I am hesitant to accept that. If this is needed in tests, it is possible. But I would wait until we migrate the test suite to TS before we decide what API-breaking tests we want to add; that way, we can be deliberate about them.

Comment thread test/test-helpers.js Outdated
Comment thread test/test-helpers.js Outdated
Comment thread test/DummyServer.js Outdated
Comment thread test/assets/test-key.pem Outdated
Comment thread test/assets/test-cert.pem Outdated
Comment thread packages/core/test/datasources/Datasource-test.js Outdated
Comment thread packages/core/test/datasources/Datasource-test.js Outdated
Comment thread packages/core/test/datasources/Datasource-test.js Outdated
Comment thread packages/core/test/datasources/Datasource-test.js Outdated
Comment thread packages/core/test/datasources/Datasource-test.js Outdated
Comment thread packages/core/test/routers/DatasourceRouter-test.js Outdated
Comment thread packages/core/test/views/error/ErrorHtmlView-test.js Outdated
Comment thread packages/core/test/views/error/ErrorRdfView-test.js Outdated
Comment thread packages/core/test/views/forbidden/ForbiddenHtmlView-test.js Outdated
Comment thread packages/core/test/views/notfound/NotFoundHtmlView-test.js Outdated
Comment thread packages/core/test/LinkedDataFragmentsServerWorker-test.js Outdated
Comment thread packages/core/test/LinkedDataFragmentsServerWorker-test.js Outdated
Comment thread packages/core/test/Util-test.js Outdated
Comment thread packages/datasource-composite/test/datasources/CompositeDatasource-test.js Outdated
Comment thread packages/datasource-composite/test/datasources/CompositeDatasource-test.js Outdated
Comment thread packages/datasource-hdt/test/datasources/ExternalHdtDatasource-test.js Outdated
Comment thread packages/datasource-hdt/test/datasources/ExternalHdtDatasource-test.js Outdated
promisify is Node-specific and required detaching close() from its
instance (needing .bind()) to wrap it. Calling close(resolve) as a
normal method avoids both: no Node-only API, and this stays correct
without an explicit bind.
Comment thread packages/core/test/datasources/Datasource-test.js Outdated
Comment thread packages/datasource-composite/test/datasources/CompositeDatasource-test.js Outdated
…mise executors

Promise.race([once(result, 'end'), promise]) was hard to follow; collecting
into resolve() directly inside a single new Promise executor is simpler and
covers the same success/error semantics. Once that was the only remaining
Promise.race use, and withResolvers had no non-trivial callers left, remove
the withResolvers helper entirely and inline new Promise(...) at every site.

@jitsedesmet jitsedesmet left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, good improvements

Comment thread packages/core/test/datasources/Datasource-test.js Outdated
Comment thread test/test-helpers.js Outdated
Comment thread test/test-helpers.js
Michiel-VandeVelde and others added 4 commits August 28, 2026 10:27
Co-authored-by: Jitse De Smet <35114273+jitsedesmet@users.noreply.github.com>
Co-authored-by: Jitse De Smet <35114273+jitsedesmet@users.noreply.github.com>
Co-authored-by: Jitse De Smet <35114273+jitsedesmet@users.noreply.github.com>
…file

The applied suggestion left a TypeScript return-type annotation
(: Promise<number>) in test/test-helpers.js, which isn't compiled through
tsc, so it failed to parse and broke every test file importing from here.
It also dropped the `once` import streamLength depends on. Fix both.
@jitsedesmet jitsedesmet changed the title Improve test coverage and change test suite to vitest Migrate chai and sinon to vitest Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants