@1aboveio/skills 1.0.8 → 1.0.9

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 (214) hide show
  1. package/.codex-plugin/plugin.json +13 -0
  2. package/.codex-plugin/resources.json +1827 -0
  3. package/README.md +22 -0
  4. package/package.json +9 -2
  5. package/skills/app-dev/airflow/SKILL.md +1 -1
  6. package/skills/app-dev/airflow/release-check.mjs +3 -1
  7. package/skills/app-dev/android-foundation/SKILL.md +1 -1
  8. package/skills/app-dev/android-foundation/release-check.mjs +3 -1
  9. package/skills/app-dev/app-debug/SKILL.md +1 -1
  10. package/skills/app-dev/app-debug/release-check.mjs +3 -1
  11. package/skills/app-dev/better-auth/SKILL.md +1 -1
  12. package/skills/app-dev/better-auth/release-check.mjs +3 -1
  13. package/skills/app-dev/data-catalog/SKILL.md +1 -1
  14. package/skills/app-dev/data-catalog/release-check.mjs +3 -1
  15. package/skills/app-dev/data-quality/SKILL.md +1 -1
  16. package/skills/app-dev/data-quality/release-check.mjs +3 -1
  17. package/skills/app-dev/ios-foundation/SKILL.md +1 -1
  18. package/skills/app-dev/ios-foundation/release-check.mjs +3 -1
  19. package/skills/app-dev/monorepo/SKILL.md +1 -1
  20. package/skills/app-dev/monorepo/release-check.mjs +3 -1
  21. package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
  22. package/skills/app-dev/nextjs-fullstack/release-check.mjs +3 -1
  23. package/skills/app-dev/prisma-setup/SKILL.md +1 -1
  24. package/skills/app-dev/prisma-setup/release-check.mjs +3 -1
  25. package/skills/app-dev/pyspark/SKILL.md +1 -1
  26. package/skills/app-dev/pyspark/release-check.mjs +3 -1
  27. package/skills/app-dev/python-backend/SKILL.md +1 -1
  28. package/skills/app-dev/python-backend/release-check.mjs +3 -1
  29. package/skills/app-dev/shadcn/SKILL.md +1 -1
  30. package/skills/app-dev/shadcn/release-check.mjs +3 -1
  31. package/skills/app-dev/zod-v4/SKILL.md +1 -1
  32. package/skills/app-dev/zod-v4/release-check.mjs +3 -1
  33. package/skills/cicd/cloud-build/SKILL.md +1 -1
  34. package/skills/cicd/cloud-build/release-check.mjs +3 -1
  35. package/skills/cicd/cloud-debug/SKILL.md +1 -1
  36. package/skills/cicd/cloud-debug/release-check.mjs +3 -1
  37. package/skills/cicd/cloud-deploy/SKILL.md +1 -1
  38. package/skills/cicd/cloud-deploy/release-check.mjs +3 -1
  39. package/skills/cicd/docker/SKILL.md +1 -1
  40. package/skills/cicd/docker/release-check.mjs +3 -1
  41. package/skills/cicd/github-actions/SKILL.md +1 -1
  42. package/skills/cicd/github-actions/release-check.mjs +3 -1
  43. package/skills/cicd/github-flow/SKILL.md +1 -1
  44. package/skills/cicd/github-flow/release-check.mjs +3 -1
  45. package/skills/cicd/google-cloud/SKILL.md +1 -1
  46. package/skills/cicd/google-cloud/release-check.mjs +3 -1
  47. package/skills/cicd/mergify/SKILL.md +1 -1
  48. package/skills/cicd/mergify/release-check.mjs +3 -1
  49. package/skills/cicd/podman/SKILL.md +1 -1
  50. package/skills/cicd/podman/release-check.mjs +3 -1
  51. package/skills/content/article-review/SKILL.md +1 -1
  52. package/skills/content/article-review/release-check.mjs +3 -1
  53. package/skills/content/article-to-image/SKILL.md +1 -1
  54. package/skills/content/article-to-image/release-check.mjs +3 -1
  55. package/skills/content/flowchart-svg/SKILL.md +1 -1
  56. package/skills/content/flowchart-svg/release-check.mjs +3 -1
  57. package/skills/content/image-gen/SKILL.md +1 -1
  58. package/skills/content/image-gen/release-check.mjs +3 -1
  59. package/skills/content/mermaid/SKILL.md +1 -1
  60. package/skills/content/mermaid/release-check.mjs +3 -1
  61. package/skills/content/wechat-article-writer/SKILL.md +1 -1
  62. package/skills/content/wechat-article-writer/release-check.mjs +3 -1
  63. package/skills/content/wechat-publisher/SKILL.md +1 -1
  64. package/skills/content/wechat-publisher/release-check.mjs +3 -1
  65. package/skills/content/wechat-search/SKILL.md +1 -1
  66. package/skills/content/wechat-search/release-check.mjs +3 -1
  67. package/skills/content/xai-search/SKILL.md +88 -13
  68. package/skills/content/xai-search/release-check.mjs +3 -1
  69. package/skills/content/xai-search/scripts/xai_search.sh +125 -149
  70. package/skills/core/distill-writing/SKILL.md +1 -1
  71. package/skills/core/distill-writing/release-check.mjs +3 -1
  72. package/skills/core/doc-to-md/SKILL.md +1 -1
  73. package/skills/core/doc-to-md/release-check.mjs +3 -1
  74. package/skills/core/editorial-review/SKILL.md +1 -1
  75. package/skills/core/editorial-review/release-check.mjs +3 -1
  76. package/skills/core/house-style/SKILL.md +1 -1
  77. package/skills/core/house-style/release-check.mjs +3 -1
  78. package/skills/core/plain-language/SKILL.md +1 -1
  79. package/skills/core/plain-language/release-check.mjs +3 -1
  80. package/skills/core/polish-cn/SKILL.md +1 -1
  81. package/skills/core/polish-cn/release-check.mjs +3 -1
  82. package/skills/core/reg-parser/SKILL.md +1 -1
  83. package/skills/core/reg-parser/release-check.mjs +3 -1
  84. package/skills/core/terminology/SKILL.md +1 -1
  85. package/skills/core/terminology/release-check.mjs +3 -1
  86. package/skills/core/write-doc/SKILL.md +1 -1
  87. package/skills/core/write-doc/release-check.mjs +3 -1
  88. package/skills/engineering/better-review/SKILL.md +1 -1
  89. package/skills/engineering/better-review/release-check.mjs +3 -1
  90. package/skills/engineering/contributing/SKILL.md +1 -1
  91. package/skills/engineering/contributing/release-check.mjs +3 -1
  92. package/skills/engineering/e2e-test/SKILL.md +1 -1
  93. package/skills/engineering/e2e-test/release-check.mjs +3 -1
  94. package/skills/engineering/engineering-runtime/SKILL.md +1 -1
  95. package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
  96. package/skills/engineering/engineering-runtime/release-check.mjs +3 -1
  97. package/skills/engineering/engineering-runtime/scripts/installation-resolver.mjs +191 -0
  98. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +51 -10
  99. package/skills/engineering/ensure-coverage/SKILL.md +1 -1
  100. package/skills/engineering/ensure-coverage/release-check.mjs +3 -1
  101. package/skills/engineering/golden-path/SKILL.md +1 -1
  102. package/skills/engineering/golden-path/release-check.mjs +3 -1
  103. package/skills/engineering/harness-runtime/SKILL.md +1 -1
  104. package/skills/engineering/harness-runtime/release-check.mjs +3 -1
  105. package/skills/engineering/resolve-issues/SKILL.md +1 -1
  106. package/skills/engineering/resolve-issues/references/preflight.md +7 -0
  107. package/skills/engineering/resolve-issues/references/shared-modules.md +27 -0
  108. package/skills/engineering/resolve-issues/references/task-plan.md +5 -1
  109. package/skills/engineering/resolve-issues/release-check.mjs +3 -1
  110. package/skills/engineering/resolve-issues/scripts/active-installation.mjs +32 -0
  111. package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +3 -0
  112. package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +17 -1
  113. package/skills/engineering/resolve-release/SKILL.md +1 -1
  114. package/skills/engineering/resolve-release/release-check.mjs +3 -1
  115. package/skills/engineering/rush-issues/SKILL.md +1 -1
  116. package/skills/engineering/rush-issues/release-check.mjs +3 -1
  117. package/skills/engineering/rush-release/SKILL.md +1 -1
  118. package/skills/engineering/rush-release/release-check.mjs +3 -1
  119. package/skills/engineering/test-quality/SKILL.md +1 -1
  120. package/skills/engineering/test-quality/release-check.mjs +3 -1
  121. package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
  122. package/skills/risk-compliance/compliance-audit/release-check.mjs +3 -1
  123. package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
  124. package/skills/risk-compliance/contract-compare/release-check.mjs +3 -1
  125. package/skills/risk-compliance/contract-review/SKILL.md +1 -1
  126. package/skills/risk-compliance/contract-review/release-check.mjs +3 -1
  127. package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
  128. package/skills/risk-compliance/doc-authenticity/release-check.mjs +3 -1
  129. package/skills/risk-compliance/fraud-analysis/SKILL.md +1 -1
  130. package/skills/risk-compliance/fraud-analysis/release-check.mjs +3 -1
  131. package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
  132. package/skills/risk-compliance/payment-analysis/release-check.mjs +3 -1
  133. package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
  134. package/skills/risk-compliance/similar-domain/release-check.mjs +3 -1
  135. package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
  136. package/skills/risk-compliance/tld-detection/release-check.mjs +3 -1
  137. package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +0 -436
  138. package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +0 -36
  139. package/skills/app-dev/data-quality/scripts/data-quality.test.mjs +0 -12
  140. package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +0 -637
  141. package/skills/cicd/github-flow/scripts/flow.test.mjs +0 -114
  142. package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +0 -108
  143. package/skills/cicd/mergify/scripts/audit.test.mjs +0 -201
  144. package/skills/cicd/mergify/scripts/entrypoints.test.mjs +0 -106
  145. package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +0 -30
  146. package/skills/cicd/mergify/scripts/stack-push.test.mjs +0 -233
  147. package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +0 -1826
  148. package/skills/content/image-gen/scripts/credentials.test.mjs +0 -212
  149. package/skills/content/image-gen/scripts/options.test.mjs +0 -245
  150. package/skills/content/xai-search/tests/smoke_test.sh +0 -36
  151. package/skills/core/polish-cn/scripts/polish-cn.test.mjs +0 -244
  152. package/skills/core/reg-parser/scripts/reg-parser.test.mjs +0 -165
  153. package/skills/engineering/better-review/scripts/pr-context.test.mjs +0 -168
  154. package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +0 -587
  155. package/skills/engineering/better-review/scripts/scan-diff.test.mjs +0 -414
  156. package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +0 -96
  157. package/skills/engineering/contributing/scripts/persist-conventions.test.mjs +0 -118
  158. package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +0 -106
  159. package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +0 -117
  160. package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +0 -69
  161. package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +0 -98
  162. package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +0 -71
  163. package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +0 -59
  164. package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +0 -76
  165. package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +0 -68
  166. package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +0 -95
  167. package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +0 -288
  168. package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +0 -96
  169. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +0 -96
  170. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +0 -47
  171. package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +0 -86
  172. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +0 -447
  173. package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +0 -552
  174. package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +0 -289
  175. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +0 -119
  176. package/skills/engineering/golden-path/scripts/golden-path.test.mjs +0 -1457
  177. package/skills/engineering/harness-runtime/discover-models.test.mjs +0 -363
  178. package/skills/engineering/harness-runtime/harness-runtime.test.mjs +0 -967
  179. package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +0 -829
  180. package/skills/engineering/harness-runtime/model-catalog.test.mjs +0 -366
  181. package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +0 -280
  182. package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +0 -346
  183. package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +0 -88
  184. package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +0 -264
  185. package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +0 -79
  186. package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +0 -107
  187. package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +0 -14
  188. package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +0 -149
  189. package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +0 -915
  190. package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +0 -156
  191. package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +0 -448
  192. package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +0 -217
  193. package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +0 -91
  194. package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +0 -1060
  195. package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +0 -458
  196. package/skills/engineering/resolve-release/scripts/apply.test.mjs +0 -99
  197. package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +0 -100
  198. package/skills/engineering/resolve-release/scripts/flow.test.mjs +0 -340
  199. package/skills/engineering/resolve-release/scripts/green-head.test.mjs +0 -101
  200. package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +0 -426
  201. package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +0 -659
  202. package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +0 -317
  203. package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +0 -291
  204. package/skills/engineering/resolve-release/scripts/plan.test.mjs +0 -428
  205. package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +0 -591
  206. package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +0 -119
  207. package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +0 -104
  208. package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +0 -14
  209. package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +0 -12
  210. package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +0 -212
  211. package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +0 -14
  212. package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +0 -14
  213. package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +0 -134
  214. package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +0 -520
@@ -1,289 +0,0 @@
1
- // Tests for the lint-tests gate engine (pure core, no filesystem/git).
2
- import { test } from 'node:test'
3
- import assert from 'node:assert/strict'
4
-
5
- import { scanText, scanDiff, selectRules, RULES, ALL_RULES, isTestFile, stripComment, runCli } from './lint-tests.mjs'
6
- import { resolveMockPolicy } from './mock-policy-config.mjs'
7
-
8
- test('default rules = all gate rules incl. the default-on mock-internal-seam', () => {
9
- assert.deepEqual(
10
- selectRules().map((r) => r.id).sort(),
11
- ['mock-internal-seam', 'no-empty-test', 'no-fixed-timeout', 'no-skip', 'no-swallowed-assertion'],
12
- )
13
- assert.equal(RULES.length, 4) // the four authoring gates; mock-internal-seam lives in ALL_RULES
14
- })
15
-
16
- test('no-skip rule flags skip/only/xfail (carries rule + kind)', () => {
17
- // non-empty bodies so this isolates no-skip from the no-empty-test rule
18
- const f = scanText('a.spec.ts', 'test.skip("x", () => { go() })\ndescribe.only("y", () => { go() })')
19
- assert.deepEqual(f.map((x) => [x.rule, x.kind]), [['no-skip', 'skip'], ['no-skip', 'only']])
20
- })
21
-
22
- test('no-fixed-timeout flags waitForTimeout / numeric cy.wait / time.sleep', () => {
23
- const f = scanText('a.spec.ts', [
24
- 'await page.waitForTimeout(500)',
25
- "cy.wait(1000)",
26
- 'time.sleep(2)',
27
- ].join('\n'))
28
- assert.deepEqual(f.map((x) => x.kind), ['waitForTimeout', 'cy.wait', 'time.sleep'])
29
- assert.ok(f.every((x) => x.rule === 'no-fixed-timeout'))
30
- })
31
-
32
- test('no-fixed-timeout does NOT flag an aliased cy.wait (not a fixed sleep)', () => {
33
- assert.deepEqual(scanText('a.spec.ts', "cy.wait('@getUser')"), [])
34
- })
35
-
36
- test('--rules selection runs only the chosen rule', () => {
37
- const text = 'test.skip("x", () => {})\nawait page.waitForTimeout(500)'
38
- const onlySkip = scanText('a.spec.ts', text, ['no-skip'])
39
- assert.deepEqual(onlySkip.map((x) => x.rule), ['no-skip'])
40
- const onlyTimeout = scanText('a.spec.ts', text, ['no-fixed-timeout'])
41
- assert.deepEqual(onlyTimeout.map((x) => x.rule), ['no-fixed-timeout'])
42
- })
43
-
44
- test('a single line can trip two different rules', () => {
45
- // contrived but valid: a skipped test on the same line as a timeout call
46
- const f = scanText('a.spec.ts', 'test.skip("x", async () => { await page.waitForTimeout(1) })')
47
- assert.deepEqual(f.map((x) => x.rule).sort(), ['no-fixed-timeout', 'no-skip'])
48
- })
49
-
50
- test('scanDiff flags only ADDED violations in test files, with new-file line numbers', () => {
51
- const diff = [
52
- '+++ b/e2e/x.spec.ts',
53
- '@@ -10,2 +10,3 @@',
54
- ' context',
55
- '+await page.waitForTimeout(300)',
56
- '-old line',
57
- ].join('\n')
58
- const f = scanDiff(diff)
59
- assert.equal(f.length, 1)
60
- assert.equal(f[0].rule, 'no-fixed-timeout')
61
- assert.equal(f[0].line, 11)
62
- })
63
-
64
- test('scanDiff ignores violations added to NON-test files', () => {
65
- const diff = ['+++ b/src/util.ts', '@@ -1,1 +1,2 @@', '+await sleepThing.waitForTimeout(5)'].join('\n')
66
- assert.deepEqual(scanDiff(diff), [])
67
- })
68
-
69
- test('isTestFile is shared and recognizes spec/test paths, rejects app code', () => {
70
- for (const p of ['e2e/a.spec.ts', 'src/x.test.tsx', 'tests/e2e/b.spec.js', 'api/test_views.py', 'pkg/foo_test.py', '__tests__/c.ts']) {
71
- assert.equal(isTestFile(p), true, p)
72
- }
73
- for (const p of ['src/app/page.tsx', 'lib/util.ts', 'README.md']) {
74
- assert.equal(isTestFile(p), false, p)
75
- }
76
- })
77
-
78
- // ---- no-skip rule: richer cases (folded in from the former skip-lint suite) ----
79
-
80
- test('no-skip leaves conditional skips to test-quality (a lead, not a gate)', () => {
81
- // A runtime or annotated skip depends on a condition: legitimate for a platform
82
- // CI still runs elsewhere, a hole otherwise. A gate cannot tell which.
83
- const f = scanText('a.spec.ts', 'if (!user) test.skip();\ntest.skip(true, "https://github.com/o/r/issues/1")')
84
- assert.equal(f.filter((x) => x.rule === 'no-skip').length, 0)
85
- })
86
-
87
- test('no-skip flags unconditional Python skips, not skipif/runtime skip/xfail', () => {
88
- const text = [
89
- '@pytest.mark.skip(reason="x")',
90
- '@pytest.mark.skipif(cond)',
91
- '@unittest.skip("x")',
92
- ' pytest.skip("x")',
93
- '@pytest.mark.xfail',
94
- ].join('\n')
95
- assert.deepEqual(scanText('test_x.py', text).filter((f) => f.rule === 'no-skip').map((f) => [f.line, f.kind]), [[1, 'skip'], [3, 'skip']])
96
- })
97
-
98
- test('no-skip flags declared-skipped and todo tests', () => {
99
- const f = scanText('a.spec.ts', 'test.skip("later", () => { go() })\ntest.todo("write me")')
100
- assert.deepEqual(f.filter((x) => x.rule === 'no-skip').map((x) => x.kind), ['skip', 'todo'])
101
- })
102
-
103
- test('no-skip does not flag a commented-out or doc mention', () => {
104
- const text = [
105
- '// never use test.skip() — banned',
106
- '# doc: test.skip is not allowed',
107
- 'const xs = items.skip(2) // unrelated array method',
108
- ].join('\n')
109
- assert.deepEqual(scanText('a.spec.ts', text), [])
110
- })
111
-
112
- test('no-skip does not flag .only/.skip method calls that are not test forms', () => {
113
- assert.deepEqual(scanText('a.spec.ts', 'arr.skip(1); foo.only;'), [])
114
- })
115
-
116
- // ---- no-empty-test rule: the decidable floor of the Missing-Assertion smell ----
117
-
118
- test('no-empty-test flags empty arrow/function/playwright/.each/.concurrent bodies', () => {
119
- const cases = [
120
- "test('a', () => {})",
121
- 'it("b", async () => {})',
122
- "test('c', function () {})",
123
- "test('d', async ({ page }) => {})",
124
- "it.each([1,2])('e', () => {})",
125
- "test.concurrent('f', () => {})",
126
- ]
127
- for (const c of cases) {
128
- const f = scanText('a.spec.ts', c, ['no-empty-test'])
129
- assert.equal(f.length, 1, `should flag: ${c}`)
130
- assert.equal(f[0].kind, 'empty-test')
131
- }
132
- })
133
-
134
- test('no-empty-test does NOT flag a test that has a body', () => {
135
- const cases = [
136
- "test('a', () => { expect(1).toBe(1) })",
137
- "it('b', async () => { await verifyDashboard(page) })", // asserts via helper — not empty, not flagged
138
- "test('c', () => { doThing() })",
139
- ]
140
- for (const c of cases) assert.deepEqual(scanText('a.spec.ts', c, ['no-empty-test']), [], c)
141
- })
142
-
143
- test('no-empty-test does NOT flag describe/suite, look-alike identifiers, or 1-arg calls', () => {
144
- const text = [
145
- "describe('group', () => {})", // empty suite is not a fake test
146
- "emit('evt', () => {})", // 'it' inside emit — word boundary protects
147
- "submit('x', () => {})", // 'it' inside submit
148
- "it('pending')", // no callback — not an empty-bodied test
149
- 'const t = () => {}', // not a test call
150
- ].join('\n')
151
- assert.deepEqual(scanText('a.spec.ts', text, ['no-empty-test']), [])
152
- })
153
-
154
- test('no-empty-test leaves a multi-line empty body to the review lead (no false block)', () => {
155
- // The opening line has no closing brace, so the single-line gate does not fire.
156
- assert.deepEqual(scanText('a.spec.ts', "it('x', () => {\n})", ['no-empty-test']), [])
157
- })
158
-
159
- // ---- no-swallowed-assertion rule: the vacuous-green form behind #237 ----
160
-
161
- test('no-swallowed-assertion flags a matcher whose rejection is eaten by .catch()', () => {
162
- const cases = [
163
- "await expect(page.locator('#cta')).not.toBeVisible().catch(() => {})", // the #237 form
164
- "await expect(btn).toHaveText('Sign in').catch(() => null)",
165
- 'await expect(x).toBe(1).catch(() => {})',
166
- ]
167
- for (const c of cases) {
168
- const f = scanText('a.spec.ts', c, ['no-swallowed-assertion'])
169
- assert.equal(f.length, 1, `should flag: ${c}`)
170
- assert.equal(f[0].kind, 'swallowed-catch')
171
- assert.equal(f[0].rule, 'no-swallowed-assertion')
172
- }
173
- })
174
-
175
- test('no-swallowed-assertion does NOT flag a legitimate assertion or an unrelated .catch', () => {
176
- const cases = [
177
- "await expect(page.locator('#cta')).toBeVisible()", // real assertion, no swallow
178
- "const v = await fetchThing().catch(() => fallback)", // .catch on setup, not a matcher
179
- "promise.then(ok).catch(handleError)", // plain promise handling
180
- ]
181
- for (const c of cases) assert.deepEqual(scanText('a.spec.ts', c, ['no-swallowed-assertion']), [], c)
182
- })
183
-
184
- test('no-swallowed-assertion is a default gate and flags it in a PR diff', () => {
185
- const diff = [
186
- '+++ b/e2e/login.sweep.spec.ts',
187
- '@@ -1,1 +1,2 @@',
188
- ' context',
189
- "+await expect(page.locator('#cta')).not.toBeVisible().catch(() => {})",
190
- ].join('\n')
191
- const f = scanDiff(diff) // default rule set, no explicit --rules
192
- assert.equal(f.length, 1)
193
- assert.equal(f[0].rule, 'no-swallowed-assertion')
194
- })
195
-
196
- test('stripComment removes // and # trailing comments', () => {
197
- assert.equal(stripComment('code // test.skip()').includes('test.skip'), false)
198
- assert.equal(stripComment('code # pytest.skip').includes('pytest.skip'), false)
199
- })
200
-
201
- test('scanDiff ignores a pre-existing skip on an unchanged (context) line', () => {
202
- const diff = ['+++ b/e2e/x.spec.ts', '@@ -1,2 +1,3 @@', ' test.skip("inherited", () => {})', '+test("added clean", () => { ok() })'].join('\n')
203
- assert.deepEqual(scanDiff(diff), [])
204
- })
205
-
206
- // ---- mock-internal-seam rule: the zero-tolerance, default-on over-mock gate ----
207
-
208
- const SEAM_CTX = { policy: resolveMockPolicy({ firstPartyPackages: ['@agentier/'] }) }
209
-
210
- test('mock-internal-seam is default-on: in ALL_RULES and in the default gate set', () => {
211
- assert.ok(ALL_RULES.some((r) => r.id === 'mock-internal-seam'))
212
- // zero-tolerance: it runs by default, no opt-in needed
213
- assert.ok(selectRules().some((r) => r.id === 'mock-internal-seam'))
214
- assert.deepEqual(
215
- selectRules().map((r) => r.id).sort(),
216
- ['mock-internal-seam', 'no-empty-test', 'no-fixed-timeout', 'no-skip', 'no-swallowed-assertion'],
217
- )
218
- })
219
-
220
- test('mock-internal-seam cannot be opted out via config (enabled:false is ignored)', () => {
221
- // the gate is defaultOn:true; selectRules does not consult policy.enabled
222
- assert.ok(selectRules().some((r) => r.id === 'mock-internal-seam'))
223
- // and naming a subset still resolves it from the registry
224
- assert.deepEqual(selectRules(['mock-internal-seam']).map((r) => r.id), ['mock-internal-seam'])
225
- })
226
-
227
- test('mock-internal-seam flags a first-party alias mock (the studio incident)', () => {
228
- const f = scanText('a.test.ts', "vi." + "mock('@/lib/org-allowlist-client')", ['mock-internal-seam'], SEAM_CTX)
229
- assert.equal(f.length, 1)
230
- assert.equal(f[0].rule, 'mock-internal-seam')
231
- assert.equal(f[0].detail, '@/lib/org-allowlist-client')
232
- })
233
-
234
- test('mock-internal-seam exempts stdlib and third-party packages', () => {
235
- const text = ["vi.mock('node:fs')", "jest.mock('react')", "vi.mock('@playwright/test')"].join('\n')
236
- assert.deepEqual(scanText('a.test.ts', text, ['mock-internal-seam'], SEAM_CTX), [])
237
- })
238
-
239
- test('mock-internal-seam ignores an inline @mock-ok comment (no waivers)', () => {
240
- const text = "vi." + "mock('@/lib/cp') // @mock-ok: covered by cp.real.test.ts"
241
- const f = scanText('a.test.ts', text, ['mock-internal-seam'], SEAM_CTX)
242
- assert.equal(f.length, 1) // still flagged — zero-tolerance, no escape hatch
243
- assert.equal(f[0].detail, '@/lib/cp')
244
- })
245
-
246
- test('mock-internal-seam flags a declared first-party workspace package', () => {
247
- const f = scanText('a.test.ts', "vi.mock('@agentier/shared')", ['mock-internal-seam'], SEAM_CTX)
248
- assert.equal(f.length, 1)
249
- assert.equal(f[0].detail, '@agentier/shared')
250
- })
251
-
252
- test('mock-internal-seam fires with NO ctx policy (never silently inert; @/ defaults apply)', () => {
253
- // zero-tolerance: omitting config must not disable the gate — it falls back
254
- // to DEFAULT_MOCK_POLICY, which flags conventional @/ first-party mocks.
255
- const f = scanText('a.test.ts', "vi." + "mock('@/lib/x')", ['mock-internal-seam'])
256
- assert.equal(f.length, 1)
257
- assert.equal(f[0].detail, '@/lib/x')
258
- })
259
-
260
- test('mock-internal-seam flags an ADDED first-party mock in a PR diff (PR lane)', () => {
261
- const diff = ['+++ b/src/__tests__/x.test.ts', '@@ -1,1 +1,2 @@', " import x", "+vi." + "mock('@/lib/cp')"].join('\n')
262
- const f = scanDiff(diff, ['mock-internal-seam'], SEAM_CTX)
263
- assert.equal(f.length, 1)
264
- assert.equal(f[0].rule, 'mock-internal-seam')
265
- })
266
-
267
- test('mock-internal-seam flags an INHERITED (un-added) mock in a whole-tree scan (no grandfathering)', () => {
268
- // whole-tree lane: scanText sees every line, not just diff additions, so the
269
- // 781-style inherited debt is flagged until removed.
270
- const f = scanText('src/__tests__/x.test.ts', "import x\nvi.mock('@/lib/cp')\n", ['mock-internal-seam'], SEAM_CTX)
271
- assert.equal(f.length, 1)
272
- assert.equal(f[0].detail, '@/lib/cp')
273
- })
274
-
275
- test('mock-internal-seam does not fire on a commented-out mock line', () => {
276
- assert.deepEqual(scanText('a.test.ts', "// vi.mock('@/lib/x')", ['mock-internal-seam'], SEAM_CTX), [])
277
- })
278
-
279
- test('--help prints usage and exits 0 without scanning the tree', () => {
280
- const lines = []
281
- const orig = console.log
282
- console.log = (s) => lines.push(String(s))
283
- try {
284
- assert.equal(runCli(['--help']), 0)
285
- } finally {
286
- console.log = orig
287
- }
288
- assert.match(lines.join('\n'), /usage: lint-tests\.mjs/)
289
- })
@@ -1,119 +0,0 @@
1
- // Tests for the mock-policy classifier (pure; one fs case via a temp dir).
2
- import { test } from 'node:test'
3
- import assert from 'node:assert/strict'
4
- import fs from 'node:fs'
5
- import os from 'node:os'
6
- import path from 'node:path'
7
-
8
- import {
9
- DEFAULT_MOCK_POLICY,
10
- resolveMockPolicy,
11
- loadMockPolicy,
12
- loadMockPolicyFromFile,
13
- extractMockTarget,
14
- classifyMockTarget,
15
- } from './mock-policy-config.mjs'
16
-
17
- test('default policy is zero-tolerance: default-on, no waiver tag', () => {
18
- assert.equal(DEFAULT_MOCK_POLICY.enabled, true)
19
- // the inline-waiver escape hatch is gone
20
- assert.equal(DEFAULT_MOCK_POLICY.waiverTag, undefined)
21
- })
22
-
23
- test('extractMockTarget pulls the specifier from vi/jest/vitest mock+doMock', () => {
24
- assert.equal(extractMockTarget("vi." + "mock('@/lib/x')"), '@/lib/x')
25
- assert.equal(extractMockTarget('jest.' + 'mock("pkg")'), 'pkg')
26
- assert.equal(extractMockTarget('vi.' + 'doMock(`@/a/b`)'), '@/a/b')
27
- assert.equal(extractMockTarget('vitest.' + 'mock("./rel")'), './rel')
28
- assert.equal(extractMockTarget('const x = mockThing()'), null) // bare mock() is not a module mock
29
- assert.equal(extractMockTarget('expect(x).toBe(1)'), null)
30
- })
31
-
32
- test('classify: first-party alias @/ and ~/ are internal seams (the incident case)', () => {
33
- const p = resolveMockPolicy({})
34
- assert.equal(classifyMockTarget('@/lib/org-allowlist-client', p).internal, true)
35
- assert.equal(classifyMockTarget('~/services/cp', p).internal, true)
36
- })
37
-
38
- test('classify: stdlib and third-party packages are external (exempt)', () => {
39
- const p = resolveMockPolicy({})
40
- assert.equal(classifyMockTarget('node:fs', p).internal, false)
41
- assert.equal(classifyMockTarget('react', p).internal, false)
42
- assert.equal(classifyMockTarget('@playwright/test', p).internal, false)
43
- })
44
-
45
- test('classify: relative import into source is internal; into a test util/fixture is not', () => {
46
- const p = resolveMockPolicy({})
47
- assert.equal(classifyMockTarget('../services/payments', p).internal, true)
48
- assert.equal(classifyMockTarget('./helpers/operator-session-store', p).internal, false)
49
- assert.equal(classifyMockTarget('../__mocks__/cp', p).internal, false)
50
- assert.equal(classifyMockTarget('../fixtures/data', p).internal, false)
51
- })
52
-
53
- test('classify: declared first-party workspace package is internal', () => {
54
- const p = resolveMockPolicy({ firstPartyPackages: ['@acme/'] })
55
- assert.equal(classifyMockTarget('@acme/db', p).internal, true)
56
- assert.equal(classifyMockTarget('@acme', p).internal, true)
57
- assert.equal(classifyMockTarget('@other/db', p).internal, false)
58
- })
59
-
60
- test('classify: declared externals allowlist exempts a first-party-looking target', () => {
61
- const p = resolveMockPolicy({ externals: ['^@/generated/'] })
62
- assert.equal(classifyMockTarget('@/generated/openapi', p).internal, false) // exempted
63
- assert.equal(classifyMockTarget('@/lib/x', p).internal, true) // still flagged
64
- })
65
-
66
- test('compiled _externalsRe is non-enumerable: does not leak into JSON / enumeration', () => {
67
- const p = resolveMockPolicy({ externals: ['^@/generated/'] })
68
- // the compiled RegExp cache works...
69
- assert.equal(classifyMockTarget('@/generated/openapi', p).internal, false)
70
- // ...but is hidden from enumeration and serialization
71
- assert.ok(!Object.keys(p).includes('_externalsRe'))
72
- assert.equal(JSON.parse(JSON.stringify(p))._externalsRe, undefined)
73
- })
74
-
75
- test('loadMockPolicy reads coverage.config.json topology, defaults to on with no config', () => {
76
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mpc-'))
77
- // no config → zero-tolerance default (on), conventional topology
78
- assert.equal(loadMockPolicy(dir).enabled, true)
79
- // with config → declared topology is merged in (config declares topology, not on/off)
80
- fs.writeFileSync(
81
- path.join(dir, 'coverage.config.json'),
82
- JSON.stringify({ mockPolicy: { firstPartyPackages: ['@acme/'] } }),
83
- )
84
- const p = loadMockPolicy(dir)
85
- assert.equal(p.enabled, true)
86
- assert.deepEqual(p.firstPartyPackages, ['@acme/'])
87
- // inherited default array still present
88
- assert.ok(p.firstPartyAliasPrefixes.includes('@/'))
89
- })
90
-
91
- test('loadMockPolicy never throws on malformed config (and stays on)', () => {
92
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mpc-'))
93
- fs.writeFileSync(path.join(dir, 'coverage.config.json'), '{ not json')
94
- assert.equal(loadMockPolicy(dir).enabled, true)
95
- })
96
-
97
- test('loadMockPolicyFromFile reads the NAMED file (finding #1: not just its dirname)', () => {
98
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mpc-'))
99
- const file = path.join(dir, 'team-coverage.json') // deliberately non-standard name
100
- fs.writeFileSync(file, JSON.stringify({ mockPolicy: { enabled: true, externals: ['^@/generated/'] } }))
101
- const p = loadMockPolicyFromFile(file)
102
- assert.equal(p.enabled, true)
103
- // the declared externals must actually apply (proof the file was read, not defaults)
104
- assert.equal(classifyMockTarget('@/generated/openapi', p).internal, false)
105
- assert.equal(classifyMockTarget('@/lib/auth', p).internal, true)
106
- })
107
-
108
- test('loadMockPolicyFromFile falls back to defaults when the named file is missing', () => {
109
- // finding #1: a declared config that does not apply must not look like a clean pass.
110
- // (It warns on stderr; here we assert the zero-tolerance default — gate stays ON.)
111
- const p = loadMockPolicyFromFile(path.join(os.tmpdir(), 'definitely-absent-config-xyz.json'))
112
- assert.equal(p.enabled, true)
113
- })
114
-
115
- test('loadMockPolicyFromFile with no argument discovers coverage.config.json in cwd', () => {
116
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mpc-'))
117
- fs.writeFileSync(path.join(dir, 'coverage.config.json'), JSON.stringify({ mockPolicy: { enabled: true } }))
118
- assert.equal(loadMockPolicyFromFile(undefined, dir).enabled, true)
119
- })