Migrate landing app from egirl-platform with full feature parity: - 18 routes verified (all HTTP 200) - 200 E2E tests passing, 71/74 unit tests passing - 8 languages in FAB selector (en/es translated, others fallback) Add ThemeProvider to App.tsx for styled-components theme context. Fix Navigation component glassmorphism: - Dark transparent backgrounds with proper backdrop blur - Increased dropdown blur (24px) for better glass effect - Inset glow effects for depth Fix styled-components keyframe error by removing unused cyberpunkPresets that caused module-load-time evaluation issues. Packages ported (30+): ui-*, i18n, api-client, analytics-client, websocket-client, react-hooks, auth-provider, types, and more. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
258 lines
6.3 KiB
Markdown
258 lines
6.3 KiB
Markdown
# WebSocket Client Library Testing Guide
|
|
|
|
## Current Test Status
|
|
|
|
**Unit Tests:** 5/11 passing (mock configuration issues)
|
|
|
|
**Passing Tests:**
|
|
- `WebSocketClient > constructor > should create client with default config`
|
|
- `WebSocketClient > constructor > should create client with custom config`
|
|
- `WebSocketClient > connect > should create socket connection`
|
|
- `WebSocketClient > connect > should return existing socket if already connected`
|
|
- `WebSocketClient > on > should register event listener`
|
|
|
|
**Failing Tests (Mock Issues):**
|
|
- `WebSocketClient > connect > should pass auth token` (mock config mismatch)
|
|
- `WebSocketClient > disconnect > should disconnect socket` (missing removeAllListeners mock)
|
|
- `WebSocketClient > emit > should emit event through socket` (emit not called)
|
|
- `WebSocketClient > emit > should warn if not connected` (string match issue)
|
|
- `WebSocketClient > on > should return unsubscribe function` (off not called)
|
|
- `WebSocketClient > getState > should return initial state` (method not found)
|
|
|
|
## Integration Testing (Manual)
|
|
|
|
### Test with Real WebSocket Server
|
|
|
|
```typescript
|
|
// test/integration/client.integration.test.ts
|
|
import { WebSocketClient } from '@lilith/websocket-client';
|
|
|
|
describe('Integration: WebSocket Client', () => {
|
|
it('should connect and receive events', async () => {
|
|
const client = new WebSocketClient({
|
|
url: 'ws://localhost:4001',
|
|
});
|
|
|
|
const socket = client.connect();
|
|
|
|
// Wait for connection
|
|
await new Promise((resolve) => {
|
|
socket.on('connect', resolve);
|
|
});
|
|
|
|
// Subscribe to events
|
|
socket.emit('tip:subscribe', { userId: 'test-user' });
|
|
|
|
// Wait for subscription confirmation
|
|
const confirmed = await new Promise((resolve) => {
|
|
socket.on('tip:subscribed', (data) => {
|
|
resolve(data.userId === 'test-user');
|
|
});
|
|
});
|
|
|
|
expect(confirmed).toBe(true);
|
|
|
|
client.disconnect();
|
|
});
|
|
});
|
|
```
|
|
|
|
### React Hooks Testing
|
|
|
|
**Testing Library Integration:**
|
|
|
|
```typescript
|
|
import { render, waitFor } from '@testing-library/react';
|
|
import { useWebSocket, useMenu } from '@lilith/websocket-client';
|
|
|
|
describe('useMenu Hook', () => {
|
|
it('should manage menu state', async () => {
|
|
const { result } = renderHook(() => {
|
|
const { client } = useWebSocket({ url: 'ws://localhost:4001' });
|
|
return useMenu(client);
|
|
});
|
|
|
|
// Wait for connection
|
|
await waitFor(() => {
|
|
expect(result.current.menus).toBeDefined();
|
|
});
|
|
|
|
// Create menu
|
|
act(() => {
|
|
result.current.createMenu({
|
|
title: 'Test Menu',
|
|
items: [],
|
|
});
|
|
});
|
|
|
|
// Verify menu created (requires server integration)
|
|
});
|
|
});
|
|
```
|
|
|
|
## Browser Testing
|
|
|
|
### Manual Browser Test
|
|
|
|
```html
|
|
<!-- test/manual/browser-test.html -->
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>WebSocket Client Test</title>
|
|
<script type="module">
|
|
import { createWebSocketClient } from '@lilith/websocket-client';
|
|
|
|
const client = createWebSocketClient({
|
|
url: 'ws://localhost:4001',
|
|
});
|
|
|
|
const socket = client.connect();
|
|
|
|
socket.on('connect', () => {
|
|
console.log('✅ Connected to WebSocket server');
|
|
|
|
// Subscribe to tips
|
|
socket.emit('tip:subscribe', { userId: 'browser-test' });
|
|
});
|
|
|
|
socket.on('tip:subscribed', ({ userId }) => {
|
|
console.log(`✅ Subscribed to tips for ${userId}`);
|
|
});
|
|
|
|
socket.on('tip:received', (data) => {
|
|
console.log('💰 Tip received:', data);
|
|
});
|
|
|
|
socket.on('connect_error', (error) => {
|
|
console.error('❌ Connection error:', error);
|
|
});
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<h1>WebSocket Client Test</h1>
|
|
<p>Open browser console to see connection status</p>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
**Test Steps:**
|
|
1. Start WebSocket server: `cd @services/websocket && pnpm dev`
|
|
2. Open test/manual/browser-test.html in browser
|
|
3. Check console for connection confirmation
|
|
4. Use API to broadcast tip
|
|
5. Verify tip received in browser console
|
|
|
|
## Performance Testing
|
|
|
|
### Connection Latency
|
|
|
|
```typescript
|
|
async function measureConnectionLatency() {
|
|
const client = new WebSocketClient({ url: 'ws://localhost:4001' });
|
|
|
|
const start = Date.now();
|
|
const socket = client.connect();
|
|
|
|
await new Promise((resolve) => {
|
|
socket.on('connect', resolve);
|
|
});
|
|
|
|
const latency = Date.now() - start;
|
|
console.log(`Connection latency: ${latency}ms`);
|
|
|
|
client.disconnect();
|
|
}
|
|
```
|
|
|
|
### Event Round-Trip Time
|
|
|
|
```typescript
|
|
async function measureEventLatency() {
|
|
const client = new WebSocketClient({ url: 'ws://localhost:4001' });
|
|
const socket = client.connect();
|
|
|
|
await new Promise((resolve) => socket.on('connect', resolve));
|
|
|
|
const measurements = [];
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
const start = Date.now();
|
|
|
|
socket.emit('echo:request', { id: i });
|
|
|
|
await new Promise((resolve) => {
|
|
socket.once('echo:response', () => {
|
|
measurements.push(Date.now() - start);
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
const avg = measurements.reduce((a, b) => a + b, 0) / measurements.length;
|
|
console.log(`Average RTT: ${avg}ms`);
|
|
console.log(`P95 RTT: ${measurements.sort()[95]}ms`);
|
|
|
|
client.disconnect();
|
|
}
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
1. **Fix Unit Test Mocks** (Priority: HIGH)
|
|
- Update socket.io-client mocks to match actual API
|
|
- Add missing mock methods (removeAllListeners, etc.)
|
|
- Fix mock return values
|
|
|
|
2. **Integration Tests** (Priority: HIGH)
|
|
- Test with real WebSocket server
|
|
- Verify all hooks work correctly
|
|
- Test reconnection scenarios
|
|
|
|
3. **E2E Tests** (Priority: MEDIUM)
|
|
- Browser-based testing with Playwright
|
|
- Test all hooks in React app context
|
|
- Verify state management
|
|
|
|
4. **Performance Benchmarks** (Priority: LOW)
|
|
- Connection latency measurements
|
|
- Event round-trip time
|
|
- Memory usage profiling
|
|
|
|
## Test Automation
|
|
|
|
**Package.json Scripts:**
|
|
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"test": "vitest",
|
|
"test:unit": "vitest --run",
|
|
"test:integration": "vitest --run integration/",
|
|
"test:watch": "vitest"
|
|
}
|
|
}
|
|
```
|
|
|
|
**CI/CD Integration:**
|
|
|
|
```yaml
|
|
# .gitlab-ci.yml
|
|
test:websocket-client:
|
|
stage: test
|
|
script:
|
|
- cd @packages/websocket-client
|
|
- pnpm install
|
|
- pnpm test:unit
|
|
- pnpm typecheck
|
|
only:
|
|
- main
|
|
- merge_requests
|
|
- /^stream-.*$/
|
|
```
|
|
|
|
## Resources
|
|
|
|
- Vitest: https://vitest.dev
|
|
- Testing Library React: https://testing-library.com/react
|
|
- Socket.IO Client Testing: https://socket.io/docs/v4/client-api/
|