Playwright: Test Structure (Tiny part that bring a huge impact)
Source: Dev.to
Introduction
Hi there 👋! This is my first post since I joined dev.to.
I’m a Junior QA Engineer who recently transitioned from Customer Support into QA. While I don’t have tons of experience yet—especially when it comes to discussing automated testing at a deep level—I’ve noticed one important thing in my day‑to‑day work:
Many QA Engineers write automated tests, but not all of them truly understand their test structure. Without a clear and well‑thought‑out test structure, automated tests can quickly become:
- Hard to maintain
- Difficult to debug when tests fail
- Risky to scale as the product grows
One simple but often overlooked improvement is how we structure our automated tests. Even though test structure sounds very basic, many QA Engineers—especially those who are new to automation or have limited hands‑on experience with real projects—may not be fully aware of its importance.
In this post I’ll share a few simple tips about managing test structure, based on what I’ve learned so far. It might be a small topic, but it has a big impact.
📂 Default Playwright Test Structure (The Starting Point)
tests/
├── example.spec.ts
├── another-test.spec.ts
playwright.config.ts
This layout works fine for demos, tutorials, or very small projects. As the test suite grows, however, the structure quickly starts to hurt you.
Common problems with the default structure
- Selectors are duplicated across test files
- Tests become long and hard to read
- UI changes require updating many test files
- Debugging failed tests takes longer
That’s why, in my project, I decided to move away from the default structure early.
🧱 Custom Test Structure Used in the Repository
Instead of placing everything directly inside *.spec.ts files, I separated concerns clearly.
High‑level structure (simplified)
tests/
├── pages/
├── fixtures/
├── utils/
├── ai/
│ └── ai-movie.spec.ts
📄 1. Page Object Model (POM)
The pages/ folder contains page classes that handle:
- selectors
- page actions (click, fill, submit, etc.)
Tests interact with the page through methods such as:
searchMovie()submitPrompt()readAIResponse()
Why this matters
- UI changes only affect page files
- Test files stay clean and readable
- Less selector duplication
Compared to the default Playwright approach, this dramatically reduces maintenance cost.
🔁 2. Fixtures for Shared Setup
The fixtures/ folder contains reusable setup logic, such as:
- navigating to the app
- preparing test state
- shared test configuration
Advantages over the default structure
- Tests focus on behavior, not setup
- Easier to standardize test flow
- Fewer copy‑paste mistakes
🧰 3. Utilities for Complex Logic
In AI‑related testing, some validations are not trivial (e.g., checking response format, validating content rules, handling async behavior consistently). Those logic pieces live in utils/.
Why this beats the default structure
- Assertions stay reusable
- Test files don’t become bloated
- Logic can be improved without touching tests
📁 4. Feature‑Based Test Grouping
Instead of random spec files, tests are grouped by feature. For example:
- AI‑related tests live in their own folder (
tests/ai/) - Future features can follow the same pattern
Compared to the default structure
- Easier navigation
- Clearer ownership
- Better scalability as features grow
🧠 Final Thoughts
Even as a junior QA Engineer, I’ve learned that good structure is a skill, not a luxury.
You don’t need
- A huge project
- Years of experience
- Perfect architecture
What you do need is the mindset that: automated tests are long‑term assets, not one‑time scripts.
By moving beyond Playwright’s default structure and organizing tests intentionally, you:
- Reduce future pain
- Improve collaboration
- Build better testing habits early
Hopefully, this post helps other junior QAs avoid the mistakes I’m still learning from 🚀
Feel free to take a look at my project here and use it as a reference.