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-taskand/create-taskpages. - At line 51, we asserted if the unauthenticated user is redirected to the
/loginpage.
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-taskspage. - At line 70, we
Ask