Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
468dce0
docs(spec): design for a mock-free test architecture
btravers Jul 31, 2026
fbb3c28
docs(plan): implementation plan for the mock-free test architecture
btravers Jul 31, 2026
acf69e0
test(testing): add workflow-bundle cache and task-queue scoping helpers
btravers Jul 31, 2026
25c9b59
test(testing): cover bundleFor memoization, correct cache lifetime doc
btravers Jul 31, 2026
ab0b71b
test(testing): guard against mocking the Temporal SDK
btravers Jul 31, 2026
cc9117d
fix(testing): broaden no-sdk-mocks walk to the whole workspace
btravers Jul 31, 2026
3cf40ae
test(worker)!: assert activity options by effect, not by proxyActivit…
btravers Jul 31, 2026
f8ea72b
chore(worker): register activity-options.workflows.ts as a knip entry…
btravers Jul 31, 2026
541efab
test(worker)!: cover ContractMisuseError paths and merge precedence, …
btravers Aug 1, 2026
9eaee7e
test(worker)!: exercise signal/query/update binding on a real server
btravers Aug 1, 2026
b1d49f1
test(worker)!: restore full behavior coverage dropped in the handlers…
btravers Aug 1, 2026
087693b
test(worker): close the update-input async-schema bind-time gap
btravers Aug 1, 2026
38c200f
test(worker)!: exercise cancellation semantics on a real server
btravers Aug 1, 2026
2738fe9
test(worker): address cancellation-spec review findings
btravers Aug 1, 2026
c1fbd5d
test(worker)!: prove continue-as-new carries state across runs
btravers Aug 1, 2026
8c2946d
test(worker): close the send-side continue-as-new validation coverage…
btravers Aug 1, 2026
9855a53
test(worker)!: prove single-parse across the child-workflow boundary
btravers Aug 1, 2026
1c7c3d2
test(worker): assert the typed child handle's workflowId passthrough
btravers Aug 1, 2026
40fc6d9
test(worker)!: fold workflow-error coverage into the rehydration suite
btravers Aug 1, 2026
5bccdd7
test(worker): assert nonRetryable and the wire marker on the rehydrat…
btravers Aug 1, 2026
5f2ba79
test(worker)!: split worker config tests from registration behavior
btravers Aug 1, 2026
27ee9de
test(worker): restore dropped cause chain, fix double-run cleanup ord…
btravers Aug 1, 2026
d31995f
test: add nightly mutation testing over the pure core modules
btravers Aug 1, 2026
ccdb78f
fix(ci): build before mutation testing, bound the nightly job, keep t…
btravers Aug 1, 2026
6953b72
fix(worker): stop test:integration's Docker and inprocess tiers compe…
btravers Aug 1, 2026
e148a00
test(worker): cover the six ContractMisuseError guards in handlers.ts
btravers Aug 1, 2026
9f459a9
fix(testing): close two no-sdk-mocks evasions, guard against a vacuou…
btravers Aug 1, 2026
92349b0
fix(docs): exclude internal superpowers/ planning docs from the publi…
btravers Aug 1, 2026
9a8633c
docs(testing): changeset and typedoc entry for ./workflow-bundle
btravers Aug 1, 2026
000310c
docs(ci): record the mutation-score runner-scope caveat durably
btravers Aug 1, 2026
48cd7e2
refactor(testing): lift the copy-pasted fixture-path helper into work…
btravers Aug 1, 2026
501dadc
fix(worker): bound flakyActivity's effective retry policy in the fixture
btravers Aug 1, 2026
f217e7a
fix(deps): patch the advisories Stryker introduced, plus a newly disc…
btravers Aug 2, 2026
437ef22
fix(testing): make the no-sdk-mocks guard path-separator agnostic
btravers Aug 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/testing-workflow-bundle-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@temporal-contract/testing": minor
---

New `@temporal-contract/testing/workflow-bundle` subpath: `bundleFor` (memoizes a `bundleWorkflowCode` call per `workflowsPath` within a test file), `withTaskQueue` (scopes a contract to a per-test task queue), `nextTaskQueueId` (a reproducible, non-random monotonic id generator), and `fixturePath` (resolves a sibling fixture file relative to the caller's `import.meta.url`, working from both `.ts` source and built output). Backs the mock-free `*.inprocess.spec.ts` test tier and is now the shared home for a path-resolution helper that was previously copy-pasted into every one of those spec files.
52 changes: 52 additions & 0 deletions .github/workflows/mutation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Mutation Testing
permissions:
contents: read

# Nightly baseline only — mutation testing is too slow to run per-PR. See
# stryker.config.json: "break" is null because this establishes a baseline,
# not a gate.
#
# Reading the baseline scores — a runner-scope caveat: `vitest.stryker.config.ts`
# only composes each mutated package's "unit" Vitest project, deliberately
# excluding the "integration"/"integration-inprocess" projects (real or
# time-skipping Temporal servers, too slow to run per-mutant). That means
# `packages/worker/src/internal.ts`'s score is measured WITHOUT the 11
# mock-free suites under `packages/worker/src/__tests__/` — notably
# `rehydration.inprocess.spec.ts`, which is what exercises `internal.ts`'s
# `ChildWorkflowFailure` branch (around line 401). So `internal.ts`'s mutation
# score understates its real coverage: it is partly a scope artifact, not
# purely a test-quality gap. By contrast, `error-tags.ts`'s low score IS a
# genuine gap — its only assertions in `errors.spec.ts` are tautological
# (`_tag`-vs-own-constant). Don't read the two the same way.
on:
schedule:
- cron: "0 3 * * *"
workflow_dispatch:

jobs:
mutation:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Setup
uses: ./.github/actions/setup

# `test:mutation` (= `pnpm build && stryker run`) builds first: worker's
# unit specs import `@temporal-contract/contract` by package name, which
# resolves through its `exports` map to `dist/`. `dist/` is gitignored
# and nothing else in `setup` builds it, so skipping this leaves a fresh
# runner's dry run failing on missing dist output.
- name: Run mutation testing
run: pnpm test:mutation

- name: Upload mutation report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: mutation-report
path: reports/mutation/
retention-days: 14
if-no-files-found: ignore
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ Thumbs.db

coverage/

# Stryker mutation testing
.stryker-tmp/
reports/mutation/
stryker.log

# VitePress
**/.vitepress/cache/
**/.vitepress/dist/
Expand Down
7 changes: 7 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ export default withMermaid(
base: BASE,
lang: "en-US",

// `docs/superpowers/**` holds internal planning/spec documents for this
// repo's own development process, not end-user documentation. Without
// this exclusion VitePress builds and publishes them like any other
// page, and `deploy-docs.yml` (triggered on `push` to `main` with
// `paths: ["docs/**"]`) would ship them to the public site.
srcExclude: ["superpowers/**"],

// `@btravstack/theme` re-exports VitePress's default theme, which imports
// `.css`. Externalizing it during SSR makes Node try to `import` those
// stylesheets and throw `ERR_UNKNOWN_FILE_EXTENSION`. Transform the theme
Expand Down
Loading
Loading