1. Home
  2. Blog
  3. Test Automation
Test Automation

Test Automation Framework Example: Build a Scalable Suite

Theory is easy. Seeing a real structure is better. Follow this test automation framework example and copy the parts that fit your project.

By Stack QuoraUpdated Oct 29, 20269 min read
Test automation framework example with a scalable folder structure
Key takeaways
  • Separate tests, page objects, data and config.
  • Put each locator in one place only.
  • Use fixtures to set up and clean data.
  • Run the suite in CI and keep reports for failures.

Many teams start with a few tests in one file. It works for a week. Then the suite grows, locators repeat and one small UI change breaks twenty tests.

A good framework prevents that. Below is a simple, honest example using Playwright and TypeScript. The ideas work with any tool, so you can adapt them to Selenium, Cypress or another stack.

What we are building

We will automate a small online shop. The suite checks login, search and add to cart. We want it to be easy to read, quick to run and simple to extend when new pages appear.

Step 1: Set up the folder layout

A clear layout is half the battle. Here is a structure that works well for small and medium projects:

shop-tests/
├─ tests/
│  ├─ auth/login.spec.ts
│  ├─ cart/add-to-cart.spec.ts
│  └─ search/search.spec.ts
├─ pages/
│  ├─ LoginPage.ts
│  ├─ ProductPage.ts
│  └─ CartPage.ts
├─ fixtures/
│  └─ test-fixtures.ts
├─ data/
│  └─ users.json
├─ utils/
│  └─ api-helpers.ts
├─ playwright.config.ts
└─ .env.example
  • tests/ holds the test files, grouped by feature.
  • pages/ holds page objects with locators and actions.
  • fixtures/ holds shared setup, such as a logged-in user.
  • data/ holds test data, never hard-coded in tests.
  • utils/ holds small helpers, such as calling the API to create data.

Step 2: Keep config and data outside the tests

Put the base URL, timeouts and browser list in one config file. Keep secrets in environment variables.

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  retries: process.env.CI ? 1 : 0,
  reporter: [['html'], ['list']],
  use: {
    baseURL: process.env.BASE_URL || 'https://staging.shop.example.com',
    trace: 'retain-on-failure',
    screenshot: 'only-on-failure',
  },
});

Store test users in a JSON file so you can change them without touching test code:

// data/users.json
{
  "standard": { "email": "buyer@example.com", "password": "from-env" }
}

Step 3: Build page objects

A page object wraps one page. It keeps locators and actions in one spot. When the UI changes, you edit one file.

// pages/LoginPage.ts
import { Page, expect } from '@playwright/test';

export class LoginPage {
  constructor(private page: Page) {}

  async open() {
    await this.page.goto('/login');
  }

  async login(email: string, password: string) {
    await this.page.getByLabel('Email').fill(email);
    await this.page.getByLabel('Password').fill(password);
    await this.page.getByRole('button', { name: 'Sign in' }).click();
  }

  async expectLoggedIn() {
    await expect(this.page.getByText('My account')).toBeVisible();
  }
}

Rule of thumb: Page objects hold actions and locators. Tests hold the checks that explain the business rule.

Step 4: Share setup with fixtures

Fixtures give every test the objects it needs, already set up. This removes copy and paste.

// fixtures/test-fixtures.ts
import { test as base } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
import { CartPage } from '../pages/CartPage';

type Pages = { loginPage: LoginPage; cartPage: CartPage };

export const test = base.extend<Pages>({
  loginPage: async ({ page }, use) => { await use(new LoginPage(page)); },
  cartPage: async ({ page }, use) => { await use(new CartPage(page)); },
});

export { expect } from '@playwright/test';

Step 5: Write short, clear tests

// tests/cart/add-to-cart.spec.ts
import { test, expect } from '../../fixtures/test-fixtures';

test('shopper can add a product to the cart', async ({ page, cartPage }) => {
  await page.goto('/products/running-shoes');
  await page.getByRole('button', { name: 'Add to cart' }).click();

  await cartPage.open();
  await expect(cartPage.itemNames()).toContainText(['Running shoes']);
});

The test reads like a sentence. A new teammate can understand it in seconds. For more rules on stable tests, read our guide to end to end testing best practices.

Step 6: Add useful reports

A failing test should tell you why. Turn on screenshots, video or traces for failures only, so you keep storage small. The built-in HTML report from Playwright is a good start. Later, you can send results to a dashboard or chat channel.

Step 7: Run it in CI

Here is a simple GitHub Actions job that installs dependencies, runs the suite and saves the report:

name: e2e
on: [pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

New to pipelines? Our GitHub Actions guide explains each part.

How to keep the framework scalable

  • One locator, one home. Never repeat a locator across tests.
  • Small tests. One test, one behaviour.
  • Independent tests. Create the data you need through the API, then clean it up.
  • Tag your tests. Use tags like @smoke to run a fast subset on every pull request.
  • Review often. Remove dead tests and fix flaky ones each sprint.

Still choosing a tool? See how to pick the best test automation framework first.

Frequently asked questions

What is a good test automation framework structure?

Separate your tests, page objects, fixtures, data and config into their own folders. This keeps each file small and easy to find.

Do I need the page object model?

It is not required, but it helps a lot once you have more than a handful of tests. It removes repeated locators and makes updates simple.

Can I use this layout with Selenium or Cypress?

Yes. The folders and ideas stay the same. Only the syntax inside the files changes.

How many tests should run on each pull request?

Run a small smoke set on every pull request and the full suite on merges or at night. That balances speed and safety.

Keep learning

Work with Stack Quora

Need help with testing, WordPress or SEO?

We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.

Keep reading

More guides on testing, AI & modern development

Enjoyed this article? Pick a topic and jump straight into our newest tutorials.

Artificial Intelligence

Best AI Code Review Tools for Developers in 2026

Compare the best AI code review tools in 2026: CodeRabbit, GitHub Copilot, Qodo, Greptile and more. See what each does,…

Read article →
Software Development

What Is an API? A Simple Guide for Beginners

What is an API? Learn in plain English how APIs work, the main types, HTTP methods and status codes, with…

Read article →
Test Automation

Playwright Locators Cheat Sheet With Examples

A practical Playwright locators cheat sheet: getByRole, getByText, getByLabel, test IDs, CSS, filtering and chaining, with copy-paste examples for stable…

Read article →
Software Testing

How to Write Test Cases: Format, Examples and Best Practices

Learn how to write test cases with a clear format, login and checkout examples, a reusable template and best practices…

Read article →
Artificial Intelligence

Gemini 4 Argon: What’s New and How It Compares to Earlier Gemini Models

Gemini 4 Argon is Google's new flagship reasoning model. See its API limits, app features, coding focus and how to…

Read article →
Databases & SQL

SQL Joins Explained With Examples (Inner, Left, Right, Full)

SQL joins explained step by step with sample tables and queries: INNER, LEFT, RIGHT, FULL, CROSS and SELF joins, plus…

Read article →
Software Development

Python Virtual Environment Tutorial: venv, pip and uv

Learn how to create, activate and manage a Python virtual environment with venv, pip and uv, including requirements files, .gitignore…

Read article →
Test Automation

Playwright vs Cypress in 2026: Which Should You Pick?

Playwright vs Cypress compared for 2026: browsers, languages, speed, debugging, parallel runs, CI and cost. Find out which end-to-end testing…

Read article →
Software Testing

Smoke Testing vs Sanity Testing: Differences With Real Examples

Smoke testing checks that a build is stable enough to test. Sanity testing checks that a specific fix works. Learn…

Read article →
Artificial Intelligence

Claude Haiku 5.5: Features, Pricing and Use Cases for Developers

Claude Haiku 5.5 is Anthropic's fastest and lowest-priced model. See its 1M-token context, pricing, API changes and the best use…

Read article →
Software Testing

End to End Testing Best Practices: Boost Reliability in 2026

Flaky tests waste time and hide real bugs. Learn end to end testing best practices that make your tests stable,…

Read article →
Test Automation

Best Test Automation Framework 2026: Choose the Right One

Not sure which test automation framework to pick? Compare the main types, use a simple checklist, and see how Playwright,…

Read article →
Artificial Intelligence

AI Agents Best Practices: Deploy Reliable Intelligent Bots

AI agents can save hours of work, but only when they are built with care. Learn AI agents best practices…

Read article →
Test Automation

Test Automation Framework Example: Build a Scalable Suite

See a real test automation framework example with folder layout, page objects, test data and CI steps. Copy the structure…

Read article →
Software Testing

Best Test Automation Tools 2026: Top Picks for QA Teams

Compare the best test automation tools in 2026 for web, mobile and API testing. See what each tool does well,…

Read article →
Software Development

REST API Best Practices 2026: Build Scalable Services

Learn REST API best practices for 2026: clear URLs, correct status codes, versioning, pagination, security and error handling, with simple…

Read article →
Artificial Intelligence

MCP Stateless Architecture: What’s New in MCP 2026

The MCP 2026-07-28 spec removes sessions and the handshake. See how stateless MCP works, what breaks, what gets easier to…

Read article →
Artificial Intelligence

Agentic Resource Discovery (ARD): How AI Agents Find Tools

Agentic Resource Discovery (ARD) lets AI agents find and verify tools, agents and skills across the web. Learn how ai-catalog.json…

Read article →
Artificial Intelligence

WebMCP Explained: How AI Agents Will Interact With Websites

WebMCP lets a website publish tools that AI agents can call directly. Learn the Declarative and Imperative APIs, code examples,…

Read article →
Databases & SQL

SQL Tutorial for Beginners: Complete Guide to SQL in 2026

Learn SQL from scratch. Create tables, insert and query data, filter, sort, group, join tables and use subqueries and indexes,…

Read article →
Software Development

TypeScript Tutorial for Beginners: Complete Guide to TypeScript in 2026

Learn TypeScript from scratch. Understand types, interfaces, unions, generics and classes, set up a project, and see how TypeScript catches…

Read article →
Software Development

Git Tutorial for Beginners: Complete Guide to Git and GitHub in 2026

Learn Git from zero. Create repositories, commit, branch, merge, fix mistakes and work with GitHub pull requests, using simple commands…

Read article →
DevOps

Docker Tutorial for Beginners: Complete Guide to Docker in 2026

New to Docker? Learn containers, images, Dockerfiles, volumes, networks and Docker Compose with simple commands and a small project you…

Read article →
Databases & SQL

Vector Databases Explained: How Vector Search and AI Databases Work in 2026

Vector databases search by meaning, not just keywords. Learn embeddings, similarity search, HNSW indexes, pgvector and how to choose the…

Read article →
Software Testing

API Testing with Postman: A Complete Guide for Beginners and QA Testers

Learn API testing with Postman from scratch. Send requests, read status codes, add auth, write test scripts, build collections and…

Read article →
DevOps

GitHub Actions CI/CD: A Complete Guide to Automating Software Builds, Tests and Deployments

Learn GitHub Actions from scratch. Build a CI/CD workflow that runs tests, builds your app and deploys it, with simple…

Read article →
Test Automation

Playwright MCP: The Complete Guide to AI-Powered Test Automation

Playwright MCP lets an AI assistant control a real browser. Learn how it works, how to set it up, what…

Read article →