Skip to content

Commit 03c9a04

Browse files
committed
test(api): add CRUD tests for todo items
Added full API test coverage for todo items, including: - Creating a new todo - Retrieving todos - Updating a todo's status - Deleting a todo - Negative cases for delete with invalid ID and no auth All tests use token-based auth and assert correct responses.
1 parent fc8d508 commit 03c9a04

File tree

12 files changed

+599
-15
lines changed

12 files changed

+599
-15
lines changed

src/main/java/com/omarelsheikh/todo/api/config/EndPoints.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public class EndPoints {
44

55
public static final String API_REGISTER_END_POINT = "/api/v1/users/register";
6+
public static final String API_LOGIN_END_POINT = "/api/v1/users/login";
67
public static final String API_TASK_END_POINT = "api/v1/tasks";
78
public static final String TODO_END_POINT = "/todo";
89
public static final String NEW_TODO_END_POINT = "/todo/new";
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.omarelsheikh.todo.api.models;
2+
3+
/**
4+
* Represents the structure of the User as expected by the backend API.
5+
* Only includes fields allowed by the API contract for Logging in.
6+
*/
7+
public class UserLogin {
8+
9+
private String email;
10+
private String password;
11+
12+
public UserLogin(String email, String password) {
13+
this.email = email;
14+
this.password = password;
15+
}
16+
17+
18+
public String getEmail() {
19+
return email;
20+
}
21+
22+
public void setEmail(String email) {
23+
this.email = email;
24+
}
25+
26+
public String getPassword() {
27+
return password;
28+
}
29+
30+
public void setPassword(String password) {
31+
this.password = password;
32+
}
33+
}

src/main/java/com/omarelsheikh/todo/utils/ConfigUtil.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class ConfigUtil {
1717
// Private constructor to load properties based on the environment
1818
private ConfigUtil() throws IOException {
1919

20+
// If user didn't specify environment, it will run on PRODUCTION by default
2021
String env = System.getProperty("env", "PRODUCTION").toUpperCase();
2122

2223
switch (env) {

src/test/java/com/omarelsheikh/todo/api/requests/RegisterApi.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.omarelsheikh.todo.api.requests;
22

33
import com.omarelsheikh.todo.api.config.EndPoints;
4-
import com.omarelsheikh.todo.models.User;
4+
import com.omarelsheikh.todo.models.UserRegister;
55
import com.omarelsheikh.todo.utils.UserUtils;
66
import io.restassured.http.Cookie;
77
import io.restassured.response.Response;
@@ -13,7 +13,8 @@
1313
public class RegisterApi {
1414

1515
private String email;
16-
private User user;
16+
private String password;
17+
private UserRegister user;
1718
private List<Cookie> restAssuredCookies;
1819
private String accessToken;
1920
private String userId;
@@ -24,7 +25,11 @@ public String getEmail() {
2425
return this.email;
2526
}
2627

27-
public User getUser() {
28+
public String getPassword() {
29+
return this.password;
30+
}
31+
32+
public UserRegister getUser() {
2833
return this.user;
2934
}
3035

@@ -73,7 +78,8 @@ public void register() {
7378
userId = response.path("userID");
7479
firstName = response.path("firstName");
7580

76-
// Get the email
81+
// Get the email and password
7782
email = user.getEmail();
83+
password = user.getPassword();
7884
}
7985
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package com.omarelsheikh.todo.api.testcases;
2+
3+
import com.omarelsheikh.todo.api.config.EndPoints;
4+
import com.omarelsheikh.todo.api.models.Todo;
5+
import com.omarelsheikh.todo.api.requests.RegisterApi;
6+
import io.restassured.response.Response;
7+
import org.testng.Assert;
8+
import org.testng.annotations.Test;
9+
10+
import java.io.IOException;
11+
12+
import static io.restassured.RestAssured.given;
13+
14+
public class DeleteItemApiTest {
15+
16+
@Test
17+
public void shouldDeleteItemSuccessfullyWithValidId() throws IOException {
18+
19+
// Register and get token
20+
RegisterApi registerApi = new RegisterApi();
21+
registerApi.register();
22+
String token = registerApi.getToken();
23+
24+
// Create a todo item
25+
Todo todo = new Todo("Test item for delete", false);
26+
Response createResponse = given()
27+
.baseUri("https://todo.qacart.com")
28+
.header("Content-Type", "application/json")
29+
.auth().oauth2(token)
30+
.body(todo)
31+
.log().all()
32+
.when()
33+
.post(EndPoints.API_TASK_END_POINT)
34+
.then()
35+
.log().all()
36+
.extract().response();
37+
38+
String itemId = createResponse.path("_id");
39+
40+
// Delete the item
41+
Response deleteResponse = given()
42+
.baseUri("https://todo.qacart.com")
43+
.auth().oauth2(token)
44+
.log().all()
45+
.when()
46+
.delete(EndPoints.API_TASK_END_POINT + "/" + itemId)
47+
.then()
48+
.log().all()
49+
.extract().response();
50+
51+
// Assert only the status code
52+
Assert.assertEquals(deleteResponse.getStatusCode(), 200);
53+
}
54+
55+
56+
@Test
57+
public void shouldFailToDeleteItemWithInvalidId() {
58+
59+
// Register and get a valid token
60+
RegisterApi registerApi = new RegisterApi();
61+
registerApi.register();
62+
String token = registerApi.getToken();
63+
64+
// Use a fake ID (but well-formatted)
65+
String fakeId = "64b83b219e03c8a9d0f0f111";
66+
67+
// Try deleting with fake ID
68+
Response deleteResponse = given()
69+
.baseUri("https://todo.qacart.com")
70+
.auth().oauth2(token)
71+
.when()
72+
.delete(EndPoints.API_TASK_END_POINT + "/" + fakeId)
73+
.then()
74+
.extract().response();
75+
76+
// Assert status
77+
Assert.assertEquals(deleteResponse.getStatusCode(), 400);
78+
79+
// Assert a message
80+
String message = deleteResponse.jsonPath().getString("message");
81+
Assert.assertEquals(message, "We could not find the task in our database");
82+
}
83+
84+
@Test
85+
public void shouldFailToDeleteItemWhenUnauthorized() {
86+
87+
// Register and get a token
88+
RegisterApi registerApi = new RegisterApi();
89+
registerApi.register();
90+
String token = registerApi.getToken();
91+
92+
// Create a real todo item
93+
Todo todo = new Todo("Item to test unauthorized delete", false);
94+
Response createResponse = given()
95+
.baseUri("https://todo.qacart.com")
96+
.header("Content-Type", "application/json")
97+
.auth().oauth2(token)
98+
.body(todo)
99+
.post(EndPoints.API_TASK_END_POINT)
100+
.then()
101+
.extract().response();
102+
103+
String itemId = createResponse.path("_id");
104+
105+
// Try to delete the item without a token
106+
Response deleteResponse = given()
107+
.baseUri("https://todo.qacart.com")
108+
.when()
109+
.delete(EndPoints.API_TASK_END_POINT + "/" + itemId)
110+
.then()
111+
.extract().response();
112+
113+
Assert.assertEquals(deleteResponse.getStatusCode(), 401);
114+
}
115+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.omarelsheikh.todo.api.testcases;
2+
3+
import com.omarelsheikh.todo.api.config.EndPoints;
4+
import com.omarelsheikh.todo.api.requests.RegisterApi;
5+
import com.omarelsheikh.todo.api.requests.TasksApi;
6+
import com.omarelsheikh.todo.utils.ConfigUtil;
7+
import io.restassured.response.Response;
8+
import org.testng.Assert;
9+
import org.testng.annotations.Test;
10+
11+
import java.io.IOException;
12+
13+
import static io.restassured.RestAssured.given;
14+
15+
public class GetItemsApiTest {
16+
17+
@Test
18+
public void shouldGetItemsSuccessfullyWithValidAuth() throws IOException {
19+
20+
// Register a new user via the API and retrieve their access token
21+
RegisterApi registerApi = new RegisterApi();
22+
registerApi.register();
23+
String accessToken = registerApi.getToken();
24+
25+
// Add a new todo item for the user using the valid token
26+
TasksApi tasksApi = new TasksApi();
27+
tasksApi.addTodo(accessToken);
28+
29+
// Send a GET request to retrieve the user's todo items
30+
Response response =
31+
given()
32+
.baseUri("https://todo.qacart.com") // Set base URL from config
33+
.auth().oauth2(accessToken) // Use the valid token for authorization
34+
.log().all() // Log request details
35+
.when()
36+
.get(EndPoints.API_TASK_END_POINT) // Hit the tasks endpoint
37+
.then()
38+
.log().all() // Log response details
39+
.extract().response();
40+
41+
// Verify the response status code is 200 OK
42+
Assert.assertEquals(response.statusCode(), 200, "Expected 200 OK");
43+
}
44+
45+
46+
@Test
47+
public void shouldFailToGetItemsWhenUnauthorized() throws IOException {
48+
49+
// Register a new user via the API and retrieve their access token
50+
RegisterApi registerApi = new RegisterApi();
51+
registerApi.register();
52+
String accessToken = registerApi.getToken();
53+
54+
// Add a new todo item for the user using the valid token
55+
TasksApi tasksApi = new TasksApi();
56+
tasksApi.addTodo(accessToken);
57+
58+
// Send a GET request to retrieve the user's todo items
59+
Response response =
60+
given()
61+
.baseUri("https://todo.qacart.com") // Set base URL from config
62+
.log().all() // Log request details
63+
.when()
64+
.get(EndPoints.API_TASK_END_POINT) // Hit the tasks endpoint
65+
.then()
66+
.log().all() // Log response details
67+
.extract().response();
68+
69+
// Verify the response status code is 200 OK
70+
Assert.assertEquals(response.statusCode(), 401, "Expected 401 Unauthorized for invalid token");
71+
}
72+
}

0 commit comments

Comments
 (0)