diff --git a/platform/features/timeline/bundle.js b/platform/features/timeline/bundle.js index 5be95f643c..f298cb887e 100644 --- a/platform/features/timeline/bundle.js +++ b/platform/features/timeline/bundle.js @@ -22,6 +22,7 @@ /*global define*/ define([ + "./src/actions/ExportTimelineAsCSVAction", "./src/controllers/TimelineController", "./src/controllers/TimelineGraphController", "./src/controllers/TimelineDateTimeController", @@ -50,6 +51,7 @@ define([ "text!./res/templates/controls/datetime.html", 'legacyRegistry' ], function ( + ExportTimelineAsCSVAction, TimelineController, TimelineGraphController, TimelineDateTimeController, @@ -85,6 +87,15 @@ define([ "description": "Resources, templates, CSS, and code for Timelines.", "resources": "res", "extensions": { + "actions": [ + { + "key": "timeline.export", + "name": "Export Timeline as CSV", + "category": "contextual", + "implementation": ExportTimelineAsCSVAction, + "depends": [ "exportService", "notificationService" ] + } + ], "constants": [ { "key": "TIMELINE_MINIMUM_DURATION", diff --git a/platform/features/timeline/src/actions/CompositionColumn.js b/platform/features/timeline/src/actions/CompositionColumn.js new file mode 100644 index 0000000000..b7208c3e92 --- /dev/null +++ b/platform/features/timeline/src/actions/CompositionColumn.js @@ -0,0 +1,50 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define*/ + +define([], function () { + "use strict"; + + /** + * A column containing references to other objects contained + * in a domain object's composition. + * @param {number} index the zero-based index of the composition + * element associated with this column + * @constructor + * @implements {platform/features/timeline.TimelineCSVColumn} + */ + function CompositionColumn(index) { + this.index = index; + } + + CompositionColumn.prototype.name = function () { + return "Child " + (this.index + 1); + }; + + CompositionColumn.prototype.value = function (domainObject) { + var model = domainObject.getModel(), + composition = model.composition || []; + return (composition[this.index]) || ""; + }; + + return CompositionColumn; +}); diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js new file mode 100644 index 0000000000..387c0839a0 --- /dev/null +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js @@ -0,0 +1,70 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define*/ + +define(["./ExportTimelineAsCSVTask"], function (ExportTimelineAsCSVTask) { + 'use strict'; + + /** + * Implements the "Export Timeline as CSV" action. + * + * @param exportService the service used to perform the CSV export + * @param notificationService the service used to show notifications + * @param context the Action's context + * @implements {Action} + * @constructor + * @memberof {platform/features/timeline} + */ + function ExportTimelineAsCSVAction(exportService, notificationService, context) { + this.task = new ExportTimelineAsCSVTask( + exportService, + context.domainObject + ); + this.notificationService = notificationService; + } + + ExportTimelineAsCSVAction.prototype.perform = function () { + var notificationService = this.notificationService, + notification = notificationService.notify({ + title: "Exporting CSV", + unknownProgress: true + }); + + return this.task.run() + .then(function () { + notification.dismiss(); + }) + .catch(function () { + notification.dismiss(); + notificationService.error("Error exporting CSV"); + }); + }; + + ExportTimelineAsCSVAction.appliesTo = function (context) { + return context.domainObject && + context.domainObject.hasCapability('type') && + context.domainObject.getCapability('type') + .instanceOf('timeline'); + }; + + return ExportTimelineAsCSVAction; +}); \ No newline at end of file diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js new file mode 100644 index 0000000000..253db5c8b9 --- /dev/null +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -0,0 +1,70 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,Promise*/ + +/** + * Module defining ExportTimelineAsCSVTask. Created by vwoeltje on 2/8/16. + */ +define([ + "./TimelineTraverser", + "./TimelineColumnizer" +], function (TimelineTraverser, TimelineColumnizer) { + "use strict"; + + /** + * Runs (and coordinates) the preparation and export of CSV data + * for the "Export Timeline as CSV" action. + * + * @constructor + * @memberof {platform/features/timeline} + * @param exportService the service used to export as CSV + * @param {DomainObject} domainObject the timeline being exported + */ + function ExportTimelineAsCSVTask(exportService, domainObject) { + this.domainObject = domainObject; + this.exportService = exportService; + } + + /** + * Run this CSV export task. + * + * @returns {Promise} a promise that will be resolved when the + * export has finished (or rejected if there are problems.) + */ + ExportTimelineAsCSVTask.prototype.run = function () { + var exportService = this.exportService; + + function doExport(objects) { + var exporter = new TimelineColumnizer(objects), + options = { headers: exporter.headers() }; + return exporter.rows().then(function (rows) { + return exportService.exportCSV(rows, options); + }); + } + + return new TimelineTraverser(this.domainObject) + .buildObjectList() + .then(doExport); + }; + + return ExportTimelineAsCSVTask; +}); diff --git a/platform/features/timeline/src/actions/IdColumn.js b/platform/features/timeline/src/actions/IdColumn.js new file mode 100644 index 0000000000..56ddfe385f --- /dev/null +++ b/platform/features/timeline/src/actions/IdColumn.js @@ -0,0 +1,44 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define*/ + +define([], function () { + "use strict"; + + /** + * A column showing domain object identifiers. + * @constructor + * @implements {platform/features/timeline.TimelineCSVColumn} + */ + function IdColumn() { + } + + IdColumn.prototype.name = function () { + return "Identifier"; + }; + + IdColumn.prototype.value = function (domainObject) { + return domainObject.getId(); + }; + + return IdColumn; +}); diff --git a/platform/features/timeline/src/actions/MetadataColumn.js b/platform/features/timeline/src/actions/MetadataColumn.js new file mode 100644 index 0000000000..c94237a917 --- /dev/null +++ b/platform/features/timeline/src/actions/MetadataColumn.js @@ -0,0 +1,50 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define*/ + +define([], function () { + "use strict"; + + /** + * A column reflecting properties from domain object metadata. + * @constructor + * @implements {platform/features/timeline.TimelineCSVColumn} + */ + function MetadataColumn(propertyName) { + this.propertyName = propertyName; + } + + MetadataColumn.prototype.name = function () { + return this.propertyName; + }; + + MetadataColumn.prototype.value = function (domainObject) { + var properties = domainObject.useCapability('metadata'), + name = this.propertyName; + return properties.reduce(function (value, property) { + return property.name === name ? + property.value : value; + }, ""); + }; + + return MetadataColumn; +}); diff --git a/platform/features/timeline/src/actions/ModeColumn.js b/platform/features/timeline/src/actions/ModeColumn.js new file mode 100644 index 0000000000..4ae61b30d3 --- /dev/null +++ b/platform/features/timeline/src/actions/ModeColumn.js @@ -0,0 +1,49 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define*/ + +define([], function () { + "use strict"; + + /** + * A column showing relationships to activity modes. + * @constructor + * @param {number} index the zero-based index of the composition + * element associated with this column + * @implements {platform/features/timeline.TimelineCSVColumn} + */ + function ModeColumn(index) { + this.index = index; + } + + ModeColumn.prototype.name = function () { + return "Activity Mode " + (this.index + 1); + }; + + ModeColumn.prototype.value = function (domainObject) { + var model = domainObject.getModel(), + composition = (model.relationships || {}).modes || []; + return (composition[this.index]) || ""; + }; + + return ModeColumn; +}); diff --git a/platform/features/timeline/src/actions/TimelineColumnizer.js b/platform/features/timeline/src/actions/TimelineColumnizer.js new file mode 100644 index 0000000000..3069bd8b96 --- /dev/null +++ b/platform/features/timeline/src/actions/TimelineColumnizer.js @@ -0,0 +1,161 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,Promise*/ + +define([ + "./IdColumn", + "./ModeColumn", + "./CompositionColumn", + "./MetadataColumn", + "./TimespanColumn" +], function ( + IdColumn, + ModeColumn, + CompositionColumn, + MetadataColumn, + TimespanColumn +) { + 'use strict'; + + /** + * A description of how to populate a given column within a + * prepared table of domain object data, for CSV export. + * @interface platform/features/timeline.TimelineCSVColumn + */ + + /** + * Get the value that belongs in this column for a given + * domain object. + * @memberof {platform/features/timeline.TimelineCSVColumn#} + * @method value + * @param {DomainObject} domainObject the domain object + * represented by this row + * @returns {string|Promise} the value for this cell + */ + + /** + * Get the name of this column, as belongs in a header. + * @memberof {platform/features/timeline.TimelineCSVColumn#} + * @method name + * @returns {string} the name of this column + */ + + /** + * Handles conversion of a list of domain objects to a table + * representation appropriate for CSV export. + * + * @param {DomainObject[]} domainObjects the objects to include + * in the exported data + * @constructor + * @memberof {platform/features/timeline} + */ + function TimelineColumnizer(domainObjects) { + var maxComposition = 0, + maxRelationships = 0, + columnNames = {}, + columns = [], + foundTimespan = false, + i; + + function addMetadataProperty(property) { + var name = property.name; + if (!columnNames[name]) { + columnNames[name] = true; + columns.push(new MetadataColumn(name)); + } + } + + columns.push(new IdColumn()); + + domainObjects.forEach(function (domainObject) { + var model = domainObject.getModel(), + composition = model.composition, + relationships = model.relationships, + modes = relationships && relationships.modes, + metadataProperties = domainObject.useCapability('metadata'); + + if (composition) { + maxComposition = Math.max(maxComposition, composition.length); + } + + if (modes) { + maxRelationships = Math.max(maxRelationships, modes.length); + } + + if (domainObject.hasCapability('timespan')) { + foundTimespan = true; + } + + if (metadataProperties) { + metadataProperties.forEach(addMetadataProperty); + } + }); + + if (foundTimespan) { + columns.push(new TimespanColumn(true)); + columns.push(new TimespanColumn(false)); + } + + for (i = 0; i < maxComposition; i += 1) { + columns.push(new CompositionColumn(i)); + } + + for (i = 0; i < maxRelationships; i += 1) { + columns.push(new ModeColumn(i)); + } + + this.domainObjects = domainObjects; + this.columns = columns; + } + + /** + * Get a tabular representation of domain object data. + * Each row corresponds to a single object; each element + * in each row corresponds to a property designated by + * the `headers`, correlated by index. + * @returns {Promise.} domain object data + */ + TimelineColumnizer.prototype.rows = function () { + var columns = this.columns; + + function toRow(domainObject) { + return Promise.all(columns.map(function (column) { + return column.value(domainObject); + })); + } + + return Promise.all(this.domainObjects.map(toRow)); + }; + + /** + * Get the column headers associated with this tabular + * representation of objects. + * @returns {string[]} column headers + */ + TimelineColumnizer.prototype.headers = function () { + return this.columns.map(function (column) { + return column.name(); + }); + }; + + return TimelineColumnizer; +}); diff --git a/platform/features/timeline/src/actions/TimelineTraverser.js b/platform/features/timeline/src/actions/TimelineTraverser.js new file mode 100644 index 0000000000..f6857658fb --- /dev/null +++ b/platform/features/timeline/src/actions/TimelineTraverser.js @@ -0,0 +1,85 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,Promise*/ + +define([], function () { + "use strict"; + + /** + * Builds a list of domain objects which should be included + * in the CSV export of a given timeline. + * @param {DomainObject} domainObject the object being exported + * @constructor + */ + function TimelineTraverser(domainObject) { + this.domainObject = domainObject; + } + + /** + * Get a list of domain objects for CSV export. + * @returns {Promise.} a list of domain objects + */ + TimelineTraverser.prototype.buildObjectList = function () { + var idSet = {}, + objects = []; + + function addObject(domainObject) { + var id = domainObject.getId(), + subtasks = []; + + function addCompositionObjects() { + return domainObject.useCapability('composition') + .then(function (childObjects) { + return Promise.all(childObjects.map(addObject)); + }); + } + + function addRelationships() { + var relationship = domainObject.getCapability('relationship'); + relationship.getRelatedObjects('modes') + .then(function (modeObjects) { + return Promise.all(modeObjects.map(addObject)); + }); + } + + if (!idSet[id]) { + idSet[id] = true; + objects.push(domainObject); + if (domainObject.hasCapability('composition')) { + subtasks.push(addCompositionObjects()); + } + if (domainObject.hasCapability('relationship')) { + subtasks.push(addRelationships()); + } + } + + return Promise.all(subtasks); + } + + return addObject(this.domainObject).then(function () { + return objects; + }); + }; + + return TimelineTraverser; + +}); \ No newline at end of file diff --git a/platform/features/timeline/src/actions/TimespanColumn.js b/platform/features/timeline/src/actions/TimespanColumn.js new file mode 100644 index 0000000000..6d0c4e05a9 --- /dev/null +++ b/platform/features/timeline/src/actions/TimespanColumn.js @@ -0,0 +1,55 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define*/ + +define(['../TimelineFormatter'], function (TimelineFormatter) { + "use strict"; + + var FORMATTER = new TimelineFormatter(); + + /** + * A column showing start or end times associated with a domain object. + * @constructor + * @param {boolean} isStart true if this column refers to the object's + * start time; false if it refers to the object's end time + * @implements {platform/features/timeline.TimelineCSVColumn} + */ + function TimespanColumn(isStart) { + this.isStart = isStart; + } + + TimespanColumn.prototype.name = function () { + return this.isStart ? "Start" : "End"; + }; + + TimespanColumn.prototype.value = function (domainObject) { + var isStart = this.isStart; + return domainObject.hasCapability('timespan') ? + domainObject.useCapability('timespan').then(function (timespan) { + return FORMATTER.format( + isStart ? timespan.getStart() : timespan.getEnd() + ); + }) : ""; + }; + + return TimespanColumn; +}); diff --git a/platform/features/timeline/test/actions/CompositionColumnSpec.js b/platform/features/timeline/test/actions/CompositionColumnSpec.js new file mode 100644 index 0000000000..99e23d5597 --- /dev/null +++ b/platform/features/timeline/test/actions/CompositionColumnSpec.js @@ -0,0 +1,74 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/CompositionColumn'], + function (CompositionColumn) { + describe("CompositionColumn", function () { + var testIndex, + column; + + beforeEach(function () { + testIndex = 3; + column = new CompositionColumn(testIndex); + }); + + it("includes a one-based index in its name", function () { + expect(column.name().indexOf(String(testIndex + 1))) + .not.toEqual(-1); + }); + + describe("value", function () { + var mockDomainObject, + testModel; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability' ] + ); + testModel = { + composition: [ 'a', 'b', 'c', 'd', 'e', 'f' ] + }; + mockDomainObject.getModel.andReturn(testModel); + }); + + it("returns a corresponding identifier", function () { + expect(column.value(mockDomainObject)) + .toEqual(testModel.composition[testIndex]); + }); + + it("returns nothing when composition is exceeded", function () { + testModel.composition = [ 'foo' ]; + expect(column.value(mockDomainObject)).toEqual(""); + }); + + it("returns nothing when composition is absent", function () { + delete testModel.composition; + expect(column.value(mockDomainObject)).toEqual(""); + }); + }); + + }); + } +); \ No newline at end of file diff --git a/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js b/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js new file mode 100644 index 0000000000..3d5cd8b01c --- /dev/null +++ b/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js @@ -0,0 +1,153 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/ExportTimelineAsCSVAction'], + function (ExportTimelineAsCSVAction) { + describe("ExportTimelineAsCSVAction", function () { + var mockExportService, + mockNotificationService, + mockNotification, + mockDomainObject, + mockType, + testContext, + testType, + action; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability', 'hasCapability' ] + ); + mockType = jasmine.createSpyObj('type', [ 'instanceOf' ]); + mockExportService = jasmine.createSpyObj( + 'exportService', + [ 'exportCSV' ] + ); + mockNotificationService = jasmine.createSpyObj( + 'notificationService', + [ 'notify', 'error' ] + ); + mockNotification = jasmine.createSpyObj( + 'notification', + [ 'dismiss' ] + ); + + mockNotificationService.notify.andReturn(mockNotification); + + mockDomainObject.hasCapability.andReturn(true); + mockDomainObject.getCapability.andReturn(mockType); + mockType.instanceOf.andCallFake(function (type) { + return type === testType; + }); + + testContext = { domainObject: mockDomainObject }; + + action = new ExportTimelineAsCSVAction( + mockExportService, + mockNotificationService, + testContext + ); + }); + + it("is applicable to timelines", function () { + testType = 'timeline'; + expect(ExportTimelineAsCSVAction.appliesTo(testContext)) + .toBe(true); + }); + + it("is not applicable to non-timelines", function () { + testType = 'folder'; + expect(ExportTimelineAsCSVAction.appliesTo(testContext)) + .toBe(false); + }); + + describe("when performed", function () { + var testPromise, + mockCallback; + + beforeEach(function () { + mockCallback = jasmine.createSpy('callback'); + // White-boxy; we know most work is delegated + // to the associated Task, so stub out that interaction. + spyOn(action.task, "run").andCallFake(function () { + return new Promise(function (resolve, reject) { + testPromise = { + resolve: resolve, + reject: reject + }; + }); + }); + action.perform().then(mockCallback); + }); + + it("shows a notification", function () { + expect(mockNotificationService.notify) + .toHaveBeenCalled(); + }); + + it("starts an export task", function () { + expect(action.task.run).toHaveBeenCalled(); + }); + + describe("and completed", function () { + beforeEach(function () { + testPromise.resolve(); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + }); + + it("dismisses the displayed notification", function () { + expect(mockNotification.dismiss) + .toHaveBeenCalled(); + }); + + it("shows no error messages", function () { + expect(mockNotificationService.error) + .not.toHaveBeenCalled(); + }); + }); + + describe("and an error occurs", function () { + beforeEach(function () { + testPromise.reject(); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + }); + + it("dismisses the displayed notification", function () { + expect(mockNotification.dismiss) + .toHaveBeenCalled(); + }); + + it("shows an error message", function () { + expect(mockNotificationService.error) + .toHaveBeenCalledWith(jasmine.any(String)); + }); + }); + }); + }); + } +); \ No newline at end of file diff --git a/platform/features/timeline/test/actions/ExportTimelineAsCSVTaskSpec.js b/platform/features/timeline/test/actions/ExportTimelineAsCSVTaskSpec.js new file mode 100644 index 0000000000..7979104ee5 --- /dev/null +++ b/platform/features/timeline/test/actions/ExportTimelineAsCSVTaskSpec.js @@ -0,0 +1,79 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/ExportTimelineAsCSVTask'], + function (ExportTimelineAsCSVTask) { + 'use strict'; + + // Note that most responsibility is delegated to helper + // classes, so testing here is minimal. + describe("EXportTimelineAsCSVTask", function () { + var mockExportService, + mockDomainObject, + task; + + beforeEach(function () { + mockExportService = jasmine.createSpyObj( + 'exportService', + [ 'exportCSV' ] + ); + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ + 'getCapability', + 'useCapability', + 'hasCapability', + 'getId', + 'getModel' + ] + ); + + mockDomainObject.getId.andReturn('mock'); + mockDomainObject.getModel.andReturn({}); + + task = new ExportTimelineAsCSVTask( + mockExportService, + mockDomainObject + ); + }); + + describe("when run", function () { + var mockCallback; + + beforeEach(function () { + mockCallback = jasmine.createSpy('callback'); + task.run().then(mockCallback); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + }); + + it("exports to CSV", function () { + expect(mockExportService.exportCSV) + .toHaveBeenCalled(); + }); + }); + }); + } +); diff --git a/platform/features/timeline/test/actions/IdColumnSpec.js b/platform/features/timeline/test/actions/IdColumnSpec.js new file mode 100644 index 0000000000..a12b6145a9 --- /dev/null +++ b/platform/features/timeline/test/actions/IdColumnSpec.js @@ -0,0 +1,59 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/IdColumn'], + function (IdColumn) { + describe("IdColumn", function () { + var column; + + beforeEach(function () { + column = new IdColumn(); + }); + + it("has a name", function () { + expect(column.name()).toEqual(jasmine.any(String)); + }); + + describe("value", function () { + var mockDomainObject, + testId; + + beforeEach(function () { + testId = "foo"; + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability' ] + ); + mockDomainObject.getId.andReturn(testId); + }); + + it("provides a domain object's identifier", function () { + expect(column.value(mockDomainObject)) + .toEqual(testId); + }); + }); + + }); + } +); \ No newline at end of file diff --git a/platform/features/timeline/test/actions/MetadataColumnSpec.js b/platform/features/timeline/test/actions/MetadataColumnSpec.js new file mode 100644 index 0000000000..ba38fc83c0 --- /dev/null +++ b/platform/features/timeline/test/actions/MetadataColumnSpec.js @@ -0,0 +1,76 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/MetadataColumn'], + function (MetadataColumn) { + describe("MetadataColumn", function () { + var testName, + column; + + beforeEach(function () { + testName = 'Foo'; + column = new MetadataColumn(testName); + }); + + it("reports its property name", function () { + expect(column.name()).toEqual(testName); + }); + + describe("value", function () { + var mockDomainObject, + testMetadata, + testIndex; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability', 'useCapability' ] + ); + testMetadata = [ + { name: "Something else", value: 123 }, + { value: 456 }, + { name: "And something else", value: 789 } + ]; + testIndex = 1; + testMetadata[testIndex].name = testName; + + mockDomainObject.useCapability.andCallFake(function (c) { + return (c === 'metadata') && testMetadata; + }); + }); + + it("returns a corresponding value", function () { + expect(column.value(mockDomainObject)) + .toEqual(testMetadata[testIndex].value); + }); + + it("returns nothing when no such property is present", function () { + testMetadata[testIndex].name = "Not " + testName; + expect(column.value(mockDomainObject)).toEqual(""); + }); + }); + + }); + } +); \ No newline at end of file diff --git a/platform/features/timeline/test/actions/ModeColumnSpec.js b/platform/features/timeline/test/actions/ModeColumnSpec.js new file mode 100644 index 0000000000..ab15d696c2 --- /dev/null +++ b/platform/features/timeline/test/actions/ModeColumnSpec.js @@ -0,0 +1,76 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/ModeColumn'], + function (ModeColumn) { + describe("ModeColumn", function () { + var testIndex, + column; + + beforeEach(function () { + testIndex = 3; + column = new ModeColumn(testIndex); + }); + + it("includes a one-based index in its name", function () { + expect(column.name().indexOf(String(testIndex + 1))) + .not.toEqual(-1); + }); + + describe("value", function () { + var mockDomainObject, + testModel; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability' ] + ); + testModel = { + relationships: { + modes: [ 'a', 'b', 'c', 'd', 'e', 'f' ] + } + }; + mockDomainObject.getModel.andReturn(testModel); + }); + + it("returns a corresponding identifier", function () { + expect(column.value(mockDomainObject)) + .toEqual(testModel.relationships.modes[testIndex]); + }); + + it("returns nothing when relationships are exceeded", function () { + testModel.relationships.modes = [ 'foo' ]; + expect(column.value(mockDomainObject)).toEqual(""); + }); + + it("returns nothing when mode relationships are absent", function () { + delete testModel.relationships.modes; + expect(column.value(mockDomainObject)).toEqual(""); + }); + }); + + }); + } +); \ No newline at end of file diff --git a/platform/features/timeline/test/actions/TimelineColumnizerSpec.js b/platform/features/timeline/test/actions/TimelineColumnizerSpec.js new file mode 100644 index 0000000000..9eacf4f3b3 --- /dev/null +++ b/platform/features/timeline/test/actions/TimelineColumnizerSpec.js @@ -0,0 +1,129 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/TimelineColumnizer'], + function (TimelineColumnizer) { + describe("TimelineColumnizer", function () { + var mockDomainObjects, + testMetadata, + exporter; + + function makeMockDomainObject(model, index) { + var mockDomainObject = jasmine.createSpyObj( + 'domainObject-' + index, + [ + 'getId', + 'getCapability', + 'useCapability', + 'hasCapability', + 'getModel' + ] + ); + mockDomainObject.getId.andReturn('id-' + index); + mockDomainObject.getModel.andReturn(model); + mockDomainObject.useCapability.andCallFake(function (c) { + return c === 'metadata' && []; + }); + return mockDomainObject; + } + + beforeEach(function () { + var mockTimespan = jasmine.createSpyObj( + 'timespan', + [ 'getStart', 'getEnd' ] + ); + + testMetadata = [ + { name: "abc", value: 123 }, + { name: "xyz", value: 456 } + ]; + + mockDomainObjects = [ + { composition: [ 'a', 'b', 'c' ] }, + { relationships: { modes: [ 'x', 'y' ] } }, + { } + ].map(makeMockDomainObject); + + mockDomainObjects[1].hasCapability.andCallFake(function (c) { + return c === 'timespan'; + }); + mockDomainObjects[1].useCapability.andCallFake(function (c) { + return c === 'timespan' ? Promise.resolve(mockTimespan) : + c === 'metadata' ? [] : undefined; + }); + mockDomainObjects[2].useCapability.andCallFake(function (c) { + return c === 'metadata' && testMetadata; + }); + + exporter = new TimelineColumnizer(mockDomainObjects); + }); + + describe("rows", function () { + var rows; + + beforeEach(function () { + exporter.rows().then(function (r) { + rows = r; + }); + waitsFor(function () { + return rows !== undefined; + }); + }); + + + it("include one row per domain object", function () { + expect(rows.length).toEqual(mockDomainObjects.length); + }); + + it("includes identifiers for each domain object", function () { + rows.forEach(function (row, index) { + var id = mockDomainObjects[index].getId(); + expect(row.indexOf(id)).not.toEqual(-1); + }); + }); + }); + + describe("headers", function () { + var headers; + + beforeEach(function () { + headers = exporter.headers(); + }); + + it("contains all metadata properties", function () { + testMetadata.forEach(function (property) { + expect(headers.indexOf(property.name)) + .not.toEqual(-1); + }); + }); + + it("contains timespan properties", function () { + expect(headers.indexOf("Start")).not.toEqual(-1); + expect(headers.indexOf("End")).not.toEqual(-1); + }); + }); + + }); + } +); diff --git a/platform/features/timeline/test/actions/TimelineTraverserSpec.js b/platform/features/timeline/test/actions/TimelineTraverserSpec.js new file mode 100644 index 0000000000..6962373ff9 --- /dev/null +++ b/platform/features/timeline/test/actions/TimelineTraverserSpec.js @@ -0,0 +1,137 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define([ + "../../src/actions/TimelineTraverser" +], function (TimelineTraverser) { + 'use strict'; + + describe("TimelineTraverser", function () { + var testModels, + mockDomainObjects, + traverser; + + function addMockDomainObject(id) { + var mockDomainObject = jasmine.createSpyObj( + 'domainObject-' + id, + [ + 'getId', + 'getCapability', + 'useCapability', + 'hasCapability', + 'getModel' + ] + ), + mockRelationships, + model = testModels[id]; + + mockDomainObject.getId.andReturn(id); + mockDomainObject.getModel.andReturn(model); + + mockDomainObject.hasCapability.andCallFake(function (c) { + return c === 'composition' ? !!model.composition : + c === 'relationship' ? !!model.relationships : + false; + }); + + if (!!model.composition) { + mockDomainObject.useCapability.andCallFake(function (c) { + return c === 'composition' && + Promise.resolve(model.composition.map(function (id) { + return mockDomainObjects[id]; + })); + }); + } + + if (!!model.relationships) { + mockRelationships = jasmine.createSpyObj( + 'relationship', + ['getRelatedObjects'] + ); + mockRelationships.getRelatedObjects.andCallFake(function (k) { + var ids = model.relationships[k] || []; + return Promise.resolve(ids.map(function (id) { + return mockDomainObjects[id]; + })); + }); + mockDomainObject.getCapability.andCallFake(function (c) { + return c === 'relationship' && mockRelationships; + }); + } + + mockDomainObjects[id] = mockDomainObject; + } + + beforeEach(function () { + testModels = { + a: { composition: [ 'b', 'c' ]}, + b: { composition: [ 'c' ] }, + c: { relationships: { modes: [ 'd' ] } }, + d: {}, + unreachable: {} + }; + + mockDomainObjects = {}; + Object.keys(testModels).forEach(addMockDomainObject); + + traverser = new TimelineTraverser(mockDomainObjects.a); + }); + + describe("buildObjectList", function () { + var objects; + + function contains(id) { + return objects.some(function (object) { + return object.getId() === id; + }); + } + + beforeEach(function () { + traverser.buildObjectList().then(function (objectList) { + objects = objectList; + }); + waitsFor(function () { + return objects !== undefined; + }); + }); + + it("includes the object originally passed in", function () { + expect(contains('a')).toBe(true); + }); + + it("includes objects reachable via composition", function () { + expect(contains('b')).toBe(true); + expect(contains('c')).toBe(true); + }); + + it("includes objects reachable via relationships", function () { + expect(contains('d')).toBe(true); + }); + + it("does not include unreachable objects", function () { + expect(contains('unreachable')).toBe(false); + }); + }); + + }); +}); \ No newline at end of file diff --git a/platform/features/timeline/test/actions/TimespanColumnSpec.js b/platform/features/timeline/test/actions/TimespanColumnSpec.js new file mode 100644 index 0000000000..f4970b778e --- /dev/null +++ b/platform/features/timeline/test/actions/TimespanColumnSpec.js @@ -0,0 +1,94 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/TimespanColumn', '../../src/TimelineFormatter'], + function (TimespanColumn, TimelineFormatter) { + describe("TimespanColumn", function () { + var testTimes, + mockTimespan, + mockDomainObject, + column; + + beforeEach(function () { + testTimes = { + start: 101000, + end: 987654321 + }; + mockTimespan = jasmine.createSpyObj( + 'timespan', + [ 'getStart', 'getEnd' ] + ); + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'useCapability', 'hasCapability' ] + ); + mockTimespan.getStart.andReturn(testTimes.start); + mockTimespan.getEnd.andReturn(testTimes.end); + mockDomainObject.useCapability.andCallFake(function (c) { + return c === 'timespan' && Promise.resolve(mockTimespan); + }); + mockDomainObject.hasCapability.andCallFake(function (c) { + return c === 'timespan'; + }); + }); + + [ "start", "end" ].forEach(function (bound) { + describe("when referring to " + bound + " times", function () { + var name = bound.charAt(0).toUpperCase() + bound.slice(1); + + beforeEach(function () { + column = new TimespanColumn(bound === "start"); + }); + + it("is named \"" + name + "\"", function () { + expect(column.name()).toEqual(name); + }); + + describe("value", function () { + var testFormatter, + value; + + beforeEach(function () { + value = undefined; + testFormatter = new TimelineFormatter(); + column.value(mockDomainObject).then(function (v) { + value = v; + }); + waitsFor(function () { + return value !== undefined; + }); + }); + + it("returns a formatted " + bound + " time", function () { + var expected = + testFormatter.format(testTimes[bound]); + expect(value).toEqual(expected); + }); + }); + }); + }); + + }); + } +); \ No newline at end of file