test(Project and Todo Tests):

Created test cases for project and todo functionality + validations
This commit is contained in:
devoalda 2023-08-07 14:38:11 +08:00
parent 6dbeb8e992
commit 6e4c8f68e0
4 changed files with 241 additions and 20 deletions

View File

@ -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');
}
/**

View File

@ -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',
];
}
}

View File

@ -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');
}
}

View File

@ -0,0 +1,210 @@
<?php
namespace Tests\Feature\Project;
use App\Models\Project;
use App\Models\Todo;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class TodoCRUDTest extends TestCase
{
use RefreshDatabase;
private User $user;
private Project $project;
private Todo $todo;
protected function setUp(): void
{
parent::setUp();
$this->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');
}
}