@@ -35,6 +35,23 @@ var videoListSpec = &command.Spec{
3535 Examples : []string {"heygen video list --limit 10" },
3636}
3737
38+ var videoCreateWaitSpec = & command.Spec {
39+ Group : "video" ,
40+ Name : "create" ,
41+ Summary : "Create a video" ,
42+ Endpoint : "/v3/videos" ,
43+ Method : "POST" ,
44+ BodyEncoding : "json" ,
45+ PollConfig : & command.PollConfig {
46+ StatusEndpoint : "/v3/videos/{video_id}" ,
47+ StatusField : "data.status" ,
48+ TerminalOK : []string {"completed" },
49+ TerminalFail : []string {"failed" , "error" },
50+ IDField : "data.video_id" ,
51+ },
52+ Examples : []string {"heygen video create --wait" },
53+ }
54+
3855func TestGenBuilder_VideoList_Success (t * testing.T ) {
3956 srv := setupTestServer (t , map [string ]testHandler {
4057 "GET /v3/videos" : {
@@ -262,6 +279,166 @@ func TestGenBuilder_VideoList_AllPages_Truncated(t *testing.T) {
262279 }
263280}
264281
282+ func TestGenBuilder_VideoCreate_Wait_Success (t * testing.T ) {
283+ var statusCalls int
284+ srv := setupTestServer (t , map [string ]testHandler {
285+ "POST /v3/videos" : {
286+ StatusCode : 200 ,
287+ Body : `{"data":{"video_id":"vid_123"}}` ,
288+ },
289+ "GET /v3/videos/vid_123" : {
290+ StatusCode : 200 ,
291+ ValidateRequest : func (t * testing.T , r * http.Request ) {
292+ t .Helper ()
293+ statusCalls ++
294+ },
295+ Body : `{"data":{"video_id":"vid_123","status":"processing"}}` ,
296+ },
297+ })
298+ defer srv .Close ()
299+
300+ originalHandler := srv .Config .Handler
301+ srv .Config .Handler = http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
302+ if r .Method == http .MethodGet && r .URL .Path == "/v3/videos/vid_123" {
303+ statusCalls ++
304+ w .WriteHeader (http .StatusOK )
305+ if statusCalls < 2 {
306+ _ , _ = w .Write ([]byte (`{"data":{"video_id":"vid_123","status":"processing"}}` ))
307+ return
308+ }
309+ _ , _ = w .Write ([]byte (`{"data":{"video_id":"vid_123","status":"completed","video_url":"https://cdn.test/video.mp4"}}` ))
310+ return
311+ }
312+ originalHandler .ServeHTTP (w , r )
313+ })
314+
315+ res := runGenCommand (t , srv .URL , "test-key" , videoCreateWaitSpec , "create" , "--wait" )
316+
317+ if res .ExitCode != 0 {
318+ t .Fatalf ("ExitCode = %d, want 0\n stderr: %s" , res .ExitCode , res .Stderr )
319+ }
320+
321+ var parsed map [string ]any
322+ if err := json .Unmarshal ([]byte (res .Stdout ), & parsed ); err != nil {
323+ t .Fatalf ("stdout is not valid JSON: %v\n stdout: %s" , err , res .Stdout )
324+ }
325+ data := parsed ["data" ].(map [string ]any )
326+ if data ["status" ] != "completed" {
327+ t .Fatalf ("status = %v, want completed" , data ["status" ])
328+ }
329+ if strings .Count (res .Stderr , "Polling: status=processing" ) != 1 {
330+ t .Fatalf ("stderr = %s, want exactly one processing line" , res .Stderr )
331+ }
332+ }
333+
334+ func TestGenBuilder_VideoCreate_Wait_Failure (t * testing.T ) {
335+ srv := setupTestServer (t , map [string ]testHandler {
336+ "POST /v3/videos" : {
337+ StatusCode : 200 ,
338+ Body : `{"data":{"video_id":"vid_123"}}` ,
339+ },
340+ "GET /v3/videos/vid_123" : {
341+ StatusCode : 200 ,
342+ Body : `{"data":{"video_id":"vid_123","status":"failed"}}` ,
343+ },
344+ })
345+ defer srv .Close ()
346+
347+ res := runGenCommand (t , srv .URL , "test-key" , videoCreateWaitSpec , "create" , "--wait" )
348+
349+ if res .ExitCode != 1 {
350+ t .Fatalf ("ExitCode = %d, want 1\n stderr: %s" , res .ExitCode , res .Stderr )
351+ }
352+ if ! strings .Contains (res .Stderr , "operation reached terminal failure state: failed" ) {
353+ t .Fatalf ("stderr = %s, want failure message" , res .Stderr )
354+ }
355+ }
356+
357+ func TestGenBuilder_VideoCreate_Wait_Timeout (t * testing.T ) {
358+ srv := setupTestServer (t , map [string ]testHandler {
359+ "POST /v3/videos" : {
360+ StatusCode : 200 ,
361+ Body : `{"data":{"video_id":"vid_123"}}` ,
362+ },
363+ "GET /v3/videos/vid_123" : {
364+ StatusCode : 200 ,
365+ Body : `{"data":{"video_id":"vid_123","status":"processing"}}` ,
366+ },
367+ })
368+ defer srv .Close ()
369+
370+ res := runGenCommand (t , srv .URL , "test-key" , videoCreateWaitSpec , "create" , "--wait" , "--timeout" , "20ms" )
371+
372+ if res .ExitCode != 1 {
373+ t .Fatalf ("ExitCode = %d, want 1\n stderr: %s" , res .ExitCode , res .Stderr )
374+ }
375+ if ! strings .Contains (res .Stderr , "polling timed out before the operation completed" ) {
376+ t .Fatalf ("stderr = %s, want timeout message" , res .Stderr )
377+ }
378+ }
379+
380+ func TestGenBuilder_VideoCreate_NoWait (t * testing.T ) {
381+ var statusCalled bool
382+ srv := setupTestServer (t , map [string ]testHandler {
383+ "POST /v3/videos" : {
384+ StatusCode : 200 ,
385+ Body : `{"data":{"video_id":"vid_123","status":"pending"}}` ,
386+ },
387+ "GET /v3/videos/vid_123" : {
388+ StatusCode : 200 ,
389+ ValidateRequest : func (t * testing.T , r * http.Request ) {
390+ t .Helper ()
391+ statusCalled = true
392+ },
393+ Body : `{"data":{"video_id":"vid_123","status":"completed"}}` ,
394+ },
395+ })
396+ defer srv .Close ()
397+
398+ res := runGenCommand (t , srv .URL , "test-key" , videoCreateWaitSpec , "create" )
399+
400+ if res .ExitCode != 0 {
401+ t .Fatalf ("ExitCode = %d, want 0\n stderr: %s" , res .ExitCode , res .Stderr )
402+ }
403+ if statusCalled {
404+ t .Fatal ("status endpoint should not be called without --wait" )
405+ }
406+ var parsed map [string ]any
407+ if err := json .Unmarshal ([]byte (res .Stdout ), & parsed ); err != nil {
408+ t .Fatalf ("stdout is not valid JSON: %v\n stdout: %s" , err , res .Stdout )
409+ }
410+ data := parsed ["data" ].(map [string ]any )
411+ if data ["status" ] != "pending" {
412+ t .Fatalf ("status = %v, want pending" , data ["status" ])
413+ }
414+ }
415+
416+ func TestGenBuilder_VideoCreate_WaitNotAvailable (t * testing.T ) {
417+ nonPollable := & command.Spec {
418+ Group : "video" ,
419+ Name : "get" ,
420+ Summary : "Get video" ,
421+ Endpoint : "/v3/videos/{video_id}" ,
422+ Method : "GET" ,
423+ Args : []command.ArgSpec {
424+ {Name : "video-id" , Param : "video_id" },
425+ },
426+ Examples : []string {"heygen video get <video-id>" },
427+ }
428+
429+ srv := setupTestServer (t , map [string ]testHandler {})
430+ defer srv .Close ()
431+
432+ res := runGenCommand (t , srv .URL , "test-key" , nonPollable , "get" , "vid_123" , "--wait" )
433+
434+ if res .ExitCode != 2 {
435+ t .Fatalf ("ExitCode = %d, want 2\n stderr: %s" , res .ExitCode , res .Stderr )
436+ }
437+ if ! strings .Contains (res .Stderr , "unknown flag: --wait" ) {
438+ t .Fatalf ("stderr = %s, want unknown flag error" , res .Stderr )
439+ }
440+ }
441+
265442func TestGenBuilder_PostWithBodyFlags (t * testing.T ) {
266443 var gotBody map [string ]any
267444
@@ -579,6 +756,9 @@ func runGeneratedRootCommand(t *testing.T, serverURL, apiKey string, groups map[
579756
580757 t .Setenv ("HEYGEN_API_KEY" , apiKey )
581758 t .Setenv ("HEYGEN_API_BASE" , serverURL )
759+ if _ , ok := os .LookupEnv ("HEYGEN_CONFIG_DIR" ); ! ok {
760+ t .Setenv ("HEYGEN_CONFIG_DIR" , t .TempDir ())
761+ }
582762
583763 root := newRootCmdWithSpecs ("test" , formatter , groups )
584764 root .SetOut (& stdout )
0 commit comments