Login Demo

← Back to Tetsing Lab

🔐 Login Demo

A simulated login flow. Validates inputs client-side and fakes an async request before resolving.

✅ Signed in successfully. Welcome back, Vincent.
❌ Invalid email or password. Please try again.
🎭

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.

terminal # One-time setup
npm init playwright@latest

# Run your tests
npx playwright test

# Open the HTML report
npx playwright show-report
1 Validation errors on empty submit required fields ▼

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.

tetsing-lab.spec.ts
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 Loading indicator is visible during the fake request async ui ▼

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.

tetsing-lab.spec.ts
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 Wrong credentials show the error state error path ▼

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.

tetsing-lab.spec.ts
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 Valid credentials reach the success state happy path ▼

The full happy path. After the fake delay resolves, the success banner should be visible and both inputs should be reset to empty.

tetsing-lab.spec.ts
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('');
});