Menguasai dasar test automation: test lifecycle, assertions, debugging, dan menulis test pertama dengan Playwright yang reliable

Setelah di episode 2 kita memahami automation strategy, pada episode ini kita mulai hands-on: menulis test automation pertama. Ini adalah fondasi yang akan kalian bangun sepanjang series.
// Arrange: setup test data & conditions
await page.goto('http://localhost:3000/login');
await page.fill('#email', 'user@test.com');
await page.fill('#password', 'password123');
// Act: perform action
await page.click('#login-button');
// Assert: verify result
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('.welcome')).toContainText('Welcome');test.describe('Login Feature', () => {
test.beforeEach(async ({ page }) => {
await page.goto('http://localhost:3000/login');
});
test('should login with valid credentials', async ({ page }) => {
// Arrange
await page.fill('#email', 'user@test.com');
await page.fill('#password', 'password123');
// Act
await page.click('#login-button');
// Assert
await expect(page).toHaveURL('/dashboard');
});
test('should show error with invalid credentials', async ({ page }) => {
// Arrange
await page.fill('#email', 'wrong@test.com');
await page.fill('#password', 'wrongpass');
// Act
await page.click('#login-button');
// Assert
await expect(page.locator('.error-message')).toBeVisible();
await expect(page.locator('.error-message')).toContainText('Invalid');
});
});// Visibility
await expect(page.locator('.alert')).toBeVisible();
await expect(page.locator('.loading')).toBeHidden();
// Text content
await expect(page.locator('h1')).toHaveText('Welcome');
await expect(page.locator('.message')).toContainText('success');
// URL
await expect(page).toHaveURL('/dashboard');
await expect(page).toHaveURL(/dashboard/);
// Count
await expect(page.locator('.item')).toHaveCount(5);
// Form values
await expect(page.locator('#email')).toHaveValue('user@test.com');
// Attribute
await expect(page.locator('button')).toHaveAttribute('type', 'submit');
// CSS
await expect(page.locator('.success')).toHaveCSS('color', 'green');// Helper function untuk custom assertion
async function expectNoConsoleErrors(page) {
const errors = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
});
await page.waitForTimeout(1000);
expect(errors).toEqual([]);
}# Jalankan dengan inspector
npx playwright test --debug
# Atau set env variable
PWDEBUG=1 npx playwright test# Lihat browser executing
npx playwright test --headed
# Single test
npx playwright test --headed login.spec.ts# Record trace
npx playwright test --trace on
# View trace
npx playwright show-trace trace.zipTip
Gunakan page.pause() untuk pause execution dan inspect state. Ini adalah cara paling cepat untuk debug test yang gagal.
# Create project
npm init playwright@latest
# Create first test
cat > tests/login.spec.ts << 'EOF'
import { test, expect } from '@playwright/test';
test('homepage has title', async ({ page }) => {
await page.goto('http://localhost:3000');
await expect(page).toHaveTitle(/.*/);
});
test('can navigate to login', async ({ page }) => {
await page.goto('http://localhost:3000');
await page.click('a[href="/login"]');
await expect(page).toHaveURL('/login');
});
EOF
# Run test
npx playwright testDi episode 4 selanjutnya kita akan membahas selectors & locators — CSS, XPath, accessibility-based selectors, dan best practices untuk locator yang robust. Sampai jumpa di episode 4!