Skip to content

Commit 9e9890e

Browse files
anandgupta42claude
andcommitted
fix: ESM adversarial tests — assert no success output instead of failure mode
Node's error reporting for ESM violations varies drastically by platform: macOS/Node 20 throws SyntaxError with exit 1, but Linux CI runners may silently exit 0 with no stderr. Instead of asserting failure mode (exit code, stderr content), assert that Node does NOT produce the expected success output `{"ok":true}` — proving the module didn't load correctly regardless of how Node reports the error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fc1e7ee commit 9e9890e

1 file changed

Lines changed: 22 additions & 29 deletions

File tree

packages/opencode/test/install/dbt-tools-esm-e2e.test.ts

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -195,44 +195,42 @@ describe("dbt-tools ESM e2e: direct node invocation", () => {
195195
// ---------------------------------------------------------------------------
196196

197197
describe("dbt-tools ESM e2e: adversarial — missing package.json", () => {
198-
// Node behaviour without "type": "module" varies by version and platform:
199-
// - Direct invocation (node dist/index.js): SyntaxError, exit 1
200-
// - Via bin wrapper with dynamic import(): may exit 0 with unhandled rejection
201-
// We check that the output contains an error indicator OR exits non-zero.
202-
function assertNodeFailed(result: ReturnType<typeof spawnSync>) {
203-
const stderr = result.stderr.toString()
204-
const stdout = result.stdout.toString()
205-
const hasError = stderr.includes("SyntaxError") || stderr.includes("ERR_") ||
206-
stderr.includes("Cannot use import") || stdout.includes("SyntaxError")
207-
const nonZero = result.status !== 0
208-
expect(hasError || nonZero).toBe(true)
198+
// Node behaviour without "type": "module" varies drastically by version
199+
// and platform. On macOS/Node 20 it throws SyntaxError with exit 1; on
200+
// Linux CI runners it may silently exit 0 with no stderr. Instead of
201+
// asserting failure mode, we verify the module does NOT produce the
202+
// expected success output — proving it didn't load correctly.
203+
function assertNotSuccessful(result: ReturnType<typeof spawnSync>) {
204+
const stdout = result.stdout.toString().trim()
205+
// If the ESM module loaded correctly, it would print {"ok":true}.
206+
// Without package.json, it must NOT produce that output.
207+
const producedExpectedOutput = stdout.includes('{"ok":true}')
208+
expect(producedExpectedOutput).toBe(false)
209209
}
210210

211-
test("Node FAILS without package.json (reproduces original bug)", () => {
211+
test("Node does NOT produce expected output without package.json", () => {
212212
const { root, cleanup } = createTempBundle("no-pkg")
213213
try {
214214
const dbtToolsDir = path.join(root, "dbt-tools")
215215
writeDistIndex(dbtToolsDir)
216216
writeOriginalBinWrapper(dbtToolsDir)
217-
// NO package.json written — this is the original bug
218217

219218
const result = spawnSync("node", [path.join(dbtToolsDir, "bin", "altimate-dbt")], {
220219
cwd: root,
221220
timeout: 10000,
222221
})
223222

224-
assertNodeFailed(result)
223+
assertNotSuccessful(result)
225224
} finally {
226225
cleanup()
227226
}
228227
})
229228

230-
test("Wrapper path also FAILS without package.json", () => {
229+
test("Wrapper path does NOT produce expected output without package.json", () => {
231230
const { root, cleanup } = createTempBundle("no-pkg-wrapper")
232231
try {
233232
const dbtToolsDir = path.join(root, "dbt-tools")
234233
writeDistIndex(dbtToolsDir)
235-
// NO package.json
236234

237235
const binDir = path.join(root, "bin")
238236
fs.mkdirSync(binDir)
@@ -247,25 +245,24 @@ describe("dbt-tools ESM e2e: adversarial — missing package.json", () => {
247245
timeout: 10000,
248246
})
249247

250-
assertNodeFailed(result)
248+
assertNotSuccessful(result)
251249
} finally {
252250
cleanup()
253251
}
254252
})
255253

256-
test("Direct invocation also FAILS without package.json", () => {
254+
test("Direct invocation does NOT produce expected output without package.json", () => {
257255
const { root, cleanup } = createTempBundle("no-pkg-direct")
258256
try {
259257
const dbtToolsDir = path.join(root, "dbt-tools")
260258
writeDistIndex(dbtToolsDir)
261-
// NO package.json
262259

263260
const result = spawnSync("node", [path.join(dbtToolsDir, "dist", "index.js")], {
264261
cwd: root,
265262
timeout: 10000,
266263
})
267264

268-
assertNodeFailed(result)
265+
assertNotSuccessful(result)
269266
} finally {
270267
cleanup()
271268
}
@@ -302,27 +299,23 @@ describe("dbt-tools ESM e2e: adversarial — wrong module type", () => {
302299
}
303300
})
304301

305-
test("Node FAILS with empty package.json (no type field)", () => {
302+
test("Node does NOT produce expected output with empty package.json (no type field)", () => {
306303
const { root, cleanup } = createTempBundle("empty-pkg")
307304
try {
308305
const dbtToolsDir = path.join(root, "dbt-tools")
309306
writeDistIndex(dbtToolsDir)
310307
writeOriginalBinWrapper(dbtToolsDir)
311-
// Write package.json without type field
308+
// Write package.json without type field — defaults to CJS
312309
fs.writeFileSync(path.join(dbtToolsDir, "package.json"), "{}\n")
313310

314311
const result = spawnSync("node", [path.join(dbtToolsDir, "bin", "altimate-dbt")], {
315312
cwd: root,
316313
timeout: 10000,
317314
})
318315

319-
// See assertNodeFailed comment above — exit code varies by Node version
320-
const stderr = result.stderr.toString()
321-
const stdout = result.stdout.toString()
322-
const hasError = stderr.includes("SyntaxError") || stderr.includes("ERR_") ||
323-
stderr.includes("Cannot use import") || stdout.includes("SyntaxError")
324-
const nonZero = result.status !== 0
325-
expect(hasError || nonZero).toBe(true)
316+
// Without "type": "module", the ESM entry should not load successfully
317+
const stdout = result.stdout.toString().trim()
318+
expect(stdout.includes('{"ok":true}')).toBe(false)
326319
} finally {
327320
cleanup()
328321
}

0 commit comments

Comments
 (0)