openmct/src/utils/testing.js
2024-01-09 13:31:51 -08:00

365 lines
8.9 KiB
JavaScript

/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { MCT } from 'MCT';
import { markRaw } from 'vue';
let nativeFunctions = [];
let mockObjects = setMockObjects();
const EXAMPLE_ROLE = 'flight';
const DEFAULT_TIME_OPTIONS = {
timeSystemKey: 'utc',
bounds: {
start: 0,
end: 1
}
};
export function createOpenMct(timeSystemOptions = DEFAULT_TIME_OPTIONS) {
const openmct = markRaw(new MCT());
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.setAssetPath('/base');
openmct.user.setActiveRole(EXAMPLE_ROLE);
const timeSystemKey = timeSystemOptions.timeSystemKey;
const start = timeSystemOptions.bounds.start;
const end = timeSystemOptions.bounds.end;
openmct.time.setTimeSystem(timeSystemKey, {
start,
end
});
return openmct;
}
export function createMouseEvent(eventName) {
return new MouseEvent(eventName, {
bubbles: true,
cancelable: true,
view: window
});
}
export function spyOnBuiltins(functionNames, object = window) {
functionNames.forEach((functionName) => {
if (nativeFunctions[functionName]) {
throw `Builtin spy function already defined for ${functionName}`;
}
nativeFunctions.push({
functionName,
object,
nativeFunction: object[functionName]
});
spyOn(object, functionName);
});
}
export function clearBuiltinSpies() {
nativeFunctions.forEach(clearBuiltinSpy);
nativeFunctions = [];
}
export function resetApplicationState(openmct) {
let promise;
clearBuiltinSpies();
if (openmct !== undefined) {
openmct.destroy();
}
if (window.location.hash !== '#' && window.location.hash !== '') {
promise = new Promise((resolve, reject) => {
window.addEventListener('hashchange', cleanup);
window.location.hash = '#';
function cleanup() {
window.removeEventListener('hashchange', cleanup);
resolve();
}
});
} else {
promise = Promise.resolve();
}
return promise;
}
// required: key
// optional: element, keyCode, type
export function simulateKeyEvent(opts) {
if (!opts.key) {
console.warn('simulateKeyEvent needs a key');
return;
}
const el = opts.element || document;
const key = opts.key;
const keyCode = opts.keyCode || key;
const type = opts.type || 'keydown';
const event = new Event(type);
event.keyCode = keyCode;
event.key = key;
el.dispatchEvent(event);
}
function clearBuiltinSpy(funcDefinition) {
funcDefinition.object[funcDefinition.functionName] = funcDefinition.nativeFunction;
}
export function getLatestTelemetry(telemetry = [], opts = {}) {
let latest = [];
let timeFormat = opts.timeFormat || 'utc';
if (telemetry.length) {
latest = telemetry.reduce((prev, cur) => {
return prev[timeFormat] > cur[timeFormat] ? prev : cur;
});
}
return latest;
}
// EXAMPLE:
// getMockObjects({
// name: 'Jamie Telemetry',
// keys: ['test','other','yeah','sup'],
// format: 'local',
// telemetryConfig: {
// hints: {
// test: {
// domain: 1
// },
// other: {
// range: 2
// }
// }
// }
// })
export function getMockObjects(opts = {}) {
opts.type = opts.type || 'default';
if (opts.objectKeyStrings && !Array.isArray(opts.objectKeyStrings)) {
throw `"getMockObjects" optional parameter "objectKeyStrings" must be an array of string object keys`;
}
let requestedMocks = {};
if (!opts.objectKeyStrings) {
requestedMocks = copyObj(mockObjects[opts.type]);
} else {
opts.objectKeyStrings.forEach((objKey) => {
if (mockObjects[opts.type] && mockObjects[opts.type][objKey]) {
requestedMocks[objKey] = copyObj(mockObjects[opts.type][objKey]);
} else {
throw `No mock object for object key "${objKey}" of type "${opts.type}"`;
}
});
}
// build out custom telemetry mappings if necessary
if (requestedMocks.telemetry && opts.telemetryConfig) {
let keys = opts.telemetryConfig.keys;
let format = opts.telemetryConfig.format || 'utc';
let hints = opts.telemetryConfig.hints;
let values;
// if utc, keep default
if (format === 'utc') {
// save for later if new keys
if (keys) {
format = requestedMocks.telemetry.telemetry.values.find((vals) => vals.key === 'utc');
}
} else {
format = {
key: format,
name: 'Time',
format: format === 'local' ? 'local-format' : format,
hints: {
domain: 1
}
};
}
if (keys) {
values = keys.map((key) => ({
key,
name: key + ' attribute'
}));
values.push(format); // add time format back in
} else {
values = requestedMocks.telemetry.telemetry.values;
}
if (hints) {
for (let val of values) {
if (hints[val.key]) {
val.hints = hints[val.key];
}
}
}
requestedMocks.telemetry.telemetry.values = values;
}
// overwrite any field keys
if (opts.overwrite) {
for (let mock in requestedMocks) {
if (opts.overwrite[mock]) {
requestedMocks[mock] = Object.assign(requestedMocks[mock], opts.overwrite[mock]);
}
}
}
return requestedMocks;
}
// EXAMPLE:
// getMockTelemetry({
// name: 'My Telemetry',
// keys: ['test','other','yeah','sup'],
// count: 8,
// format: 'local'
// })
export function getMockTelemetry(opts = {}) {
let count = opts.count || 2;
let format = opts.format || 'utc';
let name = opts.name || 'Mock Telemetry Datum';
let keyCount = 2;
let keys = false;
let telemetry = [];
if (opts.keys && Array.isArray(opts.keys)) {
keyCount = opts.keys.length;
keys = opts.keys;
} else if (opts.keyCount) {
keyCount = opts.keyCount;
}
for (let i = 1; i < count + 1; i++) {
let datum = {
[format]: i,
name
};
for (let k = 1; k < keyCount + 1; k++) {
let key = keys ? keys[k - 1] : 'some-key-' + k;
let value = keys ? keys[k - 1] + ' value ' + i : 'some value ' + i + '-' + k;
datum[key] = value;
}
telemetry.push(datum);
}
return telemetry;
}
// used to inject into tests that require a render
export function renderWhenVisible(func) {
func();
return true;
}
// copy objects a bit more easily
function copyObj(obj) {
return JSON.parse(JSON.stringify(obj));
}
// add any other necessary types to this mockObjects object
function setMockObjects() {
return {
default: {
folder: {
identifier: {
namespace: '',
key: 'folder-object'
},
name: 'Test Folder Object',
type: 'folder',
composition: [],
location: 'mine'
},
ladTable: {
identifier: {
namespace: '',
key: 'lad-object'
},
type: 'LadTable',
composition: []
},
ladTableSet: {
identifier: {
namespace: '',
key: 'lad-set-object'
},
type: 'LadTableSet',
composition: []
},
telemetry: {
identifier: {
namespace: '',
key: 'telemetry-object'
},
type: 'test-telemetry-object',
name: 'Test Telemetry Object',
telemetry: {
values: [
{
key: 'name',
name: 'Name',
format: 'string'
},
{
key: 'utc',
name: 'Time',
format: 'utc',
hints: {
domain: 1
}
},
{
name: 'Some attribute 1',
key: 'some-key-1',
hints: {
range: 1
}
},
{
name: 'Some attribute 2',
key: 'some-key-2'
}
]
}
}
},
otherType: {
example: {}
}
};
}