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.
![QA Automation Tutorial: Build Your First Test Suite from Scratch [2026]](https://weifsejwancwjzlaxuzj.supabase.co/storage/v1/object/public/blog-media/covers/1780149277405-rfp5yn.webp)
In this article⌃
- Step 1: Set Up Playwright
- Step 2: Understand the Test File Structure
- Step 3: Write Your First Automated Test Cases
- Step 4: Run Your Tests Locally
- npx playwright test e2e/login.spec.ts
- Step 5: Configure CI/CD with GitHub Actions
- Step 6: Send Results to Trulit
- 6.1 Generate an ingest API key
- 6.2 Add the JUnit reporter
- 6.3 Upload results from GitHub Actions
- Step 7: Review Results in Trulit
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 --headedStep 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
In Trulit: Project → Settings → Integrations → CI/CD ingest.
Click Generate API key, copy the tru_live_... token (shown only once).
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.
