🔐 Login Demo
A simulated login flow. Validates inputs client-side and fakes an async request before resolving.
demo@falcoma.comPassword:
test1234Anything else triggers an error state.
How to automate this page
Each step maps directly to a data-testid already on this page. Copy, paste into your spec file, and run.
npm init playwright@latest
# Run your tests
npx playwright test
# Open the HTML report
npx playwright show-report
1 ▼
Submit the form without entering anything. Both fields should immediately show their required-field messages. No async wait needed — this is synchronous client-side validation.
import { test, expect } from '@playwright/test';
test('shows required-field errors on empty submit', async ({ page }) => {
await page.goto('https://falcoma.com/tetsing-lab/login-demo');
await page.click('[data-testid=btn-submit]');
await expect(page.locator('[data-testid=error-email]'))
.toHaveText('Email is required.');
await expect(page.locator('[data-testid=error-password]'))
.toHaveText('Password is required.');
});
2 ▼
After clicking submit with valid-looking input, the loading indicator should appear before the fake 1.5s response resolves. Click and immediately assert — no await needed.
import { test, expect } from '@playwright/test';
test('shows loading indicator immediately after submit', async ({ page }) => {
await page.goto('https://falcoma.com/tetsing-lab/login-demo');
await page.fill('[data-testid=input-email]', 'demo@falcoma.com');
await page.fill('[data-testid=input-password]', 'test1234');
await page.click('[data-testid=btn-submit]');
// Assert the spinner before the 1.5s delay resolves
await expect(page.locator('[data-testid=loading-indicator]')).toBeVisible();
});
3 ▼
Enter a valid email format but wrong credentials. The fake request takes 1.5s, so extend the assertion timeout beyond that to avoid a flaky test.
import { test, expect } from '@playwright/test';
test('shows error state for wrong credentials', async ({ page }) => {
await page.goto('https://falcoma.com/tetsing-lab/login-demo');
await page.fill('[data-testid=input-email]', 'wrong@example.com');
await page.fill('[data-testid=input-password]', 'badpassword');
await page.click('[data-testid=btn-submit]');
// Fake delay is 1.5s — allow up to 4s to avoid flakiness
await expect(page.locator('[data-testid=status-error]'))
.toBeVisible({ timeout: 4000 });
});
4 ▼
The full happy path. After the fake delay resolves, the success banner should be visible and both inputs should be reset to empty.
import { test, expect } from '@playwright/test';
test('signs in successfully with demo credentials', async ({ page }) => {
await page.goto('https://falcoma.com/tetsing-lab/login-demo');
await page.fill('[data-testid=input-email]', 'demo@falcoma.com');
await page.fill('[data-testid=input-password]', 'test1234');
await page.click('[data-testid=btn-submit]');
await expect(page.locator('[data-testid=status-success]'))
.toBeVisible({ timeout: 4000 });
// Inputs should be cleared after a successful login
await expect(page.locator('[data-testid=input-email]')).toHaveValue('');
});