TypeScript for QA Engineers: The Essentials You Actually Need for Test Automation
You do not need to learn all of TypeScript to write Playwright tests. You need the 20% that covers 95% of test automation scenarios. Here are the essentials — nothing more, nothing less.
Contents
Types That Matter for Tests
// Basic types you will use daily
const testName: string = 'login flow';
const retryCount: number = 3;
const isEnabled: boolean = true;
const testIds: number[] = [1, 2, 3];
// Object types for test data
interface User {
name: string;
email: string;
role: 'admin' | 'user' | 'guest'; // Union type = only these values
}
// Optional fields (common in API responses)
interface ApiResponse {
id: number;
data: User;
error?: string; // Optional — may or may not exist
}
Async/Await (The Most Important Concept)
// Every Playwright action is async
test('login flow', async ({ page }) => {
await page.goto('/login'); // Wait for navigation
await page.getByLabel('Email').fill('test@test.com'); // Wait for fill
await page.getByRole('button', { name: 'Login' }).click(); // Wait for click
await expect(page.getByText('Dashboard')).toBeVisible(); // Wait for assertion
});
// Common mistake: forgetting await
// page.goto('/login'); // BAD: does not wait, test continues immediately
Interfaces for Page Objects
// Type-safe Page Object
class LoginPage {
constructor(private page: Page) {}
async login(email: string, password: string): Promise<void> {
await this.page.getByLabel('Email').fill(email);
await this.page.getByLabel('Password').fill(password);
await this.page.getByRole('button', { name: 'Login' }).click();
}
async getErrorMessage(): Promise<string> {
return await this.page.getByRole('alert').textContent() ?? '';
}
}
Generics for Reusable Utilities
// Generic API helper — works with any response type
async function apiGet<T>(request: APIRequestContext, path: string): Promise<T> {
const response = await request.get(path);
expect(response.ok()).toBeTruthy();
return await response.json() as T;
}
// Usage — TypeScript knows the return type
const user = await apiGet<User>(request, '/api/users/1');
console.log(user.email); // TypeScript autocomplete works!
Enums for Test Configuration
enum Environment {
Dev = 'https://dev.example.com',
Staging = 'https://staging.example.com',
Production = 'https://example.com',
}
enum UserRole {
Admin = 'admin',
User = 'user',
Guest = 'guest',
}
// Type-safe configuration
const config = {
baseUrl: Environment.Staging,
defaultRole: UserRole.Admin,
};
What You Can Skip (For Now)
- Decorators — rarely used in test code
- Abstract classes — keep it simple with interfaces
- Mapped types / conditional types — advanced and unnecessary for tests
- Module declarations — Playwright handles this
- Namespaces — use ES modules instead
