skills/playwright-pro/templates/search/sorting.md

132 lines
5.1 KiB
Markdown

# Search Sorting Template
Tests sorting results by name, date, and price.
## Prerequisites
- Search results for `{{searchQuery}}` with multiple items
- App running at `{{baseUrl}}`
---
## TypeScript
```typescript
import { test, expect } from '@playwright/test';
test.describe('Search Sorting', () => {
test.beforeEach(async ({ page }) => {
await page.goto('{{baseUrl}}/search?q={{searchQuery}}');
});
// Happy path: sort by name A-Z
test('sorts results alphabetically A-Z', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('name_asc');
await expect(page).toHaveURL(/sort=name_asc/);
const names = page.getByTestId('result-name');
const first = await names.first().textContent();
const second = await names.nth(1).textContent();
expect(first!.localeCompare(second!)).toBeLessThanOrEqual(0);
});
// Happy path: sort by name Z-A
test('sorts results alphabetically Z-A', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('name_desc');
const names = page.getByTestId('result-name');
const first = await names.first().textContent();
const second = await names.nth(1).textContent();
expect(first!.localeCompare(second!)).toBeGreaterThanOrEqual(0);
});
// Happy path: sort by date newest
test('sorts results by newest date first', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('date_desc');
await expect(page).toHaveURL(/sort=date_desc/);
const dates = page.getByTestId('result-date');
const firstDate = new Date(await dates.first().getAttribute('datetime') ?? '');
const secondDate = new Date(await dates.nth(1).getAttribute('datetime') ?? '');
expect(firstDate.getTime()).toBeGreaterThanOrEqual(secondDate.getTime());
});
// Happy path: sort by price low-high
test('sorts by price low to high', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('price_asc');
const prices = page.getByTestId('result-price');
const firstText = await prices.first().textContent() ?? '';
const secondText = await prices.nth(1).textContent() ?? '';
const first = parseFloat(firstText.replace(/[^0-9.]/g, ''));
const second = parseFloat(secondText.replace(/[^0-9.]/g, ''));
expect(first).toBeLessThanOrEqual(second);
});
// Happy path: sort by price high-low
test('sorts by price high to low', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('price_desc');
const prices = page.getByTestId('result-price');
const firstText = await prices.first().textContent() ?? '';
const secondText = await prices.nth(1).textContent() ?? '';
const first = parseFloat(firstText.replace(/[^0-9.]/g, ''));
const second = parseFloat(secondText.replace(/[^0-9.]/g, ''));
expect(first).toBeGreaterThanOrEqual(second);
});
// Happy path: sort persists with filters
test('sort selection persists when filter applied', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('price_asc');
await page.getByRole('checkbox', { name: '{{filterCategory}}' }).check();
await expect(page).toHaveURL(/sort=price_asc/);
await expect(page.getByRole('combobox', { name: /sort by/i })).toHaveValue('price_asc');
});
// Edge case: default sort is relevance
test('default sort is relevance', async ({ page }) => {
await expect(page.getByRole('combobox', { name: /sort by/i })).toHaveValue('relevance');
});
});
```
---
## JavaScript
```javascript
const { test, expect } = require('@playwright/test');
test.describe('Search Sorting', () => {
test.beforeEach(async ({ page }) => {
await page.goto('{{baseUrl}}/search?q={{searchQuery}}');
});
test('sorts alphabetically A-Z', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('name_asc');
await expect(page).toHaveURL(/sort=name_asc/);
const names = page.getByTestId('result-name');
const first = await names.first().textContent();
const second = await names.nth(1).textContent();
expect(first.localeCompare(second)).toBeLessThanOrEqual(0);
});
test('sorts by price low to high', async ({ page }) => {
await page.getByRole('combobox', { name: /sort by/i }).selectOption('price_asc');
const prices = page.getByTestId('result-price');
const a = parseFloat((await prices.first().textContent()).replace(/[^0-9.]/g, ''));
const b = parseFloat((await prices.nth(1).textContent()).replace(/[^0-9.]/g, ''));
expect(a).toBeLessThanOrEqual(b);
});
test('default sort is relevance', async ({ page }) => {
await expect(page.getByRole('combobox', { name: /sort by/i })).toHaveValue('relevance');
});
});
```
## Variants
| Variant | Description |
|---------|-------------|
| Name A-Z | First result ≤ second alphabetically |
| Name Z-A | First result ≥ second alphabetically |
| Date newest | Dates in descending order |
| Price low-high | Prices in ascending order |
| Price high-low | Prices in descending order |
| Sort + filter | Sort param persists when filter applied |
| Default sort | Relevance selected by default |