VALIDATION LAB•MULTI SELECT
Selection
Multi Select
Select several skills, verify chips render in selection order, and assert removal via chip × button.
Scenario
Multi-selects show up in tag pickers, role assignment, country filters. Common bugs: order changes on removal, the same item appears twice, the form posts a comma-string instead of an array.
Skills
No skills picked yet.
Live widget · interact freely
Manual test checklist
- 1Select three skills and confirm chips appear in the order picked, not alphabetically
- 2Remove the middle chip — confirm the surrounding chips don't reorder
- 3Re-add the same skill — does the chip return to its original spot or the end?
- 4Use Backspace in the input area — does it remove the last chip?
- 5Submit and inspect the network request — is the value an array, not a CSV string?
Expected result
Picking three skills produces three chips; removing the middle chip leaves two in their original order.
Automation challenge
Pick 3 chips, assert `count = 3` via `[data-testid^=ms-chip-]`. Remove the middle one, then assert the two remaining chips are in their original order — `expect(chips.first()).toHaveText('Cypress')`.
Stable selectors
- Skill option Cypress
[data-testid="ms-cypress"] - Skill option Playwright
[data-testid="ms-playwright"] - Skill option K6
[data-testid="ms-k6"] - Selected chip Playwright
[data-testid="ms-chip-playwright"] - Remove chip Cypress
[data-testid="ms-remove-cypress"]
Locator strategy
Three levels from simple IDs to scoped Playwright locators. IDs and names are easy to learn but are not always the best long-term choice when labels change or components repeat.
Use simple IDs and names to understand how locating elements works.
123
await page.goto('https://lab.hakdogan.com/practice/multi-select');
await page.locator('#ms-playwright').click();Avoid as primary strategies
XPath (unless there is no alternative), long CSS chains, Tailwind-style utility class selectors, generated or unstable IDs, and volatile framework internals break when layout, styling, or DOM structure shifts.
12
await page.locator('.w-full.rounded-xl.border.bg-blue-500').fill('demo@example.com');
await page.locator('//div[2]/form/div[1]/input').fill('demo@example.com');Reference Playwright spec
12345678910111213
import { test, expect } from '@playwright/test';
test('multi-select chips behave correctly', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/practice/multi-select');
await page.getByTestId('ms-cypress').click();
await page.getByTestId('ms-playwright').click();
await page.getByTestId('ms-k6').click();
await expect(page.locator('[data-testid^="ms-chip-"]')).toHaveCount(3);
await page.getByTestId('ms-remove-cypress').click();
await expect(page.locator('[data-testid^="ms-chip-"]')).toHaveCount(2);
});Headed Test Playback
Simulated headed-browser flow — no real browser is launched.
Automation-style playback (Playwright-shaped logs). No real browser; no commands run on your machine.
Mixed: fill() for stable fields, type() / press() where keyboard semantics matter.
multi-select.spec.ts- Show multi-select field
- Open dropdown
- Type "play"
- Select Playwright
- Select TypeScript
- Select Cypress
- Remove Cypress chip
- Assert chip count is 2
- Pass