feat(player): add reconnect loading and fallback join state (#187)
CI / test-and-quality (push) Successful in 2m5s
CI / test-and-quality (pull_request) Successful in 2m8s

This commit is contained in:
2026-03-01 16:55:33 +00:00
parent c4850f2e0e
commit d26d2b1a09
2 changed files with 125 additions and 2 deletions
@@ -227,4 +227,72 @@ describe('PlayerShellComponent gameplay wiring', () => {
expect(component.connectionState).toBe('offline');
expect(component.error).toContain('Session refresh failed');
});
it('tracks loading transition message for join action', async () => {
let resolveJoin: ((value: Response) => void) | null = null;
const fetchMock: FetchMock = vi.fn().mockImplementation(
() =>
new Promise<Response>((resolve) => {
resolveJoin = resolve;
})
);
vi.stubGlobal('fetch', fetchMock);
const component = new PlayerShellComponent();
component.sessionCode = 'ABCD12';
component.nickname = 'Luna';
const joinPromise = component.joinSession();
expect(component.loading).toBe(true);
expect(component.loadingMessage).toBe('Joining session… restoring your player state.');
resolveJoin?.(jsonResponse(201, sessionDetailPayload('lobby', { roundQuestionId: null })));
await joinPromise;
expect(component.loading).toBe(false);
expect(component.loadingTransition).toBeNull();
});
it('returnToJoin clears persisted session context and transient state', () => {
const values = new Map<string, string>();
const localStorage = {
getItem: vi.fn((key: string) => values.get(key) ?? null),
setItem: vi.fn((key: string, value: string) => {
values.set(key, value);
}),
removeItem: vi.fn((key: string) => {
values.delete(key);
}),
};
vi.stubGlobal('window', {
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
localStorage,
});
values.set('wpp.session-context', JSON.stringify({ sessionCode: 'ABCD12', playerId: 9, token: 'tok-1' }));
const component = new PlayerShellComponent();
component.sessionCode = 'ABCD12';
component.playerId = 9;
component.sessionToken = 'tok-1';
component.error = 'Session refresh failed';
component.submitError = { kind: 'guess', message: 'Guess submit failed' };
component.session = {
session: { code: 'ABCD12', status: 'guess', current_round: 1 },
round_question: { id: 11, prompt: 'Q?', answers: [{ text: 'A' }] },
players: [],
};
component.returnToJoin();
expect(component.playerId).toBe(0);
expect(component.sessionToken).toBe('');
expect(component.session).toBeNull();
expect(component.error).toBe('');
expect(component.submitError).toBeNull();
expect(values.get('wpp.session-context')).toBeUndefined();
});
});