FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
hydration.test.ts
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
3
4import { describe, expect, test } from 'bun:test';
5import { defaultGlobalParameters } from './defaults';
6import { buildHydratedScenarioState } from './hydration';
7import { ScenarioData, ScenarioState } from './types';
8
9function createScenarioData(): ScenarioData {
10 return {
11 globalParameters: {
12 ...defaultGlobalParameters,
13 start: 5,
14 end: 20,
15 },
16 waveforms: [],
17 timings: [],
18 antennas: [],
19 platforms: [
20 {
21 id: 'platform-1',
22 type: 'Platform',
23 name: 'Platform 1',
24 motionPath: {
25 interpolation: 'static',
26 waypoints: [
27 {
28 id: 'waypoint-1',
29 x: 0,
30 y: 0,
31 altitude: 0,
32 time: 0,
33 },
34 ],
35 },
36 rotation: {
37 type: 'fixed',
38 startAzimuth: 0,
39 startElevation: 0,
40 azimuthRate: 0,
41 elevationRate: 0,
42 },
43 components: [
44 {
45 id: 'component-1',
46 type: 'transmitter',
47 name: 'TX 1',
48 radarType: 'pulsed',
49 prf: 1000,
50 antennaId: null,
51 waveformId: null,
52 timingId: null,
53 schedule: [],
54 },
55 ],
56 },
57 ],
58 };
59}
60
61function createState(overrides: Partial<ScenarioState> = {}): ScenarioState {
62 return {
63 globalParameters: defaultGlobalParameters,
64 waveforms: [],
65 timings: [],
66 antennas: [],
67 platforms: [],
68 selectedItemId: null,
69 selectedComponentId: null,
70 isDirty: false,
71 isPlaying: false,
72 currentTime: 0,
73 targetPlaybackDuration: null,
74 isBackendSyncing: false,
75 backendVersion: 0,
76 scenarioFilePath: null,
77 outputDirectory: null,
78 antennaPreviewErrors: {},
79 notificationSnackbar: {
80 open: false,
81 message: '',
82 severity: 'error',
83 },
84 notificationQueue: [],
85 viewControlAction: { type: null, timestamp: 0 },
86 visibility: {
87 showAxes: true,
88 showPatterns: true,
89 showBoresights: true,
90 showLinks: true,
91 showLinkLabels: true,
92 showLinkMonostatic: true,
93 showLinkIlluminator: true,
94 showLinkScattered: true,
95 showLinkDirect: true,
96 showVelocities: true,
97 showPlatforms: true,
98 showPlatformLabels: true,
99 showMotionPaths: true,
100 },
101 ...overrides,
102 };
103}
104
105describe('buildHydratedScenarioState', () => {
106 test('preserves selection and clamps current time during backend recovery', () => {
107 const hydrated = buildHydratedScenarioState(
108 createState({
109 selectedItemId: 'platform-1',
110 selectedComponentId: 'component-1',
111 currentTime: 99,
112 }),
113 createScenarioData(),
114 {
115 isDirty: false,
116 preserveSelection: true,
117 preserveCurrentTime: true,
118 }
119 );
120
121 expect(hydrated.selectedItemId).toBe('platform-1');
122 expect(hydrated.selectedComponentId).toBe('component-1');
123 expect(hydrated.currentTime).toBe(20);
124 expect(hydrated.isDirty).toBe(false);
125 });
126
127 test('clears stale selection and resets time for import-style loads', () => {
128 const hydrated = buildHydratedScenarioState(
129 createState({
130 selectedItemId: 'missing-platform',
131 selectedComponentId: 'missing-component',
132 currentTime: 12,
133 }),
134 createScenarioData(),
135 {
136 isDirty: true,
137 }
138 );
139
140 expect(hydrated.selectedItemId).toBeNull();
141 expect(hydrated.selectedComponentId).toBeNull();
142 expect(hydrated.currentTime).toBe(5);
143 expect(hydrated.isDirty).toBe(true);
144 });
145});