Migrated 80 ghost/core unit tests to vitest (bin/shared/adapters/data/lib/web)#27900
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
WalkthroughUpdates Vitest configuration and test infra, disables strict c8 coverage thresholds, and adjusts the unit test script. Multiple unit test files are converted to Vitest-compatible patterns: suite timeouts moved to describe options, Mocha hook registrations standardized, before/after hooks replaced with beforeAll/afterAll where appropriate, and arrow callbacks changed to function() when using Mocha-style Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…/lib/web)
- expanded vitest's include glob to cover test/unit/{bin,shared,server/{adapters,data,lib,web}}
- 80 files / 821 tests pass under vitest; PR 1's 4 files still included
- mocha continues to run the same files in parallel (no mocha-side changes) — the 11s vitest cost on top of the existing mocha unit run is negligible, and dual-running gives us a safety net through PR 14 when mocha is removed entirely
- added before/after shim to vitest-setup.ts so mocha's before/after aliases work as beforeAll/afterAll without rewriting every test file
- per-file mocha-this fixes for the 3 files that needed them: lexical.test.js (this.timeout → describe-level options), sentry.test.js + importer/index.test.js (this.beforeEach → top-level beforeEach — these were technically already misuses in mocha that happened to work)
- 6 files using the mocha done() callback are excluded from vitest for now; vitest 4.x removed done() support, and converting ~50 callbacks to promises is its own focused follow-up PR. Listed explicitly in vitest.config.ts under exclude.
6d2c34d to
8e9b3a0
Compare
- the previous dual-runner approach in #27898/#27900 required every migrated file to be cross-compatible with both mocha and vitest, which broke down on lexical.test.js: `describe(name, {timeout}, fn)` is valid vitest syntax but mocha treats the options object as the `fn` arg, registers 0 tests, and leaves the suite stack open so subsequent files (mrr.test.js) get nested under it — that's the source of the 14 CI failures - shimming `before`/`after` onto vitest globals papered over one symptom but encouraged more dual-compat workarounds across the migration; dropping the shim and converting the 5 affected files to `beforeAll`/`afterAll` is the cleaner path - mocha now skips migrated bucket dirs (bin, shared, server/{adapters,api, data,lib,web}) while still running the 6 deferred `done()`-callback files explicitly; vitest is the sole runner for the migrated buckets - future migration PRs just shrink the mocha path list and grow the vitest include list, with no dual-compat constraint on individual test files
- moving 800+ tests from mocha to vitest in the prior commit dropped c8's numerator (it only instruments the mocha run) while leaving the denominator unchanged because c8's "all": true counts every source file in core/ regardless of whether mocha touches it - result: c8 reports 62.84% lines / 61.83% functions, below the old 65% gate even though true coverage (mocha + vitest combined) is unchanged - proper merge of vitest's v8 coverage into c8 isn't viable in this PR: vitest's `forks` pool workers don't flush V8 coverage on exit, and enabling @vitest/coverage-v8 breaks `require()` of `.ts` files (tsx loader hook conflict) - pragmatic fix: lower statements/functions/lines from 65 to 60 to match the mocha-only baseline. Branches (85) is unchanged — still passes at 85.47%. Worth a follow-up to merge coverage properly once a vitest/tsx combination supports it
There was a problem hiding this comment.
🧹 Nitpick comments (1)
ghost/core/.c8rc.json (1)
9-12: ⚡ Quick winAdd an explicit expiration/follow-up marker for lowered thresholds.
Lowering gates is understandable for this migration, but this can easily become permanent drift. Please add a nearby comment (or linked issue ID in commit/PR metadata) with a clear restore target so the 60% thresholds are temporary by contract, not convention.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ghost/core/.c8rc.json` around lines 9 - 12, The coverage thresholds for "statements", "branches", "functions", and "lines" are temporarily lowered to 60%; add an explicit expiration/follow-up marker so this change isn’t permanent drift by adding a clear adjacent comment or a linked issue/PR ID noting the restore target and date (e.g., restore thresholds to previous values or X% by YYYY-MM-DD) and reference the exact keys ("statements", "branches", "functions", "lines") in that comment so reviewers and automation can find and enforce the rollback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@ghost/core/.c8rc.json`:
- Around line 9-12: The coverage thresholds for "statements", "branches",
"functions", and "lines" are temporarily lowered to 60%; add an explicit
expiration/follow-up marker so this change isn’t permanent drift by adding a
clear adjacent comment or a linked issue/PR ID noting the restore target and
date (e.g., restore thresholds to previous values or X% by YYYY-MM-DD) and
reference the exact keys ("statements", "branches", "functions", "lines") in
that comment so reviewers and automation can find and enforce the rollback.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ff81a8f1-325f-4f39-90ea-61860b6ff9d0
📒 Files selected for processing (1)
ghost/core/.c8rc.json
- c8 only sees mocha's run; every PR that moves a bucket from mocha to vitest shrinks c8's covered-files count while the denominator (all source files in core/) stays constant - if the gate stays on, each migration PR has to lower the threshold to match — that's noise that masks real regressions - proper fix is to merge vitest and mocha coverage, but @vitest/coverage-v8 conflicts with the tsx loader (require'd .ts files fail to resolve) and vitest's forks pool workers don't flush V8 coverage on exit, so the merge isn't viable yet - removed thresholds and set check-coverage: false; reporters stay so the numbers are still visible. Re-enable a merged gate once the migration completes
no ref Final big bucket of the vitest migration (after #27898 / #27900 / #27974 / #27991 / #27992 / #27996) — moves `test/unit/server/services` (256 files, ~3290 tests) from mocha to vitest. It also fixes a **vitest worker-teardown bug** that this DB-heavy bucket exposed (the previous buckets happened not to trigger it).
Summary
Second in the planned sequence migrating
ghost/core's tests from mocha to vitest (after #27898). Expands vitest to covertest/unit/{bin,shared,server/{adapters,api,data,lib,web}}— 81 files / 824 tests.Update (post-review): the original approach ran each migrated file under both runners as a safety net. That broke down on
lexical.test.js— see findings below. Switched to vitest-only for migrated buckets: each bucket migration removes paths from mocha's run list and adds them to vitest's include glob. No more dual-compat constraint on individual files; future migrations are mechanical.What's changed
vitest.config.ts—includeexpanded to the new buckets; sixdone()-callback files stayexcluded (deferred to a focused follow-up; ~50 callbacks to convert to promises)package.json—test:unit:basenow lists the remaining mocha paths explicitly (unmigrated dirs + the six deferreddone()files), instead of scanning all of./test/unitvitest-setup.ts— kept the snapshot/port normalization and the bridgedmochaHooks; nobefore/aftershimtest/.eslintrc.js— addedbeforeAll/afterAllto globals so the vitest-only files lint cleanly.c8rc.json— disabled the coverage gate (reporters still run). See "Coverage gate" below.Findings from this bucket
describe(name, {options}, fn)is not valid Mocha syntax. Vitest accepts it, but Mocha treats the options object as thefnarg — the describe registers 0 tests and leaves the suite stack open, so subsequent files (e.g.mrr.test.js) end up nested under it. That's the source of the 14 failures on the previous run. Revertinglexical.test.jsto its originalthis.timeout(5000)would have worked in mocha but failed in vitest (thisis undefined), confirming there was no clean dual-compat option. Fix: lexical keeps the vitest-native{timeout: 5000}syntax and runs under vitest only.before/afteraren't vitest globals. Original PR aliased them invitest-setup.ts. Removed the shim and converted the 5 affected files in migrated buckets tobeforeAll/afterAll(storage/index, scheduling/utils, web/shared/middleware/brute, shared/config/loader, shared/config/adapter-config).thispatterns inside describes —lexical.test.js(this.timeout(5000)),sentry.test.jsandimporter/index.test.js(this.beforeEach(fn)). Thethis.beforeEachcalls were already mocha-API misuses (they happen to work because mocha bindsthisto the Suite object); replaced with top-levelbeforeEach(fn).done()callback — vitest 4.x removed support. Listed underexcludeinvitest.config.tsand explicitly included intest:unit:baseso they continue to run under mocha. Deferred to a focused follow-up PR:test/unit/server/adapters/scheduling/scheduling-default.test.jstest/unit/server/adapters/storage/local-images-storage.test.jstest/unit/server/lib/image/blog-icon.test.jstest/unit/server/lib/image/gravatar.test.jstest/unit/server/lib/package-json/parse.test.jstest/unit/server/web/api/middleware/cors.test.jsCoverage gate
c8 only sees mocha's run. Moving tests to vitest shrinks c8's covered-files count while the denominator (all source files in core/) stays constant, so coverage % drops on every migration PR even though true coverage is unchanged. If the gate stays on, each PR has to lower the threshold — pure noise.
Proper fix is to merge vitest's coverage into c8's report, but two blockers:
@vitest/coverage-v8instrumentation conflicts with thetsxloader:require('./bulk-filters')fails to resolve.tsfiles when coverage is enabledforkspool workers don't flush native V8 coverage on exit (NODE_V8_COVERAGE propagates, but the worker doesn't write itscoverage-<pid>.jsonbefore being torn down)For now:
check-coverage: false, reporters left on so numbers stay visible (~63% statements, ~62% functions, ~85% branches at this point). Re-enable a merged gate once the migration completes or a vitest+tsx coverage combo becomes viable.Test plan
pnpm test:vitest(fromghost/core): 81 files / 824 tests pass (+ 3 skipped)pnpm test:unit:base(mocha): 5689 tests pass — no more cross-file pollution from the broken describe options syntaxpnpm exec eslintclean for changed files