@ingissa/navcore-simulator 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +3 -3
  2. package/README.md +161 -356
  3. package/dist/index.d.mts +87 -0
  4. package/dist/{simulator/src/react-native/useSimulator.d.ts → index.d.ts} +37 -9
  5. package/dist/index.js +1393 -0
  6. package/dist/index.mjs +1383 -0
  7. package/dist/node.d.mts +527 -0
  8. package/dist/node.d.ts +527 -0
  9. package/dist/node.js +957 -0
  10. package/dist/node.mjs +949 -0
  11. package/dist/react-native.d.mts +4 -0
  12. package/dist/react-native.d.ts +4 -0
  13. package/dist/react-native.js +1393 -0
  14. package/dist/react-native.mjs +1383 -0
  15. package/package.json +61 -58
  16. package/dist/core/src/NavCore.d.ts +0 -142
  17. package/dist/core/src/NavCore.d.ts.map +0 -1
  18. package/dist/core/src/NavCore.js +0 -390
  19. package/dist/core/src/bearing/BearingEngine.d.ts +0 -24
  20. package/dist/core/src/bearing/BearingEngine.d.ts.map +0 -1
  21. package/dist/core/src/bearing/BearingEngine.js +0 -50
  22. package/dist/core/src/constants.d.ts +0 -34
  23. package/dist/core/src/constants.d.ts.map +0 -1
  24. package/dist/core/src/constants.js +0 -41
  25. package/dist/core/src/corridor/DeviationDetector.d.ts +0 -33
  26. package/dist/core/src/corridor/DeviationDetector.d.ts.map +0 -1
  27. package/dist/core/src/corridor/DeviationDetector.js +0 -83
  28. package/dist/core/src/corridor/DynamicCorridor.d.ts +0 -13
  29. package/dist/core/src/corridor/DynamicCorridor.d.ts.map +0 -1
  30. package/dist/core/src/corridor/DynamicCorridor.js +0 -26
  31. package/dist/core/src/dead-reckoning/DeadReckoning.d.ts +0 -35
  32. package/dist/core/src/dead-reckoning/DeadReckoning.d.ts.map +0 -1
  33. package/dist/core/src/dead-reckoning/DeadReckoning.js +0 -49
  34. package/dist/core/src/directions/DirectionsProvider.d.ts +0 -70
  35. package/dist/core/src/directions/DirectionsProvider.d.ts.map +0 -1
  36. package/dist/core/src/directions/DirectionsProvider.js +0 -7
  37. package/dist/core/src/directions/OSRMDirectionsProvider.d.ts +0 -26
  38. package/dist/core/src/directions/OSRMDirectionsProvider.d.ts.map +0 -1
  39. package/dist/core/src/directions/OSRMDirectionsProvider.js +0 -90
  40. package/dist/core/src/directions/OpenRouteServiceProvider.d.ts +0 -30
  41. package/dist/core/src/directions/OpenRouteServiceProvider.d.ts.map +0 -1
  42. package/dist/core/src/directions/OpenRouteServiceProvider.js +0 -111
  43. package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts +0 -33
  44. package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts.map +0 -1
  45. package/dist/core/src/directions/ValhallaDirectionsProvider.js +0 -155
  46. package/dist/core/src/eta/ETAEngine.d.ts +0 -61
  47. package/dist/core/src/eta/ETAEngine.d.ts.map +0 -1
  48. package/dist/core/src/eta/ETAEngine.js +0 -74
  49. package/dist/core/src/features.d.ts +0 -76
  50. package/dist/core/src/features.d.ts.map +0 -1
  51. package/dist/core/src/features.js +0 -76
  52. package/dist/core/src/geo/bearing.d.ts +0 -11
  53. package/dist/core/src/geo/bearing.d.ts.map +0 -1
  54. package/dist/core/src/geo/bearing.js +0 -25
  55. package/dist/core/src/geo/cumulative.d.ts +0 -9
  56. package/dist/core/src/geo/cumulative.d.ts.map +0 -1
  57. package/dist/core/src/geo/cumulative.js +0 -20
  58. package/dist/core/src/geo/haversine.d.ts +0 -13
  59. package/dist/core/src/geo/haversine.d.ts.map +0 -1
  60. package/dist/core/src/geo/haversine.js +0 -39
  61. package/dist/core/src/geo/projection.d.ts +0 -7
  62. package/dist/core/src/geo/projection.d.ts.map +0 -1
  63. package/dist/core/src/geo/projection.js +0 -17
  64. package/dist/core/src/geofencing/GeofencingEngine.d.ts +0 -93
  65. package/dist/core/src/geofencing/GeofencingEngine.d.ts.map +0 -1
  66. package/dist/core/src/geofencing/GeofencingEngine.js +0 -154
  67. package/dist/core/src/index.d.ts +0 -66
  68. package/dist/core/src/index.d.ts.map +0 -1
  69. package/dist/core/src/index.js +0 -62
  70. package/dist/core/src/kalman/KalmanFilter2D.d.ts +0 -46
  71. package/dist/core/src/kalman/KalmanFilter2D.d.ts.map +0 -1
  72. package/dist/core/src/kalman/KalmanFilter2D.js +0 -77
  73. package/dist/core/src/license/LicenseManager.d.ts +0 -40
  74. package/dist/core/src/license/LicenseManager.d.ts.map +0 -1
  75. package/dist/core/src/license/LicenseManager.js +0 -119
  76. package/dist/core/src/license/verifyP256Signature.d.ts +0 -2
  77. package/dist/core/src/license/verifyP256Signature.d.ts.map +0 -1
  78. package/dist/core/src/license/verifyP256Signature.js +0 -26
  79. package/dist/core/src/off-route/NavigationFSM.d.ts +0 -42
  80. package/dist/core/src/off-route/NavigationFSM.d.ts.map +0 -1
  81. package/dist/core/src/off-route/NavigationFSM.js +0 -56
  82. package/dist/core/src/off-route/OffRouteFSM.d.ts +0 -70
  83. package/dist/core/src/off-route/OffRouteFSM.d.ts.map +0 -1
  84. package/dist/core/src/off-route/OffRouteFSM.js +0 -151
  85. package/dist/core/src/predictor/RouteOffsetPredictor.d.ts +0 -24
  86. package/dist/core/src/predictor/RouteOffsetPredictor.d.ts.map +0 -1
  87. package/dist/core/src/predictor/RouteOffsetPredictor.js +0 -55
  88. package/dist/core/src/progress/InstructionEditor.d.ts +0 -77
  89. package/dist/core/src/progress/InstructionEditor.d.ts.map +0 -1
  90. package/dist/core/src/progress/InstructionEditor.js +0 -151
  91. package/dist/core/src/progress/InstructionResolver.d.ts +0 -25
  92. package/dist/core/src/progress/InstructionResolver.d.ts.map +0 -1
  93. package/dist/core/src/progress/InstructionResolver.js +0 -78
  94. package/dist/core/src/progress/ProgressTracker.d.ts +0 -12
  95. package/dist/core/src/progress/ProgressTracker.d.ts.map +0 -1
  96. package/dist/core/src/progress/ProgressTracker.js +0 -22
  97. package/dist/core/src/renderer/MapRendererAdapter.d.ts +0 -72
  98. package/dist/core/src/renderer/MapRendererAdapter.d.ts.map +0 -1
  99. package/dist/core/src/renderer/MapRendererAdapter.js +0 -19
  100. package/dist/core/src/route-builder/CustomRouteBuilder.d.ts +0 -83
  101. package/dist/core/src/route-builder/CustomRouteBuilder.d.ts.map +0 -1
  102. package/dist/core/src/route-builder/CustomRouteBuilder.js +0 -160
  103. package/dist/core/src/route-plan/RoutePlan.d.ts +0 -38
  104. package/dist/core/src/route-plan/RoutePlan.d.ts.map +0 -1
  105. package/dist/core/src/route-plan/RoutePlan.js +0 -102
  106. package/dist/core/src/session/NavigationSession.d.ts +0 -81
  107. package/dist/core/src/session/NavigationSession.d.ts.map +0 -1
  108. package/dist/core/src/session/NavigationSession.js +0 -115
  109. package/dist/core/src/snapper/ParallelRoadResolver.d.ts +0 -86
  110. package/dist/core/src/snapper/ParallelRoadResolver.d.ts.map +0 -1
  111. package/dist/core/src/snapper/ParallelRoadResolver.js +0 -83
  112. package/dist/core/src/snapper/RouteSnapper.d.ts +0 -38
  113. package/dist/core/src/snapper/RouteSnapper.d.ts.map +0 -1
  114. package/dist/core/src/snapper/RouteSnapper.js +0 -80
  115. package/dist/core/src/voice/VoiceTriggerEngine.d.ts +0 -80
  116. package/dist/core/src/voice/VoiceTriggerEngine.d.ts.map +0 -1
  117. package/dist/core/src/voice/VoiceTriggerEngine.js +0 -108
  118. package/dist/simulator/src/core/NoiseEngine.d.ts +0 -46
  119. package/dist/simulator/src/core/NoiseEngine.d.ts.map +0 -1
  120. package/dist/simulator/src/core/NoiseEngine.js +0 -106
  121. package/dist/simulator/src/core/RouteWalker.d.ts +0 -78
  122. package/dist/simulator/src/core/RouteWalker.d.ts.map +0 -1
  123. package/dist/simulator/src/core/RouteWalker.js +0 -180
  124. package/dist/simulator/src/core/SimulatorEngine.d.ts +0 -53
  125. package/dist/simulator/src/core/SimulatorEngine.d.ts.map +0 -1
  126. package/dist/simulator/src/core/SimulatorEngine.js +0 -298
  127. package/dist/simulator/src/core/types.d.ts +0 -157
  128. package/dist/simulator/src/core/types.d.ts.map +0 -1
  129. package/dist/simulator/src/core/types.js +0 -7
  130. package/dist/simulator/src/fleet/FleetSimulator.d.ts +0 -60
  131. package/dist/simulator/src/fleet/FleetSimulator.d.ts.map +0 -1
  132. package/dist/simulator/src/fleet/FleetSimulator.js +0 -114
  133. package/dist/simulator/src/index.d.ts +0 -28
  134. package/dist/simulator/src/index.d.ts.map +0 -1
  135. package/dist/simulator/src/index.js +0 -29
  136. package/dist/simulator/src/node.d.ts +0 -26
  137. package/dist/simulator/src/node.d.ts.map +0 -1
  138. package/dist/simulator/src/node.js +0 -25
  139. package/dist/simulator/src/react-native/SimulatorControls.d.ts +0 -35
  140. package/dist/simulator/src/react-native/SimulatorControls.d.ts.map +0 -1
  141. package/dist/simulator/src/react-native/SimulatorControls.js +0 -254
  142. package/dist/simulator/src/react-native/useSimulator.d.ts.map +0 -1
  143. package/dist/simulator/src/react-native/useSimulator.js +0 -100
  144. package/dist/simulator/src/replay/GpxParser.d.ts +0 -40
  145. package/dist/simulator/src/replay/GpxParser.d.ts.map +0 -1
  146. package/dist/simulator/src/replay/GpxParser.js +0 -95
  147. package/dist/simulator/src/replay/SessionRecorder.d.ts +0 -37
  148. package/dist/simulator/src/replay/SessionRecorder.d.ts.map +0 -1
  149. package/dist/simulator/src/replay/SessionRecorder.js +0 -120
  150. package/dist/simulator/src/scenarios/ScenarioInjector.d.ts +0 -55
  151. package/dist/simulator/src/scenarios/ScenarioInjector.d.ts.map +0 -1
  152. package/dist/simulator/src/scenarios/ScenarioInjector.js +0 -150
  153. package/src/__tests__/integration/simulator-pipeline.test.ts +0 -233
  154. package/src/core/NoiseEngine.ts +0 -137
  155. package/src/core/RouteWalker.ts +0 -227
  156. package/src/core/SimulatorEngine.ts +0 -364
  157. package/src/core/__tests__/NoiseEngine.test.ts +0 -131
  158. package/src/core/__tests__/RouteWalker.test.ts +0 -139
  159. package/src/core/__tests__/SimulatorEngine.test.ts +0 -317
  160. package/src/core/types.ts +0 -191
  161. package/src/fleet/FleetSimulator.ts +0 -162
  162. package/src/index.ts +0 -54
  163. package/src/node.ts +0 -48
  164. package/src/react-native/SimulatorControls.tsx +0 -473
  165. package/src/react-native/useSimulator.ts +0 -155
  166. package/src/replay/GpxParser.ts +0 -122
  167. package/src/replay/SessionRecorder.ts +0 -138
  168. package/src/replay/__tests__/GpxParser.test.ts +0 -136
  169. package/src/scenarios/ScenarioInjector.ts +0 -170
  170. package/src/scenarios/__tests__/ScenarioInjector.test.ts +0 -171
@@ -1,170 +0,0 @@
1
- /**
2
- * ScenarioInjector — Registers and fires Scenario objects at geometry indices.
3
- *
4
- * Called internally by SimulatorEngine on each tick.
5
- * Also provides static factory methods for the built-in scenario types.
6
- */
7
-
8
- import type { Scenario } from '../core/types';
9
-
10
- export type ScenarioFireCallback = (scenario: Scenario) => void;
11
- export type ScenarioEndCallback = (scenario: Scenario) => void;
12
-
13
- export class ScenarioInjector {
14
- /** Map from triggerIndex → Scenario */
15
- private readonly scenarios = new Map<number, Scenario>();
16
- /** Tracks which scenarios have already fired (by name) to avoid double-fire */
17
- private readonly fired = new Set<string>();
18
- /** Currently active scenario, if any */
19
- private _activeScenario: Scenario | null = null;
20
- private _activeEndTimer: ReturnType<typeof setTimeout> | null = null;
21
-
22
- private onStart: ScenarioFireCallback;
23
- private onEnd: ScenarioEndCallback;
24
-
25
- constructor(onStart?: ScenarioFireCallback, onEnd?: ScenarioEndCallback) {
26
- this.onStart = onStart ?? (() => undefined);
27
- this.onEnd = onEnd ?? (() => undefined);
28
- }
29
-
30
- // ── Registration ────────────────────────────────────────────────────────────
31
-
32
- register(scenario: Scenario): void {
33
- this.scenarios.set(scenario.triggerIndex, scenario);
34
- }
35
-
36
- remove(name: string): void {
37
- for (const [idx, s] of this.scenarios) {
38
- if (s.name === name) {
39
- this.scenarios.delete(idx);
40
- break;
41
- }
42
- }
43
- }
44
-
45
- clear(): void {
46
- this.scenarios.clear();
47
- this.fired.clear();
48
- this._clearActiveTimer();
49
- this._activeScenario = null;
50
- }
51
-
52
- // ── Tick ────────────────────────────────────────────────────────────────────
53
-
54
- /**
55
- * Check and fire any scenario whose triggerIndex matches (or was passed) by
56
- * currentIndex. Called by SimulatorEngine on every tick.
57
- *
58
- * Returns the name of the active scenario (if any), for metadata injection.
59
- */
60
- tick(currentIndex: number): string | undefined {
61
- const floorIdx = Math.floor(currentIndex);
62
-
63
- for (const [triggerIdx, scenario] of this.scenarios) {
64
- if (floorIdx >= triggerIdx && !this.fired.has(scenario.name)) {
65
- this.fired.add(scenario.name);
66
- this._fire(scenario);
67
- }
68
- }
69
-
70
- return this._activeScenario?.name;
71
- }
72
-
73
- get activeScenario(): Scenario | null {
74
- return this._activeScenario;
75
- }
76
-
77
- /** Clean up any pending timers */
78
- destroy(): void {
79
- this._clearActiveTimer();
80
- }
81
-
82
- // ── Static factories ────────────────────────────────────────────────────────
83
-
84
- /**
85
- * GPS blackout: no position updates for `durationMs`.
86
- * Engine handles signal loss; this scenario signals the blackout period.
87
- */
88
- static gpsBlackout(atIndex: number, durationMs: number): Scenario {
89
- return {
90
- name: `gps-blackout-@${atIndex}`,
91
- triggerIndex: atIndex,
92
- type: 'GPS_BLACKOUT',
93
- durationMs,
94
- params: { durationMs },
95
- };
96
- }
97
-
98
- /**
99
- * Wrong-side road: offset the simulated position by `offsetM` metres
100
- * perpendicular to the route to stress-test the parallel road resolver.
101
- */
102
- static wrongSideRoad(atIndex: number, offsetM: number): Scenario {
103
- return {
104
- name: `wrong-side-@${atIndex}`,
105
- triggerIndex: atIndex,
106
- type: 'WRONG_SIDE_ROAD',
107
- params: { offsetM },
108
- };
109
- }
110
-
111
- /** U-turn at the given index — stress-tests U-turn protection. */
112
- static uTurn(atIndex: number): Scenario {
113
- return {
114
- name: `uturn-@${atIndex}`,
115
- triggerIndex: atIndex,
116
- type: 'UTURN',
117
- params: {},
118
- };
119
- }
120
-
121
- /** Speed spike: briefly report spikeKmh instead of the configured speed. */
122
- static speedSpike(atIndex: number, spikeKmh: number, durationMs = 2000): Scenario {
123
- return {
124
- name: `speed-spike-@${atIndex}`,
125
- triggerIndex: atIndex,
126
- type: 'SPEED_SPIKE',
127
- durationMs,
128
- params: { spikeKmh },
129
- };
130
- }
131
-
132
- /**
133
- * Accuracy drop: GPS accuracy degrades to newAccuracyM for durationMs.
134
- */
135
- static accuracyDrop(atIndex: number, newAccuracyM: number, durationMs: number): Scenario {
136
- return {
137
- name: `accuracy-drop-@${atIndex}`,
138
- triggerIndex: atIndex,
139
- type: 'ACCURACY_DROP',
140
- durationMs,
141
- params: { newAccuracyM },
142
- };
143
- }
144
-
145
- // ── Private ─────────────────────────────────────────────────────────────────
146
-
147
- private _fire(scenario: Scenario): void {
148
- this._activeScenario = scenario;
149
- try { this.onStart(scenario); } catch (_) { /* never throw from callback */ }
150
-
151
- if (scenario.durationMs != null && scenario.durationMs > 0) {
152
- this._clearActiveTimer();
153
- this._activeEndTimer = setTimeout(() => {
154
- this._activeScenario = null;
155
- try { this.onEnd(scenario); } catch (_) { /* never throw */ }
156
- }, scenario.durationMs);
157
- } else {
158
- // Instantaneous scenario — end immediately
159
- this._activeScenario = null;
160
- try { this.onEnd(scenario); } catch (_) { /* never throw */ }
161
- }
162
- }
163
-
164
- private _clearActiveTimer(): void {
165
- if (this._activeEndTimer !== null) {
166
- clearTimeout(this._activeEndTimer);
167
- this._activeEndTimer = null;
168
- }
169
- }
170
- }
@@ -1,171 +0,0 @@
1
- /**
2
- * ScenarioInjector unit tests
3
- */
4
- import { describe, it, expect, vi, beforeEach } from 'vitest';
5
- import { ScenarioInjector } from '@ingissa/navcore-simulator';
6
-
7
- describe('ScenarioInjector', () => {
8
- describe('register + tick', () => {
9
- it('fires callback at the correct index', () => {
10
- const onStart = vi.fn();
11
- const injector = new ScenarioInjector(onStart);
12
- const scenario = ScenarioInjector.gpsBlackout(5, 1000);
13
- injector.register(scenario);
14
-
15
- // Not yet
16
- injector.tick(3);
17
- expect(onStart).not.toHaveBeenCalled();
18
-
19
- // At trigger index
20
- injector.tick(5);
21
- expect(onStart).toHaveBeenCalledOnce();
22
- expect(onStart.mock.calls[0]![0].type).toBe('GPS_BLACKOUT');
23
- });
24
-
25
- it('fires when index passes the trigger (skipped frame)', () => {
26
- const onStart = vi.fn();
27
- const injector = new ScenarioInjector(onStart);
28
- injector.register(ScenarioInjector.gpsBlackout(10, 500));
29
-
30
- // Jump from 5 to 15 — trigger at 10 should still fire
31
- injector.tick(15);
32
- expect(onStart).toHaveBeenCalledOnce();
33
- });
34
-
35
- it('does NOT double-fire the same scenario', () => {
36
- const onStart = vi.fn();
37
- const injector = new ScenarioInjector(onStart);
38
- injector.register(ScenarioInjector.gpsBlackout(3, 500));
39
-
40
- injector.tick(3);
41
- injector.tick(3);
42
- injector.tick(5);
43
- expect(onStart).toHaveBeenCalledTimes(1);
44
- });
45
-
46
- it('fires onEnd after durationMs (via setTimeout)', () => {
47
- vi.useFakeTimers();
48
- const onEnd = vi.fn();
49
- const injector = new ScenarioInjector(undefined, onEnd);
50
- injector.register(ScenarioInjector.gpsBlackout(0, 2000));
51
-
52
- injector.tick(0);
53
- expect(onEnd).not.toHaveBeenCalled();
54
-
55
- vi.advanceTimersByTime(2000);
56
- expect(onEnd).toHaveBeenCalledOnce();
57
- vi.useRealTimers();
58
- });
59
-
60
- it('fires onEnd immediately for instantaneous scenario (no durationMs)', () => {
61
- const onEnd = vi.fn();
62
- const injector = new ScenarioInjector(undefined, onEnd);
63
- injector.register(ScenarioInjector.uTurn(5));
64
-
65
- injector.tick(5);
66
- expect(onEnd).toHaveBeenCalledOnce();
67
- });
68
- });
69
-
70
- describe('remove', () => {
71
- it('removes a scenario by name before it fires', () => {
72
- const onStart = vi.fn();
73
- const injector = new ScenarioInjector(onStart);
74
- const s = ScenarioInjector.gpsBlackout(4, 1000);
75
- injector.register(s);
76
- injector.remove(s.name);
77
-
78
- injector.tick(4);
79
- expect(onStart).not.toHaveBeenCalled();
80
- });
81
- });
82
-
83
- describe('clear', () => {
84
- it('removes all scenarios', () => {
85
- const onStart = vi.fn();
86
- const injector = new ScenarioInjector(onStart);
87
- injector.register(ScenarioInjector.gpsBlackout(1, 500));
88
- injector.register(ScenarioInjector.uTurn(2));
89
- injector.clear();
90
-
91
- injector.tick(5);
92
- expect(onStart).not.toHaveBeenCalled();
93
- });
94
- });
95
-
96
- describe('activeScenario', () => {
97
- it('is null before firing', () => {
98
- const injector = new ScenarioInjector();
99
- injector.register(ScenarioInjector.gpsBlackout(5, 5000));
100
- expect(injector.activeScenario).toBeNull();
101
- });
102
-
103
- it('is set after firing (while durationMs pending)', () => {
104
- vi.useFakeTimers();
105
- const injector = new ScenarioInjector();
106
- injector.register(ScenarioInjector.gpsBlackout(0, 5000));
107
- injector.tick(0);
108
- expect(injector.activeScenario?.type).toBe('GPS_BLACKOUT');
109
- vi.useRealTimers();
110
- });
111
- });
112
-
113
- describe('tick returns active scenario name', () => {
114
- it('returns undefined when no scenario is active', () => {
115
- const injector = new ScenarioInjector();
116
- injector.register(ScenarioInjector.gpsBlackout(10, 1000));
117
- const result = injector.tick(0);
118
- expect(result).toBeUndefined();
119
- });
120
-
121
- it('returns scenario name after it fires', () => {
122
- vi.useFakeTimers();
123
- const injector = new ScenarioInjector();
124
- const s = ScenarioInjector.gpsBlackout(0, 5000);
125
- injector.register(s);
126
- injector.tick(0);
127
- const name = injector.tick(1);
128
- expect(name).toBe(s.name);
129
- vi.useRealTimers();
130
- });
131
- });
132
-
133
- describe('Static factories', () => {
134
- it('gpsBlackout returns GPS_BLACKOUT type', () => {
135
- const s = ScenarioInjector.gpsBlackout(10, 3000);
136
- expect(s.type).toBe('GPS_BLACKOUT');
137
- expect(s.triggerIndex).toBe(10);
138
- expect(s.durationMs).toBe(3000);
139
- });
140
-
141
- it('wrongSideRoad returns WRONG_SIDE_ROAD type', () => {
142
- const s = ScenarioInjector.wrongSideRoad(20, 18);
143
- expect(s.type).toBe('WRONG_SIDE_ROAD');
144
- expect(s.params?.['offsetM']).toBe(18);
145
- });
146
-
147
- it('uTurn returns UTURN type', () => {
148
- const s = ScenarioInjector.uTurn(15);
149
- expect(s.type).toBe('UTURN');
150
- });
151
-
152
- it('speedSpike returns SPEED_SPIKE type with spikeKmh', () => {
153
- const s = ScenarioInjector.speedSpike(5, 120);
154
- expect(s.type).toBe('SPEED_SPIKE');
155
- expect(s.params?.['spikeKmh']).toBe(120);
156
- });
157
-
158
- it('accuracyDrop returns ACCURACY_DROP type', () => {
159
- const s = ScenarioInjector.accuracyDrop(8, 50, 4000);
160
- expect(s.type).toBe('ACCURACY_DROP');
161
- expect(s.durationMs).toBe(4000);
162
- expect(s.params?.['newAccuracyM']).toBe(50);
163
- });
164
-
165
- it('all factories produce unique names for different indices', () => {
166
- const a = ScenarioInjector.gpsBlackout(1, 1000);
167
- const b = ScenarioInjector.gpsBlackout(2, 1000);
168
- expect(a.name).not.toBe(b.name);
169
- });
170
- });
171
- });