22
33import  pytest 
44import  responses 
5+ from  pydantic  import  ValidationError 
56
67from  mailtrap .api .resources .projects  import  ProjectsApi 
78from  mailtrap .config  import  MAILTRAP_HOST 
@@ -40,6 +41,34 @@ def sample_project_dict() -> dict[str, Any]:
4041
4142
4243class  TestProjectsApi :
44+ 
45+     @pytest .mark .parametrize ( 
46+         "status_code,response_json,expected_error_message" , 
47+         [ 
48+             (401 , {"error" : "Incorrect API token" }, "Incorrect API token" ), 
49+             (403 , {"errors" : "Access forbidden" }, "Access forbidden" ), 
50+         ], 
51+     ) 
52+     @responses .activate  
53+     def  test_get_list_should_raise_api_errors (
54+         self ,
55+         client : ProjectsApi ,
56+         status_code : int ,
57+         response_json : dict ,
58+         expected_error_message : str ,
59+     ) ->  None :
60+         responses .add (
61+             responses .GET ,
62+             BASE_PROJECTS_URL ,
63+             status = status_code ,
64+             json = response_json ,
65+         )
66+ 
67+         with  pytest .raises (APIError ) as  exc_info :
68+             client .get_list ()
69+ 
70+         assert  expected_error_message  in  str (exc_info .value )
71+ 
4372    @responses .activate  
4473    def  test_get_list_should_return_project_list (
4574        self , client : ProjectsApi , sample_project_dict : dict 
@@ -57,20 +86,34 @@ def test_get_list_should_return_project_list(
5786        assert  all (isinstance (p , Project ) for  p  in  projects )
5887        assert  projects [0 ].id  ==  PROJECT_ID 
5988
89+     @pytest .mark .parametrize ( 
90+         "status_code,response_json,expected_error_message" , 
91+         [ 
92+             (401 , {"error" : "Incorrect API token" }, "Incorrect API token" ), 
93+             (403 , {"errors" : "Access forbidden" }, "Access forbidden" ), 
94+             (404 , {"error" : "Not Found" }, "Not Found" ), 
95+         ], 
96+     ) 
6097    @responses .activate  
61-     def  test_get_by_id_should_raise_not_found_error (self , client : ProjectsApi ) ->  None :
98+     def  test_get_by_id_should_raise_api_errors (
99+         self ,
100+         client : ProjectsApi ,
101+         status_code : int ,
102+         response_json : dict ,
103+         expected_error_message : str ,
104+     ) ->  None :
62105        url  =  f"{ BASE_PROJECTS_URL }  /{ PROJECT_ID }  " 
63106        responses .add (
64107            responses .GET ,
65108            url ,
66-             status = 404 ,
67-             json = { "error" :  "Not Found" } ,
109+             status = status_code ,
110+             json = response_json ,
68111        )
69112
70113        with  pytest .raises (APIError ) as  exc_info :
71114            client .get_by_id (PROJECT_ID )
72115
73-         assert  "Not Found"   in  str (exc_info )
116+         assert  expected_error_message   in  str (exc_info . value )
74117
75118    @responses .activate  
76119    def  test_get_by_id_should_return_single_project (
@@ -89,6 +132,54 @@ def test_get_by_id_should_return_single_project(
89132        assert  isinstance (project , Project )
90133        assert  project .id  ==  PROJECT_ID 
91134
135+     @pytest .mark .parametrize ( 
136+         "status_code,response_json,expected_error_message" , 
137+         [ 
138+             (401 , {"error" : "Incorrect API token" }, "Incorrect API token" ), 
139+             (403 , {"errors" : "Access forbidden" }, "Access forbidden" ), 
140+         ], 
141+     ) 
142+     @responses .activate  
143+     def  test_create_should_raise_api_errors (
144+         self ,
145+         client : ProjectsApi ,
146+         status_code : int ,
147+         response_json : dict ,
148+         expected_error_message : str ,
149+     ) ->  None :
150+         responses .add (
151+             responses .POST ,
152+             BASE_PROJECTS_URL ,
153+             status = status_code ,
154+             json = response_json ,
155+         )
156+ 
157+         with  pytest .raises (APIError ) as  exc_info :
158+             client .create (project_name = "New Project" )
159+ 
160+         assert  expected_error_message  in  str (exc_info .value )
161+ 
162+     @pytest .mark .parametrize ( 
163+         "project_name, expected_errors" , 
164+         [ 
165+             (None , ["Input should be a valid string" ]), 
166+             ("" , ["String should have at least 2 characters" ]), 
167+             ("a" , ["String should have at least 2 characters" ]), 
168+             ("a"  *  101 , ["String should have at most 100 characters" ]), 
169+         ], 
170+     ) 
171+     def  test_create_should_raise_validation_error_on_pydantic_validation (
172+         self , client : ProjectsApi , project_name : str , expected_errors : list [str ]
173+     ) ->  None :
174+         with  pytest .raises (ValidationError ) as  exc_info :
175+             client .create (project_name = project_name )
176+ 
177+         errors  =  exc_info .value .errors ()
178+         error_messages  =  [err ["msg" ] for  err  in  errors ]
179+ 
180+         for  expected_msg  in  expected_errors :
181+             assert  any (expected_msg  in  actual_msg  for  actual_msg  in  error_messages )
182+ 
92183    @responses .activate  
93184    def  test_create_should_return_new_project (
94185        self , client : ProjectsApi , sample_project_dict : dict 
@@ -105,20 +196,55 @@ def test_create_should_return_new_project(
105196        assert  isinstance (project , Project )
106197        assert  project .name  ==  "Test Project" 
107198
199+     @pytest .mark .parametrize ( 
200+         "status_code,response_json,expected_error_message" , 
201+         [ 
202+             (401 , {"error" : "Incorrect API token" }, "Incorrect API token" ), 
203+             (403 , {"errors" : "Access forbidden" }, "Access forbidden" ), 
204+             (404 , {"error" : "Not Found" }, "Not Found" ), 
205+         ], 
206+     ) 
108207    @responses .activate  
109-     def  test_update_should_raise_not_found_error (self , client : ProjectsApi ) ->  None :
208+     def  test_update_should_raise_api_errors (
209+         self ,
210+         client : ProjectsApi ,
211+         status_code : int ,
212+         response_json : dict ,
213+         expected_error_message : str ,
214+     ) ->  None :
110215        url  =  f"{ BASE_PROJECTS_URL }  /{ PROJECT_ID }  " 
111216        responses .add (
112217            responses .PATCH ,
113218            url ,
114-             status = 404 ,
115-             json = { "error" :  "Not Found" } ,
219+             status = status_code ,
220+             json = response_json ,
116221        )
117222
118223        with  pytest .raises (APIError ) as  exc_info :
119224            client .update (PROJECT_ID , project_name = "Update Project Name" )
120225
121-         assert  "Not Found"  in  str (exc_info )
226+         assert  expected_error_message  in  str (exc_info .value )
227+ 
228+     @pytest .mark .parametrize ( 
229+         "project_name, expected_errors" , 
230+         [ 
231+             (None , ["Input should be a valid string" ]), 
232+             ("" , ["String should have at least 2 characters" ]), 
233+             ("a" , ["String should have at least 2 characters" ]), 
234+             ("a"  *  101 , ["String should have at most 100 characters" ]), 
235+         ], 
236+     ) 
237+     def  test_update_should_raise_validation_error_on_pydantic_validation (
238+         self , client : ProjectsApi , project_name : str , expected_errors : list [str ]
239+     ) ->  None :
240+         with  pytest .raises (ValidationError ) as  exc_info :
241+             client .update (project_id = PROJECT_ID , project_name = project_name )
242+ 
243+         errors  =  exc_info .value .errors ()
244+         error_messages  =  [err ["msg" ] for  err  in  errors ]
245+ 
246+         for  expected_msg  in  expected_errors :
247+             assert  any (expected_msg  in  actual_msg  for  actual_msg  in  error_messages )
122248
123249    @responses .activate  
124250    def  test_update_should_return_updated_project (
@@ -141,20 +267,34 @@ def test_update_should_return_updated_project(
141267        assert  isinstance (project , Project )
142268        assert  project .name  ==  updated_name 
143269
270+     @pytest .mark .parametrize ( 
271+         "status_code,response_json,expected_error_message" , 
272+         [ 
273+             (401 , {"error" : "Incorrect API token" }, "Incorrect API token" ), 
274+             (403 , {"errors" : "Access forbidden" }, "Access forbidden" ), 
275+             (404 , {"error" : "Not Found" }, "Not Found" ), 
276+         ], 
277+     ) 
144278    @responses .activate  
145-     def  test_delete_should_raise_not_found_error (self , client : ProjectsApi ) ->  None :
279+     def  test_delete_should_raise_api_errors (
280+         self ,
281+         client : ProjectsApi ,
282+         status_code : int ,
283+         response_json : dict ,
284+         expected_error_message : str ,
285+     ) ->  None :
146286        url  =  f"{ BASE_PROJECTS_URL }  /{ PROJECT_ID }  " 
147287        responses .add (
148288            responses .DELETE ,
149289            url ,
150-             status = 404 ,
151-             json = { "error" :  "Not Found" } ,
290+             status = status_code ,
291+             json = response_json ,
152292        )
153293
154294        with  pytest .raises (APIError ) as  exc_info :
155295            client .delete (PROJECT_ID )
156296
157-         assert  "Not Found"   in  str (exc_info )
297+         assert  expected_error_message   in  str (exc_info . value )
158298
159299    @responses .activate  
160300    def  test_delete_should_return_deleted_object (self , client : ProjectsApi ) ->  None :
0 commit comments