@gfdelarue/testkit 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/README.md +590 -165
  2. package/bin/testkit-windows-owner-arm64.exe +0 -0
  3. package/bin/testkit-windows-owner-x64.exe +0 -0
  4. package/dist/app/bugs/batch.js +1 -0
  5. package/dist/app/bugs/ci-report.js +2 -2
  6. package/dist/app/bugs/ci-summary.js +3 -3
  7. package/dist/app/bugs/draft.js +2 -2
  8. package/dist/app/bugs/file.js +1 -1
  9. package/dist/app/bugs/guide.js +1 -1
  10. package/dist/app/bugs/record.js +2 -2
  11. package/dist/app/bugs/run-reading.js +1 -1
  12. package/dist/app/bugs/store.js +1 -1
  13. package/dist/app/campaigns/index.js +2 -2
  14. package/dist/app/campaigns/summary.js +1 -1
  15. package/dist/app/cleanup/index.js +1 -1
  16. package/dist/app/db-schema/prepare.js +1 -1
  17. package/dist/app/db-schema/refresh.js +1 -1
  18. package/dist/app/db-schema/verify.js +1 -1
  19. package/dist/app/destroy/index.js +1 -1
  20. package/dist/app/discover/index.js +2 -2
  21. package/dist/app/environments/config-driven.js +1 -1
  22. package/dist/app/environments/file-setup.js +1 -1
  23. package/dist/app/environments/routing.js +1 -1
  24. package/dist/app/environments/static-values.js +1 -1
  25. package/dist/app/environments/supplied.js +1 -1
  26. package/dist/app/inspect/index.js +1 -1
  27. package/dist/app/lint/native.js +1 -1
  28. package/dist/app/lint/options.js +1 -1
  29. package/dist/app/lint/shared.js +1 -1
  30. package/dist/app/run/engine-orchestration.js +1 -1
  31. package/dist/app/run/environment.js +1 -1
  32. package/dist/app/run/live-run.js +1 -1
  33. package/dist/app/run/orchestrator.js +1 -1
  34. package/dist/app/run/planning.js +1 -1
  35. package/dist/app/run/request.js +1 -1
  36. package/dist/app/run/results.js +1 -1
  37. package/dist/app/run/run-finalization.js +1 -1
  38. package/dist/app/run/run-finisher.js +1 -0
  39. package/dist/app/run/setup/runtime-node-setup-protocol.js +1 -1
  40. package/dist/app/run/setup/runtime-node-setup-worker.js +1 -1
  41. package/dist/app/run/setup/runtime-node-setup.js +2 -2
  42. package/dist/app/run/task-batches.js +1 -1
  43. package/dist/app/run/worker-loop.js +1 -1
  44. package/dist/app/status/model.js +1 -1
  45. package/dist/app/status/runs.js +1 -1
  46. package/dist/app/stop/index.js +1 -1
  47. package/dist/app/tracker/index.js +1 -1
  48. package/dist/app/tracker/token.js +2 -2
  49. package/dist/app/typecheck/index.js +4 -4
  50. package/dist/cli/command-catalog.js +1 -1
  51. package/dist/cli/command-flags.js +1 -1
  52. package/dist/cli/commands/artifacts.js +2 -2
  53. package/dist/cli/commands/bug/file.js +3 -2
  54. package/dist/cli/commands/discover.js +1 -1
  55. package/dist/cli/commands/guard/unsafe-entrypoint.js +1 -1
  56. package/dist/cli/commands/run.js +2 -2
  57. package/dist/cli/commands/typecheck.js +1 -1
  58. package/dist/cli/commands/workspace.js +1 -1
  59. package/dist/cli/framework/help.js +5 -5
  60. package/dist/cli/framework/parser.js +1 -1
  61. package/dist/cli/json-errors.js +1 -1
  62. package/dist/cli/renderers/bug/text.js +1 -1
  63. package/dist/cli/renderers/run/formatting.js +1 -1
  64. package/dist/config/authoring/database-fixture-discovery.js +1 -0
  65. package/dist/config/authoring/index.js +1 -1
  66. package/dist/config/loader/config-loader.js +1 -1
  67. package/dist/config/loader/decode-discovery.js +1 -1
  68. package/dist/config/loader/discover-tests.js +1 -1
  69. package/dist/config/loader/discovery-result.js +1 -0
  70. package/dist/config/loader/discovery.js +2 -2
  71. package/dist/config/loader/file-metadata.js +1 -1
  72. package/dist/config/loader/groups.js +2 -1
  73. package/dist/config/loader/index.js +1 -1
  74. package/dist/config/loader/load.js +1 -1
  75. package/dist/config/loader/managed-configs.js +1 -1
  76. package/dist/config/loader/owned-discovery.js +1 -1
  77. package/dist/config/loader/runtime-isolation.js +1 -1
  78. package/dist/config/loader/skip-config.js +1 -1
  79. package/dist/config/loader/test-selection.js +1 -1
  80. package/dist/database/admin.js +5 -2
  81. package/dist/database/call-caps.js +1 -0
  82. package/dist/database/cleanup.js +1 -1
  83. package/dist/database/configured-steps.js +1 -1
  84. package/dist/database/constants.js +1 -1
  85. package/dist/database/docker-endpoint.js +1 -0
  86. package/dist/database/docker-metadata.js +2 -2
  87. package/dist/database/docker.js +5 -5
  88. package/dist/database/index.js +2 -1
  89. package/dist/database/lifecycle-cleanup.js +1 -1
  90. package/dist/database/local-postgres.js +4 -1
  91. package/dist/database/naming.js +1 -1
  92. package/dist/database/operation-deadline.js +1 -0
  93. package/dist/database/postgres/connection-check.js +1 -1
  94. package/dist/database/postgres/index.js +2 -2
  95. package/dist/database/postgres/owned-exec.js +27 -0
  96. package/dist/database/postgres/protocol.js +2 -2
  97. package/dist/database/provider.js +1 -0
  98. package/dist/database/roles.js +2 -2
  99. package/dist/database/schema-operations.js +5 -1
  100. package/dist/database/schema-source.js +3 -3
  101. package/dist/database/steps.js +1 -1
  102. package/dist/database/template-steps.js +4 -4
  103. package/dist/domain/identifiers.js +1 -1
  104. package/dist/domain/retired-test-types.js +1 -1
  105. package/dist/domain/suite-selection.js +1 -1
  106. package/dist/domain/test-types.js +1 -1
  107. package/dist/engines/adapters/evidence-files.js +1 -1
  108. package/dist/engines/adapters/execution.js +1 -1
  109. package/dist/engines/catalog.js +1 -1
  110. package/dist/engines/definitions.js +1 -1
  111. package/dist/engines/environment/index.js +1 -1
  112. package/dist/engines/installations/node-vitest.js +1 -1
  113. package/dist/engines/installations/playwright.js +1 -1
  114. package/dist/engines/managed-module-resolution.js +6 -2
  115. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  116. package/dist/engines/node-vitest/adapter/driver.js +2 -2
  117. package/dist/engines/node-vitest/adapter/evidence.js +2 -2
  118. package/dist/engines/node-vitest/adapter/workspace.js +8 -24
  119. package/dist/engines/node-vitest/inventory/index.js +2 -2
  120. package/dist/engines/node-vitest/inventory/list-files.js +3 -3
  121. package/dist/engines/node-vitest/runtime/data/index.js +1 -1
  122. package/dist/engines/node-vitest/runtime/data/report.js +1 -1
  123. package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
  124. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  125. package/dist/engines/playwright/adapter/adapter.js +1 -1
  126. package/dist/engines/playwright/adapter/browser-network-evidence.js +4 -0
  127. package/dist/engines/playwright/adapter/config.js +16 -6
  128. package/dist/engines/playwright/adapter/evidence.js +2 -1
  129. package/dist/engines/playwright/adapter/failure-details.js +2 -2
  130. package/dist/engines/playwright/adapter/reporter.js +1 -1
  131. package/dist/engines/playwright/runtime/browser-network.js +1 -0
  132. package/dist/engines/playwright/runtime/browser-traffic.js +1 -0
  133. package/dist/engines/playwright/runtime/chromium-environment.js +1 -0
  134. package/dist/engines/playwright/runtime/emulation.js +1 -0
  135. package/dist/engines/playwright/runtime/index.js +1 -1
  136. package/dist/engines/playwright/runtime/managed-test.js +1 -0
  137. package/dist/engines/playwright/runtime/runtime-input.js +2 -2
  138. package/dist/environment/lifecycle-controller.js +1 -1
  139. package/dist/environment/lifecycle.js +1 -1
  140. package/dist/environment/maintenance.js +1 -1
  141. package/dist/environment/run-environment.js +1 -1
  142. package/dist/environment/run-stopping.js +1 -1
  143. package/dist/environment/runtime-manager.js +1 -1
  144. package/dist/evidence/artifact-config.js +1 -1
  145. package/dist/evidence/artifacts.js +5 -2
  146. package/dist/evidence/bundles.js +2 -1
  147. package/dist/evidence/compressed-artifacts.js +1 -0
  148. package/dist/evidence/environment-record.js +1 -1
  149. package/dist/evidence/index.js +1 -1
  150. package/dist/evidence/live-run-summary.js +1 -0
  151. package/dist/evidence/local-paths.js +1 -0
  152. package/dist/evidence/maintenance.js +1 -0
  153. package/dist/evidence/operation-timings.js +1 -1
  154. package/dist/evidence/read-run.js +1 -1
  155. package/dist/evidence/redaction.js +4 -4
  156. package/dist/evidence/run-evidence.js +1 -0
  157. package/dist/evidence/setup-progress.js +1 -1
  158. package/dist/evidence/storage-inventory.js +1 -1
  159. package/dist/evidence/storage.js +2 -2
  160. package/dist/kernel/known-keys.js +1 -0
  161. package/dist/kernel/redaction-targets.js +1 -1
  162. package/dist/kernel/redaction.js +7 -4
  163. package/dist/process/engine-environment-keys.js +1 -0
  164. package/dist/process/environment-overlay.js +1 -1
  165. package/dist/process/environment.js +1 -1
  166. package/dist/process/execa-bundle.json +3 -3
  167. package/dist/process/files/evidence-writes.js +1 -0
  168. package/dist/process/files/product-dir.js +1 -1
  169. package/dist/process/host-process.js +1 -1
  170. package/dist/process/index.js +1 -1
  171. package/dist/process/lifecycle-fence.js +1 -1
  172. package/dist/process/lock-progress.js +2 -0
  173. package/dist/process/locks.js +4 -4
  174. package/dist/process/process-identity.js +1 -1
  175. package/dist/process/process.js +35 -35
  176. package/dist/process/recovery.js +1 -1
  177. package/dist/process/runs/manifest.js +1 -1
  178. package/dist/process/runs/ownership.js +1 -1
  179. package/dist/process/runs/stop.js +1 -1
  180. package/dist/process/shutdown.js +1 -1
  181. package/dist/process/windows-native.js +1 -1
  182. package/dist/repo/fingerprint-policy.js +1 -1
  183. package/dist/repo/history.js +7 -4
  184. package/dist/repo/managed-git.js +1 -1
  185. package/dist/repo/state.js +4 -4
  186. package/dist/steps/configured-step-testkit-modules.js +1 -1
  187. package/dist/steps/environment.js +1 -1
  188. package/dist/toolchains/index.js +2 -2
  189. package/dist/toolchains/node-provisioning.js +2 -2
  190. package/dist/toolchains/vitest/index.js +1 -1
  191. package/dist/tracker/gitea.js +1 -1
  192. package/dist/tracker/github.js +1 -1
  193. package/dist/tracker/http.js +1 -1
  194. package/dist/tracker/ownership.js +1 -0
  195. package/dist/tracker/redaction.js +1 -1
  196. package/dist/tracker/responses.js +1 -1
  197. package/dist/types/config.d.ts +7 -86
  198. package/dist/types/environment.d.ts +6 -0
  199. package/dist/types/node-vitest-data.d.ts +2 -218
  200. package/dist/types/playwright.d.ts +21 -0
  201. package/dist/types/workspace.d.ts +30 -14
  202. package/docs/bug-records.md +19 -18
  203. package/docs/engines.md +115 -21
  204. package/docs/release-notes.md +2846 -0
  205. package/docs/test-types.md +19 -69
  206. package/package.json +15 -6
  207. package/testkit-config-schema.md +101 -170
  208. package/dist/app/lint/rules/data.js +0 -1
  209. package/dist/config/authoring/runtime.js +0 -1
  210. package/dist/config/loader/task-policy.js +0 -1
  211. package/dist/engines/node-vitest/runtime/contract/index.js +0 -1
  212. package/dist/engines/node-vitest/runtime/data/http.js +0 -1
  213. package/dist/engines/node-vitest/runtime/data/runner.js +0 -1
  214. package/dist/environment/lifecycle-artifacts.js +0 -1
  215. package/dist/types/node-vitest-contract.d.ts +0 -75
@@ -45,10 +45,10 @@ Two overlapping refund requests for one order both pay out.
45
45
  ## Reproduce
46
46
 
47
47
  ```sh
48
- npx testkit run --file src/checkout/__testkit__/refund.contract.testkit.ts
48
+ npx testkit run --file src/checkout/refund.test.ts
49
49
  ```
50
50
 
51
- Test: `src/checkout/__testkit__/refund.contract.testkit.ts`, "a refund pays out once".
51
+ Test: `src/checkout/refund.test.ts`, "a refund pays out once".
52
52
  Found at `4f0c2d1e9b7a4c3d8e6f5a4b3c2d1e0f9a8b7c6d`.
53
53
  Fault: `src/checkout/refunds.ts`, lines 41 to 58.
54
54
 
@@ -66,9 +66,8 @@ Fault: `src/checkout/refunds.ts`, lines 41 to 58.
66
66
  "escape": "no-test",
67
67
  "caughtBy": "campaign",
68
68
  "campaign": "refunds-2026-10",
69
- "testType": "contract",
70
69
  "test": {
71
- "file": "src/checkout/__testkit__/refund.contract.testkit.ts",
70
+ "file": "src/checkout/refund.test.ts",
72
71
  "title": "a refund pays out once"
73
72
  },
74
73
  "foundAt": "4f0c2d1e9b7a4c3d8e6f5a4b3c2d1e0f9a8b7c6d",
@@ -90,39 +89,41 @@ When `testkit bug file` ran the test against [supplied values](../README.md#run-
90
89
 
91
90
  A fault on one line reads `line 41`.
92
91
 
93
- ```markdown
94
- Test: `src/health/__testkit__/health.contract.testkit.ts`, the whole script, recorded as "the health endpoint answers".
95
- ```
96
-
97
92
  Testkit redacts the secrets it recognises in the title, in every section, and in `test.title`. It does so when it records the bug and again when it files the issue. `testkit run` applies the same rules when it stores a run result. Testkit recognises these forms.
98
93
 
99
94
  - The value of a `KEY=value` assignment whose key names a secret.
100
95
  - The password in a URL.
101
- - The value of an `Authorization`, `Proxy-Authorization`, `Cookie`, or `Set-Cookie` header.
96
+ - The value of an `Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie`, `Api-Key`, or `X-Api-Key` header. When a double-quoted string holds the header, the value ends at the quote that closes the string, at the string's own escape depth, so a value that ends in an escaped backslash ends there too.
102
97
  - A JSON string value whose key names a secret, including JSON that is itself inside a JSON string, as in `{"message":"{\"token\":\"…\"}"}`. Testkit reads the key's escapes, so `"\u0074oken"` names a secret too.
103
- - The value of a single-quoted `'password': '…'` member, in any letter case. It ends at the next apostrophe that no backslash precedes, or with the line.
98
+ - Every string in a JSON array or object whose key names a secret, as in `{"tokens":["…"]}`, unless the key names a secret only through `AUTH`, `COOKIE`, or `SESSION`. So `session` and `auth` settings stay. In an object with a `name` string and a `value` string, only the `value` and members whose own key names a secret count. Numbers and booleans stay. In a `cookies` array, the `value` string of each object directly in it counts, and the rules above still apply inside it.
99
+ - The value of a single-quoted member whose key names a secret, as in `{'token': '…'}`. It ends at the next apostrophe that no backslash precedes, or with the line.
100
+ - The value after a key whose last word is `PASSWORD` or `PASSWD` and a colon, outside JSON, as in `{ password: '…' }` or a YAML `password: …` line. A quoted value counts anywhere and ends as a quoted assigned value does. An unquoted value counts at the start of a line, after spaces and an optional `- `, when it is the line's one word. A value that is one word of letters, perhaps followed by `.`, `,`, `;`, `:`, `!`, `?`, or `)`, stays, so `password: 'Required'`, `password: required!`, and `rejects a password: too short` stay as they are.
101
+ - The token after `Bearer` and a space or a tab, wherever it appears, when it is at least eight characters long and holds a digit. The token is made of letters, digits, `-`, `.`, `_`, `~`, `+`, and `/`, and may end in `=` signs. `Bearer authentication` stays as it is.
102
+ - The value in a `"name": "…", "value": "…"` pair whose name names a secret, as traces store headers, as in `{"name":"Authorization","value":"…"}`.
104
103
 
105
- A key names a secret when it contains `PASSWORD`, `TOKEN`, `SECRET`, `PRIVATE_KEY`, `AUTH`, `COOKIE`, `SESSION`, or `API_KEY` in any letter case. Still keep credentials, tokens, and passwords out of the record.
104
+ A key names a secret when it contains `PASSWORD`, `TOKEN`, `SECRET`, `PRIVATE_KEY`, `AUTH`, `COOKIE`, `SESSION`, or `API_KEY` in any letter case, or when its last word is `PASS`, `PASSWD`, `PAT`, `DSN`, `CREDENTIAL`, or `CREDENTIALS`. `AUTH` doesn't count in `AUTHOR` or `AUTHORITY`, so `GIT_AUTHOR_NAME` and `author` name no secret, though `AUTHORIZATION` and `AUTHORISE` still do. `SESSION` doesn't count when an optional `S`, at most one other character, and then `COUNT`, `DURATION`, `EXPIR`, `LENGTH`, `LIMIT`, `MAX`, `TIMEOUT`, or `TTL` follow it, as in `sessionCount` and `SESSION_TIMEOUT`. A key whose last two words are `API`, `PRIVATE`, `SIGNING`, or `ENCRYPTION` and then `KEY`, as in `apiKey`, `x-api-key`, and `privateKey`, names a secret too, and so does an upper-case key whose last word is `KEY`, such as `STRIPE_KEY` or `SIGNING_KEY`, unless the word before it is `PUBLIC` or `PUBLISHABLE`. Words break at any character other than a letter or a digit, and before an upper-case letter that follows a lower-case letter or a digit, so `GITHUB_PAT` and `dbPass` name secrets and `PATH`, `BYPASS`, and `cacheKey` don't. Still keep credentials, tokens, and passwords out of the record.
106
105
 
107
106
  An assigned value ends at the first space, with four exceptions.
108
107
 
109
108
  - A value that starts with `"` or `'` ends at the next such quote on its line. When the line has no such quote, the value ends with the line.
110
109
  - A quoted value inside a JSON string (`\"`), or inside JSON that is itself inside a JSON string (`\\\"`), ends at the next quote escaped to the same depth. A quote escaped more deeply belongs to the value. The value ends sooner at a quote escaped less deeply, such as the quote that closes the JSON string, at an escaped line break at its own depth or less, or with the line. A value quoted with an escaped apostrophe, `\'`, works the same way. JSON doesn't escape apostrophes, so each JSON layer only doubles the backslashes (`\\'`). A plain apostrophe inside the value belongs to it.
111
110
  - A value that starts with `Basic`, `Bearer`, `Digest`, `Negotiate`, or `Token` and then a space or a tab ends with the line.
112
- - Under a key that ends in `_URL`, Testkit keeps a value that starts with a scheme, such as `https://`, and redacts the URL's password only.
111
+ - Under a key that ends in `_URL`, Testkit keeps a value that starts with a scheme, such as `https://`, or with a single `/`, such as `/oauth/authorize`. A value that starts with `//` is redacted whole. It redacts what the other rules find in it, such as the URL's password or a `token=` query parameter.
113
112
 
114
- When `testkit run` stores a result, it redacts JSON one string value at a time. That covers text that is a JSON object, array, or string, and a line whose text from its first `{` or `[` is JSON. Each string value gets the rules above, and so does JSON inside a string. A value that runs to a space or to the end of its line therefore ends with its string, and the record's other values stay as they are. Other text gets the rules as written, and so does JSON in two cases:
113
+ When `testkit run` stores a result, it redacts JSON one string value at a time. That covers text that is a JSON object, array, or string, and a line whose text from its first `{` or `[` is JSON. Each string value gets the rules above, and so does JSON inside a string. A value that runs to a space or to the end of its line therefore ends with its string, and the record's other values stay as they are. In an object with `name` and `value` members, in either order, the `value` string is redacted when the name names a secret, and always when the object is in a `cookies` array. Other text gets the rules as written, and so does JSON in two cases:
115
114
 
116
115
  - a rule reading the whole line would redact across the line's first `{` or `[`;
117
116
  - a secret Testkit resolved from the run's environment, whole or cut short, crosses the JSON's edge or spans more than one string.
118
117
 
119
118
  A string that holds such a secret in escaped form is redacted as decoded text when the escaped text decodes to the secret, or, for a secret cut short, to the start of one, and redacted whole otherwise. Where these rules and a resolved secret overlap, Testkit redacts every character that either would redact.
120
119
 
120
+ Testkit applies every rule to the same text and redacts each character that any rule finds. A value that runs to a space therefore doesn't hide the secret after it, so `PASSWORD=…"Cookie: sid=…` loses both.
121
+
121
122
  Testkit writes `<redacted>` in place of the value. A quoted value keeps its quotes, as in `PASSWORD="<redacted>"`, so redacting the text again changes nothing. A `<redacted>` that the text already holds counts as part of the value, so `TOKEN=<redacted>example-secret` becomes `TOKEN=<redacted>`. A secret resolved from the run's environment can itself contain part of `<redacted>`, or a character Testkit reserves. Such a secret can match text that redaction creates, so where it takes part, `testkit run` redacts the whole line of a log, or the whole JSON string, when it stores the result. When such a secret spans lines, or takes part only across lines, `testkit run` redacts every line between the nearest JSON lines instead, or the whole text when it holds none.
122
123
 
123
- A URL password is the text between `://user:` and the last `@` before the next `/` or space. The user can be empty, as in `redis://:password@cache`. Testkit does not recognise a password that holds a `/`, or a token that stands alone as the user, as in `https://token@host`.
124
+ A URL password is the text after `://user:`, up to the first `@` whose host runs to a `/`, `?`, `#`, space, or the end of the text with no other `@`. The user can be empty, as in `redis://:password@cache`. The password can hold `/` and `@`, as in `postgres://app:pa/ss@db`, A password that starts with digits and then a `/`, `?`, or `#`, and also ends with one of them before the `@`, reads as a port and a path, so `https://registry.example.com:8443/@scope/pkg` stays and `postgres://app:1234/secret@db` loses `1234/secret`. The user can't hold `[` or `]`, so an IPv6 host such as `http://[::1]:5173/@vite/client` stays. A directory name keeps one slash of a URL, so Testkit also reads `postgres:/app:password@db`. In an `http` or `https` URL, a user that stands alone, as in `https://token@host`, is redacted when it is at least 20 characters of letters, digits, `-`, `.`, `_`, and `~`, and holds a digit, so `https://ada@host` and `ssh://deploy2024@host` stay.
124
125
 
125
- Testkit does not rewrite a path or an area's name. `testkit bug record` rejects a record whose `test.file` or `fault.path` holds text that Testkit redacts. `testkit bug file` stops when the area's name or the reproduce command holds such text.
126
+ Testkit does not rewrite a path or an area's name. `testkit bug record` rejects a record whose `test.file`, `fault.path`, or reproduce command holds text that Testkit redacts. The reproduce command holds the product directory's path, the test's path from it, and the `--vitest-config` and `--vitest-project` selectors. `testkit bug file` stops when the area's name or the reproduce command holds such text.
126
127
 
127
128
  Testkit reads the facts back from the body before it files the issue. It files nothing when they do not read back as written. That happens when `test.title`, `test.file`, `fault.path`, or the area's name holds one of the two marker comments.
128
129
 
@@ -239,7 +240,7 @@ A named failure's title comes from the engine.
239
240
  | Vitest | The names of the `describe` blocks around the test and the test's own name, joined by single spaces. |
240
241
  | Playwright | The names of the `describe` blocks around the spec and the spec's own title, joined by single spaces. |
241
242
 
242
- A Playwright title holds neither the file path nor the project name. A spec that fails in two projects is one named failure.
243
+ A Playwright title holds neither the file path nor the project name. A spec that fails in two projects is one named failure. When a Playwright config sets `failOnFlakyTests`, a spec that passes only on a retry fails the run, and it is a named failure.
243
244
 
244
245
  When a file reports named failures, `testkit bug file` rejects a bug record whose `test.title` is not one of their titles. Its message lists the titles a bug record can use.
245
246
 
@@ -253,8 +254,8 @@ A file also reports one unnamed failure beside its named failures when the engin
253
254
 
254
255
  - A Vitest file runs past its timeout, writes more output than Testkit keeps, or ends on a signal or with an exit code other than 1.
255
256
  - A Playwright run is interrupted or runs past its timeout.
256
- - A Playwright process ends on a signal or with an exit code other than 1. A reporter in the Playwright config that ends the process does that.
257
- - A Playwright config sets `failOnFlakyTests` and a spec passes only on a retry. A spec that passes on a retry is no named failure, so no issue can cover it.
257
+ - A Playwright process ends on a signal, with an exit code other than 1, or before every reporter in the Playwright config has finished. A reporter that ends the process from one of its hooks does that, whatever its exit code. A reporter that ends the process with exit code 1 after its hooks have returned, such as from a timer, still reads as the failed specs.
258
+ - Playwright does not run a spec of the selected file that was expected to run. A failed spec stops the later specs of a serial group, a failed `beforeAll` hook stops the specs after the one it failed, and a run that reaches `maxFailures` stops the rest. A spec that the file skips with `test.skip` or `test.fixme` is not such a spec.
258
259
  - A Playwright spec fails in a file other than the selected one, such as a spec in a project that the selected file's project depends on or a spec in a teardown project. That spec is no named failure of the selected file, so no issue can cover it. A spec's file is the file that Playwright loaded. A compiled file whose source map names the selected file is still another file.
259
260
  - Testkit cannot keep a file that a Playwright spec attached, or cannot store the evidence of the Playwright run.
260
261
 
package/docs/engines.md CHANGED
@@ -11,18 +11,17 @@ attachments, and installation.
11
11
  Each engine keeps its own test language. The root package declares a typed
12
12
  file's engine, and each engine's subpath exposes that engine's API.
13
13
 
14
- Node/Vitest runs plain Vitest test files, and data and contract suites:
14
+ Node/Vitest runs plain Vitest test files. A plain file records data-flow
15
+ evidence with `dataFlow(context)`:
15
16
 
16
17
  ```ts
17
- import { defineFile } from "@gfdelarue/testkit";
18
- import { dataScenario } from "@gfdelarue/testkit/node-vitest/data";
19
- import { expect } from "vitest";
20
-
21
- export const testkit = defineFile({ engine: "node-vitest" });
18
+ import { dataFlow } from "@gfdelarue/testkit/node-vitest/data";
19
+ import { expect, test } from "vitest";
22
20
 
23
- dataScenario("records checkout traffic", ({ count, record }) => {
24
- record("checkout", { count: 1 });
25
- count("orders", 1);
21
+ test("records checkout traffic", (context) => {
22
+ const flow = dataFlow(context);
23
+ flow.record("checkout", { count: 1 });
24
+ flow.count("orders", 1);
26
25
  expect(1).toBe(1);
27
26
  });
28
27
  ```
@@ -41,14 +40,73 @@ test("shows the account", async ({ page }) => {
41
40
  });
42
41
  ```
43
42
 
43
+ ### Browser launch options
44
+
45
+ A UI file can set Playwright's `launchOptions` with `test.use`. Testkit applies
46
+ them and sets `executablePath` last, so the file still runs on the Chromium
47
+ that Testkit manages, and a file's own `executablePath` has no effect. This
48
+ holds whether the file imports `test` from `@playwright/test`,
49
+ `playwright/test`, or `@gfdelarue/testkit/playwright`.
50
+
51
+ Playwright starts Chromium with `--disable-back-forward-cache`. To check that
52
+ Back restores a page from the back/forward cache, drop that flag in the file:
53
+
54
+ ```ts
55
+ test.use({ launchOptions: { ignoreDefaultArgs: ["--disable-back-forward-cache"] } });
56
+ ```
57
+
58
+ Testkit starts managed Chromium with its sandbox on, which confines a
59
+ compromised renderer. Playwright on its own starts Chromium with
60
+ `--no-sandbox`, where a renderer runs with the user's access to the checkout and
61
+ their files. A project's `launchOptions` and a file's `test.use` keep the
62
+ config's `chromiumSandbox` unless they set it.
63
+
64
+ Some hosts can't start the sandbox, such as root in a container, or a Linux host
65
+ that doesn't allow unprivileged user namespaces. There Chromium fails to launch,
66
+ and Testkit reports an infrastructure failure that names the opt-out. Turn the
67
+ sandbox off in `playwright.config.ts`:
68
+
69
+ ```ts
70
+ export default defineTestkitConfig({
71
+ use: { launchOptions: { chromiumSandbox: false } },
72
+ });
73
+ ```
74
+
75
+ `playwright.config.ts` sees only the environment that its group's services
76
+ declare, so to turn the sandbox off on one host only, pass the host's variable
77
+ through a service's `env` in `testkit.config.ts` and read it in
78
+ `playwright.config.ts`:
79
+
80
+ ```ts
81
+ // testkit.config.ts, in a service the UI group uses
82
+ env: { CHROMIUM_SANDBOX: process.env.CHROMIUM_SANDBOX ?? "on" },
83
+
84
+ // playwright.config.ts
85
+ use: { launchOptions: { chromiumSandbox: process.env.CHROMIUM_SANDBOX !== "off" } },
86
+ ```
87
+
88
+ `app.node(...)` and `app.next(...)` take the same value as
89
+ `env: { values: { CHROMIUM_SANDBOX: … } }`.
90
+
91
+ The config's value also applies to browsers that `globalSetup` and
92
+ `globalTeardown` launch.
93
+
94
+ A file can turn it off for itself with
95
+ `test.use({ launchOptions: { chromiumSandbox: false } })`.
96
+
44
97
  ## Typechecking
45
98
 
46
99
  `testkit typecheck` groups the discovered test files by engine and by their
47
100
  nearest tsconfig, and checks each group with native `tsc --noEmit`. Plain Vitest
48
101
  test files written in TypeScript join the Node/Vitest program, and plain
49
- JavaScript files are skipped. Config and Node/Vitest use Node types and ES2022;
50
- Playwright adds DOM and DOM.Iterable. Each check has a deadline and can be
51
- cancelled. When a program fails, the report includes the programs that passed
102
+ JavaScript files are skipped. Every program uses Node types. The config program
103
+ uses ES2022, and Playwright programs use ES2022, DOM, and DOM.Iterable. A
104
+ Node/Vitest program uses the `lib` of the tsconfig it extends, as the
105
+ repository's own `tsc` does, so a test that runs in a jsdom or happy-dom
106
+ environment can use the DOM libraries that tsconfig lists. When that tsconfig
107
+ sets no `lib`, TypeScript's default for ES2022 applies, which includes DOM.
108
+ Without a tsconfig, a Node/Vitest program uses ES2022. Each check has a deadline
109
+ and can be cancelled. When a program fails, the report includes the programs that passed
52
110
  before it.
53
111
 
54
112
  Testkit supports consumer TypeScript 5.9.3 and 6.0.2. Each program uses the
@@ -64,7 +122,29 @@ over conflicting consumer packages. A helper shared by several engines must
64
122
  typecheck in each engine's program. Testkit's generated configs don't set
65
123
  `baseUrl`, so they need no deprecation suppression and you never edit them.
66
124
  Aliases inherited from a config with `baseUrl` keep their target directory and
67
- fallback order.
125
+ fallback order. The generated configs also clear the inherited output paths,
126
+ `outDir`, `outFile`, `declarationDir`, `sourceRoot`, `mapRoot`, and, for test
127
+ programs, `rootDir`. TypeScript holds every file to an explicit `rootDir`, and
128
+ when an output path is set without one, TypeScript 6 uses the tsconfig's own
129
+ directory. With both cleared, a test file outside the tsconfig's `rootDir`, or
130
+ outside TypeScript 6's default, still type-checks. When the tsconfig sets `incremental`
131
+ or `composite`, Testkit writes its build info beside the generated config in
132
+ `.testkit/_typecheck`, never over the repository's own.
133
+
134
+ A plain file's program also includes the TypeScript setup files of its Vitest
135
+ project, because Vitest loads them before the file and a setup file can declare
136
+ types, such as the matchers that `@testing-library/jest-dom/vitest` adds. Those
137
+ setup files are type-checked too. Files whose projects load different setup
138
+ files go to separate programs, so one project's setup types never reach another
139
+ project's files, and a file that two such projects include is checked in both.
140
+ The label of a program with setup files names them, as in
141
+ `node-vitest with tests/setup.ts`. A JavaScript setup file, or a package named
142
+ directly in `setupFiles`, adds no types. Import the package from a TypeScript
143
+ setup file instead.
144
+
145
+ `testkit typecheck --group <name>` checks the config and the files that group
146
+ owns, with the setup files of their Vitest projects. An unknown group fails and
147
+ lists the groups.
68
148
 
69
149
  ### Playwright support files
70
150
 
@@ -89,8 +169,10 @@ support files that join the Playwright program. Use it for global setup and
89
169
  teardown, reporters, fixtures, and dependency and teardown projects, including
90
170
  every variant of a multi-project config. An empty companion can supply options
91
171
  alone. Without a companion, Testkit checks the implicit roots, what they import,
92
- and the existing Next ambient and fixture defaults. Project references don't
93
- run.
172
+ and the existing Next ambient and fixture defaults. A companion replaces those
173
+ Next defaults: list `next-env.d.ts`, `tests/playwright-fixtures`, or generated
174
+ types such as `.next/types` in it when the suites need them. Project references
175
+ don't run.
94
176
 
95
177
  TypeScript follows imported helpers, but it can't find a file that only a
96
178
  runtime string or function names. Include those files in the companion.
@@ -100,15 +182,15 @@ runtime string or function names. Include those files in the companion.
100
182
  The environment declared for a test is part of the test's input. Each engine
101
183
  exposes it through its own authoring surface:
102
184
 
103
- - Node/Vitest data and contract callbacks read it from immutable `context.env`.
185
+ - Node/Vitest tests read it from `process.env`, and named values from
186
+ `@gfdelarue/testkit/environment`.
104
187
  - Playwright files read immutable `context.env` from `readPlaywrightContext()`
105
188
  when Testkit runs them.
106
189
 
107
- Outside a Testkit run, a Node/Vitest authoring context has an empty `env`, and
108
- `readPlaywrightContext()` returns `null`.
190
+ Outside a Testkit run, `readPlaywrightContext()` returns `null`.
109
191
 
110
- Typed Node/Vitest files, and plain files under `--vitest-runner managed`, also
111
- see each value as an immutable, non-enumerable `process.env.KEY` property, so
192
+ Plain files under `--vitest-runner managed` see each value as an immutable,
193
+ non-enumerable `process.env.KEY` property, so
112
194
  libraries that read `process.env` see it. `process.env` isn't the enumerable
113
195
  list of the test's values, though. A Node child that inherits Testkit's
114
196
  bootstrap sees the values too. A non-Node child process receives only the
@@ -116,6 +198,18 @@ values the test passes it. Plain files under the repository's Vitest get the
116
198
  values as ordinary environment variables, which tests and child processes can
117
199
  read, enumerate, change, and delete like any other.
118
200
 
201
+ Vitest and Vite write some keys into each test process's environment
202
+ themselves. Under either runner, a test sees:
203
+
204
+ - the group's `NODE_ENV`, or `test` when the group sets none
205
+ - the group's `VITE_` values, ahead of the same keys in `.env` files
206
+ - Vitest's own `TEST`, `VITEST`, `VITEST_MODE`, `FORCE_TTY`, `MODE`, `DEV`,
207
+ `PROD`, and `SSR`, whatever the group sets
208
+
209
+ Under `--vitest-runner managed`, `NODE_ENV` and `VITE_` values are ordinary
210
+ variables rather than immutable ones, and they count toward the process
211
+ environment limit.
212
+
119
213
  Test files of every engine may import `@gfdelarue/testkit/environment` and read
120
214
  named endpoints, databases, and handles with `endpoint(name)`, `database(name)`,
121
215
  and `handle(name)`. See
@@ -137,7 +231,7 @@ environment:
137
231
  | Engine | Reserved prefixes | Other reserved keys | Consumer environment limit |
138
232
  | ------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
139
233
  | `node-vitest` | none | `BASE_URL`, `FORCE_COLOR`, `NODE_OPTIONS`, `NO_COLOR`, `UPDATE_SNAPSHOT`, `VITEST_POOL_ID`, `VITEST_WORKER_ID`, `TESTKIT_ACTIVE`, `TESTKIT_DATA_ARTIFACT_DIR`, `TESTKIT_INVOCATION_ID`, `TESTKIT_LEASE_DIR`, `TESTKIT_LEASE_ID`, `TESTKIT_MODE`, `TESTKIT_NODE_VITEST_INPUT_FILE`, `TESTKIT_NODE_VITEST_INPUT_SHA256`, `TESTKIT_RUNTIME_ID`, `TESTKIT_TEST_FILE`, `TESTKIT_TEST_ID` | 512 entries and 4 MiB of UTF-8 key/value data; 8 MiB for all of the test's inputs together |
140
- | `playwright` | `TESTKIT_`, `PLAYWRIGHT_`, `PWTEST_`, `PW_TEST_` | `BASE_URL`, `FORCE_COLOR`, `NODE_OPTIONS`, `NO_COLOR` | 512 entries and 2 MiB of UTF-8 key/value data; 4 MiB for all of the test's inputs together |
234
+ | `playwright` | `TESTKIT_`, `PLAYWRIGHT_`, `PWTEST_`, `PW_TEST_` | `BASE_URL`, `DBUS_SESSION_BUS_ADDRESS`, `FC_FONTATIONS`, `FORCE_COLOR`, `NODE_OPTIONS`, `NO_COLOR` | 512 entries and 2 MiB of UTF-8 key/value data; 4 MiB for all of the test's inputs together |
141
235
 
142
236
  Prefixes and keys match in any letter case. The processes Testkit starts have
143
237
  separate environment limits, which consumer values don't count toward: 24,576