Lesson 12 / الدرس 12
Every test on its own / كل اختبار قائم بذاته
A test that needs another test to have run first is not a test, it is step four of a procedure. Independence is what lets a suite run in any order, in parallel, and tell you the truth when one thing breaks.
الاختبار الذي يحتاج إلى إجراء اختبار آخر قبله ليس اختبارًا، بل الخطوة الرابعة من إجراء. والاستقلال هو ما يتيح للمجموعة أن تجري بأي ترتيب، وعلى التوازي، وأن تقول لك الصدق حين ينكسر شيء واحد.
It is tempting to write test 1 that registers an account, test 2 that signs in with it, and test 3 that places an order. It reads like a story and it works — once, in that order, on one machine. Then somebody runs the suite in parallel, or reruns only test 3, and the story falls apart — and the failure blames test 3 for something test 1 did not do.
What independence costs, and buys
| Dependent suite | Independent suite |
|---|---|
| Must run in one fixed order | Runs in any order, and in parallel |
| One early failure fails everything after it | One failure fails one test |
| Cannot rerun a single test | Any test can be run alone |
| Shorter to write | Each test creates what it needs |
The only column in favour of dependence is the last row, and it is a one-time saving paid back every single run thereafter.
// Dependent: test 2 only works if test 1 ran, first, on this machine.
test('registers an account', async () => { /* creates sara@example.com */ });
test('signs in', async () => { /* uses sara@example.com */ });
// Independent: each test makes its own world, with a unique email so two
// parallel runs cannot collide.
test('signs in with a valid password', async ({ page }) => {
const email = `test-${Date.now()}@example.com`;
await createAccount(email, 'Passw0rd!'); // arrange, via the API: fast
await signIn(page, email, 'Passw0rd!'); // act
await expect(page).toHaveURL(/dashboard/); // assert
});
Clean up, or make collision impossible
Two strategies, and the second is usually better. You can delete what you created at the end of each test — correct, but it does not run when the test crashes halfway. Or you can make every test's data unique, with a timestamp or a random suffix, so nothing can ever collide. Unique data survives a crashed test; cleanup does not.
Check yourself / اختبر نفسك
1. Why should each test create its own data rather than reuse a shared account?
Shared state is what forces a fixed order and blocks parallel runs. It also produces the worst failure mode there is: a red test that names the wrong feature.
2. Why is unique test data usually better than cleaning up afterwards?
Cleanup is a promise the test keeps only if it finishes. Unique data needs nothing to go right — a crashed test leaves rubbish behind, but rubbish that can never collide with the next run.
3. Setting up an account before a browser test: which door should you use?
Clicking through registration to test something else makes the test slow and gives it a second way to fail for reasons that are not what it is about. Register through the API; test the one behaviour through the browser.
Score / النتيجة: 0 / 3