diff --git a/e2e/ux.spec.ts b/e2e/ux.spec.ts index 2d9aacb..d0bac36 100644 --- a/e2e/ux.spec.ts +++ b/e2e/ux.spec.ts @@ -80,3 +80,36 @@ test('legacy /admin redirects to /lessons', async ({ page }) => { await page.goto('/admin'); await expect(page).toHaveURL(/\/lessons$/); }); + +test('practice progress bar updates after answering a card', async ({ page }) => { + const email = `progress+${Date.now()}@example.com`; + await registerVerifyLogin(page, 'ProgressUser', email, 'secretpass'); + await page.goto('/lessons'); + await page.getByPlaceholder(/Nieuwe wortel-les/).fill('Progress-test'); + await page.getByRole('button', { name: /Toevoegen/ }).first().click(); + await page.getByRole('link', { name: /Progress-test/ }).first().click(); + // Add two cards so the session does not end on the first answer. + await page.getByPlaceholder('Nieuwe vraag').fill('q1'); + await page.getByPlaceholder('Antwoord').fill('a1'); + await page.getByRole('button', { name: 'Kaart toevoegen' }).click(); + // Wait for the add to settle (draft clears) before adding the next card. + await expect(page.getByPlaceholder('Nieuwe vraag')).toHaveValue(''); + await page.getByPlaceholder('Nieuwe vraag').fill('q2'); + await page.getByPlaceholder('Antwoord').fill('a2'); + await expect(page.getByRole('button', { name: 'Kaart toevoegen' })).toBeEnabled(); + await page.getByRole('button', { name: 'Kaart toevoegen' }).click(); + await expect(page.getByPlaceholder('Nieuwe vraag')).toHaveValue(''); + + await page.getByRole('link', { name: /Start oefenen/ }).click(); + await page.getByRole('button', { name: /Start sessie/ }).click(); + + // Before answering: 0 behandeld + await expect(page.getByText('0 behandeld')).toBeVisible(); + await page.getByRole('button', { name: 'Toon antwoord' }).click(); + await page.getByRole('button', { name: /Goed/ }).click(); + + // After answering: bar reflects 1 handled + 1 correct + 100% accuracy + await expect(page.getByText('1 behandeld')).toBeVisible({ timeout: 5_000 }); + await expect(page.getByText('✓ 1')).toBeVisible(); + await expect(page.getByText('100% goed')).toBeVisible(); +}); diff --git a/packages/frontend/src/stores/sessionStore.ts b/packages/frontend/src/stores/sessionStore.ts index 56bd5e9..b6cc838 100644 --- a/packages/frontend/src/stores/sessionStore.ts +++ b/packages/frontend/src/stores/sessionStore.ts @@ -40,11 +40,20 @@ export const useSession = create((set, get) => ({ await sessionsApi.attempt(s.session.id, { cardId: s.current.cardId, direction: s.current.direction, result, timeToAnswerMs: ttm, }); + // Mirror the backend's counter increments locally so the in-session + // progress bar updates immediately (end() later replaces these with + // the authoritative server totals). + const updatedSession: SessionRow = { + ...s.session, + cardsShown: s.session.cardsShown + 1, + cardsCorrect: s.session.cardsCorrect + (result === 'correct' ? 1 : 0), + cardsIncorrect: s.session.cardsIncorrect + (result === 'incorrect' ? 1 : 0), + }; const nx = await sessionsApi.next(s.session.id); if (nx.done) { - set({ done: true, current: null, showAnswer: false }); + set({ session: updatedSession, done: true, current: null, showAnswer: false }); } else { - set({ current: nx.item, showAnswer: false, shownAt: Date.now() }); + set({ session: updatedSession, current: nx.item, showAnswer: false, shownAt: Date.now() }); } },