11import { chmodSync , mkdtempSync , readFileSync , rmSync , statSync , writeFileSync } from 'node:fs'
22import { tmpdir } from 'node:os'
33import path from 'node:path'
4+ import { loadEnvConfig } from '@next/env'
45import { afterEach , describe , expect , it } from 'vitest'
56import { parseEnv , reconcileEnvContent , upsertEnv , writeEnvFile } from './env-files'
67
@@ -21,16 +22,28 @@ describe('upsertEnv', () => {
2122 ) . toThrow ( 'Duplicate active RESEND_API_KEY entries' )
2223 } )
2324
24- it . each ( [ 'ab #cd' , 'a#b' , ' padded ' , "'starts-with-quote" , "it's #1" ] ) (
25+ it . each ( [ 'ab #cd' , 'a#b' , ' padded ' , "'starts-with-quote" , "it's #1" , "it's $5 #1" ] ) (
2526 'reads back %j exactly as it was written' ,
2627 ( value ) => {
2728 expect ( parseEnv ( upsertEnv ( '' , 'SECRET' , value ) ) . get ( 'SECRET' ) ) . toBe ( value )
2829 }
2930 )
3031
31- it ( 'single-quotes a value with $ so dotenv, Bun, and Compose do not expand it' , ( ) => {
32- expect ( upsertEnv ( '' , 'SMTP_PASSWORD' , 'pa$$word$HOME' ) ) . toBe ( "SMTP_PASSWORD='pa$$word$HOME'\n" )
33- } )
32+ it . each ( [ 'pa$$word' , 'key$HOME' , `key\${HOME}suffix` , "it's $5" ] ) (
33+ 'Next loads %j back exactly as it was written' ,
34+ ( value ) => {
35+ const root = mkdtempSync ( path . join ( tmpdir ( ) , 'sim-setup-env-expand-' ) )
36+ roots . push ( root )
37+ writeFileSync ( path . join ( root , '.env' ) , upsertEnv ( '' , 'SIM_SETUP_EXPAND_PROBE' , value ) )
38+ const silent = { info : ( ) => { } , error : ( ) => { } }
39+ try {
40+ const { parsedEnv } = loadEnvConfig ( root , false , silent , true )
41+ expect ( parsedEnv ?. SIM_SETUP_EXPAND_PROBE ) . toBe ( value )
42+ } finally {
43+ Reflect . deleteProperty ( process . env , 'SIM_SETUP_EXPAND_PROBE' )
44+ }
45+ }
46+ )
3447
3548 it ( 'writes an ordinary value without quotes' , ( ) => {
3649 const dsn = 'postgresql://postgres:p%23w@127.0.0.1:5432/simstudio'
0 commit comments