The "has title" test was a warmup. Now let us write a real test against a real application. We will test the Banking Portal login flow on TesterRank. This is the kind of test you will write at work every day -- navigate, fill a form, click a button, verify the result.
import { test, expect } from '@playwright/test';
test('should login to Banking Portal with valid credentials', async ({ page }) => {
// Step 1: Navigate to the Banking Portal login page
await page.goto('/banking');
// Step 2: Fill in the login form
await page.getByLabel('Username').fill('testuser');
await page.getByLabel('Password').fill('password123');
// Step 3: Click the Login button
await page.getByRole('button', { name: 'Login' }).click();
// Step 4: Verify the dashboard loaded
await expect(page.getByRole('heading', { name: /dashboard/i })).toBeVisible();
await expect(page.getByText('testuser')).toBeVisible();
});Let me break down the new APIs you just saw.
| Method | What It Does | Example |
|---|---|---|
| page.getByLabel() | Finds input by its associated <label> text | getByLabel('Username') finds the input labeled "Username" |
| page.getByRole() | Finds element by its ARIA role and accessible name | getByRole('button', { name: 'Login' }) |
| .fill() | Clears the input and types the given text | fill('testuser') replaces whatever was in the field |
| .click() | Clicks the element (auto-waits for it to be clickable) | Waits for visible, enabled, not obscured, then clicks |
| expect().toBeVisible() | Asserts the element is visible on the page | Auto-retries for 5 seconds by default |
Good testers do not just test the happy path. What happens with wrong credentials? A real test suite covers both.
test('should show error for invalid credentials', async ({ page }) => {
await page.goto('/banking');
await page.getByLabel('Username').fill('wronguser');
await page.getByLabel('Password').fill('wrongpassword');
await page.getByRole('button', { name: 'Login' }).click();
// Verify error message appears
await expect(page.getByText(/invalid credentials/i)).toBeVisible();
// Verify we are still on the login page (not redirected)
await expect(page).toHaveURL(/banking/);
});Use regex in assertions when the exact text might change slightly. /invalid credentials/i matches "Invalid Credentials", "Invalid credentials", "invalid credentials" -- case insensitive. Hardcoding exact strings makes tests brittle.
Never hardcode real passwords in test files. Use environment variables or a test data file that is excluded from Git. For practice apps like TesterRank, dummy credentials are fine. For work projects, use .env files.
Key Point: A real test follows the user flow: navigate, interact (fill, click), and assert the result. Always test both the happy path and the error path.
Key Point: Real tests follow user flows: goto, fill, click, assert. Use getByLabel and getByRole to find elements the way users see them.