@@ -336,7 +336,7 @@ def test_asks_for_app_name_after_team(
336336def test_creates_app_on_backend (
337337 logged_in_cli : None , tmp_path : Path , respx_mock : respx .MockRouter
338338) -> None :
339- steps = [Keys .ENTER , Keys .ENTER , * "demo" , Keys .ENTER , Keys .ENTER ]
339+ steps = [Keys .ENTER , Keys .ENTER , * "demo" , Keys .ENTER , Keys .ENTER , Keys . ENTER ]
340340
341341 team = _get_random_team ()
342342
@@ -347,10 +347,50 @@ def test_creates_app_on_backend(
347347 )
348348 )
349349
350- respx_mock .post ("/apps/" , json = {"name" : "demo" , "team_id" : team ["id" ]}).mock (
351- return_value = Response (201 , json = _get_random_app (team_id = team ["id" ]))
350+ respx_mock .post (
351+ "/apps/" , json = {"name" : "demo" , "team_id" : team ["id" ], "directory" : None }
352+ ).mock (return_value = Response (201 , json = _get_random_app (team_id = team ["id" ])))
353+
354+ with (
355+ changing_dir (tmp_path ),
356+ patch ("rich_toolkit.container.getchar" ) as mock_getchar ,
357+ ):
358+ mock_getchar .side_effect = steps
359+
360+ result = runner .invoke (app , ["deploy" ])
361+
362+ assert result .exit_code == 1
363+
364+ assert "App created successfully" in result .output
365+
366+
367+ @pytest .mark .respx
368+ def test_creates_app_with_directory (
369+ logged_in_cli : None , tmp_path : Path , respx_mock : respx .MockRouter
370+ ) -> None :
371+ steps = [
372+ Keys .ENTER ,
373+ Keys .ENTER ,
374+ * "demo" ,
375+ Keys .ENTER ,
376+ * "src" ,
377+ Keys .ENTER ,
378+ Keys .ENTER ,
379+ ]
380+
381+ team = _get_random_team ()
382+
383+ respx_mock .get ("/teams/" ).mock (
384+ return_value = Response (
385+ 200 ,
386+ json = {"data" : [team ]},
387+ )
352388 )
353389
390+ respx_mock .post (
391+ "/apps/" , json = {"name" : "demo" , "team_id" : team ["id" ], "directory" : "src" }
392+ ).mock (return_value = Response (201 , json = _get_random_app (team_id = team ["id" ])))
393+
354394 with (
355395 changing_dir (tmp_path ),
356396 patch ("rich_toolkit.container.getchar" ) as mock_getchar ,
@@ -362,6 +402,52 @@ def test_creates_app_on_backend(
362402 assert result .exit_code == 1
363403
364404 assert "App created successfully" in result .output
405+ assert "Directory: src" in result .output
406+
407+
408+ @pytest .mark .respx
409+ @pytest .mark .parametrize (
410+ "directory,expected_error" ,
411+ [
412+ ("~/src" , "cannot start with '~'" ),
413+ ("/absolute/path" , "must be a relative path, not absolute" ),
414+ ("src/../etc" , "cannot contain '..' path segments" ),
415+ ("src/@app" , "contains invalid characters" ),
416+ ],
417+ )
418+ def test_shows_validation_error_for_invalid_directory (
419+ logged_in_cli : None ,
420+ tmp_path : Path ,
421+ respx_mock : respx .MockRouter ,
422+ directory : str ,
423+ expected_error : str ,
424+ ) -> None :
425+ steps = [
426+ Keys .ENTER , # Select team
427+ Keys .ENTER , # Confirm new app
428+ * "demo" ,
429+ Keys .ENTER , # App name
430+ * directory ,
431+ Keys .ENTER , # Submit invalid directory -> validation error shown
432+ Keys .CTRL_C , # Cancel
433+ ]
434+
435+ respx_mock .get ("/teams/" ).mock (
436+ return_value = Response (
437+ 200 ,
438+ json = {"data" : [_get_random_team ()]},
439+ )
440+ )
441+
442+ with (
443+ changing_dir (tmp_path ),
444+ patch ("rich_toolkit.container.getchar" ) as mock_getchar ,
445+ ):
446+ mock_getchar .side_effect = steps
447+
448+ result = runner .invoke (app , ["deploy" ])
449+
450+ assert expected_error in result .output
365451
366452
367453@pytest .mark .respx
@@ -373,6 +459,7 @@ def test_cancels_deployment_when_user_selects_no(
373459 Keys .ENTER ,
374460 * "demo" ,
375461 Keys .ENTER ,
462+ Keys .ENTER ,
376463 Keys .DOWN_ARROW ,
377464 Keys .ENTER ,
378465 ]
@@ -438,6 +525,7 @@ def test_exits_successfully_when_deployment_is_done(
438525 * "demo" ,
439526 Keys .ENTER ,
440527 Keys .ENTER ,
528+ Keys .ENTER ,
441529 ]
442530
443531 team_data = _get_random_team ()
@@ -447,9 +535,9 @@ def test_exits_successfully_when_deployment_is_done(
447535 return_value = Response (200 , json = {"data" : [team_data ]})
448536 )
449537
450- respx_mock .post ("/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ]}). mock (
451- return_value = Response ( 201 , json = app_data )
452- )
538+ respx_mock .post (
539+ "/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ], "directory" : None }
540+ ). mock ( return_value = Response ( 201 , json = app_data ))
453541
454542 respx_mock .get (f"/apps/{ app_data ['id' ]} " ).mock (
455543 return_value = Response (200 , json = app_data )
@@ -689,6 +777,7 @@ def _deploy_without_waiting(respx_mock: respx.MockRouter, tmp_path: Path) -> Res
689777 * "demo" ,
690778 Keys .ENTER ,
691779 Keys .ENTER ,
780+ Keys .ENTER ,
692781 ]
693782
694783 team_data = _get_random_team ()
@@ -702,9 +791,9 @@ def _deploy_without_waiting(respx_mock: respx.MockRouter, tmp_path: Path) -> Res
702791 )
703792 )
704793
705- respx_mock .post ("/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ]}). mock (
706- return_value = Response ( 201 , json = app_data )
707- )
794+ respx_mock .post (
795+ "/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ], "directory" : None }
796+ ). mock ( return_value = Response ( 201 , json = app_data ))
708797
709798 respx_mock .get (f"/apps/{ app_data ['id' ]} " ).mock (
710799 return_value = Response (200 , json = app_data )
0 commit comments