test(geschichten): decouple multi-person e2e from seed names
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 3m56s
CI / OCR Service Tests (pull_request) Successful in 48s
CI / Backend Unit Tests (pull_request) Failing after 3m13s
CI / Unit & Component Tests (push) Failing after 4m40s
CI / OCR Service Tests (push) Successful in 56s
CI / Backend Unit Tests (push) Failing after 3m20s
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 3m56s
CI / OCR Service Tests (pull_request) Successful in 48s
CI / Backend Unit Tests (pull_request) Failing after 3m13s
CI / Unit & Component Tests (push) Failing after 4m40s
CI / OCR Service Tests (push) Successful in 56s
CI / Backend Unit Tests (push) Failing after 3m20s
The multi-person filter e2e previously typed 'a' then 'b' into the
typeahead and trusted the dev seed to contain matching names.
If the seed ever changes, the test would silently degrade — both
calls might resolve to the same row, or the listbox might never
populate.
Refactor to use a single broadly-occurring probe vowel ('e') and
extract person ids straight from the listbox option DOM (the option
id encodes the person id as `${listboxId}-option-${personId}`).
For the second pick, iterate options and select the first whose
id differs from the first selection. The test now only depends on
the seed having ≥2 distinct persons whose name contains 'e' — a
much weaker, more durable assumption — and asserts on the URL
params with full equality instead of toHaveLength + first-element
spot checks.
Addresses Sara's iteration-3 concern #4 on PR #382.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit was merged in pull request #382.
This commit is contained in:
@@ -68,43 +68,71 @@ test.describe('Geschichten — writer + reader journey', () => {
|
||||
await page.goto('/geschichten');
|
||||
await page.waitForSelector('[data-hydrated]');
|
||||
|
||||
// We need two persons to filter by. Open the picker and pick one whose name
|
||||
// the dev seed reliably contains. Then open the picker again and pick a
|
||||
// second one. Picking is via the typeahead — we type, wait for the listbox,
|
||||
// click the first option.
|
||||
async function pickPerson(query: string) {
|
||||
// We need two distinct persons to filter by, but we don't want to couple this
|
||||
// test to specific seed names. Strategy: type a single broadly-occurring vowel
|
||||
// ("e" is present in the vast majority of German names), open the listbox,
|
||||
// and pick whichever option matches the predicate.
|
||||
//
|
||||
// option DOM ids encode the person id as `${listboxId}-option-${personId}`,
|
||||
// so we can identify the *first different* option without knowing the seed.
|
||||
const PROBE = 'e';
|
||||
|
||||
async function openPicker() {
|
||||
await page.getByRole('button', { name: /Person wählen/ }).click();
|
||||
const input = page.getByRole('combobox', { name: /Person wählen/ });
|
||||
await input.fill(query);
|
||||
// Wait for at least one option in the listbox, then click it
|
||||
const firstOption = page.getByRole('option').first();
|
||||
await expect(firstOption).toBeVisible();
|
||||
await firstOption.click();
|
||||
await input.fill(PROBE);
|
||||
// Wait for the listbox to be populated.
|
||||
await expect(page.getByRole('option').first()).toBeVisible();
|
||||
}
|
||||
|
||||
await pickPerson('a');
|
||||
await page.waitForURL(/personId=/);
|
||||
const firstUrl = new URL(page.url());
|
||||
const firstIds = firstUrl.searchParams.getAll('personId');
|
||||
expect(firstIds).toHaveLength(1);
|
||||
async function pickFirstOption(): Promise<string> {
|
||||
const opt = page.getByRole('option').first();
|
||||
const optId = (await opt.getAttribute('id')) ?? '';
|
||||
const personId = optId.split('-option-')[1] ?? '';
|
||||
expect(personId).not.toEqual('');
|
||||
await opt.click();
|
||||
return personId;
|
||||
}
|
||||
|
||||
await pickPerson('b');
|
||||
async function pickFirstOptionDifferentFrom(excludeId: string): Promise<string> {
|
||||
// Iterate through visible options and return the first whose person id != excludeId.
|
||||
const optionCount = await page.getByRole('option').count();
|
||||
for (let i = 0; i < optionCount; i++) {
|
||||
const candidate = page.getByRole('option').nth(i);
|
||||
const optId = (await candidate.getAttribute('id')) ?? '';
|
||||
const personId = optId.split('-option-')[1] ?? '';
|
||||
if (personId && personId !== excludeId) {
|
||||
await candidate.click();
|
||||
return personId;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Expected at least two distinct persons matching "${PROBE}" in the seed, found only one.`
|
||||
);
|
||||
}
|
||||
|
||||
await openPicker();
|
||||
const firstId = await pickFirstOption();
|
||||
await page.waitForURL(/personId=/);
|
||||
const firstIds = new URL(page.url()).searchParams.getAll('personId');
|
||||
expect(firstIds).toEqual([firstId]);
|
||||
|
||||
await openPicker();
|
||||
const secondId = await pickFirstOptionDifferentFrom(firstId);
|
||||
await page.waitForURL((url) => url.searchParams.getAll('personId').length === 2);
|
||||
const secondUrl = new URL(page.url());
|
||||
const secondIds = secondUrl.searchParams.getAll('personId');
|
||||
expect(secondIds).toHaveLength(2);
|
||||
expect(secondIds[0]).toBe(firstIds[0]); // first one persists
|
||||
expect(secondIds[1]).not.toBe(firstIds[0]); // second is different
|
||||
const secondIds = new URL(page.url()).searchParams.getAll('personId');
|
||||
expect(secondIds).toEqual([firstId, secondId]);
|
||||
expect(secondId).not.toEqual(firstId);
|
||||
|
||||
// Two chips visible — find them by their remove-aria-label pattern
|
||||
const chipButtons = page.getByRole('button', { name: /aus Filter entfernen/ });
|
||||
await expect(chipButtons).toHaveCount(2);
|
||||
|
||||
// Remove the first chip — URL drops to one param
|
||||
// Remove the first chip — URL drops to one param, only the second id remains
|
||||
await chipButtons.first().click();
|
||||
await page.waitForURL((url) => url.searchParams.getAll('personId').length === 1);
|
||||
const finalIds = new URL(page.url()).searchParams.getAll('personId');
|
||||
expect(finalIds).toEqual([secondIds[1]]);
|
||||
expect(finalIds).toEqual([secondId]);
|
||||
});
|
||||
|
||||
test('AxeBuilder finds no critical violations on the index', async ({ page }) => {
|
||||
|
||||
Reference in New Issue
Block a user