11import { expect } from 'chai' ;
2- import { exec } from 'child_process' ;
2+ import { exec , spawn } from 'child_process' ;
33import path from 'path' ;
44import { fileURLToPath } from 'url' ;
5+ import { writeFileSync , unlinkSync , existsSync , readFileSync } from 'fs' ;
56
67const __filename = fileURLToPath ( import . meta. url ) ;
78const __dirname = path . dirname ( __filename ) ;
@@ -23,4 +24,114 @@ describe('CLI', () => {
2324 done ( ) ;
2425 } ) ;
2526 } ) ;
27+
28+ describe ( 'watch functionality' , ( ) => {
29+ const testInputPath = path . join ( __dirname , 'test-input.json' ) ;
30+ const testOutputPath = path . join ( __dirname , 'test-output.js' ) ;
31+ const sampleSpec = {
32+ "openapi" : "3.0.1" ,
33+ "info" : { "title" : "Watch Test API" , "version" : "1.0.0" } ,
34+ "paths" : {
35+ "/test" : {
36+ "get" : {
37+ "operationId" : "getTest" ,
38+ "responses" : { "200" : { "description" : "OK" } }
39+ }
40+ }
41+ }
42+ } ;
43+
44+ beforeEach ( ( ) => {
45+ writeFileSync ( testInputPath , JSON . stringify ( sampleSpec , null , 2 ) ) ;
46+ } ) ;
47+
48+ afterEach ( ( ) => {
49+ [ testInputPath , testOutputPath ] . forEach ( file => {
50+ if ( existsSync ( file ) ) {
51+ unlinkSync ( file ) ;
52+ }
53+ } ) ;
54+ } ) ;
55+
56+ it ( 'should regenerate client when input file changes' , function ( done ) {
57+ this . timeout ( 5000 ) ;
58+
59+ const cliPath = path . join ( __dirname , '../bin/cli.js' ) ;
60+ const child = spawn ( 'node' , [ cliPath , 'generate' , '-i' , testInputPath , '-o' , testOutputPath , '--watch' ] , {
61+ stdio : [ 'pipe' , 'pipe' , 'pipe' ]
62+ } ) ;
63+
64+ let outputReceived = false ;
65+ let regenerateReceived = false ;
66+
67+ child . stdout . on ( 'data' , ( data ) => {
68+ const output = data . toString ( ) ;
69+
70+ if ( output . includes ( '✓ Fetch client generated successfully!' ) && ! outputReceived ) {
71+ outputReceived = true ;
72+ expect ( existsSync ( testOutputPath ) ) . to . be . true ;
73+
74+ setTimeout ( ( ) => {
75+ const updatedSpec = { ...sampleSpec } ;
76+ updatedSpec . info . title = "Updated Watch Test API" ;
77+ writeFileSync ( testInputPath , JSON . stringify ( updatedSpec , null , 2 ) ) ;
78+ } , 100 ) ;
79+ }
80+
81+ if ( output . includes ( 'File changed, regenerating...' ) && ! regenerateReceived ) {
82+ regenerateReceived = true ;
83+ }
84+
85+ if ( outputReceived && regenerateReceived && output . includes ( '✓ Fetch client generated successfully!' ) ) {
86+ const clientCode = readFileSync ( testOutputPath , 'utf8' ) ;
87+ expect ( clientCode ) . to . include ( 'class ApiClient' ) ;
88+ child . kill ( 'SIGINT' ) ;
89+ done ( ) ;
90+ }
91+ } ) ;
92+
93+ child . stderr . on ( 'data' , ( data ) => {
94+ console . error ( 'CLI stderr:' , data . toString ( ) ) ;
95+ } ) ;
96+
97+ child . on ( 'error' , ( error ) => {
98+ done ( error ) ;
99+ } ) ;
100+ } ) ;
101+
102+ it ( 'should handle watch mode with invalid input gracefully' , function ( done ) {
103+ this . timeout ( 3000 ) ;
104+
105+ const cliPath = path . join ( __dirname , '../bin/cli.js' ) ;
106+ const child = spawn ( 'node' , [ cliPath , 'generate' , '-i' , testInputPath , '-o' , testOutputPath , '--watch' ] , {
107+ stdio : [ 'pipe' , 'pipe' , 'pipe' ]
108+ } ) ;
109+
110+ let initialGeneration = false ;
111+
112+ child . stdout . on ( 'data' , ( data ) => {
113+ const output = data . toString ( ) ;
114+
115+ if ( output . includes ( '✓ Fetch client generated successfully!' ) && ! initialGeneration ) {
116+ initialGeneration = true ;
117+
118+ setTimeout ( ( ) => {
119+ writeFileSync ( testInputPath , 'invalid json' ) ;
120+ } , 100 ) ;
121+ }
122+ } ) ;
123+
124+ child . stderr . on ( 'data' , ( data ) => {
125+ const errorOutput = data . toString ( ) ;
126+ if ( errorOutput . includes ( 'Error generating client:' ) ) {
127+ child . kill ( 'SIGINT' ) ;
128+ done ( ) ;
129+ }
130+ } ) ;
131+
132+ child . on ( 'error' , ( error ) => {
133+ done ( error ) ;
134+ } ) ;
135+ } ) ;
136+ } ) ;
26137} ) ;
0 commit comments