Files
openmct/src/plugins/condition/pluginSpec.js
Shefali Joshi e32f465f7a Display layout plugin test coverage to 20% or more (#3158)
* Display layout plugin test coverage to 20% or more
Resolves #3157

* Changes address original issue? Yes
* Unit tests included and/or updated with changes? Yes
* Command line build passes? Yes
* Changes have been smoke-tested? Yes
* Testing instructions included? Yes

* Add disable-dev-shm-usage flag to ChromeHeadless launcher config in karma

* Adding disable dev shm usage flag to chromeheadless launcher and setting log level to debug

* Adding np activity timeout to 60000

* Adding no-sandbox flag for headless chrome

* Run tests without headless chrome to see if that fixes the fonts issue

* Fix typo

* Trying chrome headless with increased memory

* Reset karma.conf back to master

* Trying karma chrome launcher 3.1.0

* Revert to master code for package.json and karma.conf.js

* Trying node 12 browsers

* Revert back to node:13 browsers

* Revert to 10.2.1-browsers circle ci node browsers variant image for docker

* Rebuild node-sass for node 10.x

* Upgrading to 13.14.0 node

* Remove node options

* Don't restore cache before npm install

* Comment out tests with setTimeout

* Trying node 8-browsers

* Try firefox headless

* Firefox version typo

* Revert focused tests

* Exclude setTimeout tests

* Increase browser connectivity timeout

* Trying large timeout with Chromeheadless

* Going back to Firefox and setting browser timeout to 1.5 mins

* Fixes linting issues

* Fix broken tests and add some null checks in the code

* Change double quotes to single quotes
2020-08-03 13:41:57 -07:00

514 lines
19 KiB
JavaScript

/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, 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 { createOpenMct, resetApplicationState } from "utils/testing";
import ConditionPlugin from "./plugin";
import StylesView from "./components/inspector/StylesView.vue";
import Vue from 'vue';
import {getApplicableStylesForItem} from "./utils/styleUtils";
import ConditionManager from "@/plugins/condition/ConditionManager";
describe('the plugin', function () {
let conditionSetDefinition;
let mockConditionSetDomainObject;
let mockListener;
let element;
let child;
let openmct;
let testTelemetryObject;
beforeAll(() => {
resetApplicationState(openmct);
});
beforeEach((done) => {
testTelemetryObject = {
identifier: {
namespace: "",
key: "test-object"
},
type: "test-object",
name: "Test Object",
telemetry: {
valueMetadatas: [{
key: "some-key",
name: "Some attribute",
hints: {
range: 2
}
},
{
key: "utc",
name: "Time",
format: "utc",
hints: {
domain: 1
}
}, {
key: "testSource",
source: "value",
name: "Test",
format: "string"
}]
}
};
openmct = createOpenMct();
openmct.install(new ConditionPlugin());
conditionSetDefinition = openmct.types.get('conditionSet').definition;
element = document.createElement('div');
child = document.createElement('div');
element.appendChild(child);
mockConditionSetDomainObject = {
identifier: {
key: 'testConditionSetKey',
namespace: ''
},
type: 'conditionSet'
};
mockListener = jasmine.createSpy('mockListener');
conditionSetDefinition.initialize(mockConditionSetDomainObject);
openmct.on('start', done);
openmct.startHeadless();
});
afterEach(() => {
resetApplicationState(openmct);
});
let mockConditionSetObject = {
name: 'Condition Set',
key: 'conditionSet',
creatable: true
};
it('defines a conditionSet object type with the correct key', () => {
expect(conditionSetDefinition.key).toEqual(mockConditionSetObject.key);
});
describe('the conditionSet object', () => {
it('is creatable', () => {
expect(conditionSetDefinition.creatable).toEqual(mockConditionSetObject.creatable);
});
it('initializes with an empty composition list', () => {
expect(mockConditionSetDomainObject.composition instanceof Array).toBeTrue();
expect(mockConditionSetDomainObject.composition.length).toEqual(0);
});
it('provides a view', () => {
const testViewObject = {
id: "test-object",
type: "conditionSet",
configuration: {
conditionCollection: []
}
};
const applicableViews = openmct.objectViews.get(testViewObject);
let conditionSetView = applicableViews.find((viewProvider) => viewProvider.key === 'conditionSet.view');
expect(conditionSetView).toBeDefined();
});
});
describe('the condition set usage for multiple display layout items', () => {
let displayLayoutItem;
let lineLayoutItem;
let boxLayoutItem;
let selection;
let component;
let styleViewComponentObject;
const conditionSetDomainObject = {
"configuration": {
"conditionTestData": [
{
"telemetry": "",
"metadata": "",
"input": ""
}
],
"conditionCollection": [
{
"id": "39584410-cbf9-499e-96dc-76f27e69885d",
"configuration": {
"name": "Unnamed Condition",
"output": "Sine > 0",
"trigger": "all",
"criteria": [
{
"id": "85fbb2f7-7595-42bd-9767-a932266c5225",
"telemetry": {
"namespace": "",
"key": "be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
},
"operation": "greaterThan",
"input": [
"0"
],
"metadata": "sin"
},
{
"id": "35400132-63b0-425c-ac30-8197df7d5862",
"telemetry": "any",
"operation": "enumValueIs",
"input": [
"0"
],
"metadata": "state"
}
]
},
"summary": "Match if all criteria are met: Sine Wave Generator Sine > 0 and any telemetry State is OFF "
},
{
"isDefault": true,
"id": "2532d90a-e0d6-4935-b546-3123522da2de",
"configuration": {
"name": "Default",
"output": "Default",
"trigger": "all",
"criteria": [
]
},
"summary": ""
}
]
},
"composition": [
{
"namespace": "",
"key": "be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
},
{
"namespace": "",
"key": "077ffa67-e78f-4e99-80e0-522ac33a3888"
}
],
"telemetry": {
},
"name": "Condition Set",
"type": "conditionSet",
"identifier": {
"namespace": "",
"key": "863012c1-f6ca-4ab0-aed7-fd43d5e4cd12"
}
};
const staticStyle = {
"style": {
"backgroundColor": "#717171",
"border": "1px solid #00ffff"
}
};
const conditionalStyle = {
"conditionId": "39584410-cbf9-499e-96dc-76f27e69885d",
"style": {
"isStyleInvisible": "",
"backgroundColor": "#717171",
"border": "1px solid #ffff00"
}
};
beforeEach(() => {
displayLayoutItem = {
"composition": [
],
"configuration": {
"items": [
{
"fill": "#717171",
"stroke": "",
"x": 1,
"y": 1,
"width": 10,
"height": 5,
"type": "box-view",
"id": "89b88746-d325-487b-aec4-11b79afff9e8"
},
{
"x": 18,
"y": 9,
"x2": 23,
"y2": 4,
"stroke": "#717171",
"type": "line-view",
"id": "57d49a28-7863-43bd-9593-6570758916f0"
}
],
"layoutGrid": [
10,
10
]
},
"name": "Display Layout",
"type": "layout",
"identifier": {
"namespace": "",
"key": "c5e636c1-6771-4c9c-b933-8665cab189b3"
}
};
lineLayoutItem = {
"x": 18,
"y": 9,
"x2": 23,
"y2": 4,
"stroke": "#717171",
"type": "line-view",
"id": "57d49a28-7863-43bd-9593-6570758916f0"
};
boxLayoutItem = {
"fill": "#717171",
"stroke": "",
"x": 1,
"y": 1,
"width": 10,
"height": 5,
"type": "box-view",
"id": "89b88746-d325-487b-aec4-11b79afff9e8"
};
selection = [
[{
context: {
"layoutItem": lineLayoutItem,
"index": 1
}
},
{
context: {
"item": displayLayoutItem,
"supportsMultiSelect": true
}
}],
[{
context: {
"layoutItem": boxLayoutItem,
"index": 0
}
},
{
context: {
item: displayLayoutItem,
"supportsMultiSelect": true
}
}]
];
let viewContainer = document.createElement('div');
child.append(viewContainer);
component = new Vue({
provide: {
openmct: openmct,
selection: selection
},
el: viewContainer,
components: {
StylesView
},
template: '<styles-view/>'
});
return Vue.nextTick().then(() => {
styleViewComponentObject = component.$root.$children[0];
styleViewComponentObject.setEditState(true);
});
});
it('initializes the items in the view', () => {
expect(styleViewComponentObject.items.length).toBe(2);
});
it('initializes conditional styles', () => {
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
styleViewComponentObject.conditionalStyles = [];
styleViewComponentObject.initializeConditionalStyles();
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
});
it('updates applicable conditional styles', () => {
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
styleViewComponentObject.conditionalStyles = [];
styleViewComponentObject.initializeConditionalStyles();
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
styleViewComponentObject.updateConditionalStyle(conditionalStyle, 'border');
return Vue.nextTick().then(() => {
expect(styleViewComponentObject.domainObject.configuration.objectStyles).toBeDefined();
[boxLayoutItem, lineLayoutItem].forEach((item) => {
const itemStyles = styleViewComponentObject.domainObject.configuration.objectStyles[item.id].styles;
expect(itemStyles.length).toBe(2);
const foundStyle = itemStyles.find((style) => {
return style.conditionId === conditionalStyle.conditionId;
});
expect(foundStyle).toBeDefined();
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
Object.keys(foundStyle.style).forEach((key) => {
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
expect(foundStyle.style[key]).toEqual(conditionalStyle.style[key]);
});
});
});
});
it('updates applicable static styles', () => {
styleViewComponentObject.updateStaticStyle(staticStyle, 'border');
return Vue.nextTick().then(() => {
expect(styleViewComponentObject.domainObject.configuration.objectStyles).toBeDefined();
[boxLayoutItem, lineLayoutItem].forEach((item) => {
const itemStyle = styleViewComponentObject.domainObject.configuration.objectStyles[item.id].staticStyle;
expect(itemStyle).toBeDefined();
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
Object.keys(itemStyle.style).forEach((key) => {
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
expect(itemStyle.style[key]).toEqual(staticStyle.style[key]);
});
});
});
});
});
describe('the condition check for staleness', () => {
let conditionSetDomainObject;
beforeEach(() => {
conditionSetDomainObject = {
"configuration": {
"conditionTestData": [
{
"telemetry": "",
"metadata": "",
"input": ""
}
],
"conditionCollection": [
{
"id": "39584410-cbf9-499e-96dc-76f27e69885d",
"configuration": {
"name": "Unnamed Condition",
"output": "Any stale telemetry",
"trigger": "all",
"criteria": [
{
"id": "35400132-63b0-425c-ac30-8197df7d5862",
"telemetry": "any",
"operation": "isStale",
"input": [
"0.2"
],
"metadata": "dataReceived"
}
]
},
"summary": "Match if all criteria are met: Any telemetry is stale after 5 seconds"
},
{
"isDefault": true,
"id": "2532d90a-e0d6-4935-b546-3123522da2de",
"configuration": {
"name": "Default",
"output": "Default",
"trigger": "all",
"criteria": [
]
},
"summary": ""
}
]
},
"composition": [
{
"namespace": "",
"key": "test-object"
}
],
"telemetry": {
},
"name": "Condition Set",
"type": "conditionSet",
"identifier": {
"namespace": "",
"key": "cf4456a9-296a-4e6b-b182-62ed29cd15b9"
}
};
});
it('should evaluate as stale when telemetry is not received in the allotted time', (done) => {
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
conditionMgr.on('conditionSetResultUpdated', mockListener);
conditionMgr.telemetryObjects = {
"test-object": testTelemetryObject
};
conditionMgr.updateConditionTelemetryObjects();
setTimeout(() => {
expect(mockListener).toHaveBeenCalledWith({
output: 'Any stale telemetry',
id: {
namespace: '',
key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9'
},
conditionId: '39584410-cbf9-499e-96dc-76f27e69885d',
utc: undefined
});
done();
}, 300);
});
it('should not evaluate as stale when telemetry is received in the allotted time', (done) => {
const date = Date.now();
conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input = ["0.4"];
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
conditionMgr.on('conditionSetResultUpdated', mockListener);
conditionMgr.telemetryObjects = {
"test-object": testTelemetryObject
};
conditionMgr.updateConditionTelemetryObjects();
conditionMgr.telemetryReceived(testTelemetryObject, {
utc: date
});
setTimeout(() => {
expect(mockListener).toHaveBeenCalledWith({
output: 'Default',
id: {
namespace: '',
key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9'
},
conditionId: '2532d90a-e0d6-4935-b546-3123522da2de',
utc: undefined
});
done();
}, 300);
});
});
});