Testing "Complete Task" Feature
Become more familiar with Jest and Selenium and further develop our app in the following two lessons.
We'll cover the following
The task at hand
Now that you have the defining idea behind testing, we will further develop your experience by writing more tests and features.
As we are developing a TODO app, it would be a good idea to be able to complete tasks. Here is how a potential user story might look:
A user must be able to mark any task as completed by clicking on it. He can also mark any completed task as incomplete by clicking on it. Completed tasks must have a
completed
CSS class.
Integration test
As always, the first step to implementing a user story would be to write the integration test. In this test, we are looking to create a few tasks. Try to complete one of them (and verify that it completes), and then uncomplete it. Firstly, create the file complete-task.test.js
under /integration-tests
. Copy over the imports and beforeAll
/afterAll
functions from create-task.test.js
. After you have done that, we will write a new helper function called createTask
:
const createTask = async (taskName) => {
await driver.wait(until.elementLocated(By.xpath("//input[@placeholder='Enter new task']")), 1000);
const input = await driver.findElement(By.xpath("//input[@placeholder='Enter new task']"));
await input.clear();
await input.sendKeys(taskName + Key.ENTER);
await driver.wait(until.elementLocated(By.xpath(`//*[text()='${taskName}']`)), 1000);
};
We do not want to clutter the test code with unrelated code, so we moved the task creation code outside. Time to write the actual test:
test('should complete tasks', async () => {
// Creating tasks
await driver.get('http://localhost:3000');
await createTask('Task 1');
await createTask('Task 2');
await createTask('Task 3');
// Complete task
const task = await driver.findElement(By.xpath("//*[text()='Task 2']"));
await task.click();
// Check that it completed
expect(await task.getAttribute('class')).toMatch(/completed/);
// Uncomplete task
await task.click();
// Check that it uncompleted
expect(await task.getAttribute('class')).not.toMatch(/completed/);
});
This code should be pretty straightforward. First, we create three tasks using the function we wrote earlier. Then, we click on Task 2
, and check if it gets a completed
class. Lastly, we click one more time, and verify that the completed
class is removed.
Battling ambiguity
You might have noticed that our definition of a task being completed relies completely on a CSS class. In reality, this may not be the case. The specifications may say that a completed task must be at the bottom of a list or have a checked checkbox or have a disabled
attribute. To make sure all teams are on the same page, the user story must specify what it means for a task to be completed as it did in our case. Otherwise, come up with a criterion yourself and stick with it until someone comes up with a better one.
Error
If you try to run this test as is, it will fail. This is expected, as we did not write the implementation yet. This is the error you should be getting:
FAIL integration-tests/complete-task.test.js (6.28s)
● should complete tasks
expect(received).toMatch(expected)
Expected pattern: /completed/
Received string: ""
32 | await task.click();
33 | // Check that it completed
> 34 | expect(await task.getAttribute('class')).toMatch(/completed/);
| ^
35 | });
36 |
The error is the tasks are not being disabled, as far as Selenium is concerned. We will address this in the next lesson. Here is the whole project up until now for reference:
Get hands-on with 1400+ tech skills courses.