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('');
});