fix(practice): update session counters client-side after each answer

The in-session progress bar reads session.cardsShown/cardsCorrect/cardsIncorrect,
but the session store's answer() never refreshed the session object — the backend
tracked the counters but the client kept the stale start values (all 0), so the bar
appeared frozen. answer() now mirrors the backend's increment locally; end() still
replaces with authoritative server totals. Adds an E2E regression test.
This commit is contained in:
2026-05-21 07:54:15 +02:00
parent f5000d3c58
commit 34431331e9
2 changed files with 44 additions and 2 deletions

View File

@@ -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();
});

View File

@@ -40,11 +40,20 @@ export const useSession = create<SessionState>((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() });
}
},