@@ -373,6 +373,123 @@ script:post-response {
373373 expect ( byName . host ) . toMatchObject ( { uid : 'var-host' , custom : 'keep-host' } ) ;
374374 } , 60_000 ) ;
375375
376+ // End-to-end coverage of resolveEnvFileFormat's extension-detection branching for the
377+ // two non-JSON formats. The persistence behavior for yml / bru is already proven via
378+ // --env (.bru) and --global-env (.yml); these tests prove that --env-file <path>.yml
379+ // and --env-file <path>.bru also wire through correctly — descriptor format inferred
380+ // from the extension, parser/serializer selected accordingly.
381+ it ( 'persists typed env vars to a --env-file YAML file with type/data blocks' , async ( ) => {
382+ writeFixtureFile (
383+ path . join ( tmpDir , 'bruno.json' ) ,
384+ JSON . stringify ( { version : '1' , name : 'yml-envfile-collection' , type : 'collection' } , null , 2 ) + '\n'
385+ ) ;
386+ writeFixtureFile (
387+ path . join ( tmpDir , 'collection.bru' ) ,
388+ 'meta {\n name: yml-envfile-collection\n seq: 1\n}\n'
389+ ) ;
390+ writeFixtureFile (
391+ path . join ( tmpDir , 'External.yml' ) ,
392+ `name: External\nvariables:\n - name: host\n value: ${ baseUrl } \n enabled: true\n secret: false\n`
393+ ) ;
394+ writeFixtureFile (
395+ path . join ( tmpDir , 'set-typed-vars.bru' ) ,
396+ `meta {
397+ name: set-typed-vars
398+ type: http
399+ seq: 1
400+ }
401+
402+ get {
403+ url: {{host}}/ping
404+ body: none
405+ auth: none
406+ }
407+
408+ script:post-response {
409+ bru.setEnvVar("port", 3000);
410+ bru.setEnvVar("enabled", true);
411+ }
412+ `
413+ ) ;
414+
415+ const result = await runCli ( [
416+ 'run' , 'set-typed-vars.bru' ,
417+ '--env-file' , 'External.yml' ,
418+ '--sandbox' , 'developer' ,
419+ '--noproxy'
420+ ] ) ;
421+
422+ if ( result . code !== 0 ) {
423+ throw new Error (
424+ `CLI exited with code ${ result . code } .\n--- stdout ---\n${ result . stdout } \n--- stderr ---\n${ result . stderr } `
425+ ) ;
426+ }
427+
428+ // yml serializer encodes typed values as `value: { type, data }` blocks.
429+ const written = fs . readFileSync ( path . join ( tmpDir , 'External.yml' ) , 'utf8' ) ;
430+ expect ( written ) . toMatch ( / n a m e : \s * p o r t [ \s \S ] * ?t y p e : \s * n u m b e r [ \s \S ] * ?d a t a : \s * [ ' " ] ? 3 0 0 0 / ) ;
431+ expect ( written ) . toMatch ( / n a m e : \s * e n a b l e d [ \s \S ] * ?t y p e : \s * b o o l e a n [ \s \S ] * ?d a t a : \s * [ ' " ] ? t r u e / ) ;
432+ // String values stay as raw `value: ...` — no type/data block.
433+ expect ( written ) . toMatch ( / n a m e : \s * h o s t [ \s \S ] * ?v a l u e : \s * [ ' " ] ? h t t p : \/ \/ 1 2 7 \. 0 \. 0 \. 1 / ) ;
434+ expect ( written ) . not . toMatch ( / n a m e : \s * h o s t [ \s \S ] * ?t y p e : \s * s t r i n g / ) ;
435+ } , 60_000 ) ;
436+
437+ it ( 'persists typed env vars to a --env-file .bru file with @dataType annotations' , async ( ) => {
438+ writeFixtureFile (
439+ path . join ( tmpDir , 'bruno.json' ) ,
440+ JSON . stringify ( { version : '1' , name : 'bru-envfile-collection' , type : 'collection' } , null , 2 ) + '\n'
441+ ) ;
442+ writeFixtureFile (
443+ path . join ( tmpDir , 'collection.bru' ) ,
444+ 'meta {\n name: bru-envfile-collection\n seq: 1\n}\n'
445+ ) ;
446+ writeFixtureFile (
447+ path . join ( tmpDir , 'External.bru' ) ,
448+ `vars {\n host: ${ baseUrl } \n}\n`
449+ ) ;
450+ writeFixtureFile (
451+ path . join ( tmpDir , 'set-typed-vars.bru' ) ,
452+ `meta {
453+ name: set-typed-vars
454+ type: http
455+ seq: 1
456+ }
457+
458+ get {
459+ url: {{host}}/ping
460+ body: none
461+ auth: none
462+ }
463+
464+ script:post-response {
465+ bru.setEnvVar("port", 3000);
466+ bru.setEnvVar("enabled", true);
467+ }
468+ `
469+ ) ;
470+
471+ const result = await runCli ( [
472+ 'run' , 'set-typed-vars.bru' ,
473+ '--env-file' , 'External.bru' ,
474+ '--sandbox' , 'developer' ,
475+ '--noproxy'
476+ ] ) ;
477+
478+ if ( result . code !== 0 ) {
479+ throw new Error (
480+ `CLI exited with code ${ result . code } .\n--- stdout ---\n${ result . stdout } \n--- stderr ---\n${ result . stderr } `
481+ ) ;
482+ }
483+
484+ // .bru serializer emits typed values as `@dataType` decorators on the preceding line.
485+ const written = fs . readFileSync ( path . join ( tmpDir , 'External.bru' ) , 'utf8' ) ;
486+ expect ( written ) . toMatch ( / @ n u m b e r \s + p o r t : \s * 3 0 0 0 / ) ;
487+ expect ( written ) . toMatch ( / @ b o o l e a n \s + e n a b l e d : \s * t r u e / ) ;
488+ // String values get no annotation.
489+ expect ( written ) . not . toMatch ( / @ s t r i n g \s + h o s t / ) ;
490+ expect ( written ) . toMatch ( / h o s t : \s * h t t p : \/ \/ 1 2 7 \. 0 \. 0 \. 1 / ) ;
491+ } , 60_000 ) ;
492+
376493 // Regression guard at the CLI binary boundary: --env-var values are transient (the CLI
377494 // can't decrypt at-rest secrets, so users pass them in for a single run). Even though a
378495 // script writes an unrelated env var — which dirties the env scope and makes the runtime
0 commit comments