test: cover grid filter OR/AND (extract pure fn + unit + real e2e)
The two filter-search cases were test.fixme placeholders (expect(true).toBe(true)), so the OR/AND chip rules were untested. - Extract the grid-filter predicate from feed/+page.svelte into a pure filterUploads(uploads, filters) in $lib/feed-filter (behavior-preserving) and unit-test it (9 cases): tag OR, user OR, tag+user AND, AND-excludes-partial, case-insensitive caption match, null caption. - Replace the e2e fixmes with real tests that seed known captions/uploaders, switch to grid view, activate chips via the search suggestions, and count grid tiles: OR widens 1→2, AND narrows 2→1. Frontend unit: 27 passing. filter-search e2e: 3 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,29 +1,68 @@
|
||||
/**
|
||||
* USER_JOURNEYS.md §8 — search and filter chips. Asserts the OR / AND
|
||||
* combination rules described in the journey.
|
||||
* USER_JOURNEYS.md §8 — grid-view search & filter chips. Verifies the OR / AND
|
||||
* combination rules end-to-end by seeding uploads with known captions/uploaders,
|
||||
* activating chips, and counting the resulting grid tiles.
|
||||
*
|
||||
* Most of this test currently drives the UI; the data-seeding happens
|
||||
* via API once a Node-side upload helper lands. For now we ship the
|
||||
* structure and the UI assertions, marked with `test.fixme` where they
|
||||
* depend on seeded data we can't yet create.
|
||||
* (The pure combination logic is also unit-tested in
|
||||
* frontend/src/lib/feed-filter.test.ts.)
|
||||
*/
|
||||
import { test, expect } from '../../fixtures/test';
|
||||
import { seedUpload } from '../../helpers/seed';
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
/** Grid tiles render as buttons labelled "Upload anzeigen". */
|
||||
const tiles = (page: Page) => page.getByRole('button', { name: 'Upload anzeigen' });
|
||||
|
||||
async function switchToGrid(page: Page) {
|
||||
await page.getByRole('button', { name: 'Rasteransicht' }).click();
|
||||
}
|
||||
|
||||
/** Type a query into the grid search box and click the matching suggestion. */
|
||||
async function addFilter(page: Page, query: string, suggestionName: string | RegExp) {
|
||||
const search = page.getByPlaceholder('Nutzer oder #Tag suchen…');
|
||||
await search.click();
|
||||
await search.fill(query);
|
||||
await page.getByRole('button', { name: suggestionName }).click();
|
||||
}
|
||||
|
||||
test.describe('Feed — filter & search', () => {
|
||||
test.fixme('two hashtag chips combine with OR', async ({ page, guest, signIn }) => {
|
||||
const h = await guest('Searcher');
|
||||
await signIn(page, h);
|
||||
// TODO: seed 2 uploads with different hashtags, then activate two chips
|
||||
// and assert both cards remain visible.
|
||||
await page.goto('/feed');
|
||||
expect(true).toBe(true);
|
||||
test('two hashtag chips combine with OR', async ({ page, guest, signIn }) => {
|
||||
const a = await guest('OrUser');
|
||||
await seedUpload(a.jwt, { caption: 'pic #wedding' });
|
||||
await seedUpload(a.jwt, { caption: 'pic #party' });
|
||||
await seedUpload(a.jwt, { caption: 'pic #other' });
|
||||
|
||||
await signIn(page, a); // lands on /feed
|
||||
await switchToGrid(page);
|
||||
await expect(tiles(page)).toHaveCount(3);
|
||||
|
||||
// One tag → only its card.
|
||||
await addFilter(page, '#wedding', /wedding/i);
|
||||
await expect(tiles(page)).toHaveCount(1);
|
||||
|
||||
// Adding a second tag widens the result (OR), not narrows it.
|
||||
await addFilter(page, '#party', /party/i);
|
||||
await expect(tiles(page)).toHaveCount(2);
|
||||
});
|
||||
|
||||
test.fixme('uploader chip + hashtag chip combines with AND', async ({ page, guest, signIn }) => {
|
||||
const h = await guest('Searcher2');
|
||||
await signIn(page, h);
|
||||
await page.goto('/feed');
|
||||
expect(true).toBe(true);
|
||||
test('uploader chip + hashtag chip combines with AND', async ({ page, guest, signIn }) => {
|
||||
const alice = await guest('AndAlice');
|
||||
const bob = await guest('AndBob');
|
||||
await seedUpload(alice.jwt, { caption: 'pic #wedding' }); // Alice + wedding
|
||||
await seedUpload(bob.jwt, { caption: 'pic #wedding' }); // Bob + wedding
|
||||
await seedUpload(alice.jwt, { caption: 'pic #party' }); // Alice + party
|
||||
|
||||
await signIn(page, alice); // feed is event-wide → sees all three
|
||||
await switchToGrid(page);
|
||||
await expect(tiles(page)).toHaveCount(3);
|
||||
|
||||
// Filter by uploader → Alice's two uploads.
|
||||
await addFilter(page, 'AndAlice', 'AndAlice');
|
||||
await expect(tiles(page)).toHaveCount(2);
|
||||
|
||||
// Add a tag → must satisfy BOTH (Alice AND #wedding) → just the one.
|
||||
await addFilter(page, '#wedding', /wedding/i);
|
||||
await expect(tiles(page)).toHaveCount(1);
|
||||
});
|
||||
|
||||
test('feed page renders without crashing for an authed user', async ({ page, guest, signIn }) => {
|
||||
|
||||
Reference in New Issue
Block a user