From ba4c66866ced191428d57362afd25ba8698429f5 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 29 Dec 2015 13:59:06 -0800 Subject: [PATCH 1/8] [Time Conductor] Add tests for date-time picker --- .../DateTimePickerControllerSpec.js | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js b/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js index 957df1b36d..0c676f6548 100644 --- a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js +++ b/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js @@ -22,8 +22,8 @@ /*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ define( - ["../../src/controllers/DateTimePickerController"], - function (DateTimePickerController) { + ["../../src/controllers/DateTimePickerController", "moment"], + function (DateTimePickerController, moment) { "use strict"; describe("The DateTimePickerController", function () { @@ -39,6 +39,14 @@ define( }); } + function fireWatchCollection(expr, value) { + mockScope.$watchCollection.calls.forEach(function (call) { + if (call.args[0] === expr) { + call.args[1](value); + } + }); + } + beforeEach(function () { mockScope = jasmine.createSpyObj( "$scope", @@ -57,6 +65,34 @@ define( ); }); + it("updates date/time state in scope when model changes", function () { + fireWatch( + "ngModel[field]", + moment.utc("1998-01-06 12:34:56").valueOf() + ); + expect(mockScope.date.year).toEqual(1998); + expect(mockScope.date.month).toEqual(0); // Months are zero-indexed + expect(mockScope.date.day).toEqual(6); + expect(mockScope.time.hours).toEqual(12); + expect(mockScope.time.minutes).toEqual(34); + expect(mockScope.time.seconds).toEqual(56); + }); + + it("updates value in model when values in scope change", function () { + mockScope.date = { + year: 1998, + month: 0, + day: 6 + }; + mockScope.time = { + hours: 12, + minutes: 34, + seconds: 56 + }; + fireWatchCollection("date", mockScope.date); + expect(mockScope.ngModel[mockScope.field]) + .toEqual(moment.utc("1998-01-06 12:34:56").valueOf()); + }); }); } From 3f4ed46c1c18f96eb8561e9160114bbaf956a791 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 29 Dec 2015 15:26:18 -0800 Subject: [PATCH 2/8] [Time Conductor] More tests for date-time picker Sufficient for 100% line coverage. --- .../DateTimePickerControllerSpec.js | 111 ++++++++++++++++-- 1 file changed, 98 insertions(+), 13 deletions(-) diff --git a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js b/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js index 0c676f6548..8fa122e438 100644 --- a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js +++ b/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js @@ -65,19 +65,6 @@ define( ); }); - it("updates date/time state in scope when model changes", function () { - fireWatch( - "ngModel[field]", - moment.utc("1998-01-06 12:34:56").valueOf() - ); - expect(mockScope.date.year).toEqual(1998); - expect(mockScope.date.month).toEqual(0); // Months are zero-indexed - expect(mockScope.date.day).toEqual(6); - expect(mockScope.time.hours).toEqual(12); - expect(mockScope.time.minutes).toEqual(34); - expect(mockScope.time.seconds).toEqual(56); - }); - it("updates value in model when values in scope change", function () { mockScope.date = { year: 1998, @@ -94,6 +81,104 @@ define( .toEqual(moment.utc("1998-01-06 12:34:56").valueOf()); }); + describe("once initialized with model state", function () { + var testTime = moment.utc("1998-01-06 12:34:56").valueOf(); + + beforeEach(function () { + fireWatch("ngModel[field]", testTime); + }); + + it("exposes date/time values in scope", function () { + expect(mockScope.date.year).toEqual(1998); + expect(mockScope.date.month).toEqual(0); // Months are zero-indexed + expect(mockScope.date.day).toEqual(6); + expect(mockScope.time.hours).toEqual(12); + expect(mockScope.time.minutes).toEqual(34); + expect(mockScope.time.seconds).toEqual(56); + }); + + it("provides names for time properties", function () { + Object.keys(mockScope.time).forEach(function (key) { + expect(mockScope.nameFor(key)) + .toEqual(jasmine.any(String)); + }); + }); + + it("provides options for time properties", function () { + Object.keys(mockScope.time).forEach(function (key) { + expect(mockScope.optionsFor(key)) + .toEqual(jasmine.any(Array)); + }); + }); + + it("exposes times to populate calendar as a table", function () { + var matchingCell; + // Should be able to find the selected date + mockScope.table.forEach(function (row) { + row.forEach(function (cell) { + if (cell.dayOfYear === 6) { + matchingCell = cell; + } + }); + }); + expect(matchingCell).toEqual({ + year: 1998, + month: 0, + day: 6, + dayOfYear: 6 + }); + }); + + it("allows the displayed month to be advanced", function () { + // Around the edges of the displayed calendar we + // may be in previous or subsequent month, so + // test around the middle. + var i, originalMonth = mockScope.table[2][0].month; + + function mod12(month) { + return ((month % 12) + 12) % 12; + } + + for (i = 1; i <= 12; i += 1) { + mockScope.changeMonth(1); + expect(mockScope.table[2][0].month) + .toEqual(mod12(originalMonth + i)); + } + + for (i = 11; i >= -12; i -= 1) { + mockScope.changeMonth(-1); + expect(mockScope.table[2][0].month) + .toEqual(mod12(originalMonth + i)); + } + }); + + it("allows checking if a cell is in the current month", function () { + expect(mockScope.isInCurrentMonth(mockScope.table[2][0])) + .toBe(true); + }); + + it("allows cells to be selected", function () { + mockScope.select(mockScope.table[2][0]); + expect(mockScope.isSelected(mockScope.table[2][0])) + .toBe(true); + mockScope.select(mockScope.table[2][1]); + expect(mockScope.isSelected(mockScope.table[2][0])) + .toBe(false); + expect(mockScope.isSelected(mockScope.table[2][1])) + .toBe(true); + }); + + it("allows cells to be compared", function () { + var table = mockScope.table; + expect(mockScope.dateEquals(table[2][0], table[2][1])) + .toBe(false); + expect(mockScope.dateEquals(table[2][1], table[2][1])) + .toBe(true); + }); + + }); + + }); } ); From 30fec7c2ac9285cd7c14e254a104d1ff0a9973bf Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 29 Dec 2015 15:37:09 -0800 Subject: [PATCH 3/8] [Time Conductor] Test mct-click-elsewhere --- .../test/directives/MCTClickElsewhereSpec.js | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/platform/commonUI/general/test/directives/MCTClickElsewhereSpec.js b/platform/commonUI/general/test/directives/MCTClickElsewhereSpec.js index 9fa17763fe..1d8fe5e5ce 100644 --- a/platform/commonUI/general/test/directives/MCTClickElsewhereSpec.js +++ b/platform/commonUI/general/test/directives/MCTClickElsewhereSpec.js @@ -34,14 +34,14 @@ define( mockElement, testAttrs, mockBody, - mockParentEl, + mockPlainEl, testRect, mctClickElsewhere; function testEvent(x, y) { return { - pageX: x, - pageY: y, + clientX: x, + clientY: y, preventDefault: jasmine.createSpy("preventDefault") }; } @@ -55,8 +55,8 @@ define( jasmine.createSpyObj("element", JQLITE_METHODS); mockBody = jasmine.createSpyObj("body", JQLITE_METHODS); - mockParentEl = - jasmine.createSpyObj("parent", ["getBoundingClientRect"]); + mockPlainEl = + jasmine.createSpyObj("htmlElement", ["getBoundingClientRect"]); testAttrs = { mctClickElsewhere: "some Angular expression" @@ -67,6 +67,8 @@ define( width: 60, height: 75 }; + mockElement[0] = mockPlainEl; + mockPlainEl.getBoundingClientRect.andReturn(testRect); mockDocument.find.andReturn(mockBody); @@ -78,6 +80,49 @@ define( expect(mctClickElsewhere.restrict).toEqual("A"); }); + it("detaches listeners when destroyed", function () { + expect(mockBody.off).not.toHaveBeenCalled(); + mockScope.$on.calls.forEach(function (call) { + if (call.args[0] === '$destroy') { + call.args[1](); + } + }); + expect(mockBody.off).toHaveBeenCalled(); + expect(mockBody.off.mostRecentCall.args) + .toEqual(mockBody.on.mostRecentCall.args); + }); + + it("listens for mousedown on the document's body", function () { + expect(mockBody.on) + .toHaveBeenCalledWith('mousedown', jasmine.any(Function)); + }); + + describe("when a click occurs outside the element's bounds", function () { + beforeEach(function () { + mockBody.on.mostRecentCall.args[1](testEvent( + testRect.left + testRect.width + 10, + testRect.top + testRect.height + 10 + )); + }); + + it("triggers an evaluation of its related Angular expression", function () { + expect(mockScope.$eval) + .toHaveBeenCalledWith(testAttrs.mctClickElsewhere); + }); + }); + + describe("when a click occurs within the element's bounds", function () { + beforeEach(function () { + mockBody.on.mostRecentCall.args[1](testEvent( + testRect.left + testRect.width / 2, + testRect.top + testRect.height / 2 + )); + }); + + it("triggers no evaluation", function () { + expect(mockScope.$eval).not.toHaveBeenCalled(); + }); + }); }); } From c436bcce0a405ea01e7debefe967b5fc712c3809 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 30 Dec 2015 09:29:24 -0800 Subject: [PATCH 4/8] [Time Conductor] Test updated fixed position behavior Verify interactions from FixedControllers on events issued by the time conductor. --- .../layout/test/FixedControllerSpec.js | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/platform/features/layout/test/FixedControllerSpec.js b/platform/features/layout/test/FixedControllerSpec.js index 31d5e06659..0be6fec4f3 100644 --- a/platform/features/layout/test/FixedControllerSpec.js +++ b/platform/features/layout/test/FixedControllerSpec.js @@ -423,6 +423,59 @@ define( // Style should have been updated expect(controller.selected().style).not.toEqual(oldStyle); }); + + describe("on display bounds changes", function () { + var testBounds; + + beforeEach(function () { + testBounds = { start: 123, end: 321 }; + mockScope.domainObject = mockDomainObject; + mockScope.model = testModel; + findWatch("domainObject")(mockDomainObject); + findWatch("model.modified")(testModel.modified); + findWatch("model.composition")(mockScope.model.composition); + findOn('telemetry:display:bounds')({}, testBounds); + }); + + it("issues new requests", function () { + expect(mockHandle.request).toHaveBeenCalled(); + }); + + it("requests only a single point", function () { + expect(mockHandle.request.mostRecentCall.args[0].size) + .toEqual(1); + }); + + describe("and after data has been received", function () { + var mockSeries, + testValue; + + beforeEach(function () { + testValue = 12321; + + mockSeries = jasmine.createSpyObj('series', [ + 'getPointCount', + 'getDomainValue', + 'getRangeValue' + ]); + mockSeries.getPointCount.andReturn(1); + mockSeries.getRangeValue.andReturn(testValue); + + // Fire the callback associated with the request + mockHandle.request.mostRecentCall.args[1]( + mockHandle.getTelemetryObjects()[0], + mockSeries + ); + }); + + it("updates displayed values", function () { + expect(controller.getElements()[0].value) + .toEqual("Formatted " + testValue); + }); + }); + + }); + }); } ); From 38b5756d8d3d8ed00a31a0fa399d76aae0bf5261 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 30 Dec 2015 10:04:04 -0800 Subject: [PATCH 5/8] [Time Conductor] Verify plot bounds retention Verify that the domain axis of a plot retains bounds from the time conductor, instead of doing its default behavior of fitting to the data. --- .../features/plot/test/PlotControllerSpec.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/platform/features/plot/test/PlotControllerSpec.js b/platform/features/plot/test/PlotControllerSpec.js index 8edab2fc6d..24553a79b2 100644 --- a/platform/features/plot/test/PlotControllerSpec.js +++ b/platform/features/plot/test/PlotControllerSpec.js @@ -285,6 +285,33 @@ define( fireWatch("axes[1].active.key", 'someNewKey'); expect(mockHandle.request.calls.length).toEqual(2); }); + + it("maintains externally-provided domain axis bounds after data is received", function () { + mockSeries.getPointCount.andReturn(3); + mockSeries.getRangeValue.andReturn(42); + mockSeries.getDomainValue.andCallFake(function (i) { + return 2500 + i * 2500; + }); + + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + fireEvent("telemetry:display:bounds", [ + {}, + { start: 0, end: 10000 } + ]); + mockHandle.request.mostRecentCall.args[1]( + mockDomainObject, + mockSeries + ); + + // Pan-zoom state should reflect bounds set externally; + // domain axis should not have shrunk to fit data. + expect( + controller.getSubPlots()[0].panZoomStack.getOrigin()[0] + ).toEqual(0); + expect( + controller.getSubPlots()[0].panZoomStack.getDimensions()[0] + ).toEqual(10000); + }); }); } ); From 2358541d9100e79e54307937f58e793eca1244af Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 30 Dec 2015 10:10:23 -0800 Subject: [PATCH 6/8] [Time Conductor] Update RangeColumn spec Update RangeColumn spec. Changes appear to have been related to limits (WTD-1337), but making changes in the context of updating tests for time conductor, https://github.com/nasa/openmctweb/issues/116 --- .../scrolling/test/RangeColumnSpec.js | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/platform/features/scrolling/test/RangeColumnSpec.js b/platform/features/scrolling/test/RangeColumnSpec.js index c100a9efa0..b77245bb82 100644 --- a/platform/features/scrolling/test/RangeColumnSpec.js +++ b/platform/features/scrolling/test/RangeColumnSpec.js @@ -32,16 +32,14 @@ define( var TEST_RANGE_VALUE = "some formatted range value"; describe("A range column", function () { - var mockDataSet, + var testDatum, testMetadata, mockFormatter, + mockDomainObject, column; beforeEach(function () { - mockDataSet = jasmine.createSpyObj( - "data", - [ "getRangeValue" ] - ); + testDatum = { testKey: 123, otherKey: 456 }; mockFormatter = jasmine.createSpyObj( "formatter", [ "formatDomainValue", "formatRangeValue" ] @@ -50,6 +48,10 @@ define( key: "testKey", name: "Test Name" }; + mockDomainObject = jasmine.createSpyObj( + "domainObject", + [ "getModel", "getCapability" ] + ); mockFormatter.formatRangeValue.andReturn(TEST_RANGE_VALUE); column = new RangeColumn(testMetadata, mockFormatter); @@ -59,20 +61,13 @@ define( expect(column.getTitle()).toEqual("Test Name"); }); - xit("looks up data from a data set", function () { - column.getValue(undefined, mockDataSet, 42); - expect(mockDataSet.getRangeValue) - .toHaveBeenCalledWith(42, "testKey"); - }); - - xit("formats range values as numbers", function () { - mockDataSet.getRangeValue.andReturn(123.45678); - expect(column.getValue(undefined, mockDataSet, 42).text) + it("formats range values as numbers", function () { + expect(column.getValue(mockDomainObject, testDatum).text) .toEqual(TEST_RANGE_VALUE); // Make sure that service interactions were as expected expect(mockFormatter.formatRangeValue) - .toHaveBeenCalledWith(123.45678); + .toHaveBeenCalledWith(testDatum.testKey); expect(mockFormatter.formatDomainValue) .not.toHaveBeenCalled(); }); From b9146fbeac8bbf05ebef480361024c59709a75c6 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 30 Dec 2015 10:23:02 -0800 Subject: [PATCH 7/8] [Time Conductor] Test TelemetryHandle.getDatum Test ability to look up datum object by index (used to support evaluation of limit state in Fixed Position and similar single-value views while time conducting.) --- .../telemetry/test/TelemetryHandleSpec.js | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/platform/telemetry/test/TelemetryHandleSpec.js b/platform/telemetry/test/TelemetryHandleSpec.js index 8e543d21dd..f342572045 100644 --- a/platform/telemetry/test/TelemetryHandleSpec.js +++ b/platform/telemetry/test/TelemetryHandleSpec.js @@ -47,7 +47,13 @@ define( mockQ = jasmine.createSpyObj('$q', ['when', 'all']); mockSubscription = jasmine.createSpyObj( 'subscription', - ['unsubscribe', 'getTelemetryObjects', 'promiseTelemetryObjects'] + [ + 'makeDatum', + 'getDatum', + 'unsubscribe', + 'getTelemetryObjects', + 'promiseTelemetryObjects' + ] ); mockDomainObject = jasmine.createSpyObj( 'domainObject', @@ -112,6 +118,20 @@ define( expect(handle.getSeries(mockDomainObject)) .toEqual(mockSeries); }); + + it("provides access to the datum objects by index", function () { + var testDatum = { a: 1, b: 2 }, testIndex = 42; + mockSubscription.makeDatum.andReturn(testDatum); + handle.request({}); + expect(handle.getDatum(mockDomainObject, testIndex)) + .toEqual(testDatum); + expect(mockSubscription.makeDatum) + .toHaveBeenCalledWith( + mockDomainObject, + mockSeries, + testIndex + ); + }); }); } ); From 2436c32e6df2a85b3ac571c9ddbff97483e18bbd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 6 Jan 2016 13:00:16 -0800 Subject: [PATCH 8/8] [Time Conductor] Split test cases Verify table structure separately from table contents per code review feedback, https://github.com/nasa/openmctweb/pull/451/files#r48999214 --- .../test/controllers/DateTimePickerControllerSpec.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js b/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js index 8fa122e438..78f5e973ff 100644 --- a/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js +++ b/platform/commonUI/general/test/controllers/DateTimePickerControllerSpec.js @@ -112,6 +112,18 @@ define( }); it("exposes times to populate calendar as a table", function () { + // Verify that data structure is as expected by template + expect(mockScope.table).toEqual(jasmine.any(Array)); + expect(mockScope.table[0]).toEqual(jasmine.any(Array)); + expect(mockScope.table[0][0]).toEqual({ + year: jasmine.any(Number), + month: jasmine.any(Number), + day: jasmine.any(Number), + dayOfYear: jasmine.any(Number) + }); + }); + + it("contains the current date in its initial table", function () { var matchingCell; // Should be able to find the selected date mockScope.table.forEach(function (row) {