Files
msd-core/tests/bugs-1656-1657.test.cjs
Tom Boucher f16ff7d1b3 enhance(#3545): widen no-source-grep with fold+hooks, migrate 76 sites (#4161)
* feat(#3545): widen no-source-grep with one-hop path-fold and hooks dir

Resolve a readFileSync() path argument that is a bare Identifier one hop
back to its VariableDeclarator initializer before classification, and
recognize `hooks` as a source directory alongside bin/lib/gsd-core/src.

Measured (epic #3464 phase 7): fold+hooks together newly flag 76
unsuppressed sites across 18 files that were previously invisible to
identifier-indirected or hooks/-rooted source reads. Neither widening
alone is sufficient — hooks-only surfaces 0 new sites, confirming #3520's
prior finding that the identifier-indirection gap must close first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test(#3545): migrate 76 sites newly flagged by the fold+hooks widening

Per-site classification: rewrite behaviorally (require() the real module,
assert on its actual exported behavior) wherever the read was a proxy for
code behavior; add a site-scoped `// allow-test-rule: <reason> (#3545)`
marker only where the raw source text genuinely is the product under test
(codex-config.test.cjs's adapter-header-contract checks, install.js
structural-wiring guards with no exported symbol, AST-parse fixture
inputs, etc.) — each marker cites an existing repo-sanctioned category
from CONTRIBUTING.md's allow-test-rule exception table.

Also converts two try/finally test bodies (introduced during this same
migration) to the required t.after() cleanup pattern per CONTRIBUTING.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(#3545): re-baseline effective-exemption ceiling to 81

The fold+hooks widening's own newly-detected sites are now suppressed by
site-scoped markers, moving them from invisible into the tightly-ratcheted
effective-exemption count. Ceiling rises from 10 to 81 (the exact measured
high-water mark, grace unchanged at 2) — a deliberate, measured re-baseline
per the widening working as intended, not an ordinary ceiling bump.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(#3545): use canonical allow-test-rule category tokens

4 markers added during migration cited an issue ref correctly but didn't
use one of CONTRIBUTING.md's seven recognized category tokens, unlike
every other marker in this change. Cosmetic only — same suppression
lines, same effective/live counts (81/81, 0 live).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(#3545): correct stale phase-artifact path in test comment

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-01 21:40:38 -04:00

115 lines
4.8 KiB
JavaScript

/**
* Regression tests for:
* #1656 — 3 bash hooks referenced in settings.json but never installed
* #1657 — SDK install prompt fires and fails during interactive install
*/
'use strict';
process.env.GSD_TEST_MODE = '1';
const { test, describe, before } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const { runNode } = require('./helpers/process-seam.cjs');
const { throwIfFailed } = require('./helpers/git-fixture.cjs');
const { BUILD_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
const HOOKS_DIST = path.join(__dirname, '..', 'hooks', 'dist');
const BUILD_SCRIPT = path.join(__dirname, '..', 'scripts', 'build-hooks.js');
const INSTALL_SRC = path.join(__dirname, '..', 'bin', 'install.js');
// ─── #1656 ───────────────────────────────────────────────────────────────────
describe('#1656: community .sh hooks must be present in hooks/dist', () => {
// Run the build script once before checking outputs.
// hooks/dist/ is gitignored so it must be generated; this mirrors what
// `npm run build:hooks` (prepublishOnly) does before publish.
before(() => {
const result = runNode([BUILD_SCRIPT], { timeoutMs: BUILD_TIMEOUT_MS });
throwIfFailed(result, `node ${BUILD_SCRIPT}`);
});
test('gsd-session-state.sh exists in hooks/dist', () => {
const p = path.join(HOOKS_DIST, 'gsd-session-state.sh');
assert.ok(fs.existsSync(p), 'gsd-session-state.sh must be in hooks/dist/ so the installer can copy it');
});
test('gsd-validate-commit.sh exists in hooks/dist', () => {
const p = path.join(HOOKS_DIST, 'gsd-validate-commit.sh');
assert.ok(fs.existsSync(p), 'gsd-validate-commit.sh must be in hooks/dist/ so the installer can copy it');
});
test('gsd-phase-boundary.sh exists in hooks/dist', () => {
const p = path.join(HOOKS_DIST, 'gsd-phase-boundary.sh');
assert.ok(fs.existsSync(p), 'gsd-phase-boundary.sh must be in hooks/dist/ so the installer can copy it');
});
});
// ─── #1657 / #191 follow-up ──────────────────────────────────────────────────
//
// The retired SDK package seam means installer/package metadata must no longer
// expose sdk-specific flags or publish sdk/* artifacts.
describe('#1657 / #191: installer/package metadata retires sdk seam', () => {
let src;
test('install.js does not contain the legacy promptSdk() prompt (#1657)', () => {
// allow-test-rule: structural-regression-guard (#3545) — regression guard
// against literally reintroducing dead/removed code strings (promptSdk(),
// --sdk/--no-sdk parsing, installSdkIfNeeded({) — none of them are live
// exports or behavior to exercise via require(), so the source text
// itself is the contract this test protects
src = fs.readFileSync(INSTALL_SRC, 'utf-8');
assert.ok(
!src.includes('promptSdk('),
'promptSdk() must not be reintroduced — the old interactive prompt flow was broken'
);
});
test('install.js does not parse --sdk / --no-sdk flags (#191)', () => {
src = src || fs.readFileSync(INSTALL_SRC, 'utf-8');
assert.ok(
!src.includes("args.includes('--sdk')"),
'--sdk flag must not be parsed after sdk package retirement'
);
assert.ok(
!src.includes("args.includes('--no-sdk')"),
'--no-sdk flag must not be parsed after sdk package retirement'
);
});
test('install.js does not invoke installSdkIfNeeded during install (#191)', () => {
src = src || fs.readFileSync(INSTALL_SRC, 'utf-8');
assert.ok(
!src.includes('installSdkIfNeeded({'),
'installer must not invoke installSdkIfNeeded during runtime install flow'
);
});
test('package.json does not publish sdk/* artifacts (#191)', () => {
const rootPkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
const files = rootPkg.files || [];
assert.ok(
files.every((f) => !String(f).startsWith('sdk')),
'root package.json files must not include sdk paths'
);
});
test('root tsconfig project references resolve to existing paths (#191)', () => {
const tsconfigPath = path.join(__dirname, '..', 'tsconfig.json');
if (!fs.existsSync(tsconfigPath)) return;
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
const references = tsconfig.references || [];
for (const ref of references) {
const refPath = String(ref.path || '');
assert.notEqual(refPath, 'sdk', 'root tsconfig must not reference retired sdk project');
assert.ok(
fs.existsSync(path.join(__dirname, '..', refPath)),
`root tsconfig reference must exist: ${refPath}`
);
}
});
});