From 6e4c8f68e0749774a04711b62e5687a6b145ec4b Mon Sep 17 00:00:00 2001 From: devoalda Date: Mon, 7 Aug 2023 14:38:11 +0800 Subject: [PATCH] test(Project and Todo Tests): Created test cases for project and todo functionality + validations --- .../Controllers/ProjectTodoController.php | 32 ++- .../Requests/Project/StoreTodoRequest.php | 2 +- tests/Feature/Project/ProjectCRUDTest.php | 17 ++ tests/Feature/Project/TodoCRUDTest.php | 210 ++++++++++++++++++ 4 files changed, 241 insertions(+), 20 deletions(-) create mode 100644 tests/Feature/Project/TodoCRUDTest.php diff --git a/app/Http/Controllers/ProjectTodoController.php b/app/Http/Controllers/ProjectTodoController.php index 442214e..32bc27a 100644 --- a/app/Http/Controllers/ProjectTodoController.php +++ b/app/Http/Controllers/ProjectTodoController.php @@ -20,14 +20,16 @@ class ProjectTodoController extends Controller /** * Display a listing of all Todos for a Project. */ - public function index($project_id) + public function index($project_id): Factory|Application|View|\Illuminate\Contracts\Foundation\Application|RedirectResponse { $user = User::find(auth()->user()->id); $projects = $user->projects; $project = $projects->find($project_id); if (!$project || $project->user->id !== auth()->user()->id) - return back()->with('error', 'Project not found'); + return back() + ->with('error', 'Project not found') + ->setStatusCode(404); $todos = $project->todos; @@ -56,24 +58,14 @@ class ProjectTodoController extends Controller { $validatedData = $request->validated(); - $due_end = match (true) { - isset($validatedData['due_end']) => strtotime($validatedData['due_end']), - isset($validatedData['due_start']) => strtotime($validatedData['due_start']), - default => null, - }; - - $validatedData = array_merge($validatedData, [ - // due_end = due_start if due_end is not provided and due_start is provided or null - 'due_end' => $due_end, - 'user_id' => auth()->user()->id, - ]); - - // Modify all dates to unix timestamp - if (isset($validatedData['due_start'])) + if(isset($validatedData['due_start'])) $validatedData['due_start'] = strtotime($validatedData['due_start']); + if (isset($validatedData['due_end'])) $validatedData['due_end'] = strtotime($validatedData['due_end']); - + elseif (isset($validatedData['due_start'])) + $validatedData['due_end'] = $validatedData['due_start']; +// $todo = new Todo($validatedData); $user = User::find(auth()->user()->id); @@ -82,7 +74,8 @@ class ProjectTodoController extends Controller $project->todos()->save($todo); return redirect()->route('project.todo.index', $project_id) - ->with('success', 'Todo created successfully.'); + ->with('success', 'Todo created successfully.') + ->setStatusCode(201); } /** @@ -156,7 +149,8 @@ class ProjectTodoController extends Controller $todo->update($data); - return back()->with('success', 'Todo updated successfully'); + return back() + ->with('success', 'Todo updated successfully'); } /** diff --git a/app/Http/Requests/Project/StoreTodoRequest.php b/app/Http/Requests/Project/StoreTodoRequest.php index 879a499..539888e 100644 --- a/app/Http/Requests/Project/StoreTodoRequest.php +++ b/app/Http/Requests/Project/StoreTodoRequest.php @@ -26,7 +26,7 @@ class StoreTodoRequest extends FormRequest 'title' => 'required|string|max:255', 'description' => 'nullable|string|max:255', 'due_start' => 'nullable|date', - 'due_end' => 'nullable|date', + 'due_end' => 'nullable|date|after_or_equal:due_start', ]; } } diff --git a/tests/Feature/Project/ProjectCRUDTest.php b/tests/Feature/Project/ProjectCRUDTest.php index 5c054ac..7838eec 100644 --- a/tests/Feature/Project/ProjectCRUDTest.php +++ b/tests/Feature/Project/ProjectCRUDTest.php @@ -127,4 +127,21 @@ class ProjectCRUDTest extends TestCase $response->assertNotFound(); } + public function test_other_user_cannot_see_user_projects(): void + { + $this->test_user_can_create_project(); + // Test if the current user can see the project + $this->actingAs($this->user); + $response = $this->get(route('project.index')); + $response->assertSee('Test Project'); + $response->assertSee('Test Description'); + + // Test if another user can see the project + $this->actingAs(User::factory()->create()); + $response = $this->get(route('project.index')); + $response->assertDontSee('Test Project'); + $response->assertDontSee('Test Description'); + + } + } diff --git a/tests/Feature/Project/TodoCRUDTest.php b/tests/Feature/Project/TodoCRUDTest.php new file mode 100644 index 0000000..d19ae58 --- /dev/null +++ b/tests/Feature/Project/TodoCRUDTest.php @@ -0,0 +1,210 @@ +actingAs($user = User::factory()->create()); + $this->user = $user; + $this->assertAuthenticated(); + // Create a project through POST and store it in the project property + $response = $this->post(route('project.store'), [ + 'name' => 'Test Project', + 'description' => 'Test Description', + ]); + $response->assertRedirect(route('project.index')); + $this->assertDatabaseHas('projects', [ + 'name' => 'Test Project', + 'description' => 'Test Description', + ]); + + $this->assertDatabaseHas('project_user', [ + 'project_id' => Project::where('name', 'Test Project')->first()->id, + 'user_id' => $this->user->id, + ]); + + $this->project = Project::where('name', 'Test Project')->first(); + + } + + public function test_user_can_create_todo(): void + { + $response = $this->post(route('project.todo.store', $this->project->id), [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + ]); + $response->assertRedirect(route('project.todo.index', $this->project->id)); + + $this->todo = Todo::where('title', 'Test Todo')->first(); + + $this->assertDatabaseHas('todos', [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + ]); + + $this->assertDatabaseHas('project_todo', [ + 'project_id' => $this->project->id, + 'todo_id' => Todo::where('title', 'Test Todo')->first()->id, + ]); + } + + public function test_user_can_view_todo(): void + { + $this->test_user_can_create_todo(); + $this->assertAuthenticated(); + $response = $this->get(route('project.index')); + $response->assertSee('Test Todo'); + $response->assertSee('Test Description'); + + $response = $this->get(route('project.todo.index', $this->project->id)); + $response->assertSee('Test Todo'); + } + + public function test_user_can_update_todo(): void + { + $this->test_user_can_create_todo(); + $this->assertAuthenticated(); + $response = $this->put(route('project.todo.update', [$this->project->id, $this->todo->id]), [ + 'title' => 'Updated Todo', + 'description' => 'Updated Description', + ]); + $response->assertRedirect(back()->getTargetUrl()); + + $this->assertDatabaseHas('todos', [ + 'title' => 'Updated Todo', + 'description' => 'Updated Description', + ]); + + $this->assertDatabaseMissing('todos', [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + ]); + + $response = $this->get(route('project.todo.index', $this->project->id)); + $response->assertSee('Updated Todo'); + + } + + public function test_user_can_delete_todo(): void + { + $this->test_user_can_create_todo(); + $this->assertAuthenticated(); + $response = $this->delete(route('project.todo.destroy', [$this->project->id, $this->todo->id])); + $response->assertRedirect(route('project.todo.index', $this->project->id)); + + $this->assertDatabaseMissing('todos', [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + ]); + + $response = $this->get(route('project.todo.index', $this->project->id)); + $response->assertDontSee('Test Todo'); + } + + // Additional Create Tests + public function test_user_can_create_todo_with_due_start_only(): void + { + $this->assertAuthenticated(); + $response = $this->post(route('project.todo.store', $this->project->id), [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + 'due_start' => '2020-01-01', + ]); + $response->assertRedirect(route('project.todo.index', $this->project->id)); + + $this->assertDatabaseHas('todos', [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + 'due_start' => '1577836800', + 'due_end' => '1577836800', + ]); + + $this->assertDatabaseHas('project_todo', [ + 'project_id' => $this->project->id, + 'todo_id' => Todo::where('title', 'Test Todo')->first()->id, + ]); + } + + public function test_user_can_create_todo_with_due_end_only(): void + { + $this->assertAuthenticated(); + $response = $this->post(route('project.todo.store', $this->project->id), [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + 'due_end' => '2020-01-01', + ]); + $response->assertRedirect(route('project.todo.index', $this->project->id)); + + $this->assertDatabaseHas('todos', [ + 'title' => 'Test Todo', + 'description' => 'Test Description', + 'due_start' => null, + 'due_end' => '1577836800', + ]); + + $this->assertDatabaseHas('project_todo', [ + 'project_id' => $this->project->id, + 'todo_id' => Todo::where('title', 'Test Todo')->first()->id, + ]); + } + + // Additional Update Tests + public function test_user_can_complete_todo_only(): void + { + $this->test_user_can_create_todo(); + $this->assertAuthenticated(); + // Send a PUT request to update route, with "completed_at" set to on + $response = $this->put(route('project.todo.update', [$this->project->id, $this->todo->id]), [ + 'title' => 'Updated Todo', + 'completed_at' => 'on', + ]); + $response->assertRedirect(back()->getTargetUrl()); + + // Check that the todo is completed in database completed_at value is not null + $completedTodo = $this->user->projects()->first()->todos()->first(); + $this->assertNotNull($completedTodo->completed_at); + } + + public function test_user_can_uncomplete_todo(): void + { + $this->test_user_can_complete_todo_only(); + $this->assertAuthenticated(); + // Send a PUT request to update route with empty data + $response = $this->put(route('project.todo.update', [$this->project->id, $this->todo->id]), []); + $response->assertRedirect(back()->getTargetUrl()); + + // Check that the todo is completed in database completed_at value is not null + $uncompletedTodo = $this->user->projects()->first()->todos()->first(); + $this->assertNull($uncompletedTodo->completed_at); + } + + // Additional Retrieve Tests (Validation for unauthorized users) + public function test_other_user_cannot_see_user_todo(): void + { + $this->test_user_can_create_todo(); + $this->assertAuthenticated(); + $otherUser = User::factory()->create(); + $this->actingAs($otherUser); + $response = $this->get(route('project.todo.index', $this->project->id)); + $response->assertStatus(404); + $response->assertDontSee('Test Todo'); + } + + +}