Dataintermediate hidden bug 14 min
Dynamic / Shifting Tables — Practice in Playwright, Selenium & Cypress
Practice automating dynamic tables whose columns and rows re-order on refresh. Anchor by header text and row identity instead of brittle position selectors.
Live element
Hidden bug planted — try to catch it🐞 Sort High→Low and watch your test catch a defect.
Locators cheat-sheet
| data-testid | Role | Accessible label | What it is |
|---|---|---|---|
| products-table | table | Products table | Three rows: name + price. |
| sort-price | button | Sort by price | Toggles ascending / descending price sort. 🐞 Descending is broken on purpose. |
| row-name | cell | Product name cell | Use nth-row selectors to assert order after sorting. |
| row-price | cell | Product price cell | Numeric price value used to verify sort correctness. |
Reference solutions
import { test, expect } from '@playwright/test';
test('descending price sort orders highest first', async ({ page }) => {
await page.goto('/practice/dynamic-table');
const frame = page.frameLocator('iframe[title="Dynamic table live widget"]');
// First click = ascending, second click = descending.
await frame.getByTestId('sort-price').click();
await frame.getByTestId('sort-price').click();
const prices = await frame.getByTestId('row-price').allTextContents();
const numeric = prices.map(Number);
// 🐞 With the planted bug, this assertion FAILS — descending order is broken.
expect(numeric).toEqual([...numeric].sort((a, b) => b - a));
});