@@ -195,44 +195,42 @@ describe("dbt-tools ESM e2e: direct node invocation", () => {
195195// ---------------------------------------------------------------------------
196196
197197describe ( "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