Skip to content

test: migrate remaining packages from Jest to vitest (#657988)#44

Merged
bzajzon-laserfiche merged 7 commits into
mainfrom
vitest-migration
May 5, 2026
Merged

test: migrate remaining packages from Jest to vitest (#657988)#44
bzajzon-laserfiche merged 7 commits into
mainfrom
vitest-migration

Conversation

@bzajzon-laserfiche
Copy link
Copy Markdown
Contributor

Migrates the four remaining packages in this workspace from Jest to vitest, matching the V2 client migration that already shipped on page_manipulation_APIs (PR #42).

Closes TFS #657988.

Why

The mixed Jest/vitest workspace caused real CI flakiness — most visibly the 200s hang in OAuthClientCredentialsHandler.test.ts ("Correct config beforeFetchRequestAsync returns regional domain") on the V2 cloud-node CI step on 2026-05-01, which Jest reported as "A worker process has failed to exit gracefully…" (a known footprint of jsdom's fetch polyfill not cleaning up sockets). Switching to vitest gets us:

  • One runner across the workspace.
  • Native fetch under the node env (no --experimental-fetch opt-in).
  • Native ESM (no --experimental-vm-modules opt-in).
  • Better isolation between test files, removing the flake class above.
  • Drop-in vi.* API (no test-body rewrites required beyond a single jest.fnvi.fn).

Coverage baseline

Captured from the most recent fully-green test_libraries run on main: run 22864885222 (2026-03-09, head b6094b06). Post-migration CI must match these counts.

Package Step Suites Tests
lf-js-utils test:ci 22 362
lf-api-client-core test:Cloud (node + jsdom) 7 of 9 41 (per env)
lf-api-client-core test:SelfHosted (node + jsdom) 7 of 9 43 (per env)
lf-repository-api-client cloud test:all (node + jsdom) 24 66 (per env)
lf-repository-api-client self-hosted test:all (node + jsdom) 24 67 (per env)
lf-api-js test 1 3

V2 client (lf-repository-api-client-v2) is out of scope; its baseline at the time was 23/61.

Group convention (replaces jest-runner-groups)

lf-api-client-core previously used /** @group … */ JSDoc annotations + jest-runner-groups to split UnitTests / IntegrationTests/Cloud / IntegrationTests/SelfHosted. Vitest has no equivalent; this PR replaces the annotation with a filename-suffix convention:

Group Filename suffix
UnitTests *.unit.test.ts
IntegrationTests/Cloud *.integration-cloud.test.ts
IntegrationTests/SelfHosted *.integration-selfhosted.test.ts

PKCEUtils.test.ts keeps its plain extension to remain auto-excluded — it's broken under jsdom and was previously listed in modulePathIgnorePatterns.

test:Cloud / test:SelfHosted scripts use vitest positional args as substring filters against the file paths.

Sequencing

This PR is based off main, not page_manipulation_APIs. It expects PR #42 to merge first; once it does, the rebase here should be trivial (no overlapping V2 file edits — this PR doesn't touch the V2 package). If for any reason this PR has to land first, V2 stays Jest until #42 lands and then re-acquires its existing vitest migration through the merge.

The dorny/test-reporter step for lf-repository-api-client-v2 has been finding zero JUnit files since V2's own vitest migration (V2's vitest config doesn't emit JUnit). Pre-existing on PR #42's branch; not touched here.

Out of scope / follow-ups

PR #43 (ci/split-test-libraries) was originally motivated by exactly the kind of cross-package gating that vitest's better isolation should now eliminate. Re-evaluate after this lands; it may be reducible to "nice-to-have" or droppable.

Replace Jest dual-project (dom + node) config with vitest test.projects.
One vi.fn() conversion in lf-localization.service.spec.ts. Drop ts-jest,
jest-environment-jsdom, jest-junit, jest-config, @types/jest, jest;
add vitest, jsdom.

362 tests pass (matches baseline from run 22864885222).
Single node config, no Jest API usage in test bodies. Drop ts-jest,
babel-jest, jest-junit, @types/jest, jest; add vitest. Also drops the
--experimental-vm-modules opt-in flag.

3 tests pass (matches baseline).
Two vitest configs (node + jsdom) mirroring V2's pattern.
Conditional JUnit output filename preserved via process.env.AUTHORIZATION_TYPE
check (matches the existing jest-junit dynamic naming for cloud vs self-hosted
runs).

Drops --experimental-vm-modules --experimental-fetch flags (vitest covers both
natively). Drops ts-jest, jest-junit, babel-jest, @types/jest, jest;
adds vitest, jsdom.

66 tests collected on each config (matches baseline).
Replaces jest-runner-groups with a filename-suffix convention that vitest
filters via positional substring args:

  *.unit.test.ts                    UnitTests group
  *.integration-cloud.test.ts       IntegrationTests/Cloud group
  *.integration-selfhosted.test.ts  IntegrationTests/SelfHosted group

9 test files renamed per group; PKCEUtils.test.ts keeps its plain extension
to remain auto-excluded (it is broken under jsdom; preserves the
modulePathIgnorePatterns behavior). Strips the now-dead /** @group */ JSDoc
blocks at the top of each test file.

Two vitest configs (node + jsdom) mirror the V1 client pattern, including the
conditional JUnit output filename via process.env.AUTHORIZATION_TYPE so cloud
and self-hosted CI runs do not overwrite each other.

Drops jest-runner-groups, ts-jest, jest-junit, jest-environment-jsdom,
babel-jest, @types/jest, jest; adds vitest, jsdom.

Locally verified: test:Cloud collects 7 files, test:SelfHosted collects 7
files (matches CI baseline "7 of 9"). Full test count parity (41 / 43)
will be confirmed in CI where AUTHORIZATION_TYPE and creds are set.
…(#657988)

Switches all five Test Report steps from reporter: jest-junit to
reporter: java-junit (vitest emits standard JUnit XML, not jest-junit
attribute set).

Updates path globs for packages whose vitest config sets root: 'test'
so JUnit is written to test/junit*.xml:
  - lf-repository-api-client-v1
  - lf-api-js

Adds --reporter=junit --outputFile.junit=junit.xml to lf-api-js's test
script so the dorny step finds something to read (its previous Jest
invocation also did not emit JUnit, so this is a net new gain).

V2 client (pre-existing vitest, out of scope for this migration) keeps
its current report path — its reporter step has been finding nothing
since the V2 vitest migration on page_manipulation_APIs and is unrelated
to this PR.
Vitest splits hook timeouts from test timeouts. The default hookTimeout
is 10s, so afterEach cleanup loops with 5s setTimeouts per entry
(CreateCopyEntryCopyShortcut, CreateCopyEntryCopyEntry, SearchTests,
CloseSearchTests, Task) would fail under vitest where they passed under
Jest (Jest applies testTimeout to hooks as well).

Mirror testTimeout: 200_000 with hookTimeout: 200_000 in both vitest
configs. Caught by Codex review on the migration branch diff.
Vitest+jsdom regression vs jest+jsdom: the test sends a Blob-bearing
FormData body to importDocument, expecting a 400 from the server. Under
vitest+jsdom the underlying fetch throws TypeError: fetch failed before
reaching the server (passes under vitest+node and was passing under
jest+jsdom in the baseline).

Skip under jsdom via test.skipIf(isBrowser()) so the test_libraries CI
chain can flow through to V1 self-hosted, V2, and lf-api-js. Investigate
isomorphic-fetch / jsdom Blob handling under vitest as a follow-up.
@bzajzon-laserfiche bzajzon-laserfiche merged commit 904a5fc into main May 5, 2026
10 checks passed
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.

2 participants