Files
Ruslan KonviserandClaude Opus 5.5 91d91ffca3 test: make the unit-test run hermetic and fix the Angular jest harness
The Unit Tests workflow has never been green (24 of 97 projects red at
develop eac7136562, run 36319732347). Causes addressed here:

- Env leak: Nx loads the committed .env.local (DEMO=true,
  WORKER_QUEUE_ENABLED=false, NODE_ENV=development) into every task.
  The test step now sets NX_LOAD_DOT_ENV_FILES=false, and the two specs
  that depend on a mode pin it themselves (role-permission counts pin
  environment.demo=false and gain a demo-mode suite asserting 209 per
  role; the worker spec clears the queue env before the constants load).
  .env.local is unchanged.
- Angular harness: nohoist gives each workspace its own @angular copy,
  so setupZoneTestEnv() initialised a different TestBed from the one the
  spec used. A workspace resolver (jest.resolver.js, wrapping Nx's) makes
  every @angular/* import in a Jest project resolve to one copy. The
  Angular projects now inherit the preset's transformIgnorePatterns,
  which gains the .mjs exception plus @datorama, @ngneat and lodash-es.
- ui-config's environment.ts is generated and gitignored; the workflow
  runs `yarn config:dev` before the tests, as the Playwright workflow does.
- Misconfigured targets: gauzy (jest.config.js -> .ts, Angular transform,
  setupFile moved into the config), integration-sim-ui (.ts -> .cts),
  integration-activepieces (config file added), mcp-auth (ran
  `node build/main.js --test`; now the jest executor like apps/mcp).
- Real failures: the openai "silence" case used a body with no `text`,
  which the shared helper rejects by contract; the toolbar spec read the
  tabIndex property, which is 0 on any button; the docs-ui linearity
  tests asserted wall-clock bounds, now a 4x-input growth ratio.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 17:39:40 +02:00

117 lines
6.6 KiB
YAML

name: Unit Tests
# The repository has ~330 `*.spec.ts` files and an `nx` `test` target on 20+ projects
# (`@nx/jest:jest`, already cached via `nx.json` targetDefaults) — but until now NO workflow ever
# invoked any of them. CI ran builds plus Playwright/Cypress end-to-end suites only, so a green pull
# request proved the code COMPILED and said nothing about the unit tests. This workflow wires the
# existing targets up; it adds no test tooling of its own.
#
# Scope is deliberately `stage` only (owner, 2026-08-28). Stage is where the cascade lands before
# production, pushes to it are infrequent, and keeping the job off `develop` and every pull request
# means this cannot slow the day-to-day loop while the suites' true state is still unknown.
#
# NOT a required status check, on purpose. These suites have never run in CI, so the first runs may
# well be red — that is the information this workflow exists to surface, and it should surface it
# without blocking the cascade. Promote it to a required check once it has been green for a while.
on:
push:
branches:
- stage
# So the suites can be exercised on demand from any branch that carries this file, without
# waiting for a cascade to land on stage.
workflow_dispatch:
concurrency:
group: gauzy-unit-tests-${{ github.ref }}
# Deliberately NOT `cancel-in-progress: true`. A cancelled test run produces no verdict, and a
# gate that reports nothing is worse than no gate: this repository's sibling project already lost
# a stage e2e gate that way — six consecutive runs cancelled by the next push, so the gate never
# once said pass or fail. Pushes to `stage` are infrequent, so queueing costs very little here.
cancel-in-progress: false
# Least-privilege scope for the automatic GITHUB_TOKEN: this job only reads the checkout.
permissions:
contents: read
env:
# Same archive name the build workflow uses, so the restore script finds what it expects.
NODE_MODULES_ARCHIVE: node-modules.tar.zst
jobs:
unit-tests:
name: unit-tests
runs-on: ${{ vars.RUNNER_LINUX_X64_8 || 'ubuntu-latest' }}
# A cold dependency install on this fleet is measured in hours, not minutes (the build workflow
# documents 88 min / 3h20m / 3h46m for the same work). The ceiling costs nothing on the warm
# path, which is a cache lookup.
timeout-minutes: 360
steps:
# Action versions deliberately match `build.yml` rather than the newer majors used elsewhere in
# the repository: this job consumes the node_modules cache that workflow writes, so the
# producer and the consumer are kept on the same actions.
- uses: actions/checkout@v4
with:
# This job only reads the tree — it never pushes — so the checkout credential does not need
# to outlive the step in `.git/config`.
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: 24
- name: Restore node_modules archive
# Best effort: the same key the build workflow writes, so a stage push that already built
# this exact lockfile reuses that tree instead of installing again. `restore-node-modules.sh`
# below installs from scratch when the archive is not there, so a miss is not fatal.
uses: actions/cache/restore@v4
continue-on-error: true
with:
path: ${{ env.NODE_MODULES_ARCHIVE }}
key: ${{ runner.os }}-${{ runner.arch }}-node-modules-${{ hashFiles('yarn.lock', 'package.json', 'patches/**', '.scripts/postinstall.js') }}
# Route any install through the internal Verdaccio cache. Placed AFTER the cache restore
# because this action rewrites yarn.lock's resolved URLs, and `hashFiles()` in the key above
# evaluates at step runtime — configuring the registry first would move the key and split the
# cache namespace by VIP reachability.
- name: Configure Registry
uses: ever-co/ever-gauzy/.github/actions/configure-registry@aa4ee19926fabcf820aa1294385a76aec6bdb548
with:
verdaccio-registry: ${{ vars.VERDACCIO_REGISTRY }}
verdaccio-token: ${{ secrets.VERDACCIO_TOKEN }}
force-public: ${{ vars.VERDACCIO_FORCE_PUBLIC }}
expect-vip: ${{ vars.RUNNER_LINUX_X64_8 != '' }}
- name: Restore node_modules
shell: bash
# Unpacks the archive, or installs from scratch when it is unavailable. One step, so there
# is no `if:` on a previous step's outcome to get wrong.
run: .github/scripts/restore-node-modules.sh
- name: Generate the Angular environment file
# `packages/ui-config/src/lib/environments/environment.ts` is generated (and gitignored), so a
# fresh checkout has none — and every spec that reaches `@gauzy/ui-config`, directly or through
# ui-core, failed to load with "Cannot find module './lib/environments/environment'" (about a
# dozen Angular projects). Same command the Playwright workflow runs before it builds the web
# app. It goes through yarn, not Nx, so `.env.local` is not loaded here either.
run: yarn config:dev
- name: Run unit tests
env:
# Nx loads the workspace `.env` files into every task by default, and this repository commits
# a `.env.local` tuned for LOCAL DEVELOPMENT — DEMO=true, WORKER_QUEUE_ENABLED=false,
# NODE_ENV=development, and so on. Every unit test therefore ran as a demo-mode dev process:
# the logs printed "Is DEMO: true" 141 times and never once "false", and specs asserting
# production behaviour (role-permission counts, the worker's BullMQ root) failed for that
# reason alone. The suites must not depend on whichever `.env` sits in the checkout, so this
# turns the loading off; a spec that needs a particular mode pins it itself. `.env.local`
# stays as it is — it is the local-dev default, and nothing here needs it removed.
NX_LOAD_DOT_ENV_FILES: 'false'
# `--nxBail=false` so one failing project still lets every other project report; without that
# the first failure hides the rest and each fix costs another full run to find the next
# problem. It is the real flag name — nx has no `--continue`, and an unknown option is
# forwarded to the executor, so `--continue` would have reached jest instead of doing this.
#
# `--parallel=2` rather than the nx default of 3: jest already forks per project, and this
# fleet has a documented history of Node heap exhaustion when several suites run at once.
run: yarn nx run-many -t test --nxBail=false --parallel=2