diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba346d75a..f3aff9f87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -879,16 +879,21 @@ jobs: - name: UI typecheck if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }} run: npx turbo run typecheck --filter=@loopover/ui --filter=@loopover/ui-miner - # Split into 3 independent steps (was one `&&`-chained step) -- turbo.json deliberately has no `test` + # Split into 4 independent steps (was one `&&`-chained step) -- turbo.json deliberately has no `test` # task for any package (per the plan doc: test orchestration stays out of Turborepo entirely, so # Codecov's codecov/patch keeps one centralized source of truth), so this can't use the same # union-`--filter` fix already applied to "UI lint"/"UI typecheck" two steps above. Plain `&&` meant a # failing @loopover/ui test silently prevented @loopover/ui-miner's tests from ever running in that # invocation -- same class of failure-masking bug those two steps' - # own comment already describes, just still present here. `!cancelled()` on all 3 (not `always()`) + # own comment already describes, just still present here. `!cancelled()` on all 4 (not `always()`) # matches the pattern already used by "Save Turborepo cache"/"Save TypeScript incremental build # cache" elsewhere in this file: still run after an earlier step's failure, just not after the job - # was cancelled outright. The job as a whole still fails if any of the three fails. + # was cancelled outright. The job as a whole still fails if any of the four fails. + # #10049: ui-kit's package-local vitest suite was declared and documented as "this suite runs" but + # never invoked from CI or ui:test — same silently-partial shape as #9860's typecheck gap. + - name: UI tests (ui-kit) + if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }} + run: npm --workspace @loopover/ui-kit run test - name: UI tests (ui) if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }} run: npm --workspace @loopover/ui run test diff --git a/package.json b/package.json index 8aed08f85..96771d876 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "db:migrations:immutable:check": "tsx scripts/check-released-migrations-immutable.ts", "turbo-inputs:check": "tsx scripts/check-turbo-typecheck-inputs.ts", "typecheck-coverage:check": "tsx scripts/check-typecheck-coverage.ts", + "test-wiring:check": "tsx scripts/check-test-coverage-wiring.ts", "fixture-clock-races:check": "tsx scripts/check-fixture-clock-races.ts", "workspace-dep-ranges:check": "tsx scripts/check-workspace-dep-ranges.ts", "db:schema-drift:check": "tsx scripts/check-schema-drift.ts", @@ -73,7 +74,7 @@ "ui:lint": "npm run ui:kit:build && npm --workspace @loopover/ui-kit run format:check && npm --workspace @loopover/ui run format:check && npm --workspace @loopover/ui run lint && npm --workspace @loopover/ui-miner run format:check && npm --workspace @loopover/ui-miner run lint", "ui:typecheck": "npm run ui:kit:build && npm --workspace @loopover/ui-kit run typecheck && npm --workspace @loopover/ui run typecheck && npm --workspace @loopover/ui-miner run typecheck", "preui:test": "npm run check-node-version", - "ui:test": "npm run ui:kit:build && npm --workspace @loopover/ui run test && npm --workspace @loopover/ui-miner run test", + "ui:test": "npm run ui:kit:build && npm --workspace @loopover/ui-kit run test && npm --workspace @loopover/ui run test && npm --workspace @loopover/ui-miner run test", "ui:openapi": "tsx scripts/write-ui-openapi.ts", "ui:openapi:check": "tsx scripts/write-ui-openapi.ts --check", "control-plane:contract": "tsx scripts/gen-control-plane-contract.ts", @@ -148,7 +149,7 @@ "test:smoke:browser:install": "playwright install chromium", "test:smoke:browser": "node --experimental-strip-types scripts/smoke-ui-browser.ts", "pretest:ci": "npm run check-node-version", - "test:ci": "git diff --check && npm run actionlint && npm run lint:composite-actions && npm run db:migrations:check && npm run db:migrations:immutable:check && npm run turbo-inputs:check && npm run workspace-dep-ranges:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run miner:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run build --workspace @loopover/engine && npm run build --workspace @loopover/discovery-index && npm run build:mcp && npm run build:miner && npm run build --workspace @loopover/ui-kit && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test:live-gate-parity && npm run test:driver-parity && npm run validate:mcp && npm run test --workspace @loopover/engine && npm run test:workers && npm run test:mcp-pack && npm run test:contract-pack && npm run test:miner-pack && npm run test:engine-pack && npm run test:ui-kit-pack && npm run test:miner-deployment-docs-audit && npm run rees:test && npm run ui:openapi:check && npm run control-plane:contract:check && npm run control-plane:openapi:check && npm run ui:version-audit && npm run docs:drift-check && npm run coverage-boltons:check && npm run import-specifiers:check && npm run ui-derived-types:check && npm run server-manifest:check && npm run dead-source-files:check && npm run dead-exports:check && npm run publishable-deps:check && npm run fixture-clock-races:check && npm run typecheck-coverage:check && npm run checkers-wired:check && npm run focus-manifest-fields:check && npm run release-commit-parsing:check && npm run releasable-commit-types:check && npm run regate-sort-key:check && npm run maintainer-associations:check && npm run command-redelivery-guards:check && npm run dispatch-gate-reasons:check && npm run validate:no-hand-written-js && npm run replay-runner-manifest:check && npm run coco-dev-versions:check && npm run branding-drift:check && npm run manifest:drift-check && npm run engine-parity:drift-check && npm run engines-nvmrc:check && npm run release-manifest:sync:check && npm run release-linked-versions:check && npm run command-reference:check && npm run mcp:tool-reference:check && npm run mcp:client-config:check && npm run contract:api-schemas:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build", + "test:ci": "git diff --check && npm run actionlint && npm run lint:composite-actions && npm run db:migrations:check && npm run db:migrations:immutable:check && npm run turbo-inputs:check && npm run workspace-dep-ranges:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run miner:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run build --workspace @loopover/engine && npm run build --workspace @loopover/discovery-index && npm run build:mcp && npm run build:miner && npm run build --workspace @loopover/ui-kit && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test:live-gate-parity && npm run test:driver-parity && npm run validate:mcp && npm run test --workspace @loopover/engine && npm run test:workers && npm run test:mcp-pack && npm run test:contract-pack && npm run test:miner-pack && npm run test:engine-pack && npm run test:ui-kit-pack && npm run test:miner-deployment-docs-audit && npm run rees:test && npm run ui:openapi:check && npm run control-plane:contract:check && npm run control-plane:openapi:check && npm run ui:version-audit && npm run docs:drift-check && npm run coverage-boltons:check && npm run import-specifiers:check && npm run ui-derived-types:check && npm run server-manifest:check && npm run dead-source-files:check && npm run dead-exports:check && npm run publishable-deps:check && npm run fixture-clock-races:check && npm run typecheck-coverage:check && npm run test-wiring:check && npm run checkers-wired:check && npm run focus-manifest-fields:check && npm run release-commit-parsing:check && npm run releasable-commit-types:check && npm run regate-sort-key:check && npm run maintainer-associations:check && npm run command-redelivery-guards:check && npm run dispatch-gate-reasons:check && npm run validate:no-hand-written-js && npm run replay-runner-manifest:check && npm run coco-dev-versions:check && npm run branding-drift:check && npm run manifest:drift-check && npm run engine-parity:drift-check && npm run engines-nvmrc:check && npm run release-manifest:sync:check && npm run release-linked-versions:check && npm run command-reference:check && npm run mcp:tool-reference:check && npm run mcp:client-config:check && npm run contract:api-schemas:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build", "test:release": "npm run test:ci && npm run changelog:check", "test:release:mcp": "npm run test:ci", "test:watch": "vitest", diff --git a/scripts/check-test-coverage-wiring.ts b/scripts/check-test-coverage-wiring.ts new file mode 100644 index 000000000..3f2bde80d --- /dev/null +++ b/scripts/check-test-coverage-wiring.ts @@ -0,0 +1,126 @@ +#!/usr/bin/env node +// `npm run test:ci` must actually run every workspace suite that declares a `test` script (#10049). +// +// THE INCIDENT. packages/loopover-ui-kit ships a 12-file vitest suite whose package.json declares +// `"test": "vitest run"`, and its own vitest.config.ts documents the acceptance signal as "this suite +// runs". Nothing invoked it: root `ui:test` built ui-kit but only ran @loopover/ui and @loopover/ui-miner; +// ci.yml had "UI tests (ui)" / "UI tests (ui-miner)" and no ui-kit step; turbo.json deliberately has no +// `test` task. The tests existed, could not fail, and were trusted precisely because everything around +// them was green -- the same SILENTLY PARTIAL shape #9860 named for typecheck. +// +// WHAT THIS COMPUTES. Every workspace under apps/* / packages/* that declares its own `test` script, and +// whether the root `test:ci` script reaches it -- following `npm run