Skip to content

Commit 5fdf0b9

Browse files
test/BE: increase code coverage to 90% (#15)
1 parent 10d6d28 commit 5fdf0b9

File tree

7 files changed

+484
-284
lines changed

7 files changed

+484
-284
lines changed

backend/app/controllers/WorkspaceController.scala

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,18 +114,6 @@ class WorkspaceController @Inject()(
114114
Json.toJson(ApiResponse[Unit]("Workspace updated successfully"))
115115
)
116116
}
117-
}.recover {
118-
case ex: AppException => BadRequest(
119-
Json.obj(
120-
"message" -> "Duplicate workspace name",
121-
"errors" -> Json.arr(
122-
Json.obj(
123-
"field" -> "name",
124-
"message" -> ex.message
125-
)
126-
)
127-
)
128-
)
129117
}
130118
}
131119
}

backend/app/services/WorkspaceService.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class WorkspaceService @Inject() (
9595
isWorkspaceNameExists <- workspaceRepo.isWorkspaceNameUsedByUser(workspace.name, updatedBy)
9696
result <- if (isWorkspaceNameExists) {
9797
DBIO.failed(AppException(
98-
message = "Workspace name already exists",
98+
message = "Duplicate workspace name",
9999
statusCode = Status.CONFLICT
100100
))
101101
} else {

backend/conf/application.test.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ play.evolutions.db.default.enabled = true
1111
play.evolutions.db.default.autoApply = true
1212
play.evolutions.db.default.autoApplyDowns = true
1313

14+
play.http.errorHandler = "exception.CustomErrorHandler"
1415

1516
admin {
1617
email = "test@gmail.com"

backend/test/controllers/ColumnControllerSpec.scala

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package controllers
22

3-
import dto.request.column.{
4-
CreateColumnRequest,
5-
UpdateColumnPositionRequest,
6-
UpdateColumnRequest
7-
}
3+
import dto.request.column.{CreateColumnRequest, UpdateColumnPositionRequest, UpdateColumnRequest}
4+
import dto.response.column.ColumnSummariesResponse
85
import exception.AppException
96
import org.scalatest.BeforeAndAfterAll
107
import org.scalatest.concurrent.ScalaFutures
@@ -206,6 +203,18 @@ class ColumnControllerSpec
206203
.as[String] mustBe "Column archived successfully"
207204
}
208205

206+
"should get archived columns successfully" in {
207+
val request = FakeRequest(GET, "/api/projects/1/columns/archived").withCookies(
208+
Cookie(cookieName, fakeToken)
209+
)
210+
val result = route(app, request).get
211+
212+
status(result) mustBe OK
213+
(contentAsJson(result) \ "message").as[String] mustBe "Archived columns retrieved"
214+
val data = (contentAsJson(result) \ "data").as[Seq[ColumnSummariesResponse]]
215+
data.length must be > 0
216+
}
217+
209218
"restore column successfully" in {
210219
val request = FakeRequest(PATCH, "/api/columns/1/restore")
211220
.withCookies(Cookie(cookieName, fakeToken))

backend/test/controllers/ProjectControllerSpec.scala

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class ProjectControllerSpec
2525
new GuiceApplicationBuilder()
2626
.configure(
2727
"config.resource" -> "application.test.conf",
28+
"play.http.errorHandler" -> "exception.CustomErrorHandler",
2829
"slick.dbs.default.db.url" -> s"jdbc:h2:mem:projecttest;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL;DATABASE_TO_UPPER=false"
2930
)
3031
.build()
@@ -75,6 +76,19 @@ class ProjectControllerSpec
7576
(contentAsJson(result) \ "message").as[String] must include("Project created successfully")
7677
}
7778

79+
"fail when project name already exists" in {
80+
val body = Json.toJson(CreateProjectRequest("New Project"))
81+
val request = FakeRequest(POST, "/api/workspaces/1/projects")
82+
.withCookies(Cookie(cookieName, fakeToken))
83+
.withBody(body)
84+
85+
val ex = intercept[AppException] {
86+
await(route(app, request).get)
87+
}
88+
ex.statusCode mustBe CONFLICT
89+
ex.message must include("Project name 'New Project' already exists")
90+
}
91+
7892
"fail when workspace does not exist" in {
7993
val nonExistentWorkspaceId = 9999
8094
val body = Json.toJson(CreateProjectRequest("Orphan Project"))
@@ -99,6 +113,40 @@ class ProjectControllerSpec
99113
(contentAsJson(result) \ "message").as[String] mustBe "Projects retrieved"
100114
}
101115

116+
"fail when get project in workspace not exist" in {
117+
val request = FakeRequest(GET, "/api/workspaces/0/projects")
118+
.withCookies(Cookie(cookieName, fakeToken))
119+
120+
val ex = intercept[AppException] {
121+
await(route(app, request).get)
122+
}
123+
ex.statusCode mustBe NOT_FOUND
124+
ex.message must include("Workspace not found")
125+
}
126+
127+
"retrieve projects by id" in {
128+
val request = FakeRequest(GET, "/api/projects/1")
129+
.withCookies(Cookie(cookieName, fakeToken))
130+
val result = route(app, request).get
131+
132+
status(result) mustBe OK
133+
(contentAsJson(result) \ "message").as[String] mustBe "Project retrieved"
134+
val projectId = (contentAsJson(result) \ "data" \ "id").as[Int]
135+
projectId mustBe 1
136+
}
137+
138+
"fail when get project with unexisting id" in {
139+
val request = FakeRequest(GET, "/api/projects/0")
140+
.withCookies(Cookie(cookieName, fakeToken))
141+
142+
val ex = intercept[AppException] {
143+
await(route(app, request).get)
144+
}
145+
ex.statusCode mustBe NOT_FOUND
146+
ex.message must include("Project not found")
147+
148+
}
149+
102150
"complete project successfully" in {
103151
val projectId = 1
104152
val request = FakeRequest(PATCH, s"/api/projects/$projectId/complete")
@@ -121,20 +169,6 @@ class ProjectControllerSpec
121169
ex.message must include("Project not found or you are not the owner")
122170
}
123171

124-
// "delete project successfully" in {
125-
// val projectId = 1
126-
// val completeRequest = FakeRequest(PATCH, s"/api/projects/$projectId/complete")
127-
// .withCookies(Cookie(cookieName, fakeToken))
128-
// status(route(app, completeRequest).get) mustBe OK
129-
//
130-
// val request = FakeRequest(PATCH, s"/api/projects/$projectId/delete")
131-
// .withCookies(Cookie(cookieName, fakeToken))
132-
// val result = route(app, request).get
133-
//
134-
// status(result) mustBe OK
135-
// (contentAsJson(result) \ "message").as[String] mustBe "Project deleted successfully"
136-
// }
137-
138172
"reopen project successfully" in {
139173
val projectId = 1
140174
val request = FakeRequest(PATCH, s"/api/projects/$projectId/reopen")
@@ -174,5 +208,19 @@ class ProjectControllerSpec
174208
ex.statusCode mustBe NOT_FOUND
175209
ex.message must include("Project not found")
176210
}
211+
212+
"delete project successfully" in {
213+
val projectId = 1
214+
val completeRequest = FakeRequest(PATCH, s"/api/projects/$projectId/complete")
215+
.withCookies(Cookie(cookieName, fakeToken))
216+
status(route(app, completeRequest).get) mustBe OK
217+
218+
val request = FakeRequest(PATCH, s"/api/projects/$projectId/delete")
219+
.withCookies(Cookie(cookieName, fakeToken))
220+
val result = route(app, request).get
221+
222+
status(result) mustBe OK
223+
(contentAsJson(result) \ "message").as[String] mustBe "Project deleted successfully"
224+
}
177225
}
178226
}

backend/test/controllers/TaskControllerSpec.scala

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package controllers
22

3-
import dto.request.column.CreateColumnRequest
4-
import dto.request.task.{AssignMemberRequest, CreateTaskRequest, UpdateTaskRequest}
5-
import dto.request.task.{CreateTaskRequest, UpdateTaskRequest}
3+
import dto.request.task.{
4+
AssignMemberRequest,
5+
CreateTaskRequest,
6+
UpdateTaskRequest
7+
}
68
import dto.response.task.{TaskSearchResponse, TaskSummaryResponse}
79
import exception.AppException
810
import org.scalatest.BeforeAndAfterAll
@@ -18,7 +20,7 @@ import play.api.{Application, Configuration}
1820
import services._
1921

2022
class TaskControllerSpec
21-
extends PlaySpec
23+
extends PlaySpec
2224
with GuiceOneAppPerSuite
2325
with Injecting
2426
with ScalaFutures
@@ -86,6 +88,21 @@ class TaskControllerSpec
8688
)
8789
}
8890

91+
"fail when creating task with unexisting column id" in {
92+
val body = Json.toJson(CreateTaskRequest("Task 1", 1))
93+
val request = FakeRequest(POST, "/api/columns/0/tasks")
94+
.withCookies(Cookie(cookieName, fakeToken))
95+
.withBody(body)
96+
97+
val ex = intercept[AppException] {
98+
await(route(app, request).get)
99+
}
100+
ex.statusCode mustBe NOT_FOUND
101+
ex.message must include(
102+
"Column with ID 0 does not exist or is not active"
103+
)
104+
}
105+
89106
"assign member into a task successfully" in {
90107
val body = Json.toJson(AssignMemberRequest(1))
91108
val request = FakeRequest(POST, "/api/projects/1/tasks/1/members")
@@ -100,6 +117,20 @@ class TaskControllerSpec
100117
)
101118
}
102119

120+
"fail when assign member with unexist task id" in {
121+
val body = Json.toJson(AssignMemberRequest(1))
122+
val request = FakeRequest(POST, "/api/projects/1/tasks/0/members")
123+
.withCookies(Cookie(cookieName, fakeToken))
124+
.withBody(body)
125+
126+
val ex = intercept[AppException] {
127+
await(route(app, request).get)
128+
}
129+
130+
ex.statusCode mustBe NOT_FOUND
131+
ex.message must include("Task with ID 0 does not exist")
132+
}
133+
103134
"fail when creating task with duplicate position in same column" in {
104135
val body = Json.toJson(CreateTaskRequest("Task 1", 1))
105136
val request = FakeRequest(POST, "/api/columns/1/tasks")
@@ -117,7 +148,9 @@ class TaskControllerSpec
117148

118149
"update task successfully" in {
119150
val body =
120-
Json.toJson(UpdateTaskRequest("Updated Task", None, None, None, None, None))
151+
Json.toJson(
152+
UpdateTaskRequest("Updated Task", None, None, None, None, None)
153+
)
121154
val request = FakeRequest(PATCH, "/api/tasks/1")
122155
.withCookies(Cookie(cookieName, fakeToken))
123156
.withBody(body)
@@ -130,10 +163,30 @@ class TaskControllerSpec
130163
.as[String] mustBe "Task updated successfully"
131164
}
132165

166+
"fail when updating task with unexist task id" in {
167+
val body =
168+
Json.toJson(
169+
UpdateTaskRequest("Updated Task", None, None, None, None, None)
170+
)
171+
val request = FakeRequest(PATCH, "/api/tasks/0")
172+
.withCookies(Cookie(cookieName, fakeToken))
173+
.withBody(body)
174+
.withHeaders(CONTENT_TYPE -> "application/json")
175+
176+
val ex = intercept[AppException] {
177+
await(route(app, request).get)
178+
}
179+
180+
ex.statusCode mustBe NOT_FOUND
181+
ex.message must include("Task with ID 0 does not exist")
182+
}
183+
133184
"fail to update non-existent task" in {
134185
val nonExistentTaskId = 9999
135186
val body =
136-
Json.toJson(UpdateTaskRequest("Some Task", None, None, None, None, None))
187+
Json.toJson(
188+
UpdateTaskRequest("Some Task", None, None, None, None, None)
189+
)
137190
val request = FakeRequest(PATCH, s"/api/tasks/$nonExistentTaskId")
138191
.withCookies(Cookie(cookieName, fakeToken))
139192
.withBody(body)
@@ -197,11 +250,7 @@ class TaskControllerSpec
197250

198251
// Create and archive a task in the new column
199252
val taskId = await(
200-
taskService.createNewTask(
201-
CreateTaskRequest("Task to Archive", 1),
202-
1,
203-
1
204-
)
253+
taskService.createNewTask(CreateTaskRequest("Task to Archive", 1), 1, 1)
205254
)
206255
await(taskService.archiveTask(taskId, 1))
207256

@@ -216,16 +265,24 @@ class TaskControllerSpec
216265
tasks.exists(task => task.id == taskId && task.name == "Task to Archive") mustBe true
217266
}
218267

268+
"fail when get archived tasks with unexist project id" in {
269+
val request = FakeRequest(GET, "/api/projects/0/columns/tasks/archived")
270+
.withCookies(Cookie(cookieName, fakeToken))
271+
val result = route(app, request).get
272+
273+
val ex = intercept[AppException] {
274+
await(result)
275+
}
276+
ex.statusCode mustBe NOT_FOUND
277+
ex.message must include("Project not found")
278+
}
279+
219280
"get active tasks successfully" in {
220281
val taskService = inject[TaskService]
221282

222283
// Create a new task in the existing column
223284
val taskId = await(
224-
taskService.createNewTask(
225-
CreateTaskRequest("Active Task", 1),
226-
1,
227-
1
228-
)
285+
taskService.createNewTask(CreateTaskRequest("Active Task", 1), 1, 1)
229286
)
230287

231288
val request = FakeRequest(GET, "/api/projects/1/columns/tasks/active")
@@ -239,16 +296,24 @@ class TaskControllerSpec
239296
tasks.exists(task => task.id == taskId && task.name == "Active Task") mustBe true
240297
}
241298

299+
"fail get active tasks with unexist project id" in {
300+
val request = FakeRequest(GET, "/api/projects/0/columns/tasks/active")
301+
.withCookies(Cookie(cookieName, fakeToken))
302+
val result = route(app, request).get
303+
304+
val ex = intercept[AppException] {
305+
await(result)
306+
}
307+
ex.statusCode mustBe NOT_FOUND
308+
ex.message must include("Project not found")
309+
}
310+
242311
"search tasks successfully" in {
243312
val taskService = inject[TaskService]
244313

245314
// Create a new task in the existing column
246315
val taskId = await(
247-
taskService.createNewTask(
248-
CreateTaskRequest("search Task", 1502),
249-
1,
250-
1
251-
)
316+
taskService.createNewTask(CreateTaskRequest("search Task", 1502), 1, 1)
252317
)
253318

254319
val request = FakeRequest(GET, "/api/tasks?page=1&size=10&keyword=search")

0 commit comments

Comments
 (0)