Trulit Logo

QA Automation Tutorial: Build Your First Test Suite from Scratch [2026]

This tutorial walks through building an automated test suite from scratch using Playwright, the most widely recommended test automation framework for new projects in 2026.

·May 30, 2026·4 min read
QA Automation Tutorial: Build Your First Test Suite from Scratch [2026]
In this article

This tutorial walks through building an automated test suite from scratch using Playwright, the most widely recommended test automation framework for new projects in 2026. By the end, you will have a working test suite with automated test cases, a GitHub Actions CI configuration, and results imported into Trulit.

Prerequisites: Node.js 18 or later installed. Basic familiarity with the terminal and a text editor.

Step 1: Set Up Playwright

Open your terminal and navigate to your project directory. Run:

npm init playwright@latest
Where to put your end-to-end tests: e2e (recommended)
Add a GitHub Actions workflow: Yes
Install Playwright browsers: Yes
After installation, your project will have a playwright.config.ts file and an e2e directory with an example test. Run the example to confirm setup:
npx playwright test
You should see 1 passed (2.1s). Playwright is ready.

Step 2: Understand the Test File Structure

Open e2e/example.spec.ts:

import { test, expect } from '@playwright/test';
test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await expect(page).toHaveTitle(/Playwright/);

});

This is the basic structure of every Playwright test. test defines a test case with a name and an async function. page is the browser page object. await page.goto(...) navigates to a URL. await expect(...) asserts the result.

Step 3: Write Your First Automated Test Cases

Create e2e/login.spec.ts. We will write tests for three scenarios: successful login, wrong password and empty email.

Important , naming convention: Trulit links each result to a managed test case by test-name prefix TC-<AREA>-<NNN>. Keep that prefix at the start of every test('...') title.

import { test, expect } from '@playwright/test';
const BASE_URL = 'https://app.trulit.com';
const VALID_EMAIL = 'testuser@trulit.com';
const VALID_PASSWORD = 'TestPass123!';
const WRONG_PASSWORD = 'WrongPass999';
test.describe('Login', () => {
  test('TC-LOGIN-001 successful login with valid credentials', async ({ page }) => {
    await page.goto${BASE_URL}/login);
    await page.getByLabel('Email').fill(VALID_EMAIL);
    await page.getByLabel('Password').fill(VALID_PASSWORD);
    await page.getByRole('button', { name: 'Log In' }).click();
    await expect(page).toHaveURL${BASE_URL}/dashboard);
    await expect(page.getByText('Welcome, Test User')).toBeVisible();
  });
  test('TC-LOGIN-002 login fails with wrong password', async ({ page }) => {
    await page.goto${BASE_URL}/login);
    await page.getByLabel('Email').fill(VALID_EMAIL);
    await page.getByLabel('Password').fill(WRONG_PASSWORD);
    await page.getByRole('button', { name: 'Log In' }).click();
    await expect(page.getByText('Incorrect email or password')).toBeVisible();
    await expect(page).toHaveURL${BASE_URL}/login);
  });
  test('TC-LOGIN-003 login fails with empty email field', async ({ page }) => {
    await page.goto${BASE_URL}/login);
    await page.getByLabel('Password').fill(VALID_PASSWORD);
    await page.getByRole('button', { name: 'Log In' }).click();
    await expect(page.getByText('Email is required')).toBeVisible();
  });
});

Replace the URL and selectors with your actual application's values.

Step 4: Run Your Tests Locally

npx playwright test e2e/login.spec.ts

If a test fails, Playwright shows the exact step that failed, the actual vs. expected result, plus a screenshot and video if configured. To watch the browser:

npx playwright test --headed

Step 5: Configure CI/CD with GitHub Actions

The Playwright setup created .github/workflows/playwright.yml. Confirm it runs on push to main and on pull requests. The default runs across Chromium, Firefox, and WebKit , consider limiting to Chromium only for initial setup, then expanding once the suite is stable.

Commit your test file and push to GitHub. Your Playwright tests will run automatically on the next push or pull request.

Step 6: Send Results to Trulit

Trulit ingests CI results via a simple HTTPS endpoint. There is no custom GitHub Action , any CI that can run curl works (GitHub Actions, GitLab CI, Jenkins, CircleCI, Azure Pipelines, Bitbucket).

6.1 Generate an ingest API key

  1. In Trulit: Project → Settings → Integrations → CI/CD ingest.

  2. Click Generate API key, copy the tru_live_... token (shown only once).

  3. In your GitHub repo: Settings → Secrets and variables → Actions → New repository secret, save it as TRULIT_API_KEY.

The same screen displays your ingest endpoint URL , copy it from there, since it differs per environment.

6.2 Add the JUnit reporter

// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
  reporter: [
    ['html'],
    ['junit', { outputFile: 'results.xml' }],
  ],
});

6.3 Upload results from GitHub Actions

Add this step after your test run:

- name: Upload results to Trulit
  if: always()
  run: |
    curl -X POST "https://<your-trulit-ingest-url>/ingest" \
-H "Authorization: Bearer ${{ secrets.TRULIT_API_KEY }}" \
      -F "metadata={\"format\":\"junit\",\"commit_sha\":\"${{ github.sha }}\",\"branch\":\"${{ github.ref_name }}\",\"build_url\":\"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"};type=application/json" \
-F "results=@results.xml"

Supported formats: junit, testng, cucumber. Mapping to managed test cases happens by test-name prefix (TC-XXX-NNN) , there is no suite-id parameter. Unmatched results are still ingested but won't update any managed test case's status.

Step 7: Review Results in Trulit

Log into Trulit and open your project's Test Runs. You will see the run from CI with commit SHA, branch, and a link back to the GitHub Actions build. Each TC-LOGIN-NNN result updates its matching test case's last-run status (Passed / Failed / Skipped), with the execution timestamp and browser.

Over the next several CI runs, Trulit builds trend data: pass rate over time, most frequently failing test cases, and execution-time trends as your suite grows.

What's Next?

  • Add more test cases for checkout, user profile, and settings flows

  • Use Trulit's AI generator to draft test case steps for new features, then implement them in Playwright

  • Add network interception to mock API responses for offline testing

  • Run Playwright tests in parallel across multiple CI workers for faster feedback

  • Enable Trulit's JIRA integration so failed tests automatically create defects

Internal links: /test-automation-platform | /qa-automation-tools | /blog/test-automation-frameworks

Sources: Playwright documentation (playwright.dev), GitHub Actions documentation (docs.github.com/actions)

Try Trulit

Ship better software, faster.

AI-native test management built for modern QA teams. Start free , no credit card needed.