mirror of
https://github.com/nasa/openmct.git
synced 2025-06-04 08:30:48 +00:00
* no-implicit-coercion and no-unneeded-ternary * End every line with a semicolon * Spacing and formatting * Enabled semi-spacing * Applies npm run lint:fix to code after master merge * Fix merge issues * Switched operator-linebreak to 'before' Co-authored-by: Joshi <simplyrender@gmail.com>
361 lines
15 KiB
JavaScript
361 lines
15 KiB
JavaScript
/*****************************************************************************
|
|
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
*****************************************************************************/
|
|
|
|
define([
|
|
'./AutoflowTabularPlugin',
|
|
'./AutoflowTabularConstants',
|
|
'../../MCT',
|
|
'zepto',
|
|
'./dom-observer'
|
|
], function (AutoflowTabularPlugin, AutoflowTabularConstants, MCT, $, DOMObserver) {
|
|
xdescribe("AutoflowTabularPlugin", function () {
|
|
var testType;
|
|
var testObject;
|
|
var mockmct;
|
|
|
|
beforeEach(function () {
|
|
testType = "some-type";
|
|
testObject = { type: testType };
|
|
mockmct = new MCT();
|
|
spyOn(mockmct.composition, 'get');
|
|
spyOn(mockmct.objectViews, 'addProvider');
|
|
spyOn(mockmct.telemetry, 'getMetadata');
|
|
spyOn(mockmct.telemetry, 'getValueFormatter');
|
|
spyOn(mockmct.telemetry, 'limitEvaluator');
|
|
spyOn(mockmct.telemetry, 'request');
|
|
spyOn(mockmct.telemetry, 'subscribe');
|
|
|
|
var plugin = new AutoflowTabularPlugin({ type: testType });
|
|
plugin(mockmct);
|
|
});
|
|
|
|
it("installs a view provider", function () {
|
|
expect(mockmct.objectViews.addProvider).toHaveBeenCalled();
|
|
});
|
|
|
|
describe("installs a view provider which", function () {
|
|
var provider;
|
|
|
|
beforeEach(function () {
|
|
provider =
|
|
mockmct.objectViews.addProvider.calls.mostRecent().args[0];
|
|
});
|
|
|
|
it("applies its view to the type from options", function () {
|
|
expect(provider.canView(testObject)).toBe(true);
|
|
});
|
|
|
|
it("does not apply to other types", function () {
|
|
expect(provider.canView({ type: 'foo' })).toBe(false);
|
|
});
|
|
|
|
describe("provides a view which", function () {
|
|
var testKeys;
|
|
var testChildren;
|
|
var testContainer;
|
|
var testHistories;
|
|
var mockComposition;
|
|
var mockMetadata;
|
|
var mockEvaluator;
|
|
var mockUnsubscribes;
|
|
var callbacks;
|
|
var view;
|
|
var domObserver;
|
|
|
|
function waitsForChange() {
|
|
return new Promise(function (resolve) {
|
|
window.requestAnimationFrame(resolve);
|
|
});
|
|
}
|
|
|
|
function emitEvent(mockEmitter, type, event) {
|
|
mockEmitter.on.calls.all().forEach(function (call) {
|
|
if (call.args[0] === type) {
|
|
call.args[1](event);
|
|
}
|
|
});
|
|
}
|
|
|
|
beforeEach(function () {
|
|
callbacks = {};
|
|
|
|
testObject = { type: 'some-type' };
|
|
testKeys = ['abc', 'def', 'xyz'];
|
|
testChildren = testKeys.map(function (key) {
|
|
return {
|
|
identifier: {
|
|
namespace: "test",
|
|
key: key
|
|
},
|
|
name: "Object " + key
|
|
};
|
|
});
|
|
testContainer = $('<div>')[0];
|
|
domObserver = new DOMObserver(testContainer);
|
|
|
|
testHistories = testKeys.reduce(function (histories, key, index) {
|
|
histories[key] = {
|
|
key: key,
|
|
range: index + 10,
|
|
domain: key + index
|
|
};
|
|
|
|
return histories;
|
|
}, {});
|
|
|
|
mockComposition =
|
|
jasmine.createSpyObj('composition', ['load', 'on', 'off']);
|
|
mockMetadata =
|
|
jasmine.createSpyObj('metadata', ['valuesForHints']);
|
|
|
|
mockEvaluator = jasmine.createSpyObj('evaluator', ['evaluate']);
|
|
mockUnsubscribes = testKeys.reduce(function (map, key) {
|
|
map[key] = jasmine.createSpy('unsubscribe-' + key);
|
|
|
|
return map;
|
|
}, {});
|
|
|
|
mockmct.composition.get.and.returnValue(mockComposition);
|
|
mockComposition.load.and.callFake(function () {
|
|
testChildren.forEach(emitEvent.bind(null, mockComposition, 'add'));
|
|
|
|
return Promise.resolve(testChildren);
|
|
});
|
|
|
|
mockmct.telemetry.getMetadata.and.returnValue(mockMetadata);
|
|
mockmct.telemetry.getValueFormatter.and.callFake(function (metadatum) {
|
|
var mockFormatter = jasmine.createSpyObj('formatter', ['format']);
|
|
mockFormatter.format.and.callFake(function (datum) {
|
|
return datum[metadatum.hint];
|
|
});
|
|
|
|
return mockFormatter;
|
|
});
|
|
mockmct.telemetry.limitEvaluator.and.returnValue(mockEvaluator);
|
|
mockmct.telemetry.subscribe.and.callFake(function (obj, callback) {
|
|
var key = obj.identifier.key;
|
|
callbacks[key] = callback;
|
|
|
|
return mockUnsubscribes[key];
|
|
});
|
|
mockmct.telemetry.request.and.callFake(function (obj, request) {
|
|
var key = obj.identifier.key;
|
|
|
|
return Promise.resolve([testHistories[key]]);
|
|
});
|
|
mockMetadata.valuesForHints.and.callFake(function (hints) {
|
|
return [{ hint: hints[0] }];
|
|
});
|
|
|
|
view = provider.view(testObject);
|
|
view.show(testContainer);
|
|
|
|
return waitsForChange();
|
|
});
|
|
|
|
afterEach(function () {
|
|
domObserver.destroy();
|
|
});
|
|
|
|
it("populates its container", function () {
|
|
expect(testContainer.children.length > 0).toBe(true);
|
|
});
|
|
|
|
describe("when rows have been populated", function () {
|
|
function rowsMatch() {
|
|
var rows = $(testContainer).find(".l-autoflow-row").length;
|
|
|
|
return rows === testChildren.length;
|
|
}
|
|
|
|
it("shows one row per child object", function () {
|
|
return domObserver.when(rowsMatch);
|
|
});
|
|
|
|
it("adds rows on composition change", function () {
|
|
var child = {
|
|
identifier: {
|
|
namespace: "test",
|
|
key: "123"
|
|
},
|
|
name: "Object 123"
|
|
};
|
|
testChildren.push(child);
|
|
emitEvent(mockComposition, 'add', child);
|
|
|
|
return domObserver.when(rowsMatch);
|
|
});
|
|
|
|
it("removes rows on composition change", function () {
|
|
var child = testChildren.pop();
|
|
emitEvent(mockComposition, 'remove', child.identifier);
|
|
|
|
return domObserver.when(rowsMatch);
|
|
});
|
|
});
|
|
|
|
it("removes subscriptions when destroyed", function () {
|
|
testKeys.forEach(function (key) {
|
|
expect(mockUnsubscribes[key]).not.toHaveBeenCalled();
|
|
});
|
|
view.destroy();
|
|
testKeys.forEach(function (key) {
|
|
expect(mockUnsubscribes[key]).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it("provides a button to change column width", function () {
|
|
var initialWidth = AutoflowTabularConstants.INITIAL_COLUMN_WIDTH;
|
|
var nextWidth =
|
|
initialWidth + AutoflowTabularConstants.COLUMN_WIDTH_STEP;
|
|
|
|
expect($(testContainer).find('.l-autoflow-col').css('width'))
|
|
.toEqual(initialWidth + 'px');
|
|
|
|
$(testContainer).find('.change-column-width').click();
|
|
|
|
function widthHasChanged() {
|
|
var width = $(testContainer).find('.l-autoflow-col').css('width');
|
|
|
|
return width !== initialWidth + 'px';
|
|
}
|
|
|
|
return domObserver.when(widthHasChanged)
|
|
.then(function () {
|
|
expect($(testContainer).find('.l-autoflow-col').css('width'))
|
|
.toEqual(nextWidth + 'px');
|
|
});
|
|
});
|
|
|
|
it("subscribes to all child objects", function () {
|
|
testKeys.forEach(function (key) {
|
|
expect(callbacks[key]).toEqual(jasmine.any(Function));
|
|
});
|
|
});
|
|
|
|
it("displays historical telemetry", function () {
|
|
function rowTextDefined() {
|
|
return $(testContainer).find(".l-autoflow-item").filter(".r").text() !== "";
|
|
}
|
|
|
|
return domObserver.when(rowTextDefined).then(function () {
|
|
testKeys.forEach(function (key, index) {
|
|
var datum = testHistories[key];
|
|
var $cell = $(testContainer).find(".l-autoflow-row").eq(index).find(".r");
|
|
expect($cell.text()).toEqual(String(datum.range));
|
|
});
|
|
});
|
|
});
|
|
|
|
it("displays incoming telemetry", function () {
|
|
var testData = testKeys.map(function (key, index) {
|
|
return {
|
|
key: key,
|
|
range: index * 100,
|
|
domain: key + index
|
|
};
|
|
});
|
|
|
|
testData.forEach(function (datum) {
|
|
callbacks[datum.key](datum);
|
|
});
|
|
|
|
return waitsForChange().then(function () {
|
|
testData.forEach(function (datum, index) {
|
|
var $cell = $(testContainer).find(".l-autoflow-row").eq(index).find(".r");
|
|
expect($cell.text()).toEqual(String(datum.range));
|
|
});
|
|
});
|
|
});
|
|
|
|
it("updates classes for limit violations", function () {
|
|
var testClass = "some-limit-violation";
|
|
mockEvaluator.evaluate.and.returnValue({ cssClass: testClass });
|
|
testKeys.forEach(function (key) {
|
|
callbacks[key]({
|
|
range: 'foo',
|
|
domain: 'bar'
|
|
});
|
|
});
|
|
|
|
return waitsForChange().then(function () {
|
|
testKeys.forEach(function (datum, index) {
|
|
var $cell = $(testContainer).find(".l-autoflow-row").eq(index).find(".r");
|
|
expect($cell.hasClass(testClass)).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
it("automatically flows to new columns", function () {
|
|
var rowHeight = AutoflowTabularConstants.ROW_HEIGHT;
|
|
var sliderHeight = AutoflowTabularConstants.SLIDER_HEIGHT;
|
|
var count = testKeys.length;
|
|
var $container = $(testContainer);
|
|
var promiseChain = Promise.resolve();
|
|
|
|
function columnsHaveAutoflowed() {
|
|
var itemsHeight = $container.find('.l-autoflow-items').height();
|
|
var availableHeight = itemsHeight - sliderHeight;
|
|
var availableRows = Math.max(Math.floor(availableHeight / rowHeight), 1);
|
|
var columns = Math.ceil(count / availableRows);
|
|
|
|
return $container.find('.l-autoflow-col').length === columns;
|
|
}
|
|
|
|
$container.find('.abs').css({
|
|
position: 'absolute',
|
|
left: '0px',
|
|
right: '0px',
|
|
top: '0px',
|
|
bottom: '0px'
|
|
});
|
|
$container.css({ position: 'absolute' });
|
|
|
|
$container.appendTo(document.body);
|
|
|
|
function setHeight(height) {
|
|
$container.css('height', height + 'px');
|
|
|
|
return domObserver.when(columnsHaveAutoflowed);
|
|
}
|
|
|
|
for (var height = 0; height < rowHeight * count * 2; height += rowHeight / 2) {
|
|
promiseChain = promiseChain.then(setHeight.bind(this, height));
|
|
}
|
|
|
|
return promiseChain.then(function () {
|
|
$container.remove();
|
|
});
|
|
});
|
|
|
|
it("loads composition exactly once", function () {
|
|
var testObj = testChildren.pop();
|
|
emitEvent(mockComposition, 'remove', testObj.identifier);
|
|
testChildren.push(testObj);
|
|
emitEvent(mockComposition, 'add', testObj);
|
|
expect(mockComposition.load.calls.count()).toEqual(1);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|