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 suiteIndependent suite
Must run in one fixed orderRuns in any order, and in parallel
One early failure fails everything after itOne failure fails one test
Cannot rerun a single testAny test can be run alone
Shorter to writeEach 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
});
Note the arrangement goes through the API rather than the browser. Setting up state by clicking through the interface is slow and fragile — use the fastest door you have for setup, and the real door only for the thing under test.

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?

2. Why is unique test data usually better than cleaning up afterwards?

3. Setting up an account before a browser test: which door should you use?