Skip to content

chore: migrate jest to @nx/jest plugin with swc-jest#160

Draft
X-Guardian wants to merge 9 commits intoopen-constructs:mainfrom
X-Guardian:chore/nx-jest
Draft

chore: migrate jest to @nx/jest plugin with swc-jest#160
X-Guardian wants to merge 9 commits intoopen-constructs:mainfrom
X-Guardian:chore/nx-jest

Conversation

@X-Guardian
Copy link
Copy Markdown
Contributor

@X-Guardian X-Guardian commented May 4, 2026

Description

The previous setup had the jest configuration duplicated across every package, with ts-jest doing TypeScript transforms on every test run and lerna run orchestrating package-level scripts that didn't understand the dependency graph. That meant slow tests, repeated boilerplate when adding a new package, and CI workflows that ran every package on every PR even when only one was affected.

This PR adopts the standard Nx jest setup. The motivations:

  • Speed. swc-jest replaces ts-jest, cutting per-package test time roughly 2-3x in local benchmarks. nx affected skips packages whose source (and upstream dependencies) didn't change, so PRs touching one package don't pay the full matrix cost.
  • Less boilerplate. A shared jest.preset.js plus a tiny per-package jest.config.js plus a .spec.swcrc replaces the bespoke ts-jest config each package carried. Adding a new package is now a copy-paste of three small files.
  • Correct build sequencing. The @nx/jest plugin honours dependsOn: ["^build"] from nx.json, so cross-package tests no longer fail with "module not found" when an upstream hasn't been built. The per-package pretest: yarn build workarounds disappear.
  • Coverage visibility. Coverage is now collected on every CI run and rendered as a markdown table on each job's run page, so reviewers can see which packages were exercised and at what coverage without leaving GitHub. No external service.
  • CI partitioning. Only three packages actually exercise the terraform binary in their tests; the others were paying the cost of a 2x terraform-version matrix for no reason. Tagging those three (needs:terraform) lets the rest run in a single, faster job.

Summary

Migrates the jest test pipeline from per-package ts-jest configs driven by lerna run to the @nx/jest plugin with shared swc-jest transformer, and rewires CI to use nx affected with coverage surfacing in the GitHub job summary.

Test runner

  • 9 packages converted: cdktn, cdktn-cli, @cdktn/commons, @cdktn/cli-core, @cdktn/hcl-tools, @cdktn/hcl2cdk, @cdktn/hcl2json, @cdktn/provider-generator, @cdktn/provider-schema.
  • Each package gets a .spec.swcrc and a thin jest.config.js that extends the new root jest.preset.js (which itself extends @nx/jest/preset). ts-jest, jest, and @types/jest removed from per-package devDependencies; hoisted to root.
  • @nx/jest/plugin (registered in nx.json) provides the test target, replacing per-package test and test:ci scripts. test:update and jest-watch retained.
  • Three packages whose tests genuinely exercise the terraform binary (cdktn, @cdktn/provider-schema, @cdktn/provider-generator) carry an nx.tags: ["needs:terraform"] tag for CI partitioning.
  • @cdktn/hcl2cdk's test target declares an Nx target-level dependency on cdktn-cli:build. Its globalSetup.ts spawns packages/cdktn-cli/bundle/bin/cdktn get, so the CLI bundle must exist before tests run. Wiring this in nx (rather than as a CI step) makes it work uniformly for nx affected, nx test <pkg>, and local runs.

Root scripts

  • Migrated test, test:ci, test:update from lerna run to nx run-many.
  • Removed per-package pretest: yarn build (nx now handles ^build) and the root pretest lint hook (lint runs separately via linting.yml).

CI

  • pr-unit.yml rewritten: replaces an 8x2 matrix (16 jobs) with two nx affected jobs - affected_no_terraform (no matrix) and affected_terraform (1.6.5/1.5.5 matrix). Both use --exclude patterns: the no-terraform job excludes tag:needs:terraform, @examples/*, and generate-function-bindings; the terraform job uses *,!tag:needs:terraform to keep only terraform-tagged projects.
  • nrwl/nx-set-shas action pinned to v5.0.1; explicit --base="$NX_BASE" --head="$NX_HEAD" passed to suppress info output.
  • Failures surface as inline annotations via --reporters=github-actions.
  • unit.yml (still called from release.yml and release_next.yml) updated to nx test <pkg>.
  • pr-unit.yml and unit.yml run yarn package conditionally before tests when @cdktn/hcl2cdk is affected. Its globalSetup.ts calls cdktn init --dist=... which reads jsii tarballs from the workspace-root dist/ directory — that's produced by yarn package + tools/collect-dist.sh, not by an Nx target chain. Most PRs don't pay the cost.
  • All npx nx invocations in workflows replaced with yarn nx so they use the workspace-pinned versions.
  • examples.yml matrix builder switched from npx lerna list --scope to yarn workspaces info | jq. The previous form was reaching for a globally-installed lerna whose bundled Nx couldn't resolve @nx/jest/plugin; the replacement needs neither lerna nor yarn install.
  • Coverage collected on every CI run (--coverage plus coverageReporters in the preset) and rendered to $GITHUB_STEP_SUMMARY via a new tools/test-coverage-summary.mjs ESM script that aggregates per-package coverage-summary.json into a markdown table (jest has no built-in cross-project aggregator).

knip

  • Added test/ (the integration test workspace) to knip.jsonc workspaces with TODO ignoreDependencies matching the convention used elsewhere.

Workarounds

  • cdktn/lib/private/fs.ts:archiveSync - small workaround so its execSync(node ${__filename}) self-spawn resolves the compiled .js rather than the .ts source under swc-jest. Marked TODO: remove when PR #148 lands.
  • @cdktn/cli-core - extra transformIgnorePatterns for templates/ (sscaff template hooks rely on sloppy-mode globals) and moduleFileExtensions: ['js','ts','tsx'] override (sscaff in node_modules ships both .ts source and compiled .js).
  • cdktn-cli - same moduleFileExtensions override (sscaff again).

Checklist

  • I have updated the PR title to match CDKTN's style guide
  • I have run the linter on my code locally
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation if applicable
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works if applicable
  • New and existing unit tests pass locally with my changes

@X-Guardian
Copy link
Copy Markdown
Contributor Author

Blocked by #166

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.

1 participant