upgrade packages

This commit is contained in:
seavor 2026-04-15 18:06:39 -05:00
parent c62c336a11
commit ae1bc3da38
30 changed files with 1138 additions and 1783 deletions

View file

@ -17,14 +17,14 @@ import {
export function login(options: Omit<Enriched.LoginConnectOptions, 'password'>, password?: string, passwordSalt?: string): void {
const { userName, hashedPassword } = options;
const loginConfig: MessageInitShape<typeof Data.Command_LoginSchema> = {
const loginConfig = {
...CLIENT_CONFIG,
clientid: 'webatrice',
userName,
...(passwordSalt
? { hashedPassword: hashedPassword || hashPassword(passwordSalt, password) }
: { password }),
};
} satisfies MessageInitShape<typeof Data.Command_LoginSchema>;
const onLoginError = (message: string, extra?: () => void) => {
updateStatus(App.StatusEnum.DISCONNECTED, message);

View file

@ -1,6 +1,6 @@
import { GamePersistence } from '../../persistence';
import type { Data, Enriched } from '@app/types';
export function joinGame(data: { playerProperties: Data.ServerInfo_PlayerProperties }, meta: Enriched.GameEventMeta): void {
export function joinGame(data: Data.Event_Join, meta: Enriched.GameEventMeta): void {
GamePersistence.playerJoined(meta.gameId, data.playerProperties);
}

View file

@ -1,6 +1,6 @@
import type { Data, Enriched } from '@app/types';
import { GamePersistence } from '../../persistence';
export function playerPropertiesChanged(data: { playerProperties: Data.ServerInfo_PlayerProperties }, meta: Enriched.GameEventMeta): void {
export function playerPropertiesChanged(data: Data.Event_PlayerPropertiesChanged, meta: Enriched.GameEventMeta): void {
GamePersistence.playerPropertiesChanged(meta.gameId, meta.playerId, data.playerProperties);
}

View file

@ -204,6 +204,9 @@ describe('addToList', () => {
beforeEach(() => {
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
});
afterEach(() => {
logSpy.mockRestore();
});
it('buddy list → addToBuddyList', () => {
const data = create(Data.Event_AddToListSchema, {

View file

@ -1,5 +1,5 @@
vi.mock('@bufbuild/protobuf', () => ({
create: vi.fn((_schema: unknown, fields?: Record<string, unknown>) => ({ ...(fields ?? {}) })),
vi.mock('@bufbuild/protobuf', async (importOriginal) => ({
...(await importOriginal<typeof import('@bufbuild/protobuf')>()),
fromBinary: vi.fn(),
toBinary: vi.fn().mockReturnValue(new Uint8Array()),
hasExtension: vi.fn().mockReturnValue(false),
@ -7,20 +7,6 @@ vi.mock('@bufbuild/protobuf', () => ({
setExtension: vi.fn(),
}));
vi.mock('../../generated/proto/commands_pb', () => ({
CommandContainerSchema: {},
}));
vi.mock('../../generated/proto/server_message_pb', () => ({
ServerMessageSchema: {},
ServerMessage_MessageType: {
RESPONSE: 1,
ROOM_EVENT: 2,
SESSION_EVENT: 3,
GAME_EVENT_CONTAINER: 4,
},
}));
vi.mock('../events', () => ({
GameEvents: [],
RoomEvents: [],
@ -40,6 +26,7 @@ import { GameEvents, RoomEvents, SessionEvents } from '../events';
import type { GameExtensionRegistry } from '../events/game';
import type { RoomExtensionRegistry } from '../events/room';
import type { SessionExtensionRegistry } from '../events/session';
import { withEventRegistry } from '../../__test-utils__';
import { Data } from '@app/types';
@ -53,12 +40,20 @@ type ProtobufInternal = ProtobufService & {
};
let mockSocket: { isOpen: ReturnType<typeof vi.fn>; send: ReturnType<typeof vi.fn> };
let registryTeardowns: Array<() => void>;
beforeEach(() => {
mockSocket = {
isOpen: vi.fn().mockReturnValue(true),
send: vi.fn(),
};
registryTeardowns = [];
});
afterEach(() => {
while (registryTeardowns.length > 0) {
registryTeardowns.pop()!();
}
});
describe('ProtobufService', () => {
@ -348,8 +343,7 @@ describe('ProtobufService', () => {
const mockExt = {} as GenExtension<Data.GameEvent, unknown>;
const payload = { someData: 1 };
// Temporarily override GameEvents for this test
(GameEvents as GameExtensionRegistry).push([mockExt, handler]);
registryTeardowns.push(withEventRegistry(GameEvents as GameExtensionRegistry, [mockExt, handler]));
vi.mocked(hasExtension).mockReturnValue(true);
vi.mocked(getExtension).mockReturnValue(payload);
@ -359,7 +353,6 @@ describe('ProtobufService', () => {
}, {});
expect(handler).toHaveBeenCalledWith(payload, expect.objectContaining({ gameId: 42, playerId: 5 }));
(GameEvents as GameExtensionRegistry).pop();
});
it('defaults gameId and playerId to -1 when undefined', () => {
@ -368,7 +361,7 @@ describe('ProtobufService', () => {
const mockExt = {} as GenExtension<Data.GameEvent, unknown>;
const payload = { someData: 1 };
(GameEvents as GameExtensionRegistry).push([mockExt, handler]);
registryTeardowns.push(withEventRegistry(GameEvents as GameExtensionRegistry, [mockExt, handler]));
vi.mocked(hasExtension).mockReturnValue(true);
vi.mocked(getExtension).mockReturnValue(payload);
@ -378,7 +371,6 @@ describe('ProtobufService', () => {
});
expect(handler).toHaveBeenCalledWith(payload, expect.objectContaining({ gameId: -1, playerId: -1 }));
(GameEvents as GameExtensionRegistry).pop();
});
});
@ -405,7 +397,7 @@ describe('ProtobufService', () => {
const mockExt = {} as GenExtension<Data.RoomEvent, unknown>;
const payload = { roomData: 1 };
(RoomEvents as RoomExtensionRegistry).push([mockExt, handler]);
registryTeardowns.push(withEventRegistry(RoomEvents as RoomExtensionRegistry, [mockExt, handler]));
vi.mocked(hasExtension).mockReturnValue(true);
vi.mocked(getExtension).mockReturnValue(payload);
@ -413,7 +405,6 @@ describe('ProtobufService', () => {
(service as ProtobufInternal).processRoomEvent(event);
expect(handler).toHaveBeenCalledWith(payload, event);
(RoomEvents as RoomExtensionRegistry).pop();
});
});
@ -431,14 +422,13 @@ describe('ProtobufService', () => {
const mockExt = {} as GenExtension<Data.SessionEvent, unknown>;
const payload = { sessionData: 1 };
(SessionEvents as SessionExtensionRegistry).push([mockExt, handler]);
registryTeardowns.push(withEventRegistry(SessionEvents as SessionExtensionRegistry, [mockExt, handler]));
vi.mocked(hasExtension).mockReturnValue(true);
vi.mocked(getExtension).mockReturnValue(payload);
(service as ProtobufInternal).processSessionEvent({ sessionId: 7 });
expect(handler).toHaveBeenCalledWith(payload);
(SessionEvents as SessionExtensionRegistry).pop();
expect(handler).toHaveBeenCalledWith(payload, undefined);
});
});

View file

@ -175,7 +175,7 @@ export class ProtobufService {
}
for (const [ext, handler] of SessionEvents) {
if (hasExtension(event, ext)) {
handler(getExtension(event, ext));
handler(getExtension(event, ext), undefined);
return;
}
}

View file

@ -1,4 +1,5 @@
import { installMockWebSocket } from '../__mocks__/helpers';
import { withMockLocation } from '../../__test-utils__';
import { Mock } from 'vitest';
vi.mock('../WebClient', () => ({
@ -37,6 +38,7 @@ let MockWS: Mock;
let mockInstance: ReturnType<typeof installMockWebSocket>['mockInstance'];
let restoreWebSocket: ReturnType<typeof installMockWebSocket>['restore'];
let mockConfig: WebSocketServiceConfig;
let locationRestores: Array<() => void>;
beforeEach(() => {
vi.useFakeTimers();
@ -49,9 +51,14 @@ beforeEach(() => {
mockConfig = {
keepAliveFn: vi.fn(),
};
locationRestores = [];
});
afterEach(() => {
while (locationRestores.length > 0) {
locationRestores.pop()!();
}
restoreWebSocket();
vi.useRealTimers();
});
@ -88,22 +95,14 @@ describe('WebSocketService', () => {
describe('connect', () => {
it('creates a WebSocket with wss protocol by default', () => {
const service = new WebSocketService(mockConfig);
Object.defineProperty(window, 'location', {
value: { hostname: 'example.com' },
writable: true,
configurable: true,
});
locationRestores.push(withMockLocation({ hostname: 'example.com' }));
service.connect({ host: 'example.com', port: '8080' });
expect(MockWS).toHaveBeenCalledWith('wss://example.com:8080');
});
it('switches to ws protocol when hostname is localhost', () => {
const service = new WebSocketService(mockConfig);
Object.defineProperty(window, 'location', {
value: { hostname: 'localhost' },
writable: true,
configurable: true,
});
locationRestores.push(withMockLocation({ hostname: 'localhost' }));
service.connect({ host: 'somehost', port: '1234' });
expect(MockWS).toHaveBeenCalledWith('ws://somehost:1234');
});
@ -243,22 +242,14 @@ describe('WebSocketService', () => {
describe('testConnect', () => {
it('creates a test WebSocket with correct URL', () => {
const service = new WebSocketService(mockConfig);
Object.defineProperty(window, 'location', {
value: { hostname: 'example.com' },
writable: true,
configurable: true,
});
locationRestores.push(withMockLocation({ hostname: 'example.com' }));
service.testConnect({ host: 'example.com', port: '9000' });
expect(MockWS).toHaveBeenCalledWith('wss://example.com:9000');
});
it('uses ws protocol on localhost', () => {
const service = new WebSocketService(mockConfig);
Object.defineProperty(window, 'location', {
value: { hostname: 'localhost' },
writable: true,
configurable: true,
});
locationRestores.push(withMockLocation({ hostname: 'localhost' }));
service.testConnect({ host: 'h', port: '1' });
expect(MockWS).toHaveBeenCalledWith('ws://h:1');
});

View file

@ -65,7 +65,7 @@ export class WebSocketService {
}
public send(message: Uint8Array): void {
this.socket.send(message);
this.socket.send(message as unknown as ArrayBufferView);
}
private createWebSocket(url: string): WebSocket {

View file

@ -9,9 +9,11 @@ import { create, getExtension } from '@bufbuild/protobuf';
import { handleResponse } from './command-options';
beforeEach(() => {
vi.resetAllMocks();
});
// NOTE: do NOT call `vi.resetAllMocks()` here — under `isolate: false` it
// resets `vi.fn()` implementations set inside other files' `vi.mock(...)`
// factories, which breaks any spec that relied on those factory defaults
// (e.g. ProtobufService.spec.ts expects `hasExtension` to return `false`).
// The root `setupTests.ts` afterEach already calls `vi.clearAllMocks()`.
describe('handleResponse', () => {
it('calls onResponse and returns early when provided', () => {

View file

@ -1,4 +1,5 @@
vi.mock('../../generated/proto/event_server_identification_pb', () => ({
vi.mock('../../generated/proto/event_server_identification_pb', async (importOriginal) => ({
...(await importOriginal<typeof import('../../generated/proto/event_server_identification_pb')>()),
Event_ServerIdentification_ServerOptions: { SupportsPasswordHash: 2 },
}));