test-generation
SKILL.md
Test Generation
Generate Playwright test code from test case designs.
MANDATORY: Use Discovered Data, Not Assumptions
⚠️ NEVER write tests with assumed error messages, selectors, or behaviors!
Before writing ANY test that asserts on:
- Error messages → Discover the actual text first
- Validation messages → Discover HTML5 or custom validation first
- Element selectors → Discover from accessibility snapshot first
- Success states → Discover redirect URL or success message first
// ❌ WRONG - Assumed error text (you don't know what it actually says!)
await expect(page.locator('.error')).toContainText('Invalid credentials');
// ✅ CORRECT - Use text discovered via browser_run_code
await expect(page.getByRole('alert')).toContainText('Email sau parolă incorectă');
Workflow:
- Run
browser_run_codeto trigger the behavior (login failure, validation error, etc.) - Capture actual error text and selectors
- Use those exact values in your test assertions
See site-discovery skill → Phase 4 for discovery examples.
File Structure
tests/
├── auth.spec.ts # Authentication tests
├── navigation.spec.ts # Navigation tests
├── [feature].spec.ts # Feature-specific tests
pages/
├── login.page.ts # Page objects
├── [page].page.ts
Page Object Pattern
// pages/login.page.ts
import { Page, Locator, expect } from '@playwright/test';
export class LoginPage {
readonly page: Page;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
readonly errorMessage: Locator;
constructor(page: Page) {
this.page = page;
this.emailInput = page.getByLabel('Email');
this.passwordInput = page.getByLabel('Password');
this.submitButton = page.getByRole('button', { name: 'Sign In' });
this.errorMessage = page.getByRole('alert');
}
async goto() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
async expectLoaded() {
await expect(this.emailInput).toBeVisible();
await expect(this.passwordInput).toBeVisible();
}
async expectError(message: string) {
await expect(this.errorMessage).toContainText(message);
}
}
Test Spec Pattern
// tests/auth.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/login.page';
test.describe('Authentication - Login', () => {
let loginPage: LoginPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.goto();
});
test('valid credentials redirect to dashboard', async ({ page }) => {
// Arrange
const email = process.env.TEST_USER_EMAIL!;
const password = process.env.TEST_USER_PASSWORD!;
// Act
await loginPage.login(email, password);
// Assert
await expect(page).toHaveURL(/dashboard/);
});
test('invalid password shows error', async ({ page }) => {
// Act
await loginPage.login('user@example.com', 'wrongpassword');
// Assert
await loginPage.expectError('Invalid credentials');
await expect(page).toHaveURL(/login/);
});
});
Qase Integration
Link tests to Qase case IDs:
test('valid login @qase(1)', async ({ page }) => {
// Links to Qase case ID 1
});
// Or via annotation
test('valid login', async ({ page }) => {
test.info().annotations.push({ type: 'qase', description: '1' });
});
Test Naming Convention
[action] should [expected result]
Examples:
valid credentials should redirect to dashboardempty email should show validation erroradd to cart button should update cart count
Assertions Reference
// Visibility
await expect(element).toBeVisible();
await expect(element).toBeHidden();
// Text
await expect(element).toHaveText('exact');
await expect(element).toContainText('partial');
// URL
await expect(page).toHaveURL(/dashboard/);
await expect(page).toHaveURL('https://example.com/path');
// Attributes
await expect(element).toHaveAttribute('href', '/path');
await expect(element).toHaveClass(/active/);
// State
await expect(element).toBeEnabled();
await expect(element).toBeDisabled();
await expect(element).toBeChecked();
// Count
await expect(elements).toHaveCount(5);
// Value
await expect(input).toHaveValue('text');
Data-Driven Tests
const testCases = [
{ email: '', password: 'pass', error: 'Email required' },
{ email: 'bad', password: 'pass', error: 'Invalid email' },
{ email: 'user@test.com', password: '', error: 'Password required' },
];
for (const { email, password, error } of testCases) {
test(`shows "${error}" for invalid input`, async ({ page }) => {
await loginPage.login(email, password);
await loginPage.expectError(error);
});
}
See references/templates.md for more patterns.
Weekly Installs
4
Repository
cristian-robert…n-testerFirst Seen
Feb 26, 2026
Security Audits
Installed on
opencode4
github-copilot4
codex4
amp4
cline4
kimi-cli4