132 lines
5.1 KiB
Markdown
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 |
|