Mengotomasi authentication testing: login flows, token management, session handling, dan testing auth patterns yang umum di aplikasi modern

Setelah di episode 18 kita mengamankan test automation, pada episode ini kita mendalami flow yang paling sering diuji: authentication. Login, logout, session management — semua ini harus terotomasi.
test('login with valid credentials', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@test.com');
await page.getByLabel('Password').fill('password123');
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL('/dashboard');
await expect(page.getByText('Welcome')).toBeVisible();
});// Login via API (bypass UI)
test('login via API', async ({ request, page }) => {
// Login via API
const response = await request.post('/api/auth/login', {
data: {
email: 'user@test.com',
password: 'password123',
},
});
const { token } = await response.json();
// Set token di browser
await page.goto('/');
await page.evaluate((t) => {
localStorage.setItem('token', t);
}, token);
await page.goto('/dashboard');
await expect(page.getByText('Welcome')).toBeVisible();
});// Simpan authentication state
test('save login state', async ({ page, context }) => {
await page.goto('/login');
await page.fill('#email', 'user@test.com');
await page.fill('#password', 'password123');
await page.click('#login-button');
await expect(page).toHaveURL('/dashboard');
// Simpan cookies & storage
await context.storageState({ path: 'auth.json' });
});
// Reuse authentication state
test('use saved login', async ({ browser }) => {
const context = await browser.newContext({
storageState: 'auth.json',
});
const page = await context.newPage();
await page.goto('/dashboard');
// Sudah login, tidak perlu login lagi
await expect(page.getByText('Welcome')).toBeVisible();
await context.close();
});// global-setup.ts
import { chromium } from '@playwright/test';
async function globalSetup() {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000/login');
await page.fill('#email', process.env.TEST_USER_EMAIL);
await page.fill('#password', process.env.TEST_USER_PASSWORD);
await page.click('#login-button');
await expect(page).toHaveURL('/dashboard');
await page.context().storageState({ path: 'playwright/.auth/user.json' });
await browser.close();
}
export default globalSetup;// Mock OAuth (untuk testing)
test('OAuth login', async ({ page }) => {
// Intercept OAuth callback
await page.route('**/oauth/callback**', async route => {
// Simulate OAuth success
await route.fulfill({
status: 302,
headers: {
Location: '/dashboard?token=mock-token',
},
});
});
await page.goto('/login');
await page.getByRole('button', { name: 'Sign in with Google' }).click();
await expect(page).toHaveURL(/dashboard/);
});Tip
Gunakan storageState untuk save dan reuse authentication — ini jauh lebih cepat daripada login via UI setiap test.
test.describe('Authentication', () => {
test('login and logout', async ({ page }) => {
// Login
await page.goto('/login');
await page.fill('#email', 'user@test.com');
await page.fill('#password', 'password123');
await page.click('#login-button');
await expect(page).toHaveURL('/dashboard');
// Logout
await page.getByRole('button', { name: 'Logout' }).click();
await expect(page).toHaveURL('/login');
});
test('protected route redirects to login', async ({ page }) => {
await page.goto('/dashboard');
await expect(page).toHaveURL('/login');
});
});Di episode 20 selanjutnya kita akan membahas test environment & stability — containerized environments, seeds, dan reset states. Sampai jumpa di episode 20!