1- import { describe , it , expect } from "vitest" ;
1+ import { describe , it , expect , vi , beforeEach } from "vitest" ;
22import { Command } from "commander" ;
33import { loadSpec } from "../parser/loader.js" ;
44import { extractOperations } from "../parser/extractor.js" ;
55import { buildCommands } from "./commander-builder.js" ;
66import type { RuntimeConfig } from "./types.js" ;
7+ import type { Operation } from "../parser/types.js" ;
78import path from "node:path" ;
89
910const FIXTURE = path . resolve ( "test/fixtures/petstore.yaml" ) ;
@@ -15,6 +16,8 @@ const config: RuntimeConfig = {
1516 output : "json" ,
1617 verbose : false ,
1718 quiet : false ,
19+ dryRun : false ,
20+ validate : false ,
1821} ;
1922
2023describe ( "buildCommands" , ( ) => {
@@ -103,3 +106,121 @@ describe("buildCommands", () => {
103106 expect ( listCmd . description ( ) ) . toBe ( "List all pets" ) ;
104107 } ) ;
105108} ) ;
109+
110+ describe ( "collectParams JSON parsing" , ( ) => {
111+ beforeEach ( ( ) => {
112+ vi . restoreAllMocks ( ) ;
113+ } ) ;
114+
115+ it ( "parses object params from JSON strings" , async ( ) => {
116+ const op : Operation = {
117+ id : "createVideos" ,
118+ method : "POST" ,
119+ path : "/videos" ,
120+ summary : "Create video" ,
121+ description : "" ,
122+ params : [
123+ { name : "name" , in : "body" , type : "string" , required : true , description : "" } ,
124+ { name : "content" , in : "body" , type : "object" , required : true , description : "" } ,
125+ ] ,
126+ bodyRequired : true ,
127+ security : [ ] ,
128+ } ;
129+
130+ let capturedBody : unknown ;
131+ vi . stubGlobal ( "fetch" , vi . fn ( ) . mockImplementation ( ( _url : string , init : RequestInit ) => {
132+ capturedBody = JSON . parse ( init . body as string ) ;
133+ return Promise . resolve ( {
134+ status : 200 ,
135+ statusText : "OK" ,
136+ headers : new Map ( [ [ "content-type" , "application/json" ] ] ) ,
137+ text : ( ) => Promise . resolve ( "{}" ) ,
138+ } ) ;
139+ } ) ) ;
140+
141+ const spec = await loadSpec ( FIXTURE ) ;
142+ const program = new Command ( ) ;
143+ program . exitOverride ( ) ;
144+ buildCommands ( program , [ { tag : "Videos" , description : "" , operations : [ op ] } ] , config , spec ) ;
145+
146+ await program . parseAsync ( [ "node" , "test" , "Videos" , "create" , "--name" , "Test" , "--content" , '{"text":"hello"}' ] ) ;
147+
148+ expect ( capturedBody ) . toEqual ( { name : "Test" , content : { text : "hello" } } ) ;
149+
150+ vi . unstubAllGlobals ( ) ;
151+ } ) ;
152+
153+ it ( "parses array params from JSON strings" , async ( ) => {
154+ const op : Operation = {
155+ id : "createItem" ,
156+ method : "POST" ,
157+ path : "/items" ,
158+ summary : "Create items" ,
159+ description : "" ,
160+ params : [
161+ { name : "tags" , in : "body" , type : "array" , required : true , description : "" } ,
162+ ] ,
163+ bodyRequired : true ,
164+ security : [ ] ,
165+ } ;
166+
167+ let capturedBody : unknown ;
168+ vi . stubGlobal ( "fetch" , vi . fn ( ) . mockImplementation ( ( _url : string , init : RequestInit ) => {
169+ capturedBody = JSON . parse ( init . body as string ) ;
170+ return Promise . resolve ( {
171+ status : 200 ,
172+ statusText : "OK" ,
173+ headers : new Map ( [ [ "content-type" , "application/json" ] ] ) ,
174+ text : ( ) => Promise . resolve ( "{}" ) ,
175+ } ) ;
176+ } ) ) ;
177+
178+ const spec = await loadSpec ( FIXTURE ) ;
179+ const program = new Command ( ) ;
180+ program . exitOverride ( ) ;
181+ buildCommands ( program , [ { tag : "Items" , description : "" , operations : [ op ] } ] , config , spec ) ;
182+
183+ await program . parseAsync ( [ "node" , "test" , "Items" , "create" , "--tags" , '["a","b"]' ] ) ;
184+
185+ expect ( capturedBody ) . toEqual ( { tags : [ "a" , "b" ] } ) ;
186+
187+ vi . unstubAllGlobals ( ) ;
188+ } ) ;
189+
190+ it ( "falls back to string when JSON parse fails" , async ( ) => {
191+ const op : Operation = {
192+ id : "createThings" ,
193+ method : "POST" ,
194+ path : "/things" ,
195+ summary : "Create thing" ,
196+ description : "" ,
197+ params : [
198+ { name : "data" , in : "body" , type : "object" , required : true , description : "" } ,
199+ ] ,
200+ bodyRequired : true ,
201+ security : [ ] ,
202+ } ;
203+
204+ let capturedBody : unknown ;
205+ vi . stubGlobal ( "fetch" , vi . fn ( ) . mockImplementation ( ( _url : string , init : RequestInit ) => {
206+ capturedBody = JSON . parse ( init . body as string ) ;
207+ return Promise . resolve ( {
208+ status : 200 ,
209+ statusText : "OK" ,
210+ headers : new Map ( [ [ "content-type" , "application/json" ] ] ) ,
211+ text : ( ) => Promise . resolve ( "{}" ) ,
212+ } ) ;
213+ } ) ) ;
214+
215+ const spec = await loadSpec ( FIXTURE ) ;
216+ const program = new Command ( ) ;
217+ program . exitOverride ( ) ;
218+ buildCommands ( program , [ { tag : "Things" , description : "" , operations : [ op ] } ] , config , spec ) ;
219+
220+ await program . parseAsync ( [ "node" , "test" , "Things" , "create" , "--data" , "not-json" ] ) ;
221+
222+ expect ( capturedBody ) . toEqual ( { data : "not-json" } ) ;
223+
224+ vi . unstubAllGlobals ( ) ;
225+ } ) ;
226+ } ) ;
0 commit comments