Project Challenge: Solution
Let's look at the solution to the challenge given in the previous lesson.
We'll cover the following...
Solution
Here is the complete implementation of the challenge. Check it out!
<?php use PHPUnit\Framework\TestCase; use Symfony\Component\DomCrawler\Crawler; use Symfony\Component\Panther\PantherTestCaseTrait; use Symfony\Component\BrowserKit\HttpBrowser; final class TasksTest extends TestCase { use PantherTestCaseTrait; private HttpBrowser $client; // Helper function to check if current user has a task private function currentUserHasTask(string $task): bool { // Make a request for the /list-tasks page $response = $this->client->request('GET', '/list-tasks'); // Check if there is a task return strpos($response->filter('ul.tasks')->text(), $task) !== false; } protected function setUp(): void { $tasksJsonFile = __DIR__ . '/../data/tasks.json'; if (is_file($tasksJsonFile)) { unlink($tasksJsonFile); } $this->client = self::createHttpBrowserClient( [ 'webServerDir' => __DIR__ . '/../public/' ] ); } protected function tearDown(): void { $this->client->request('GET', '/logout'); } /** * @test * @dataProvider securePaths */ public function you_need_to_be_logged_in(string $path): void { // Fetching URLs $response = $this->client->request('GET', self::$baseUri . $path); // Check if redirected to /login page self::assertStringContainsString('/login', $response->getUri(), 'Expected to be redirected to the login page'); } public function securePaths(): Generator { yield ['/list-tasks']; yield ['/create-task']; } /** * @test */ public function after_logging_in_you_have_access_to_the_list_of_tasks(): void { // Login $this->login(); // Redirecting to /list-tasks page $response = $this->client->request('GET', self::$baseUri . '/list-tasks'); // Check if the page consists the right string self::assertStringContainsString('Tasks', $response->text()); } /** * @test */ public function you_can_create_a_task(): void { // Login $this->login(); // Create a task $task = 'Build some Lego'; $this->createTask($task); // Check if the task has been created self::assertTrue($this->currentUserHasTask($task)); } /** * @test */ public function you_can_edit_a_task(): void { // Login $this->login(); // Create a Task $task = 'Build some Lego'; $this->createTask($task); // Clicking edit button $response = $this->client->clickLink('Edit'); // Check if the obtained task is equal to expected task self::assertEquals($task, $response->filter('input#task')->attr('value')); // Edit task $newTask = 'Buy some Lego'; $this->client->submitForm( 'Create', [ 'task' => $newTask ] ); // Check if the task has been edited self::assertTrue($this->currentUserHasTask($newTask)); } /** * @test */ public function you_can_not_provide_an_empty_string_as_a_task(): void { // Login $this->login(); // Create an empty string as a task $response = $this->createTask(''); // Check if the right error message shows up self::assertStringContainsString( 'Task can not be empty', $response->filter('strong')->text() ); } /** * @test */ public function you_can_not_see_other_tasks_of_other_users(): void { // Login as matthias $this->loginAs('matthias'); // Create a task $task = 'Build some Lego'; $this->createTask($task); // Login as tomas $this->loginAs('tomas'); // Check if tomas can not see the task created by matthias self::assertFalse($this->currentUserHasTask($task)); } /** * @test */ public function you_can_not_edit_the_task_of_another_user(): void { // Login as matthias $this->loginAs('matthias'); // Create a task $task = 'Build some Lego'; $this->createTask($task); // Login as tomas $this->loginAs('tomas'); // Task 1 will be owned by matthias, but tomas is the logged in user $response = $this->client->request('GET', self::$baseUri . '/edit-task?id=1'); // Check if the right error is generated self::assertStringContainsString('You can not edit a task created by another user', $response->text()); } /** * @test */ public function you_can_mark_a_task_as_done_and_it_disappears_from_the_list(): void { // Log in as matthias $this->loginAs('matthias'); // Create a task $task = 'Build some Lego'; $this->createTask($task); // Click Done $this->client->submitForm('Done'); // Check if the user has no task self::assertFalse($this->currentUserHasTask($task)); } /** * @test */ public function you_can_not_mark_the_task_of_another_user_as_done(): void { // Log in as matthias $this->loginAs('matthias'); // Create a task $task = 'Build some Lego'; $this->createTask($task); // Log in as tomas $this->loginAs('tomas'); // Task 1 will be owned by matthias, but tomas is the logged in user $response = $this->client->request('POST', self::$baseUri . '/mark-as-done', ['id' => '1']); // Check if the right error message is generated self::assertStringContainsString('You can not mark a task created by another user as done', $response->text()); // Log in as matthias $this->loginAs('matthias'); // Check if the task is still there self::assertTrue($this->currentUserHasTask($task)); } // Helper functions to log in private function login(): void { $this->loginAs('matthias'); } private function loginAs(string $username): void { $this->client->request('GET', self::$baseUri . '/login'); $this->client->submitForm( 'Submit', [ 'username' => $username, 'password' => 'test' ] ); } // Helper function to create task private function createTask(string $task): Crawler { $this->client->request('GET', self::$baseUri . '/create-task'); return $this->client->submitForm( 'Create', [ 'task' => $task ] ); } }
Explanation
Let’s have a look at the solution in detail.
tests/TasksTest.php
file
Tests 1 & 2: You need to be logged in.
- At line 49, we made requests for the
/list-task
and/create-task
pages. - At line 51, we asserted if the unauthenticated user is redirected to the
/login
page.
Test 3: You get redirected to the list of tasks after logging in.
- At line 66, we called the login function.
- At line 68, we request the
/list-tasks
page. - At line 70, we