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:
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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() });
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user