Delayed Table Demo

← Back to Tetsing Lab

📊 Delayed Table Demo

Simulates an async data load. The table appears after a deterministic 2-second delay. Try searching or sorting.

Fetching test results…

🔍
# Suite Test name Status Duration Browser
🎭

How to automate this page

These tests focus on async patterns and dynamic UI updates — the kind of scenarios that trip up most automation beginners.

terminal # One-time setup
npm init playwright@latest

# Run your tests
npx playwright test

# Open the HTML report
npx playwright show-report
1 Loader is visible before the table renders initial state

Immediately after navigation, the spinner should be visible and the table content should not yet exist in the DOM. This tests that your async loading state is properly shown.

tetsing-lab.spec.ts
import { test, expect } from '@playwright/test';

test('shows loader before the table renders', async ({ page }) => {
  await page.goto('https://falcoma.com/tetsing-lab/delayed-table-demo');

  // Immediately after load — spinner should be visible
  await expect(page.locator('[data-testid=table-loader]')).toBeVisible();

  // Table content should not be visible yet
  await expect(page.locator('[data-testid=table-content]')).not.toBeVisible();
});
2 Table content appears after the 2-second delay async wait

Wait for the table to become visible (allow up to 5s to avoid flakiness). Once it appears, the loader should be gone. This is the core async wait pattern in Playwright.

tetsing-lab.spec.ts
import { test, expect } from '@playwright/test';

test('table content appears after the 2-second delay', async ({ page }) => {
  await page.goto('https://falcoma.com/tetsing-lab/delayed-table-demo');

  // Wait for the table — toBeVisible() retries automatically
  await expect(page.locator('[data-testid=table-content]'))
    .toBeVisible({ timeout: 5000 });

  // Loader should have disappeared
  await expect(page.locator('[data-testid=table-loader]')).not.toBeVisible();
});
3 Search input filters the visible rows dynamic filtering

Type "Auth" into the search box. Only the 3 rows from the Auth suite should remain. This tests that your filter logic and DOM update work correctly together.

tetsing-lab.spec.ts
import { test, expect } from '@playwright/test';

test('search input filters the table rows', async ({ page }) => {
  await page.goto('https://falcoma.com/tetsing-lab/delayed-table-demo');

  // Wait for the table to load first
  await expect(page.locator('[data-testid=table-content]'))
    .toBeVisible({ timeout: 5000 });

  await page.fill('[data-testid=input-search]', 'Auth');

  // 3 rows belong to the Auth suite
  const rows = page.locator('[data-testid^=table-row-]');
  await expect(rows).toHaveCount(3);
});
4 No results shows the empty state edge case

Search for a string that does not exist in the dataset. The table should disappear and the empty-state element should appear. Always test the empty path, not just the happy path.

tetsing-lab.spec.ts
import { test, expect } from '@playwright/test';

test('shows empty state when no rows match the search', async ({ page }) => {
  await page.goto('https://falcoma.com/tetsing-lab/delayed-table-demo');

  await expect(page.locator('[data-testid=table-content]'))
    .toBeVisible({ timeout: 5000 });

  await page.fill('[data-testid=input-search]', 'zzznomatch');

  await expect(page.locator('[data-testid=empty-state]')).toBeVisible();
  await expect(page.locator('[data-testid=results-table]')).not.toBeVisible();
});