2
2
3
3
import pytest
4
4
import responses
5
+ from pydantic import ValidationError
5
6
6
7
from mailtrap .api .resources .projects import ProjectsApi
7
8
from mailtrap .config import MAILTRAP_HOST
@@ -40,6 +41,34 @@ def sample_project_dict() -> dict[str, Any]:
40
41
41
42
42
43
class 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
+
43
72
@responses .activate
44
73
def test_get_list_should_return_project_list (
45
74
self , client : ProjectsApi , sample_project_dict : dict
@@ -57,20 +86,34 @@ def test_get_list_should_return_project_list(
57
86
assert all (isinstance (p , Project ) for p in projects )
58
87
assert projects [0 ].id == PROJECT_ID
59
88
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
+ )
60
97
@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 :
62
105
url = f"{ BASE_PROJECTS_URL } /{ PROJECT_ID } "
63
106
responses .add (
64
107
responses .GET ,
65
108
url ,
66
- status = 404 ,
67
- json = { "error" : "Not Found" } ,
109
+ status = status_code ,
110
+ json = response_json ,
68
111
)
69
112
70
113
with pytest .raises (APIError ) as exc_info :
71
114
client .get_by_id (PROJECT_ID )
72
115
73
- assert "Not Found" in str (exc_info )
116
+ assert expected_error_message in str (exc_info . value )
74
117
75
118
@responses .activate
76
119
def test_get_by_id_should_return_single_project (
@@ -89,6 +132,54 @@ def test_get_by_id_should_return_single_project(
89
132
assert isinstance (project , Project )
90
133
assert project .id == PROJECT_ID
91
134
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
+
92
183
@responses .activate
93
184
def test_create_should_return_new_project (
94
185
self , client : ProjectsApi , sample_project_dict : dict
@@ -105,20 +196,55 @@ def test_create_should_return_new_project(
105
196
assert isinstance (project , Project )
106
197
assert project .name == "Test Project"
107
198
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
+ )
108
207
@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 :
110
215
url = f"{ BASE_PROJECTS_URL } /{ PROJECT_ID } "
111
216
responses .add (
112
217
responses .PATCH ,
113
218
url ,
114
- status = 404 ,
115
- json = { "error" : "Not Found" } ,
219
+ status = status_code ,
220
+ json = response_json ,
116
221
)
117
222
118
223
with pytest .raises (APIError ) as exc_info :
119
224
client .update (PROJECT_ID , project_name = "Update Project Name" )
120
225
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 )
122
248
123
249
@responses .activate
124
250
def test_update_should_return_updated_project (
@@ -141,20 +267,34 @@ def test_update_should_return_updated_project(
141
267
assert isinstance (project , Project )
142
268
assert project .name == updated_name
143
269
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
+ )
144
278
@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 :
146
286
url = f"{ BASE_PROJECTS_URL } /{ PROJECT_ID } "
147
287
responses .add (
148
288
responses .DELETE ,
149
289
url ,
150
- status = 404 ,
151
- json = { "error" : "Not Found" } ,
290
+ status = status_code ,
291
+ json = response_json ,
152
292
)
153
293
154
294
with pytest .raises (APIError ) as exc_info :
155
295
client .delete (PROJECT_ID )
156
296
157
- assert "Not Found" in str (exc_info )
297
+ assert expected_error_message in str (exc_info . value )
158
298
159
299
@responses .activate
160
300
def test_delete_should_return_deleted_object (self , client : ProjectsApi ) -> None :
0 commit comments