@@ -16,6 +16,10 @@ vi.mock('../../../src/ui/scan/printMissing.js', () => ({
1616 printMissing : vi . fn ( ) ,
1717} ) ) ;
1818
19+ vi . mock ( '../../../src/ui/scan/printUnused.js' , ( ) => ( {
20+ printUnused : vi . fn ( ) ,
21+ } ) ) ;
22+
1923vi . mock ( '../../../src/ui/shared/printDuplicates.js' , ( ) => ( {
2024 printDuplicates : vi . fn ( ) ,
2125} ) ) ;
@@ -60,6 +64,10 @@ vi.mock('../../../src/ui/scan/printExpireWarnings.js', () => ({
6064 printExpireWarnings : vi . fn ( ) ,
6165} ) ) ;
6266
67+ vi . mock ( '../../../src/ui/scan/printInconsistentNamingWarning.js' , ( ) => ( {
68+ printInconsistentNamingWarning : vi . fn ( ) ,
69+ } ) ) ;
70+
6371vi . mock ( '../../../src/core/scan/computeHealthScore.js' , ( ) => ( {
6472 computeHealthScore : vi . fn ( ( ) => 100 ) ,
6573} ) ) ;
@@ -72,13 +80,25 @@ vi.mock('../../../src/ui/shared/printGitignore.js', () => ({
7280 printGitignoreWarning : vi . fn ( ) ,
7381} ) ) ;
7482
75- vi . mock ( '../../../src/git.js' , ( ) => ( {
83+ vi . mock ( '../../../src/services/ git.js' , ( ) => ( {
7684 checkGitignoreStatus : vi . fn ( ( ) => null ) ,
7785} ) ) ;
7886
7987import { printScanResult } from '../../../src/services/printScanResult.js' ;
8088import { printMissing } from '../../../src/ui/scan/printMissing.js' ;
8189import { printAutoFix } from '../../../src/ui/shared/printAutoFix.js' ;
90+ import { checkGitignoreStatus } from '../../../src/services/git.js' ;
91+ import { printGitignoreWarning } from '../../../src/ui/shared/printGitignore.js' ;
92+ import { printStats } from '../../../src/ui/scan/printStats.js' ;
93+ import { printDuplicates } from '../../../src/ui/shared/printDuplicates.js' ;
94+ import { printUnused } from '../../../src/ui/scan/printUnused.js' ;
95+ import { printFrameworkWarnings } from '../../../src/ui/scan/printFrameworkWarnings.js' ;
96+ import { printUppercaseWarning } from '../../../src/ui/scan/printUppercaseWarning.js' ;
97+ import { printInconsistentNamingWarning } from '../../../src/ui/scan/printInconsistentNamingWarning.js' ;
98+ import { printExampleWarnings } from '../../../src/ui/scan/printExampleWarnings.js' ;
99+ import { printSecrets } from '../../../src/ui/scan/printSecrets.js' ;
100+ import { printExpireWarnings } from '../../../src/ui/scan/printExpireWarnings.js' ;
101+ import { printConsolelogWarning } from '../../../src/ui/scan/printConsolelogWarning.js' ;
82102
83103describe ( 'printScanResult' , ( ) => {
84104 const baseScanResult : ScanResult = {
@@ -110,6 +130,7 @@ describe('printScanResult', () => {
110130 beforeEach ( ( ) => {
111131 vi . clearAllMocks ( ) ;
112132 vi . mocked ( printMissing ) . mockReturnValue ( false ) ;
133+ vi . mocked ( checkGitignoreStatus ) . mockReturnValue ( null ) ;
113134 } ) ;
114135
115136 it ( 'returns exitWithError true when missing variables exist' , ( ) => {
@@ -162,4 +183,238 @@ describe('printScanResult', () => {
162183
163184 expect ( result . exitWithError ) . toBe ( false ) ;
164185 } ) ;
186+
187+ it ( 'prints gitignore warning when env file is not ignored' , ( ) => {
188+ vi . mocked ( checkGitignoreStatus ) . mockReturnValue ( {
189+ reason : 'not-ignored' ,
190+ } as any ) ;
191+
192+ printScanResult ( baseScanResult , baseOpts , '.env' ) ;
193+
194+ expect ( printGitignoreWarning ) . toHaveBeenCalledWith (
195+ expect . objectContaining ( { reason : 'not-ignored' , strict : false } ) ,
196+ ) ;
197+ } ) ;
198+
199+ it ( 'returns exitWithError true in strict mode when gitignore issue exists' , ( ) => {
200+ vi . mocked ( checkGitignoreStatus ) . mockReturnValue ( {
201+ reason : 'not-ignored' ,
202+ } as any ) ;
203+
204+ const result = printScanResult (
205+ baseScanResult ,
206+ { ...baseOpts , strict : true } ,
207+ '.env' ,
208+ ) ;
209+
210+ expect ( result . exitWithError ) . toBe ( true ) ;
211+ } ) ;
212+
213+ it ( 'prints framework warnings when present' , ( ) => {
214+ printScanResult (
215+ {
216+ ...baseScanResult ,
217+ frameworkWarnings : [ { type : 'nextjs' , message : 'warn' } as any ] ,
218+ } ,
219+ baseOpts ,
220+ '.env' ,
221+ ) ;
222+
223+ expect ( printFrameworkWarnings ) . toHaveBeenCalled ( ) ;
224+ } ) ;
225+
226+ it ( 'prints uppercase warnings when present' , ( ) => {
227+ printScanResult (
228+ {
229+ ...baseScanResult ,
230+ uppercaseWarnings : [ { key : 'Api_Key' , expected : 'API_KEY' } as any ] ,
231+ } ,
232+ baseOpts ,
233+ '.env' ,
234+ ) ;
235+
236+ expect ( printUppercaseWarning ) . toHaveBeenCalled ( ) ;
237+ } ) ;
238+
239+ it ( 'prints inconsistent naming warnings when present' , ( ) => {
240+ printScanResult (
241+ {
242+ ...baseScanResult ,
243+ inconsistentNamingWarnings : [ { key : 'MY-KEY' } as any ] ,
244+ } ,
245+ baseOpts ,
246+ '.env' ,
247+ ) ;
248+
249+ expect ( printInconsistentNamingWarning ) . toHaveBeenCalled ( ) ;
250+ } ) ;
251+
252+ it ( 'prints example warnings when present' , ( ) => {
253+ printScanResult (
254+ {
255+ ...baseScanResult ,
256+ exampleWarnings : [ { severity : 'low' } as any ] ,
257+ } ,
258+ baseOpts ,
259+ '.env' ,
260+ ) ;
261+
262+ expect ( printExampleWarnings ) . toHaveBeenCalled ( ) ;
263+ } ) ;
264+
265+ it ( 'prints secrets when secrets flag is enabled' , ( ) => {
266+ printScanResult (
267+ {
268+ ...baseScanResult ,
269+ secrets : [ { severity : 'low' } as any ] ,
270+ } ,
271+ { ...baseOpts , secrets : true } ,
272+ '.env' ,
273+ ) ;
274+
275+ expect ( printSecrets ) . toHaveBeenCalled ( ) ;
276+ } ) ;
277+
278+ it ( 'prints expiration warnings when present' , ( ) => {
279+ printScanResult (
280+ {
281+ ...baseScanResult ,
282+ expireWarnings : [ { key : 'TOKEN' , daysLeft : 5 } as any ] ,
283+ } ,
284+ baseOpts ,
285+ '.env' ,
286+ ) ;
287+
288+ expect ( printExpireWarnings ) . toHaveBeenCalled ( ) ;
289+ } ) ;
290+
291+ it ( 'returns exitWithError true when high severity example warning exists' , ( ) => {
292+ const result = printScanResult (
293+ {
294+ ...baseScanResult ,
295+ exampleWarnings : [ { severity : 'high' } as any ] ,
296+ } ,
297+ baseOpts ,
298+ '.env' ,
299+ ) ;
300+
301+ expect ( result . exitWithError ) . toBe ( true ) ;
302+ } ) ;
303+
304+ it ( 'checks gitignore status with cwd and default env file' , ( ) => {
305+ printScanResult ( baseScanResult , baseOpts , '.env' ) ;
306+
307+ expect ( checkGitignoreStatus ) . toHaveBeenCalledWith ( {
308+ cwd : '/root' ,
309+ envFile : '.env' ,
310+ } ) ;
311+ } ) ;
312+
313+ it ( 'does not print stats when showStats is false' , ( ) => {
314+ printScanResult ( baseScanResult , { ...baseOpts , showStats : false } , '.env' ) ;
315+
316+ expect ( printStats ) . not . toHaveBeenCalled ( ) ;
317+ } ) ;
318+
319+ it ( 'uses default env file in duplicates when comparedAgainst is empty' , ( ) => {
320+ printScanResult (
321+ {
322+ ...baseScanResult ,
323+ duplicates : undefined as any ,
324+ } ,
325+ baseOpts ,
326+ '' ,
327+ ) ;
328+
329+ expect ( printDuplicates ) . toHaveBeenCalledWith (
330+ '.env' ,
331+ 'example file' ,
332+ [ ] ,
333+ [ ] ,
334+ false ,
335+ false ,
336+ undefined ,
337+ ) ;
338+ } ) ;
339+
340+ it ( 'does not print console log warning when logged is undefined' , ( ) => {
341+ printScanResult (
342+ {
343+ ...baseScanResult ,
344+ logged : undefined as any ,
345+ } ,
346+ baseOpts ,
347+ '.env' ,
348+ ) ;
349+
350+ expect ( printConsolelogWarning ) . not . toHaveBeenCalled ( ) ;
351+ } ) ;
352+
353+ it ( 'keeps exitWithError false when secrets is undefined and no strict violations' , ( ) => {
354+ const result = printScanResult (
355+ {
356+ ...baseScanResult ,
357+ secrets : undefined as any ,
358+ } ,
359+ baseOpts ,
360+ '.env' ,
361+ ) ;
362+
363+ expect ( result . exitWithError ) . toBe ( false ) ;
364+ } ) ;
365+
366+ it ( 'evaluates full strict violation chain and stays false when all checks are clean' , ( ) => {
367+ const result = printScanResult (
368+ baseScanResult ,
369+ { ...baseOpts , strict : true } ,
370+ '.env' ,
371+ ) ;
372+
373+ expect ( result . exitWithError ) . toBe ( false ) ;
374+ } ) ;
375+
376+ it ( 'does not call printAutoFix when fix is true but no fixContext is provided' , ( ) => {
377+ printScanResult ( baseScanResult , { ...baseOpts , fix : true } , '.env' ) ;
378+
379+ expect ( printAutoFix ) . not . toHaveBeenCalled ( ) ;
380+ } ) ;
381+
382+ it ( 'does not print unused variables when showUnused is false' , ( ) => {
383+ printScanResult (
384+ {
385+ ...baseScanResult ,
386+ unused : [ 'SOME_VAR' ] ,
387+ } ,
388+ { ...baseOpts , showUnused : false } ,
389+ '.env' ,
390+ ) ;
391+
392+ expect ( printUnused ) . not . toHaveBeenCalled ( ) ;
393+ } ) ;
394+
395+ it ( 'does not call printAutoFix when fix is false even if fixContext exists' , ( ) => {
396+ printScanResult ( baseScanResult , { ...baseOpts , fix : false } , '.env' , {
397+ fixApplied : true ,
398+ removedDuplicates : [ ] ,
399+ addedEnv : [ ] ,
400+ gitignoreUpdated : false ,
401+ } ) ;
402+
403+ expect ( printAutoFix ) . not . toHaveBeenCalled ( ) ;
404+ } ) ;
405+
406+ it ( 'calls printAutoFix with default env file when comparedAgainst is empty' , ( ) => {
407+ printScanResult ( baseScanResult , { ...baseOpts , fix : true } , '' , {
408+ fixApplied : true ,
409+ removedDuplicates : [ ] ,
410+ addedEnv : [ ] ,
411+ gitignoreUpdated : false ,
412+ } ) ;
413+
414+ expect ( printAutoFix ) . toHaveBeenCalledWith (
415+ expect . objectContaining ( { fixApplied : true } ) ,
416+ '.env' ,
417+ false ,
418+ ) ;
419+ } ) ;
165420} ) ;
0 commit comments