[Styles] add unit tests (#3557)

* unit tests for inspector styles feature
* add mock capability for local storage

Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
David Tsay 2021-06-22 06:50:49 -07:00 committed by GitHub
parent 71392915c1
commit 7ca559fbe4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 456 additions and 0 deletions

View File

@ -0,0 +1,218 @@
/*****************************************************************************
* 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 {
mockLocalStorage
} from 'utils/testing/mockLocalStorage';
import {
mockTelemetryTableSelection,
mockMultiSelectionSameStyles,
mockMultiSelectionMixedStyles,
mockMultiSelectionNonSpecificStyles,
mockStyle
} from './InspectorStylesSpecMocks';
import Vue from 'vue';
import StylesView from '@/plugins/condition/components/inspector/StylesView.vue';
import SavedStylesView from '@/ui/inspector/styles/SavedStylesView.vue';
import stylesManager from '@/ui/inspector/styles/StylesManager';
describe("the inspector", () => {
let openmct;
let selection;
let stylesViewComponent;
let savedStylesViewComponent;
mockLocalStorage();
beforeEach((done) => {
openmct = createOpenMct();
openmct.on('start', done);
openmct.startHeadless();
});
afterEach(() => {
return resetApplicationState(openmct);
});
it("should allow a style to be saved", () => {
selection = mockTelemetryTableSelection;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
expect(savedStylesViewComponent.$children[0].savedStyles.length).toBe(0);
stylesViewComponent.$children[0].saveStyle(mockStyle);
expect(savedStylesViewComponent.$children[0].savedStyles.length).toBe(1);
});
it("should display all saved styles", () => {
selection = mockTelemetryTableSelection;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
expect(savedStylesViewComponent.$children[0].$children.length).toBe(0);
stylesViewComponent.$children[0].saveStyle(mockStyle);
stylesViewComponent.$nextTick().then(() => {
expect(savedStylesViewComponent.$children[0].$children.length).toBe(1);
});
});
it("should allow a saved style to be applied", () => {
spyOn(openmct.editor, 'isEditing').and.returnValue(true);
selection = mockTelemetryTableSelection;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
stylesViewComponent.$children[0].saveStyle(mockStyle);
stylesViewComponent.$nextTick().then(() => {
const styleSelectorComponent = savedStylesViewComponent.$children[0].$children[0];
styleSelectorComponent.selectStyle();
savedStylesViewComponent.$nextTick().then(() => {
const styleEditorComponentIndex = stylesViewComponent.$children[0].$children.length - 1;
const styleEditorComponent = stylesViewComponent.$children[0].$children[styleEditorComponentIndex];
const styles = styleEditorComponent.$children.filter(component => component.options.value === mockStyle.color);
expect(styles.length).toBe(3);
});
});
});
it("should allow a saved style to be deleted", () => {
selection = mockTelemetryTableSelection;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
stylesViewComponent.$children[0].saveStyle(mockStyle);
expect(savedStylesViewComponent.$children[0].savedStyles.length).toBe(1);
savedStylesViewComponent.$children[0].deleteStyle(0);
expect(savedStylesViewComponent.$children[0].savedStyles.length).toBe(0);
});
it("should prevent a style from being saved when the number of saved styles is at the limit", () => {
spyOn(SavedStylesView.methods, 'showLimitReachedDialog').and.callThrough();
selection = mockTelemetryTableSelection;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
for (let i = 1; i <= 20; i++) {
stylesViewComponent.$children[0].saveStyle(mockStyle);
}
expect(SavedStylesView.methods.showLimitReachedDialog).not.toHaveBeenCalled();
expect(savedStylesViewComponent.$children[0].savedStyles.length).toBe(20);
stylesViewComponent.$children[0].saveStyle(mockStyle);
expect(SavedStylesView.methods.showLimitReachedDialog).toHaveBeenCalled();
expect(savedStylesViewComponent.$children[0].savedStyles.length).toBe(20);
});
it("should allow styles from multi-selections to be saved", () => {
spyOn(openmct.editor, 'isEditing').and.returnValue(true);
selection = mockMultiSelectionSameStyles;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
stylesViewComponent.$nextTick().then(() => {
const styleEditorComponentIndex = stylesViewComponent.$children[0].$children.length - 1;
const styleEditorComponent = stylesViewComponent.$children[0].$children[styleEditorComponentIndex];
const saveStyleButtonIndex = styleEditorComponent.$children.length - 1;
const saveStyleButton = styleEditorComponent.$children[saveStyleButtonIndex];
expect(saveStyleButton.$listeners.click).not.toBe(undefined);
saveStyleButton.$listeners.click();
expect(savedStylesViewComponent.$children[0].savedStyles.length).toBe(1);
});
});
it("should prevent mixed styles from being saved", () => {
spyOn(openmct.editor, 'isEditing').and.returnValue(true);
selection = mockMultiSelectionMixedStyles;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
stylesViewComponent.$nextTick().then(() => {
const styleEditorComponentIndex = stylesViewComponent.$children[0].$children.length - 1;
const styleEditorComponent = stylesViewComponent.$children[0].$children[styleEditorComponentIndex];
const saveStyleButtonIndex = styleEditorComponent.$children.length - 1;
const saveStyleButton = styleEditorComponent.$children[saveStyleButtonIndex];
expect(saveStyleButton.$listeners.click).toBe(undefined);
});
});
it("should prevent non-specific styles from being saved", () => {
spyOn(openmct.editor, 'isEditing').and.returnValue(true);
selection = mockMultiSelectionNonSpecificStyles;
stylesViewComponent = createViewComponent(StylesView, selection, openmct);
savedStylesViewComponent = createViewComponent(SavedStylesView, selection, openmct);
stylesViewComponent.$nextTick().then(() => {
const styleEditorComponentIndex = stylesViewComponent.$children[0].$children.length - 1;
const styleEditorComponent = stylesViewComponent.$children[0].$children[styleEditorComponentIndex];
const saveStyleButtonIndex = styleEditorComponent.$children.length - 1;
const saveStyleButton = styleEditorComponent.$children[saveStyleButtonIndex];
expect(saveStyleButton.$listeners.click).toBe(undefined);
});
});
function createViewComponent(component) {
const element = document.createElement('div');
const child = document.createElement('div');
element.appendChild(child);
const config = {
provide: {
openmct,
selection,
stylesManager
},
el: element,
components: {},
template: `<${component.name} />`
};
config.components[component.name] = component;
return new Vue(config).$mount();
}
});

View File

@ -0,0 +1,204 @@
export const mockTelemetryTableSelection = [
[{
context: {
item: {
configuration: {},
type: 'table',
identifier: {
key: 'mock-telemetry-table-1',
namespace: ''
}
}
}
}]
];
export const mockStyle = {
backgroundColor: '#ff0000',
border: '#ff0000',
color: '#ff0000'
};
const mockDisplayLayoutPath = {
context: {
item: {
identifier: {
key: "6af3200d-928b-4ff0-8ed0-b94a0e6752d1",
namespace: ""
},
type: "layout",
configuration: {
items: [
{
id: "dd3202e5-40d0-4112-8951-00f0f1ed6a29",
type: "text-view",
fontSize: "default",
font: "default"
},
{
id: "b522d636-90b2-4f5f-9588-2a0345c30f87",
type: "text-view",
fontSize: "default",
font: "default"
},
{
id: "537b7596-b442-44fe-b464-07f56bdc67c8",
type: "text-view",
fontSize: "default",
font: "default"
},
{
id: "3f17162f-a822-4e39-8332-6aa39b79d022",
type: "text-view",
fontSize: "default",
font: "default"
},
{
id: "c1c5acd8-a14b-450c-8c94-ce0075dd9912",
type: "text-view",
fontSize: "8",
font: "monospace-bold"
}
],
objectStyles: {
"dd3202e5-40d0-4112-8951-00f0f1ed6a29": {
staticStyle: {
style: {
backgroundColor: "#0000ff",
border: "1px solid #0000ff"
}
}
},
"b522d636-90b2-4f5f-9588-2a0345c30f87": {
staticStyle: {
style: {
backgroundColor: "#ff0000",
border: "1px solid #ff0000"
}
}
},
"537b7596-b442-44fe-b464-07f56bdc67c8": {
staticStyle: {
style: {
backgroundColor: "#ff0000",
border: "1px solid #ff0000"
}
}
},
"3f17162f-a822-4e39-8332-6aa39b79d022": {
staticStyle: {
style: {
backgroundColor: "#0000ff",
border: "1px solid #0000ff",
color: "#0000ff"
}
}
},
"c1c5acd8-a14b-450c-8c94-ce0075dd9912": {
staticStyle: {
style: {
backgroundColor: "#0000ff",
border: "1px solid #0000ff",
color: "#0000ff"
}
}
}
}
}
},
supportsMultiSelect: true
}
};
const mockTextBox1Path = {
context: {
index: 0,
layoutItem: {
id: "dd3202e5-40d0-4112-8951-00f0f1ed6a29",
type: "text-view",
fontSize: "default",
font: "default"
}
}
};
const mockTextBox2Path = {
context: {
index: 1,
layoutItem: {
id: "b522d636-90b2-4f5f-9588-2a0345c30f87",
type: "text-view",
fontSize: "default",
font: "default"
}
}
};
const mockTextBox3Path = {
context: {
index: 2,
layoutItem: {
id: "537b7596-b442-44fe-b464-07f56bdc67c8",
type: "text-view",
fontSize: "default",
font: "default"
}
}
};
const mockTextBox4Path = {
context: {
index: 3,
layoutItem: {
id: "3f17162f-a822-4e39-8332-6aa39b79d022",
type: "text-view",
fontSize: "default",
font: "default"
}
}
};
const mockTextBox5Path = {
context: {
index: 4,
layoutItem: {
id: "c1c5acd8-a14b-450c-8c94-ce0075dd9912",
type: "text-view",
fontSize: "8",
font: "default-bold"
}
}
};
export const mockMultiSelectionSameStyles = [
[
mockTextBox2Path,
mockDisplayLayoutPath
],
[
mockTextBox3Path,
mockDisplayLayoutPath
]
];
export const mockMultiSelectionMixedStyles = [
[
mockTextBox1Path,
mockDisplayLayoutPath
],
[
mockTextBox2Path,
mockDisplayLayoutPath
]
];
export const mockMultiSelectionNonSpecificStyles = [
[
mockTextBox4Path,
mockDisplayLayoutPath
],
[
mockTextBox5Path,
mockDisplayLayoutPath
]
];

View File

@ -21,6 +21,7 @@
*****************************************************************************/
import MCT from 'MCT';
let nativeFunctions = [];
let mockObjects = setMockObjects();

View File

@ -0,0 +1,33 @@
export function mockLocalStorage() {
let store;
beforeEach(() => {
spyOn(Storage.prototype, 'getItem').and.callFake(getItem);
spyOn(Storage.prototype, 'setItem').and.callFake(setItem);
spyOn(Storage.prototype, 'removeItem').and.callFake(removeItem);
spyOn(Storage.prototype, 'clear').and.callFake(clear);
store = {};
function getItem(key) {
return store[key];
}
function setItem(key, value) {
store[key] = typeof value === 'string' ? value : JSON.stringify(value);
}
function removeItem(key) {
store[key] = undefined;
delete store[key];
}
function clear() {
store = {};
}
});
afterEach(() => {
store = undefined;
});
}