@@ -332,7 +332,7 @@ def test_asks_for_app_name_after_team(
332332def test_creates_app_on_backend (
333333 logged_in_cli : None , tmp_path : Path , respx_mock : respx .MockRouter
334334) -> None :
335- steps = [Keys .ENTER , Keys .ENTER , * "demo" , Keys .ENTER , Keys .ENTER ]
335+ steps = [Keys .ENTER , Keys .ENTER , * "demo" , Keys .ENTER , Keys .ENTER , Keys . ENTER ]
336336
337337 team = _get_random_team ()
338338
@@ -343,10 +343,50 @@ def test_creates_app_on_backend(
343343 )
344344 )
345345
346- respx_mock .post ("/apps/" , json = {"name" : "demo" , "team_id" : team ["id" ]}).mock (
347- return_value = Response (201 , json = _get_random_app (team_id = team ["id" ]))
346+ respx_mock .post (
347+ "/apps/" , json = {"name" : "demo" , "team_id" : team ["id" ], "directory" : None }
348+ ).mock (return_value = Response (201 , json = _get_random_app (team_id = team ["id" ])))
349+
350+ with (
351+ changing_dir (tmp_path ),
352+ patch ("rich_toolkit.container.getchar" ) as mock_getchar ,
353+ ):
354+ mock_getchar .side_effect = steps
355+
356+ result = runner .invoke (app , ["deploy" ])
357+
358+ assert result .exit_code == 1
359+
360+ assert "App created successfully" in result .output
361+
362+
363+ @pytest .mark .respx
364+ def test_creates_app_with_directory (
365+ logged_in_cli : None , tmp_path : Path , respx_mock : respx .MockRouter
366+ ) -> None :
367+ steps = [
368+ Keys .ENTER ,
369+ Keys .ENTER ,
370+ * "demo" ,
371+ Keys .ENTER ,
372+ * "src" ,
373+ Keys .ENTER ,
374+ Keys .ENTER ,
375+ ]
376+
377+ team = _get_random_team ()
378+
379+ respx_mock .get ("/teams/" ).mock (
380+ return_value = Response (
381+ 200 ,
382+ json = {"data" : [team ]},
383+ )
348384 )
349385
386+ respx_mock .post (
387+ "/apps/" , json = {"name" : "demo" , "team_id" : team ["id" ], "directory" : "src" }
388+ ).mock (return_value = Response (201 , json = _get_random_app (team_id = team ["id" ])))
389+
350390 with (
351391 changing_dir (tmp_path ),
352392 patch ("rich_toolkit.container.getchar" ) as mock_getchar ,
@@ -358,6 +398,52 @@ def test_creates_app_on_backend(
358398 assert result .exit_code == 1
359399
360400 assert "App created successfully" in result .output
401+ assert "Directory: src" in result .output
402+
403+
404+ @pytest .mark .respx
405+ @pytest .mark .parametrize (
406+ "directory,expected_error" ,
407+ [
408+ ("~/src" , "cannot start with '~'" ),
409+ ("/absolute/path" , "must be a relative path, not absolute" ),
410+ ("src/../etc" , "cannot contain '..' path segments" ),
411+ ("src/@app" , "contains invalid characters" ),
412+ ],
413+ )
414+ def test_shows_validation_error_for_invalid_directory (
415+ logged_in_cli : None ,
416+ tmp_path : Path ,
417+ respx_mock : respx .MockRouter ,
418+ directory : str ,
419+ expected_error : str ,
420+ ) -> None :
421+ steps = [
422+ Keys .ENTER , # Select team
423+ Keys .ENTER , # Confirm new app
424+ * "demo" ,
425+ Keys .ENTER , # App name
426+ * directory ,
427+ Keys .ENTER , # Submit invalid directory -> validation error shown
428+ Keys .CTRL_C , # Cancel
429+ ]
430+
431+ respx_mock .get ("/teams/" ).mock (
432+ return_value = Response (
433+ 200 ,
434+ json = {"data" : [_get_random_team ()]},
435+ )
436+ )
437+
438+ with (
439+ changing_dir (tmp_path ),
440+ patch ("rich_toolkit.container.getchar" ) as mock_getchar ,
441+ ):
442+ mock_getchar .side_effect = steps
443+
444+ result = runner .invoke (app , ["deploy" ])
445+
446+ assert expected_error in result .output
361447
362448
363449@pytest .mark .respx
@@ -369,6 +455,7 @@ def test_cancels_deployment_when_user_selects_no(
369455 Keys .ENTER ,
370456 * "demo" ,
371457 Keys .ENTER ,
458+ Keys .ENTER ,
372459 Keys .DOWN_ARROW ,
373460 Keys .ENTER ,
374461 ]
@@ -434,6 +521,7 @@ def test_exits_successfully_when_deployment_is_done(
434521 * "demo" ,
435522 Keys .ENTER ,
436523 Keys .ENTER ,
524+ Keys .ENTER ,
437525 ]
438526
439527 team_data = _get_random_team ()
@@ -443,9 +531,9 @@ def test_exits_successfully_when_deployment_is_done(
443531 return_value = Response (200 , json = {"data" : [team_data ]})
444532 )
445533
446- respx_mock .post ("/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ]}). mock (
447- return_value = Response ( 201 , json = app_data )
448- )
534+ respx_mock .post (
535+ "/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ], "directory" : None }
536+ ). mock ( return_value = Response ( 201 , json = app_data ))
449537
450538 respx_mock .get (f"/apps/{ app_data ['id' ]} " ).mock (
451539 return_value = Response (200 , json = app_data )
@@ -685,6 +773,7 @@ def _deploy_without_waiting(respx_mock: respx.MockRouter, tmp_path: Path) -> Res
685773 * "demo" ,
686774 Keys .ENTER ,
687775 Keys .ENTER ,
776+ Keys .ENTER ,
688777 ]
689778
690779 team_data = _get_random_team ()
@@ -698,9 +787,9 @@ def _deploy_without_waiting(respx_mock: respx.MockRouter, tmp_path: Path) -> Res
698787 )
699788 )
700789
701- respx_mock .post ("/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ]}). mock (
702- return_value = Response ( 201 , json = app_data )
703- )
790+ respx_mock .post (
791+ "/apps/" , json = { "name" : "demo" , "team_id" : team_data [ "id" ], "directory" : None }
792+ ). mock ( return_value = Response ( 201 , json = app_data ))
704793
705794 respx_mock .get (f"/apps/{ app_data ['id' ]} " ).mock (
706795 return_value = Response (200 , json = app_data )
0 commit comments