@avimate/msfs-jest-utils 1.0.0
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.
- package/LICENSE +22 -0
- package/README.md +170 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +24 -0
- package/dist/mocks/CoherentMock.d.ts +74 -0
- package/dist/mocks/CoherentMock.js +148 -0
- package/dist/mocks/GarminSDKAdapter.d.ts +79 -0
- package/dist/mocks/GarminSDKAdapter.js +127 -0
- package/dist/mocks/MSFSGlobals.d.ts +6 -0
- package/dist/mocks/MSFSGlobals.js +514 -0
- package/dist/mocks/SDKAdapter.d.ts +126 -0
- package/dist/mocks/SDKAdapter.js +696 -0
- package/dist/mocks/SDKClasses.d.ts +32 -0
- package/dist/mocks/SDKClasses.js +118 -0
- package/dist/mocks/SimVarMock.d.ts +97 -0
- package/dist/mocks/SimVarMock.js +215 -0
- package/dist/mocks/index.d.ts +9 -0
- package/dist/mocks/index.js +25 -0
- package/dist/setupTests.d.ts +13 -0
- package/dist/setupTests.js +109 -0
- package/dist/test-utils/ComponentTestHelper.d.ts +73 -0
- package/dist/test-utils/ComponentTestHelper.js +558 -0
- package/dist/test-utils/ObservableTestHelper.d.ts +25 -0
- package/dist/test-utils/ObservableTestHelper.js +75 -0
- package/dist/test-utils/TestEnvironment.d.ts +76 -0
- package/dist/test-utils/TestEnvironment.js +227 -0
- package/dist/test-utils/index.d.ts +6 -0
- package/dist/test-utils/index.js +22 -0
- package/package.json +64 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock implementations of MSFS SDK classes for testing.
|
|
3
|
+
*
|
|
4
|
+
* These mocks provide the minimal interface needed for components to work in tests.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Mock DisplayComponent base class
|
|
8
|
+
*/
|
|
9
|
+
export declare class MockDisplayComponent<P = any> {
|
|
10
|
+
props: P;
|
|
11
|
+
context?: any;
|
|
12
|
+
constructor(props: P);
|
|
13
|
+
onBeforeRender?(): void;
|
|
14
|
+
onAfterRender?(vnode?: any): void;
|
|
15
|
+
render(): any;
|
|
16
|
+
destroy?(): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Mock FSComponent utilities
|
|
20
|
+
*/
|
|
21
|
+
export declare const MockFSComponent: {
|
|
22
|
+
buildComponent: (type: any, props: any, ...children: any[]) => any;
|
|
23
|
+
Fragment: (props: any, ...children: any[]) => any;
|
|
24
|
+
render: (vnode: any, container: HTMLElement | Element) => Element | null;
|
|
25
|
+
createRef: <T = any>() => {
|
|
26
|
+
instance: T | null;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Setup SDK classes as globals
|
|
31
|
+
*/
|
|
32
|
+
export declare function setupSDKClasses(): void;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Mock implementations of MSFS SDK classes for testing.
|
|
4
|
+
*
|
|
5
|
+
* These mocks provide the minimal interface needed for components to work in tests.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.MockFSComponent = exports.MockDisplayComponent = void 0;
|
|
9
|
+
exports.setupSDKClasses = setupSDKClasses;
|
|
10
|
+
/**
|
|
11
|
+
* Mock DisplayComponent base class
|
|
12
|
+
*/
|
|
13
|
+
class MockDisplayComponent {
|
|
14
|
+
constructor(props) {
|
|
15
|
+
this.props = props;
|
|
16
|
+
}
|
|
17
|
+
onBeforeRender() { }
|
|
18
|
+
onAfterRender(vnode) { }
|
|
19
|
+
render() {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
destroy() { }
|
|
23
|
+
}
|
|
24
|
+
exports.MockDisplayComponent = MockDisplayComponent;
|
|
25
|
+
/**
|
|
26
|
+
* Mock FSComponent utilities
|
|
27
|
+
*/
|
|
28
|
+
exports.MockFSComponent = {
|
|
29
|
+
buildComponent: (type, props, ...children) => {
|
|
30
|
+
if (typeof type === 'function') {
|
|
31
|
+
// If it's a component class, instantiate it
|
|
32
|
+
return new type(props);
|
|
33
|
+
}
|
|
34
|
+
// If it's a string (HTML/SVG tag), return a VNode-like object
|
|
35
|
+
return {
|
|
36
|
+
type,
|
|
37
|
+
props: props || {},
|
|
38
|
+
children: children || [],
|
|
39
|
+
instance: null,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
Fragment: (props, ...children) => {
|
|
43
|
+
return {
|
|
44
|
+
type: 'Fragment',
|
|
45
|
+
props: props || {},
|
|
46
|
+
children: children || [],
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
render: (vnode, container) => {
|
|
50
|
+
if (!vnode)
|
|
51
|
+
return null;
|
|
52
|
+
// Simple rendering logic for tests
|
|
53
|
+
if (typeof vnode.type === 'string') {
|
|
54
|
+
// HTML/SVG element
|
|
55
|
+
const element = document.createElementNS(vnode.type === 'svg' || ['g', 'circle', 'line', 'text', 'polygon'].includes(vnode.type)
|
|
56
|
+
? 'http://www.w3.org/2000/svg'
|
|
57
|
+
: 'http://www.w3.org/1999/xhtml', vnode.type);
|
|
58
|
+
// Set attributes
|
|
59
|
+
if (vnode.props) {
|
|
60
|
+
Object.keys(vnode.props).forEach(key => {
|
|
61
|
+
if (key === 'class') {
|
|
62
|
+
element.setAttribute('class', vnode.props[key]);
|
|
63
|
+
}
|
|
64
|
+
else if (key === 'key' || key === 'ref') {
|
|
65
|
+
// Skip React-like props
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
element.setAttribute(key, String(vnode.props[key]));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// Set text content if it's a text node
|
|
73
|
+
if (vnode.children && vnode.children.length === 1 && typeof vnode.children[0] === 'string') {
|
|
74
|
+
element.textContent = vnode.children[0];
|
|
75
|
+
}
|
|
76
|
+
else if (vnode.children) {
|
|
77
|
+
// Recursively render children
|
|
78
|
+
vnode.children.forEach((child) => {
|
|
79
|
+
if (child) {
|
|
80
|
+
const childElement = exports.MockFSComponent.render(child, element);
|
|
81
|
+
if (childElement) {
|
|
82
|
+
element.appendChild(childElement);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
vnode.instance = element;
|
|
88
|
+
container.appendChild(element);
|
|
89
|
+
return element;
|
|
90
|
+
}
|
|
91
|
+
else if (typeof vnode.type === 'function') {
|
|
92
|
+
// Component
|
|
93
|
+
const component = new vnode.type(vnode.props);
|
|
94
|
+
const childVNode = component.render();
|
|
95
|
+
if (childVNode) {
|
|
96
|
+
return exports.MockFSComponent.render(childVNode, container);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
},
|
|
101
|
+
createRef: () => {
|
|
102
|
+
return { instance: null };
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Setup SDK classes as globals
|
|
107
|
+
*/
|
|
108
|
+
function setupSDKClasses() {
|
|
109
|
+
const globalObj = globalThis;
|
|
110
|
+
// Make DisplayComponent available globally
|
|
111
|
+
if (typeof globalObj.DisplayComponent === 'undefined') {
|
|
112
|
+
globalObj.DisplayComponent = MockDisplayComponent;
|
|
113
|
+
}
|
|
114
|
+
// Make FSComponent available globally
|
|
115
|
+
if (typeof globalObj.FSComponent === 'undefined') {
|
|
116
|
+
globalObj.FSComponent = exports.MockFSComponent;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock implementation of SimVar API for testing MSFS instruments.
|
|
3
|
+
*
|
|
4
|
+
* This provides a complete simulation of the SimVar system, allowing you to:
|
|
5
|
+
* - Set and get SimVar values
|
|
6
|
+
* - Register SimVars for efficient access
|
|
7
|
+
* - Simulate different data types (number, string, bool, structs)
|
|
8
|
+
* - Track SimVar access for testing
|
|
9
|
+
*/
|
|
10
|
+
export interface SimVarValue {
|
|
11
|
+
value: any;
|
|
12
|
+
unit: string;
|
|
13
|
+
dataSource?: string;
|
|
14
|
+
accessCount?: number;
|
|
15
|
+
lastAccessTime?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface SimVarAccessLog {
|
|
18
|
+
name: string;
|
|
19
|
+
unit: string;
|
|
20
|
+
operation: 'get' | 'set';
|
|
21
|
+
value?: any;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Mock SimVar implementation for testing
|
|
26
|
+
*/
|
|
27
|
+
export declare class SimVarMock {
|
|
28
|
+
private static instance;
|
|
29
|
+
private simVars;
|
|
30
|
+
private registeredIds;
|
|
31
|
+
private registeredSimVars;
|
|
32
|
+
private nextRegisteredId;
|
|
33
|
+
private accessLog;
|
|
34
|
+
private maxLogSize;
|
|
35
|
+
private constructor();
|
|
36
|
+
/**
|
|
37
|
+
* Get singleton instance
|
|
38
|
+
*/
|
|
39
|
+
static getInstance(): SimVarMock;
|
|
40
|
+
/**
|
|
41
|
+
* Initialize default SimVars with common values
|
|
42
|
+
*/
|
|
43
|
+
private initializeDefaults;
|
|
44
|
+
/**
|
|
45
|
+
* Get a SimVar value
|
|
46
|
+
*/
|
|
47
|
+
getSimVarValue(name: string, unit: string, dataSource?: string): any;
|
|
48
|
+
/**
|
|
49
|
+
* Set a SimVar value
|
|
50
|
+
*/
|
|
51
|
+
setSimVarValue(name: string, unit: string, value: any, dataSource?: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Register a SimVar for efficient access
|
|
54
|
+
*/
|
|
55
|
+
getRegisteredId(name: string, unit: string, dataSource?: string): number;
|
|
56
|
+
/**
|
|
57
|
+
* Get value using registered ID
|
|
58
|
+
*/
|
|
59
|
+
getValueReg(registeredId: number): any;
|
|
60
|
+
/**
|
|
61
|
+
* Set value using registered ID
|
|
62
|
+
*/
|
|
63
|
+
setValueReg(registeredId: number, value: any): void;
|
|
64
|
+
/**
|
|
65
|
+
* Get access log
|
|
66
|
+
*/
|
|
67
|
+
getAccessLog(): SimVarAccessLog[];
|
|
68
|
+
/**
|
|
69
|
+
* Clear access log
|
|
70
|
+
*/
|
|
71
|
+
clearAccessLog(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Get all SimVars
|
|
74
|
+
*/
|
|
75
|
+
getAllSimVars(): Map<string, SimVarValue>;
|
|
76
|
+
/**
|
|
77
|
+
* Reset all SimVars to defaults
|
|
78
|
+
*/
|
|
79
|
+
reset(): void;
|
|
80
|
+
/**
|
|
81
|
+
* Get SimVar by name (first match)
|
|
82
|
+
*/
|
|
83
|
+
getSimVar(name: string): SimVarValue | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Check if SimVar exists
|
|
86
|
+
*/
|
|
87
|
+
hasSimVar(name: string, unit: string, dataSource?: string): boolean;
|
|
88
|
+
private getKey;
|
|
89
|
+
private parseKey;
|
|
90
|
+
private getDefaultValue;
|
|
91
|
+
private coerceValue;
|
|
92
|
+
private logAccess;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Global SimVar mock instance
|
|
96
|
+
*/
|
|
97
|
+
export declare const simVarMock: SimVarMock;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Mock implementation of SimVar API for testing MSFS instruments.
|
|
4
|
+
*
|
|
5
|
+
* This provides a complete simulation of the SimVar system, allowing you to:
|
|
6
|
+
* - Set and get SimVar values
|
|
7
|
+
* - Register SimVars for efficient access
|
|
8
|
+
* - Simulate different data types (number, string, bool, structs)
|
|
9
|
+
* - Track SimVar access for testing
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.simVarMock = exports.SimVarMock = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Mock SimVar implementation for testing
|
|
15
|
+
*/
|
|
16
|
+
class SimVarMock {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.simVars = new Map();
|
|
19
|
+
this.registeredIds = new Map();
|
|
20
|
+
this.registeredSimVars = new Map();
|
|
21
|
+
this.nextRegisteredId = 0;
|
|
22
|
+
this.accessLog = [];
|
|
23
|
+
this.maxLogSize = 10000;
|
|
24
|
+
this.initializeDefaults();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get singleton instance
|
|
28
|
+
*/
|
|
29
|
+
static getInstance() {
|
|
30
|
+
if (!SimVarMock.instance) {
|
|
31
|
+
SimVarMock.instance = new SimVarMock();
|
|
32
|
+
}
|
|
33
|
+
return SimVarMock.instance;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Initialize default SimVars with common values
|
|
37
|
+
*/
|
|
38
|
+
initializeDefaults() {
|
|
39
|
+
// Common aircraft state SimVars
|
|
40
|
+
this.setSimVarValue('PLANE LATITUDE', 'degrees', 0);
|
|
41
|
+
this.setSimVarValue('PLANE LONGITUDE', 'degrees', 0);
|
|
42
|
+
this.setSimVarValue('PLANE ALTITUDE', 'feet', 0);
|
|
43
|
+
this.setSimVarValue('AIRSPEED INDICATED', 'knots', 0);
|
|
44
|
+
this.setSimVarValue('VERTICAL SPEED', 'feet per minute', 0);
|
|
45
|
+
this.setSimVarValue('PLANE HEADING DEGREES TRUE', 'degrees', 0);
|
|
46
|
+
this.setSimVarValue('PLANE PITCH DEGREES', 'degrees', 0);
|
|
47
|
+
this.setSimVarValue('PLANE BANK DEGREES', 'degrees', 0);
|
|
48
|
+
this.setSimVarValue('SIM ON GROUND', 'bool', 1);
|
|
49
|
+
this.setSimVarValue('ENGINE RPM:1', 'Rpm', 0);
|
|
50
|
+
this.setSimVarValue('GENERAL ENG THROTTLE LEVER POSITION:1', 'percent', 0);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get a SimVar value
|
|
54
|
+
*/
|
|
55
|
+
getSimVarValue(name, unit, dataSource = '') {
|
|
56
|
+
const key = this.getKey(name, unit, dataSource);
|
|
57
|
+
const simVar = this.simVars.get(key);
|
|
58
|
+
this.logAccess(name, unit, 'get', simVar?.value);
|
|
59
|
+
if (simVar) {
|
|
60
|
+
simVar.accessCount = (simVar.accessCount || 0) + 1;
|
|
61
|
+
simVar.lastAccessTime = Date.now();
|
|
62
|
+
return simVar.value;
|
|
63
|
+
}
|
|
64
|
+
// Return default based on unit type
|
|
65
|
+
return this.getDefaultValue(unit);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Set a SimVar value
|
|
69
|
+
*/
|
|
70
|
+
setSimVarValue(name, unit, value, dataSource = '') {
|
|
71
|
+
const key = this.getKey(name, unit, dataSource);
|
|
72
|
+
const existing = this.simVars.get(key);
|
|
73
|
+
this.simVars.set(key, {
|
|
74
|
+
value: this.coerceValue(value, unit),
|
|
75
|
+
unit,
|
|
76
|
+
dataSource,
|
|
77
|
+
accessCount: existing?.accessCount || 0,
|
|
78
|
+
lastAccessTime: Date.now()
|
|
79
|
+
});
|
|
80
|
+
this.logAccess(name, unit, 'set', value);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Register a SimVar for efficient access
|
|
84
|
+
*/
|
|
85
|
+
getRegisteredId(name, unit, dataSource = '') {
|
|
86
|
+
const key = this.getKey(name, unit, dataSource);
|
|
87
|
+
if (this.registeredSimVars.has(key)) {
|
|
88
|
+
return this.registeredSimVars.get(key);
|
|
89
|
+
}
|
|
90
|
+
const id = this.nextRegisteredId++;
|
|
91
|
+
this.registeredSimVars.set(key, id);
|
|
92
|
+
this.registeredIds.set(id, key);
|
|
93
|
+
// Initialize if not exists
|
|
94
|
+
if (!this.simVars.has(key)) {
|
|
95
|
+
this.setSimVarValue(name, unit, this.getDefaultValue(unit), dataSource);
|
|
96
|
+
}
|
|
97
|
+
return id;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get value using registered ID
|
|
101
|
+
*/
|
|
102
|
+
getValueReg(registeredId) {
|
|
103
|
+
const key = this.registeredIds.get(registeredId);
|
|
104
|
+
if (!key) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
const simVar = this.simVars.get(key);
|
|
108
|
+
if (simVar) {
|
|
109
|
+
simVar.accessCount = (simVar.accessCount || 0) + 1;
|
|
110
|
+
simVar.lastAccessTime = Date.now();
|
|
111
|
+
return simVar.value;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Set value using registered ID
|
|
117
|
+
*/
|
|
118
|
+
setValueReg(registeredId, value) {
|
|
119
|
+
const key = this.registeredIds.get(registeredId);
|
|
120
|
+
if (!key) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const [name, unit, dataSource] = this.parseKey(key);
|
|
124
|
+
this.setSimVarValue(name, unit, value, dataSource);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get access log
|
|
128
|
+
*/
|
|
129
|
+
getAccessLog() {
|
|
130
|
+
return [...this.accessLog];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Clear access log
|
|
134
|
+
*/
|
|
135
|
+
clearAccessLog() {
|
|
136
|
+
this.accessLog = [];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get all SimVars
|
|
140
|
+
*/
|
|
141
|
+
getAllSimVars() {
|
|
142
|
+
return new Map(this.simVars);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Reset all SimVars to defaults
|
|
146
|
+
*/
|
|
147
|
+
reset() {
|
|
148
|
+
this.simVars.clear();
|
|
149
|
+
this.registeredIds.clear();
|
|
150
|
+
this.registeredSimVars.clear();
|
|
151
|
+
this.nextRegisteredId = 0;
|
|
152
|
+
this.accessLog = [];
|
|
153
|
+
this.initializeDefaults();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get SimVar by name (first match)
|
|
157
|
+
*/
|
|
158
|
+
getSimVar(name) {
|
|
159
|
+
for (const [key, value] of this.simVars.entries()) {
|
|
160
|
+
if (key.startsWith(`${name}|`)) {
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if SimVar exists
|
|
168
|
+
*/
|
|
169
|
+
hasSimVar(name, unit, dataSource = '') {
|
|
170
|
+
return this.simVars.has(this.getKey(name, unit, dataSource));
|
|
171
|
+
}
|
|
172
|
+
getKey(name, unit, dataSource) {
|
|
173
|
+
return `${name}|${unit}|${dataSource}`;
|
|
174
|
+
}
|
|
175
|
+
parseKey(key) {
|
|
176
|
+
const parts = key.split('|');
|
|
177
|
+
return [parts[0], parts[1], parts[2] || ''];
|
|
178
|
+
}
|
|
179
|
+
getDefaultValue(unit) {
|
|
180
|
+
if (unit.toLowerCase().includes('bool')) {
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
if (unit.toLowerCase().includes('string')) {
|
|
184
|
+
return '';
|
|
185
|
+
}
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
coerceValue(value, unit) {
|
|
189
|
+
if (unit.toLowerCase().includes('bool')) {
|
|
190
|
+
return value ? 1 : 0;
|
|
191
|
+
}
|
|
192
|
+
if (unit.toLowerCase().includes('string')) {
|
|
193
|
+
return String(value);
|
|
194
|
+
}
|
|
195
|
+
return Number(value);
|
|
196
|
+
}
|
|
197
|
+
logAccess(name, unit, operation, value) {
|
|
198
|
+
this.accessLog.push({
|
|
199
|
+
name,
|
|
200
|
+
unit,
|
|
201
|
+
operation,
|
|
202
|
+
value,
|
|
203
|
+
timestamp: Date.now()
|
|
204
|
+
});
|
|
205
|
+
// Keep log size manageable
|
|
206
|
+
if (this.accessLog.length > this.maxLogSize) {
|
|
207
|
+
this.accessLog = this.accessLog.slice(-this.maxLogSize);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
exports.SimVarMock = SimVarMock;
|
|
212
|
+
/**
|
|
213
|
+
* Global SimVar mock instance
|
|
214
|
+
*/
|
|
215
|
+
exports.simVarMock = SimVarMock.getInstance();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MSFS Unit Test Framework - Mocks
|
|
3
|
+
*
|
|
4
|
+
* Provides mock implementations of MSFS APIs for testing instruments without the simulator.
|
|
5
|
+
*/
|
|
6
|
+
export * from './SimVarMock';
|
|
7
|
+
export * from './CoherentMock';
|
|
8
|
+
export * from './SDKAdapter';
|
|
9
|
+
export * from './MSFSGlobals';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MSFS Unit Test Framework - Mocks
|
|
4
|
+
*
|
|
5
|
+
* Provides mock implementations of MSFS APIs for testing instruments without the simulator.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
__exportStar(require("./SimVarMock"), exports);
|
|
23
|
+
__exportStar(require("./CoherentMock"), exports);
|
|
24
|
+
__exportStar(require("./SDKAdapter"), exports);
|
|
25
|
+
__exportStar(require("./MSFSGlobals"), exports);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jest setup file - runs before all tests
|
|
3
|
+
*
|
|
4
|
+
* This file is automatically loaded by Jest (configured in jest.config.js)
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT: Order matters! Setup must happen in this order:
|
|
7
|
+
* 1. TextEncoder/TextDecoder polyfills
|
|
8
|
+
* 2. JSX type definitions (for TypeScript)
|
|
9
|
+
* 3. MSFS globals (BaseInstrument, DisplayComponent, FSComponent, etc.)
|
|
10
|
+
* 4. SimVar and Coherent mocks
|
|
11
|
+
* 5. SDK can now be imported safely
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Jest setup file - runs before all tests
|
|
4
|
+
*
|
|
5
|
+
* This file is automatically loaded by Jest (configured in jest.config.js)
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Order matters! Setup must happen in this order:
|
|
8
|
+
* 1. TextEncoder/TextDecoder polyfills
|
|
9
|
+
* 2. JSX type definitions (for TypeScript)
|
|
10
|
+
* 3. MSFS globals (BaseInstrument, DisplayComponent, FSComponent, etc.)
|
|
11
|
+
* 4. SimVar and Coherent mocks
|
|
12
|
+
* 5. SDK can now be imported safely
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
// ============================================
|
|
16
|
+
// STEP 0: Load JSX type definitions
|
|
17
|
+
// ============================================
|
|
18
|
+
/// <reference path="./mocks/jsx.d.ts" />
|
|
19
|
+
// ============================================
|
|
20
|
+
// STEP 1: Polyfills for Node.js environment
|
|
21
|
+
// ============================================
|
|
22
|
+
const util_1 = require("util");
|
|
23
|
+
if (typeof globalThis.TextEncoder === 'undefined') {
|
|
24
|
+
globalThis.TextEncoder = util_1.TextEncoder;
|
|
25
|
+
}
|
|
26
|
+
if (typeof globalThis.TextDecoder === 'undefined') {
|
|
27
|
+
globalThis.TextDecoder = util_1.TextDecoder;
|
|
28
|
+
}
|
|
29
|
+
if (typeof global.TextEncoder === 'undefined') {
|
|
30
|
+
global.TextEncoder = util_1.TextEncoder;
|
|
31
|
+
}
|
|
32
|
+
if (typeof global.TextDecoder === 'undefined') {
|
|
33
|
+
global.TextDecoder = util_1.TextDecoder;
|
|
34
|
+
}
|
|
35
|
+
// ============================================
|
|
36
|
+
// STEP 2: Setup MSFS globals FIRST
|
|
37
|
+
// This must happen before any SDK imports
|
|
38
|
+
// ============================================
|
|
39
|
+
const { setupMSFSGlobals } = require('./mocks/MSFSGlobals');
|
|
40
|
+
setupMSFSGlobals();
|
|
41
|
+
// ============================================
|
|
42
|
+
// STEP 3: Setup SimVar and Coherent mocks
|
|
43
|
+
// ============================================
|
|
44
|
+
const { SimVarMock } = require('./mocks/SimVarMock');
|
|
45
|
+
const { CoherentMock } = require('./mocks/CoherentMock');
|
|
46
|
+
const simVarMock = SimVarMock.getInstance();
|
|
47
|
+
const coherentMock = CoherentMock.getInstance();
|
|
48
|
+
const globalObj = globalThis;
|
|
49
|
+
// Setup SimVar mock
|
|
50
|
+
if (typeof globalObj.SimVar === 'undefined') {
|
|
51
|
+
globalObj.SimVar = {
|
|
52
|
+
GetSimVarValue: (name, unit, dataSource = '') => {
|
|
53
|
+
return simVarMock.getSimVarValue(name, unit, dataSource);
|
|
54
|
+
},
|
|
55
|
+
SetSimVarValue: (name, unit, value, dataSource = '') => {
|
|
56
|
+
return Promise.resolve(simVarMock.setSimVarValue(name, unit, value, dataSource));
|
|
57
|
+
},
|
|
58
|
+
GetRegisteredId: (name, unit, dataSource = '') => {
|
|
59
|
+
return simVarMock.getRegisteredId(name, unit, dataSource);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Setup simvar global (used by SDK internally)
|
|
64
|
+
if (typeof globalObj.simvar === 'undefined') {
|
|
65
|
+
globalObj.simvar = {
|
|
66
|
+
getValueReg: (id) => simVarMock.getValueReg(id),
|
|
67
|
+
getValueReg_String: (id) => simVarMock.getValueReg(id),
|
|
68
|
+
getValue_LatLongAlt: () => ({ lat: 0, long: 0, alt: 0 }),
|
|
69
|
+
getValue_LatLongAltPBH: () => ({ lat: 0, long: 0, alt: 0, pitch: 0, bank: 0, heading: 0 }),
|
|
70
|
+
getValue_PBH: () => ({ pitch: 0, bank: 0, heading: 0 }),
|
|
71
|
+
getValue_PID_STRUCT: () => ({ p: 0, i: 0, d: 0 }),
|
|
72
|
+
getValue_XYZ: () => ({ x: 0, y: 0, z: 0 }),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Setup Coherent mock
|
|
76
|
+
if (typeof globalObj.Coherent === 'undefined') {
|
|
77
|
+
globalObj.Coherent = {
|
|
78
|
+
call: (method, ...args) => coherentMock.call(method, ...args),
|
|
79
|
+
on: (eventName, callback) => coherentMock.on(eventName, callback),
|
|
80
|
+
off: (eventName, callback) => coherentMock.off(eventName, callback),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Setup fetch mock (for agent logging in production code)
|
|
84
|
+
if (typeof globalObj.fetch === 'undefined') {
|
|
85
|
+
globalObj.fetch = async (url, init) => {
|
|
86
|
+
// Mock fetch - just return a successful response
|
|
87
|
+
// This prevents errors when code tries to log to agent endpoints
|
|
88
|
+
return Promise.resolve({
|
|
89
|
+
ok: true,
|
|
90
|
+
status: 200,
|
|
91
|
+
statusText: 'OK',
|
|
92
|
+
headers: new Headers(),
|
|
93
|
+
url: typeof url === 'string' ? url : url.toString(),
|
|
94
|
+
redirected: false,
|
|
95
|
+
type: 'default',
|
|
96
|
+
body: null,
|
|
97
|
+
bodyUsed: false,
|
|
98
|
+
clone: () => {
|
|
99
|
+
throw new Error('Not implemented');
|
|
100
|
+
},
|
|
101
|
+
arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)),
|
|
102
|
+
blob: () => Promise.resolve(new Blob()),
|
|
103
|
+
formData: () => Promise.resolve(new FormData()),
|
|
104
|
+
json: () => Promise.resolve({}),
|
|
105
|
+
text: () => Promise.resolve(''),
|
|
106
|
+
bytes: () => Promise.resolve(new Uint8Array(0)),
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper utilities for testing FSComponent components.
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities to render components, query DOM, and test component behavior.
|
|
5
|
+
*/
|
|
6
|
+
import { VNode } from '@microsoft/msfs-sdk';
|
|
7
|
+
import { TestEnvironment } from './TestEnvironment';
|
|
8
|
+
export declare class ComponentTestHelper {
|
|
9
|
+
private env;
|
|
10
|
+
private container;
|
|
11
|
+
constructor(env: TestEnvironment);
|
|
12
|
+
/**
|
|
13
|
+
* Render a component to DOM
|
|
14
|
+
*/
|
|
15
|
+
renderComponent<P>(ComponentClass: new (props: P) => any, // Use 'any' to avoid version conflicts
|
|
16
|
+
props: P): {
|
|
17
|
+
component: any;
|
|
18
|
+
element: HTMLElement;
|
|
19
|
+
vnode: VNode;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Query selector within container
|
|
23
|
+
*/
|
|
24
|
+
querySelector(selector: string): Element | null;
|
|
25
|
+
/**
|
|
26
|
+
* Query selector all within container
|
|
27
|
+
*/
|
|
28
|
+
querySelectorAll(selector: string): NodeListOf<Element>;
|
|
29
|
+
/**
|
|
30
|
+
* Get container element
|
|
31
|
+
*/
|
|
32
|
+
getContainer(): HTMLElement;
|
|
33
|
+
/**
|
|
34
|
+
* Clean up - remove container from DOM
|
|
35
|
+
*/
|
|
36
|
+
cleanup(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Wait for async updates (useful for Subject subscriptions)
|
|
39
|
+
*/
|
|
40
|
+
waitForUpdate(ms?: number): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Get text content of element
|
|
43
|
+
*/
|
|
44
|
+
getTextContent(selector: string): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Check if element has class
|
|
47
|
+
*/
|
|
48
|
+
hasClass(selector: string, className: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Get attribute value
|
|
51
|
+
*/
|
|
52
|
+
getAttribute(selector: string, attrName: string): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* Get computed style property
|
|
55
|
+
*/
|
|
56
|
+
getStyle(selector: string, property: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Query SVG element by selector
|
|
59
|
+
*/
|
|
60
|
+
querySelectorSVG(selector: string): SVGElement | null;
|
|
61
|
+
/**
|
|
62
|
+
* Query all SVG elements by selector
|
|
63
|
+
*/
|
|
64
|
+
querySelectorAllSVG(selector: string): SVGElement[];
|
|
65
|
+
/**
|
|
66
|
+
* Get SVG attribute value
|
|
67
|
+
*/
|
|
68
|
+
getSVGAttribute(selector: string, attrName: string): string | null;
|
|
69
|
+
/**
|
|
70
|
+
* Check if SVG element exists and has specific attribute value
|
|
71
|
+
*/
|
|
72
|
+
hasSVGAttribute(selector: string, attrName: string, value: string): boolean;
|
|
73
|
+
}
|