refactor web socket layer

This commit is contained in:
seavor 2026-04-14 14:39:46 -05:00
parent 19f5eefdd2
commit 141f0e59f5
124 changed files with 927 additions and 853 deletions

View file

@ -130,6 +130,7 @@ export function makeServerState(overrides: Partial<ServerState> = {}): ServerSta
buddyList: [],
ignoreList: [],
status: {
connectionAttemptMade: false,
state: StatusEnum.DISCONNECTED,
description: null,
},

View file

@ -25,6 +25,10 @@ describe('Actions', () => {
expect(Actions.clearStore()).toEqual({ type: Types.CLEAR_STORE });
});
it('connectionAttempted', () => {
expect(Actions.connectionAttempted()).toEqual({ type: Types.CONNECTION_ATTEMPTED });
});
it('loginSuccessful', () => {
const options = makeConnectOptions();
expect(Actions.loginSuccessful(options)).toEqual({ type: Types.LOGIN_SUCCESSFUL, options });
@ -360,4 +364,8 @@ describe('Actions', () => {
const gametypeMap = { 1: 'Standard' };
expect(Actions.gamesOfUser('alice', games, gametypeMap)).toEqual({ type: Types.GAMES_OF_USER, userName: 'alice', games, gametypeMap });
});
it('clearRegistrationErrors', () => {
expect(Actions.clearRegistrationErrors()).toEqual({ type: Types.CLEAR_REGISTRATION_ERRORS });
});
});

View file

@ -14,6 +14,9 @@ export const Actions = {
clearStore: () => ({
type: Types.CLEAR_STORE
}),
connectionAttempted: () => ({
type: Types.CONNECTION_ATTEMPTED
}),
loginSuccessful: (options: WebSocketConnectOptions) => ({
type: Types.LOGIN_SUCCESSFUL,
options

View file

@ -32,6 +32,11 @@ describe('Dispatch', () => {
expect(store.dispatch).toHaveBeenCalledWith(Actions.clearStore());
});
it('connectionAttempted dispatches Actions.connectionAttempted()', () => {
Dispatch.connectionAttempted();
expect(store.dispatch).toHaveBeenCalledWith(Actions.connectionAttempted());
});
it('loginSuccessful dispatches Actions.loginSuccessful()', () => {
const options = makeConnectOptions();
Dispatch.loginSuccessful(options);
@ -391,4 +396,9 @@ describe('Dispatch', () => {
Dispatch.gamesOfUser('alice', games, gametypeMap);
expect(store.dispatch).toHaveBeenCalledWith(Actions.gamesOfUser('alice', games, gametypeMap));
});
it('clearRegistrationErrors dispatches correctly', () => {
Dispatch.clearRegistrationErrors();
expect(store.dispatch).toHaveBeenCalledWith(Actions.clearRegistrationErrors());
});
});

View file

@ -14,6 +14,9 @@ export const Dispatch = {
clearStore: () => {
store.dispatch(Actions.clearStore());
},
connectionAttempted: () => {
store.dispatch(Actions.connectionAttempted());
},
loginSuccessful: (options: WebSocketConnectOptions) => {
store.dispatch(Actions.loginSuccessful(options));
},

View file

@ -76,6 +76,7 @@ export interface ServerState {
}
export interface ServerStateStatus {
connectionAttemptMade: boolean;
description: string;
state: number;
}

View file

@ -55,6 +55,12 @@ describe('Initialisation', () => {
// ── Account & Connection ─────────────────────────────────────────────────────
describe('Account & Connection', () => {
it('CONNECTION_ATTEMPTED → sets connectionAttemptMade to true', () => {
const state = makeServerState({ status: { connectionAttemptMade: false, state: StatusEnum.DISCONNECTED, description: null } });
const result = serverReducer(state, { type: Types.CONNECTION_ATTEMPTED });
expect(result.status.connectionAttemptMade).toBe(true);
});
it('ACCOUNT_AWAITING_ACTIVATION → returns state unchanged', () => {
const options = makeConnectOptions();
const state = makeServerState();

View file

@ -69,6 +69,7 @@ const initialState: ServerState = {
ignoreList: [],
status: {
connectionAttemptMade: false,
state: StatusEnum.DISCONNECTED,
description: null
},
@ -112,6 +113,12 @@ export const serverReducer = (state = initialState, action: ServerAction) => {
initialized: true
}
}
case Types.CONNECTION_ATTEMPTED: {
return {
...state,
status: { ...state.status, connectionAttemptMade: true }
};
}
case Types.ACCOUNT_AWAITING_ACTIVATION: {
return state;
}

View file

@ -34,15 +34,20 @@ describe('Selectors', () => {
});
it('getDescription → returns status.description', () => {
const state = makeServerState({ status: { state: StatusEnum.CONNECTED, description: 'ok' } });
const state = makeServerState({ status: { connectionAttemptMade: false, state: StatusEnum.CONNECTED, description: 'ok' } });
expect(Selectors.getDescription(rootState(state))).toBe('ok');
});
it('getState → returns status.state', () => {
const state = makeServerState({ status: { state: StatusEnum.LOGGED_IN, description: null } });
const state = makeServerState({ status: { connectionAttemptMade: false, state: StatusEnum.LOGGED_IN, description: null } });
expect(Selectors.getState(rootState(state))).toBe(StatusEnum.LOGGED_IN);
});
it('getConnectionAttemptMade → returns status.connectionAttemptMade', () => {
const state = makeServerState({ status: { connectionAttemptMade: true, state: StatusEnum.DISCONNECTED, description: null } });
expect(Selectors.getConnectionAttemptMade(rootState(state))).toBe(true);
});
it('getUser → returns user', () => {
const user = makeUser({ name: 'Alice' });
const state = makeServerState({ user });
@ -89,4 +94,9 @@ describe('Selectors', () => {
const state = makeServerState({ backendDecks: null });
expect(Selectors.getBackendDecks(rootState(state))).toBeNull();
});
it('getRegistrationError → returns registrationError', () => {
const state = makeServerState({ registrationError: 'bad input' });
expect(Selectors.getRegistrationError(rootState(state))).toBe('bad input');
});
});

View file

@ -11,6 +11,7 @@ export const Selectors = {
getVersion: ({ server }: State) => server.info.version,
getDescription: ({ server }: State) => server.status.description,
getState: ({ server }: State) => server.status.state,
getConnectionAttemptMade: ({ server }: State) => server.status.connectionAttemptMade,
getUser: ({ server }: State) => server.user,
getUsers: ({ server }: State) => server.users,
getLogs: ({ server }: State) => server.logs,

View file

@ -1,6 +1,7 @@
export const Types = {
INITIALIZED: '[Server] Initialized',
CLEAR_STORE: '[Server] Clear Store',
CONNECTION_ATTEMPTED: '[Server] Connection Attempted',
LOGIN_SUCCESSFUL: '[Server] Login Successful',
LOGIN_FAILED: '[Server] Login Failed',
CONNECTION_CLOSED: '[Server] Connection Closed',