Most QA engineers competing for automation roles have no public code to show, so a hiring engineer reviewing their application reads text about testing experience and makes a judgment call. A GitHub repository with a passing CI pipeline tells the same story in 30 seconds without requiring any judgment. This article covers exactly what to put in a QA portfolio: the Playwright suite structure, directory layout, README, and the one mistake that turns a portfolio into a liability.
Why a portfolio matters for QA roles
QA automation is a technical skill. Companies hiring for it want to see code, not descriptions of code.
A CV that says "5 years of experience with Playwright and TypeScript" and a portfolio that shows 5 years of experience with Playwright and TypeScript produce different results at the application screening stage.
The hiring engineer reviewing your application has 30–60 seconds before deciding to read further or move on. A link to a GitHub repository with clean, well-structured test code does more work in those 30 seconds than a paragraph of text.
The barrier is lower than it sounds. Most QA engineers don't have public portfolios. Showing up with one puts you in a different category immediately.
What to put in a QA portfolio
You don't need a massive project. You need evidence of specific competencies. Each item in your portfolio should demonstrate something concrete.
A Playwright test suite against a real application
This is the core piece. A repository with tests for a real application: not a tutorial app, not localhost, but a real publicly accessible website.
What to test: BecomeQA's lab environment at lab.becomeqa.com exists specifically for this purpose. It's a React application with login, CRUD operations, file upload, and a payment section. Write tests against it.
What the suite should include:
- Login flow (happy path + negative cases)
- CRUD operations for the main feature (add item, edit item, delete item)
- Form validation tests
- At least one API test using Playwright's request fixture
- Page Object Model structure
Minimum viable size: 15–20 tests that actually pass. Quality over quantity.
Directory structure that reflects real knowledge
``
my-playwright-tests/
├── playwright.config.ts
├── package.json
├── tests/
│ ├── auth/
│ │ ├── login.spec.ts
│ │ └── logout.spec.ts
│ └── items/
│ ├── create-item.spec.ts
│ ├── edit-item.spec.ts
│ └── delete-item.spec.ts
├── pages/
│ ├── BasePage.ts
│ ├── LoginPage.ts
│ └── ItemsPage.ts
└── utils/
└── testHelpers.ts
`
This structure shows you understand Page Object Model, test organization, and separating test logic from page logic. A flat directory with 20
.spec.ts files in the root shows you don't.
A README that explains what you built
Write a README that covers:
1. What the test suite does (what application, what scenarios)
2. How to run it (
npm install && npx playwright test)
3. What technologies are used (Playwright, TypeScript, POM pattern)
4. What you would add next (shows you can think about scope and priorities)
Keep it short, 200–400 words. The README is read by hiring engineers deciding whether to look at the code.
What makes portfolio code stand out
The difference between portfolio code that impresses and code that's forgettable:
Uses semantic locators. Tests using page.getByRole('button', { name: 'Submit' }) and page.getByLabel('Email') show understanding of accessibility and locator best practices. Tests using page.locator('div.modal-body > form > button:nth-child(2)') show the opposite.
Has meaningful assertions. Not just "page exists" but specific verifiable outcomes:
`typescript
// Weak
await expect(page).toHaveURL('/dashboard');
// Strong
await expect(page.getByRole('heading', { name: 'My Travel Items' })).toBeVisible();
await expect(page.getByRole('navigation')).toContainText('admin@becomeqa.com');
`
No waitForTimeout calls. Every await page.waitForTimeout(2000) in your portfolio is a flag that you don't understand auto-waiting. Replace them with web-first assertions.
Consistent naming. Test names describe the scenario: 'user can log in with valid credentials', not 'login test'. File names describe the feature: login.spec.ts, not test1.spec.ts.
TypeScript with types used correctly. If you claim TypeScript experience, your code should use types: typed page objects, typed helpers, not any everywhere.
Setting up the portfolio repository
`bash
# Initialize a new project
mkdir my-playwright-portfolio
cd my-playwright-portfolio
npm init playwright@latest
# Choose TypeScript when prompted
# Select tests/ as the test directory
# Yes to GitHub Actions workflow
`
This gives you a working Playwright setup with TypeScript and a GitHub Actions workflow file that runs your tests in CI.
Add the tests
`typescript
// tests/auth/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../../pages/LoginPage';
test.describe('Login', () => {
test('user can log in with valid credentials', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login('admin@becomeqa.com', 'testpass123');
await expect(page.getByRole('heading', { name: 'My Travel Items' })).toBeVisible();
});
test('shows error with incorrect password', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login('admin@becomeqa.com', 'wrongpassword');
await expect(page.getByText('Invalid credentials')).toBeVisible();
await expect(page).not.toHaveURL('/dashboard');
});
});
`
Push to GitHub with CI passing
The GitHub Actions workflow that
npm init playwright@latest creates will run your tests automatically on every push. Having a passing CI pipeline is more impressive than having tests that "work on my machine."
Check your Actions tab after pushing. If the tests pass: your portfolio now shows a live CI pipeline running Playwright tests. This is better than anything you can write on a CV.
If they fail: fix them before sharing the link.
What else to include
Sample bug reports
A collection of 3–5 well-written bug reports. They don't need to be from a company. They can be bugs you find on any public application, including
lab.becomeqa.com.
Format them exactly like the The Anatomy of a Bug Report That Developers Actually Fix template: title, environment, preconditions, steps, expected, actual, severity, attachments.
Put them in a
/bug-reports folder as markdown files. This demonstrates written communication and bug reporting skills that automated tests don't show.
Test plan or test case document
A short document showing how you'd approach testing a feature from scratch. Pick a specific feature (the file upload on lab.becomeqa.com, for example) and write:
- The test scenarios you'd cover
- Why you chose those scenarios
- What you'd prioritize and why
This demonstrates test strategy thinking, not just test execution.
Where to share your portfolio
LinkedIn profile. Add the GitHub repository link to your "Featured" section. Write a 2-sentence description: what it is and what it demonstrates.
CV / resume. A direct link to the repository in the "Projects" section. The link does more work than descriptions.
Job applications. When asked for "portfolio or code samples," link directly to the repository, not your general GitHub profile.
GitHub profile README. If you set up a GitHub profile README (the username/username repository), it appears on your GitHub profile. Mention your QA portfolio there.
Common mistakes to avoid
Testing localhost. Tests against http://localhost:3000 don't run for anyone reviewing your portfolio. Test against a public URL.
Committing sensitive data. Never commit real credentials. Use environment variables for test data:
`typescript
// Bad
await page.fill('#email', 'admin@becomeqa.com');
// Better (though for a portfolio, hardcoded test credentials to a test app are fine)
await page.fill('#email', process.env.TEST_EMAIL || 'admin@becomeqa.com');
`
Tests that don't pass. If your GitHub Actions is failing, fix it before sharing. A failed CI pipeline is worse than no CI pipeline.
No README. A repository with no explanation requires the reviewer to reverse-engineer what you built and why. Most reviewers won't bother.
Copied tutorials without modification. If your tests are almost identical to a tutorial you followed, adapt them. Add tests the tutorial didn't include. Change the application being tested. Show that you can apply what you learned, not just copy it.
FAQ
I don't have any real test automation work to show. What do I do?
Build a portfolio using public test environments.
lab.becomeqa.com exists for this purpose. Other options: the-internet.herokuapp.com, automationexercise.com, saucedemo.com. The application doesn't matter. The code quality does.
How long should it take to build a portfolio?
A minimum viable portfolio (15–20 tests, POM structure, CI passing, README) takes 15–25 hours of focused work for someone who knows Playwright. If you're still learning, budget 30–40 hours spread over a few weeks.
Should I include API test examples?
Yes, if you have them. One or two API tests using Playwright's request fixture show that you understand the full testing stack:
`typescript
test('API: create item returns 201', async ({ request }) => {
const response = await request.post('/api/items', {
data: { destination: 'Tokyo', status: 'Planned' },
headers: { Authorization:
Bearer ${token} },
});
expect(response.status()).toBe(201);
});
``
Will a portfolio actually make a difference in hiring?
Yes, noticeably. QA engineers without portfolios compete on CV text. QA engineers with portfolios give hiring engineers something concrete to evaluate. In practice, portfolio owners get further in the screening process at technical companies.
→ See also: QA Automation Roadmap 2026: Essential Skills to Get Hired