Files
ruvnet--RuView/ui/mobile/src/__tests__/services/simulation.service.test.ts
T
rUv d4fb7d30d3 fix: complete sensing server API, WebSocket connectivity, and mobile tests (#125)
The web UI had persistent 404 errors on model, recording, and training
endpoints, and the sensing WebSocket never connected on Dashboard/Live
Demo tabs because sensingService.start() was only called lazily on
Sensing tab visit.

Server (main.rs):
- Add 14 fully-functional Axum handlers: model CRUD (7), recording
  lifecycle (4), training control (3)
- Scan data/models/ and data/recordings/ at startup
- Recording writes CSI frames to .jsonl via tokio background task
- Model load/unload lifecycle with state tracking

Web UI (app.js):
- Import and start sensingService early in initializeServices() so
  Dashboard and Live Demo tabs connect to /ws/sensing immediately

Mobile (ws.service.ts):
- Fix WebSocket URL builder to use same-origin port instead of
  hardcoded port 3001

Mobile (jest.config.js):
- Fix testPathIgnorePatterns that was ignoring the entire test directory

Mobile (25 test files):
- Replace all it.todo() placeholder tests with real implementations
  covering components, services, stores, hooks, screens, and utils

ADR-043 documents all changes.
2026-03-03 13:27:03 -05:00

89 lines
3.4 KiB
TypeScript

import { generateSimulatedData } from '@/services/simulation.service';
describe('generateSimulatedData', () => {
it('returns a valid SensingFrame shape', () => {
const frame = generateSimulatedData();
expect(frame).toHaveProperty('type', 'sensing_update');
expect(frame).toHaveProperty('timestamp');
expect(frame).toHaveProperty('source', 'simulated');
expect(typeof frame.tick).toBe('number');
});
it('has a nodes array with at least one node', () => {
const frame = generateSimulatedData();
expect(Array.isArray(frame.nodes)).toBe(true);
expect(frame.nodes.length).toBeGreaterThanOrEqual(1);
const node = frame.nodes[0];
expect(typeof node.node_id).toBe('number');
expect(typeof node.rssi_dbm).toBe('number');
expect(Array.isArray(node.position)).toBe(true);
expect(node.position).toHaveLength(3);
});
it('has features object with expected numeric fields', () => {
const frame = generateSimulatedData();
const { features } = frame;
expect(typeof features.mean_rssi).toBe('number');
expect(typeof features.variance).toBe('number');
expect(typeof features.motion_band_power).toBe('number');
expect(typeof features.breathing_band_power).toBe('number');
expect(typeof features.spectral_entropy).toBe('number');
expect(typeof features.std).toBe('number');
expect(typeof features.dominant_freq_hz).toBe('number');
});
it('has classification with valid motion_level', () => {
const frame = generateSimulatedData();
const { classification } = frame;
expect(['absent', 'present_still', 'active']).toContain(classification.motion_level);
expect(typeof classification.presence).toBe('boolean');
expect(typeof classification.confidence).toBe('number');
expect(classification.confidence).toBeGreaterThanOrEqual(0);
expect(classification.confidence).toBeLessThanOrEqual(1);
});
it('has signal_field with correct grid_size', () => {
const frame = generateSimulatedData();
const { signal_field } = frame;
expect(signal_field.grid_size).toEqual([20, 1, 20]);
expect(Array.isArray(signal_field.values)).toBe(true);
expect(signal_field.values.length).toBe(20 * 20);
});
it('has signal_field values clamped between 0 and 1', () => {
const frame = generateSimulatedData();
for (const v of frame.signal_field.values) {
expect(v).toBeGreaterThanOrEqual(0);
expect(v).toBeLessThanOrEqual(1);
}
});
it('has vital_signs present', () => {
const frame = generateSimulatedData();
expect(frame.vital_signs).toBeDefined();
expect(typeof frame.vital_signs!.breathing_bpm).toBe('number');
expect(typeof frame.vital_signs!.hr_proxy_bpm).toBe('number');
expect(typeof frame.vital_signs!.confidence).toBe('number');
});
it('has estimated_persons field', () => {
const frame = generateSimulatedData();
expect(typeof frame.estimated_persons).toBe('number');
expect(frame.estimated_persons).toBeGreaterThanOrEqual(0);
});
it('produces different data for different timestamps', () => {
const frame1 = generateSimulatedData(1000);
const frame2 = generateSimulatedData(5000);
// The RSSI values should differ since the simulation is time-based
expect(frame1.features.mean_rssi).not.toBe(frame2.features.mean_rssi);
});
it('accepts a custom timeMs parameter', () => {
const t = 1700000000000;
const frame = generateSimulatedData(t);
expect(frame.timestamp).toBe(t);
});
});