Test Isolation
Test Isolation: A Lesson I Learned While Migrating Playwright Tests During my software engineering internship, I helped optimize our CI pipeline by identifying which E2E tests could safely run in parallel. That work quickly taught me that the biggest obstacle wasn't Playwright or Python, it was test isolation. This article is about that lesson. What is test isolation? A simple rule I now use is this: if a test can't run by itself with the same outcome, it probably isn't truly isolated. A well-isolated test should produce the same result whether it: runs by itself runs first or last runs after another test runs in parallel with hundreds of other tests To understand test isolation, it also helps to understand what state means. State isn't limited to database rows. During the migration, I found tests interacting with many different kinds of state. database records global configuration filesystem resources application caches If any of these are shared between tests, they become potential sources of hidden dependencies. How tests lose isolation As I started reading the existing test suite, I noticed a recurring pattern. Many tests assumed something about the environment instead of creating it themselves. Some expected specific data to already exist. Others modified global settings without restoring them afterward. Some searched for rows based on their position in a table instead of using a stable identifier like a name or ID. None of these looked particularly problematic when reading a single test. The problems only appeared once the entire suite started running together. One test would leave behind data another test didn't expect. A shared configuration would silently affect unrelated tests. A UI assertion would suddenly fail because another test inserted an extra row into the same table. Individually, the tests appeared independent. Together, they formed hidden dependencies. Not all shared state is equally difficult to isolate One realization that helped me reason abou