Separate node test build from browser build

This commit is contained in:
Joe Fiorini
2015-07-20 11:56:02 -04:00
parent 811d0b1403
commit b7c136aba7
35 changed files with 16 additions and 10 deletions

View File

@@ -1,5 +0,0 @@
{
"expr": true,
"esnext": true,
"node": true
}

View File

@@ -1,83 +0,0 @@
/* jshint node: true */
import '../support/node';
import {describeModule} from '../support/describe-module';
import '../../src/shared/Utilities';
import '../../src/shared/RestServices';
import JobStatusGraph from '../../src/dashboard/graphs/job-status/main';
var resizeHandler = sinon.spy();
window.$.fn.removeResize = angular.noop;
describeModule(JobStatusGraph.name)
.mockProvider('adjustGraphSize', resizeHandler)
.mockProvider('Wait', angular.noop)
.mockProvider('Rest', angular.noop)
.testDirective('jobStatusGraph', function(directive) {
directive.provideTemplate(
'/static/partials/job_status_graph.html',
"<div class='m'></div><div class='n'></div><div class='job-status-graph'><svg></svg></div>");
directive.use('<job-status-graph class="job-status-graph" data="data" job-type="all" period="month"></job-status-graph>');
directive.beforeCompile(function($scope) {
// Takes jobs grouped by result (successful or failure
// Then looks at each array of arrays, where index 0 is the timestamp & index 1 is the count of jobs with that status
$scope.data =
{ jobs:
{ successful: [[1, 0], [2, 0], [3,0], [4,0], [5,0]],
failed: [[1,0],[2,0],[3,0],[4,0],[5,0]]
}
};
});
function filterDataSeries(key, data) {
return data.map(function(datum) {
return datum.values;
})[key];
}
it('uses successes & failures from scope', function() {
var chartContainer = d3.select(directive.$element.find('svg')[0]);
var lineData = chartContainer.datum();
var successfulSeries = filterDataSeries(0, lineData);
var failedSeries = filterDataSeries(1, lineData);
expect(successfulSeries).to.eql(
[ {x: 1, y: 0, series: 0},
{x: 2, y: 0, series: 0},
{x: 3, y: 0, series: 0},
{x: 4, y: 0, series: 0},
{x: 5, y: 0, series: 0}
]);
expect(failedSeries).to.eql(
[ {x: 1, y: 0, series: 1},
{x: 2, y: 0, series: 1},
{x: 3, y: 0, series: 1},
{x: 4, y: 0, series: 1},
{x: 5, y: 0, series: 1}
]);
});
it('cleans up external bindings', function() {
directive.$element.trigger('$destroy');
resizeHandler.reset();
inject(['$window', function($window) {
angular.element($window).trigger('resize');
}]);
expect(resizeHandler).not.to.have.been.called;
});
});

View File

@@ -1,27 +0,0 @@
import '../support/node';
import featuresController from '../../src/shared/features/features.controller';
describe('featuresController', function() {
it('checks if a feature is enabled', window.inject(['$rootScope', function($rootScope) {
var actual;
$rootScope.features = {
activity_streams: true,
ldap: false
};
// TODO: extract into test controller in describeModule
var Controller = featuresController[1];
var controller = new Controller($rootScope);
actual = controller.isFeatureEnabled('activity_streams');
expect(actual).to.be.true;
actual = controller.isFeatureEnabled('ldap');
expect(actual).to.be.false;
}]));
})

View File

@@ -1,57 +0,0 @@
import '../support/node';
import features from '../../src/shared/features/main';
import {describeModule} from '../support/describe-module';
//test that it returns features, as well as test that it is returned in rootScope
describeModule(features.name)
.testService('FeaturesService', function(test, restStub) {
var service;
test.withService(function(_service) {
service = _service;
});
it('returns list of features', function() {
var features = {},
result = {
data: {
license_info: {
features: features
}
}
};
var actual = service.get();
restStub.succeed(result);
restStub.flush();
return expect(actual).to.eventually.equal(features);
});
it('caches in rootScope', window.inject(['$rootScope',
function($rootScope){
var features = {},
result = {
data: {
license_info: {
features: features
}
}
};
var actual = service.get();
restStub.succeed(result);
restStub.flush();
return actual.then(function(){
expect($rootScope.features).to.equal(features);
});
}]));
});

View File

@@ -1,26 +0,0 @@
import '../support/node';
import jobTemplates from '../../src/job-templates/main';
import {describeModule} from '../support/describe-module';
describeModule(jobTemplates.name)
.testService('deleteJobTemplate', function(test, restStub) {
var service;
test.withService(function(_service) {
service = _service;
});
it('deletes the job template', function() {
var result = {};
var actual = service();
restStub.succeedOn('destroy', result);
restStub.flush();
expect(actual).to.eventually.equal(result);
});
});

View File

@@ -1,199 +0,0 @@
import '../support/node';
import {describeModule} from '../support/describe-module';
import mod from '../../src/shared/multi-select-list/main';
describeModule(mod.name)
.testDirective('multiSelectList', function(test) {
var $scope;
var controller;
test.use('<div multi-select-list></div>');
test.afterCompile(function(outerScope, scope) {
$scope = scope;
});
test.withController(function(_controller) {
controller = _controller;
});
it('works as an attribute on elements', function() {
window.inject(['$compile', function($compile) {
var node = $compile('<div multi-select-list></div>')($scope);
var classes = Array.prototype.slice.apply(node.attr('class').split(' '));
expect(classes).to.contain('ng-scope');
}]);
});
context('controller init', function() {
it('initializes items and selection', function() {
expect($scope.items).to.be.empty;
expect($scope.selection.selectedItems).to.be.empty;
expect($scope.selection.deselectedItems).to.be.empty;
expect($scope.selection.isExtended).to.be.false;
});
it('wraps items when they are registered', function() {
var item = { name: 'blah' };
var wrapped = controller.registerItem(item);
expect(wrapped.hasOwnProperty('isSelected')).to.be.true;
expect(wrapped.hasOwnProperty('value')).to.be.true;
expect(wrapped.isSelected).to.be.false;
expect(wrapped.value).to.eql(item);
});
});
context('single select/deselect', function() {
it('marks item as selected/not selected', function() {
var item = controller.registerItem({ name: 'blah' });
controller.selectItem(item);
expect(item.isSelected).to.be.true;
controller.deselectItem(item);
expect(item.isSelected).to.be.false;
});
context('selectionChanged event', function() {
it('triggers on select/deselect', function() {
var item = controller.registerItem({ name: 'blah' });
var spy = sinon.spy();
$scope.$on('multiSelectList.selectionChanged', spy);
controller.selectItem(item);
controller.deselectItem(item);
expect(spy).to.have.been.calledTwice;
});
it('is called with the current selection', function() {
var item = controller.registerItem({ name: 'blah' });
var spy = sinon.spy();
$scope.$on('multiSelectList.selectionChanged', spy);
controller.selectItem(item);
expect(spy).to.have.been.calledWith(sinon.match.object,
{ selectedItems:
[ item.value
],
deselectedItems: [],
isExtended: false
});
});
it('is called with deselections', function() {
var item = controller.registerItem({ name: 'blah' });
controller.selectItem(item);
var spy = sinon.spy();
$scope.$on('multiSelectList.selectionChanged', spy);
controller.deselectItem(item);
expect(spy).to.have.been.calledWith(sinon.match.object,
{ selectedItems: [],
deselectedItems:
[ item.value
],
isExtended: false
});
});
});
});
context('select/deselect all items', function() {
it('marks all items as selected/deselected', function() {
var item1 = controller.registerItem({ name: 'blah' });
var item2 = controller.registerItem({ name: 'diddy' });
var item3 = controller.registerItem({ name: 'doo' });
controller.selectAll();
expect([item1, item2, item3]).to.all.have.property('isSelected', true);
controller.deselectAll();
expect([item1, item2, item3]).to.all.have.property('isSelected', false);
});
context('selectionChanged event', function() {
it('triggers with selections set to all the items', function() {
var item1 = controller.registerItem({ name: 'blah' });
var item2 = controller.registerItem({ name: 'diddy' });
var item3 = controller.registerItem({ name: 'doo' });
var spy = sinon.spy();
$scope.$on('multiSelectList.selectionChanged', spy);
controller.selectAll();
expect(spy).to.have.been.calledWith(
sinon.match.object,
{ selectedItems: _.pluck([item1, item2, item3], "value"),
deselectedItems: [],
isExtended: false
});
controller.deselectAll();
expect(spy).to.have.been.calledWith(
sinon.match.object,
{ selectedItems: [],
deselectedItems: _.pluck([item1, item2, item3], "value"),
isExtended: false
});
});
});
it('tracks extended selection state', function() {
var spy = sinon.spy();
var item1 = controller.registerItem({ name: 'blah' });
var item2 = controller.registerItem({ name: 'diddy' });
var item3 = controller.registerItem({ name: 'doo' });
var allItems = _.pluck([item1, item2, item3], 'value');
controller.selectAll();
controller.selectAllExtended();
expect($scope.selection).to.have.property('isExtended', true);
controller.deselectAllExtended();
expect($scope.selection).to.have.property('isExtended', false);
expect($scope.selection)
.to.have.property('selectedItems')
.that.is.an('array')
.deep.equals(allItems);
});
it('toggles extended state on deselectAll', function() {
controller.selectAllExtended();
controller.deselectAll();
expect($scope.selection).to.have.property('isExtended', false);
});
});
});

View File

@@ -1,97 +0,0 @@
import '../support/node';
import {describeModule} from '../support/describe-module';
import mod from '../../src/shared/multi-select-list/main';
var mockController = {
selectAll: sinon.spy(),
deselectAll: sinon.spy(),
selectAllExtended: sinon.spy(),
deselectAllExtended: sinon.spy()
};
describeModule(mod.name)
.testDirective('selectAll', function(directive) {
var $scope;
directive.use('<fake-parent><select-all selections-empty="isEmpty" extended-items-length="numItems"></select-all></fake-parent>');
beforeEach(function() {
directive.element.data('$multiSelectListController', mockController);
});
afterEach(function() {
mockController.selectAll.reset();
mockController.deselectAll.reset();
mockController.selectAllExtended.reset();
mockController.deselectAllExtended.reset();
});
directive.afterCompile(function() {
// Since we had to wrap select-all in a fake directive
// to mock the controller, we have to reach down to
// get it's isolate scope
//
$scope =
directive.$element.find('select-all').isolateScope();
});
it('works as an element tag', function() {
var classes = directive.$element.attr('class').split(' ');
expect(classes).to.contain('ng-scope');
});
it('calls select all when isSelected is true', function() {
$scope.isSelected = true;
$scope.doSelectAll();
expect(mockController.selectAll).to.have.been.calledOnce;
});
it('calls deselect all when isSelected is false', function() {
$scope.isSelected = false;
$scope.doSelectAll();
expect(mockController.deselectAll).to.have.been.calledOnce;
});
it('calls deselect all extended when deselecting all', function() {
$scope.isSelected = false;
$scope.isSelectionExtended = true;
$scope.doSelectAll();
expect(mockController.deselectAllExtended).to.have.been.calledOnce;
});
context('input parameters', function() {
var $outerScope;
// We need to grab the parent scope object so we can control
// the parameters that are passed into the directive in the
// `use` call above
directive.withScope(function(_outerScope) {
$outerScope = _outerScope;
});
it('when true sets isSelected to false', function() {
$scope.isSelected = true;
$outerScope.isEmpty = true;
$outerScope.$apply();
expect($scope).to.have.property('isSelected', false);
});
it('sets supportsExtendedItems when extendedItemsLength is given', function() {
$scope.supportsExtendedItems = false;
$outerScope.numItems = 5;
$outerScope.$apply();
expect($scope).to.have.property('supportsExtendedItems', true);
});
});
});

View File

@@ -1,79 +0,0 @@
import '../support/node';
import {describeModule} from '../support/describe-module';
import JobStatusGraph from '../../src/dashboard/graphs/job-status/main';
var processErrors = sinon.spy();
describeModule(JobStatusGraph.name)
.mockProvider('ProcessErrors', processErrors)
.testService('jobStatusGraphData', function(test, restStub) {
var q;
var service;
var jobStatusChange = {
$on: sinon.spy(),
};
beforeEach(inject(['$q', function($q) {
q = $q;
}]));
test.withService(function(_service) {
service = _service;
});
it('returns a promise to be fulfilled when data comes in', function() {
var firstResult = "result";
var result = service.get('', '');
restStub.succeed({ data: firstResult });
restStub.flush();
return expect(result).to.eventually.equal(firstResult);;
});
it('processes errors through error handler', function() {
var expected = { data: "blah", status: "bad" };
var actual = service.get().catch(function() {
return processErrors;
});
restStub.fail(expected);
restStub.flush();
return actual.catch(function() {
expect(processErrors).to
.have.been.calledWith(null, expected.data, expected.status);
});
});
it('broadcasts event when data is received', function() {
var expected = "value";
var result = q.defer();
service.setupWatcher();
inject(['$rootScope', function($rootScope) {
$rootScope.$on('DataReceived:JobStatusGraph', function(e, data) {
result.resolve(data);
});
$rootScope.$emit('JobStatusChange-home');
restStub.succeed({ data: expected });
restStub.flush();
}]);
return expect(result.promise).to.eventually.equal(expected);
});
it('requests data with given period and jobType', function() {
restStub.setUrl = sinon.spy();
service.get('1', '2');
expect(restStub.setUrl).to.have.been.calledWith('/dashboard/graphs/jobs/?period=1&job_type=2');
});
});

View File

@@ -1,77 +0,0 @@
import '../support/node';
import '../../src/shared/main';
describe('LodashAsPromised', function() {
var _;
var $q;
function addOne(num) {
return num + 1;
}
function isEven(value) {
return value % 2 === 0;
}
function sum(memo, value) {
return memo + value;
}
beforeEach(window.module('shared'));
beforeEach(inject(['lodashAsPromised', '$q', function(_lodash, _$q) {
_ = _lodash;
$q = _$q;
}]));
function checkPromiseAndArray(fnName, cb, coll, result) {
context(fnName, function() {
// var itFn = fnName === 'compact' ? it : xit;
var itFn = it;
itFn('works with a promise', function() {
var values = coll.map($q.when);
var methodName = 'then' + _.capitalize(fnName);
var promise;
// _.log('promises for _', values);
if (fnName === 'reduce') {
promise = _[methodName](values, cb, 0);
} else {
promise = _[methodName](values, cb);
}
inject(['$rootScope', function($rootScope) {
setTimeout(function() {
$rootScope.$apply();
}, 1);
}]);
return expect(promise).to.eventually.deep.equal(result);
});
itFn('works with an array', function() {
var value = _[fnName](coll, cb, 0);
expect(value).to.deep.equal(result);
});
});
}
checkPromiseAndArray('map', addOne, [1,2,3,4], [2,3,4,5]);
checkPromiseAndArray('filter', isEven, [1,2,3,4,5,6,7,8], [2,4,6,8]);
checkPromiseAndArray('reduce', sum, [1,2,3,4], 10);
checkPromiseAndArray('pluck', 'blah', [{ blah: 'diddy' }, { blah: 'doo' }], ['diddy', 'doo']);
checkPromiseAndArray('compact', null, ['blah', null, 'diddy', false, 'doo', undefined], ['blah', 'diddy', 'doo']);
checkPromiseAndArray('xor', [4,2], [1,2], [1,4]);
checkPromiseAndArray('groupBy', Math.floor, [4.2,6.1,6.4], { '4': [4.2], '6': [6.1,6.4] } );
it('allows chaining', function() {
function dub(n) { return n * 2; }
var arr = [1,2,3,4].map($q.when);
expect(_(arr).thenMap(dub)).to.eventually.deep.equal([2,4,6,8]);
});
});

View File

@@ -1,6 +0,0 @@
window.$AnsibleConfig = null;
window.$basePath = '/static/';
var testLoader = require('ember-cli/test-loader');
testLoader.default.load();

View File

@@ -1,286 +0,0 @@
import RestStub from './rest-stub';
var $provide;
function wrapInjected(dslFn) {
// wrapInjected(before(inject(..., function() {
// }));
return function(fn) {
dslFn.apply(this,
[window.inject(
[ '$injector',
function($injector) {
var $compile = $injector.get('$compile');
var $httpBackend = $injector.get('$httpBackend');
var $rootScope = $injector.get('$rootScope');
return fn.apply(this, [$httpBackend, $compile, $rootScope]);
}.bind(this)
])]);
};
};
function TestModule(name, deps) {
window.localStorage.setItem('zones', []);
return {
mockedProviders: {},
registerPreHooks: function() {
var self = this;
// beforeEach("tower module", window.module('Tower'));
beforeEach(name + " module", window.module(name));
beforeEach("templates module", window.module('templates'));
beforeEach("mock app setup", window.module(['$provide', function(_provide_) {
var getBasePath = function(path) {
return '/' + path + '/';
};
$provide = _provide_;
$provide.value('LoadBasePaths', angular.noop);
$provide.value('GetBasePath', getBasePath);
$provide.value('ProcessErrors', angular.noop);
for (var name in self.mockedProviders) {
$provide.value(name, self.mockedProviders[name]);
}
}]));
// wrapInjected(beforeEach)(function($httpBackend) {
// $httpBackend
// .expectGET('/static/js/local_config.js')
// .respond({});
// });
},
mockProvider: function(name, value) {
this.mockedProviders[name] = value;
},
describe: function(name, describeFn) {
describe(name, function() {
describeFn.apply(this);
});
},
registerPostHooks: function() {
afterEach(window.inject(['$httpBackend', function($httpBackend) {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
}]));
}
};
};
function TestService(name) {
var restStub = new RestStub();
afterEach(function() {
restStub.reset();
});
return {
withService: function(fn) {
beforeEach(name + " service", window.inject([name, function() {
var service = arguments[0];
fn(service);
}]));
},
restStub: restStub,
};
};
// Note: if you need a compile step for your directive you
// must either:
//
// 1. Use a before/after compile hook, which also allows
// you to modify the scope before compiling
// 2. If you don't use a hook, call `registerCompile`
// prior to the first `it` in your tests
function TestDirective(name, deps) {
return { name: name,
// Hooks that need to run after any hooks registered
// by the test
withScope: function(fn) {
var self = this;
beforeEach("capture outer $scope", window.inject(['$rootScope', function($rootScope) {
var $scope = self.$scope = self.$scope || $rootScope.$new();
// `this` refers to mocha test suite
fn.apply(this, [$scope]);
}]));
},
withIsolateScope: function(fn) {
var self = this;
beforeEach("capture isolate scope", window.inject(['$rootScope', function($rootScope) {
// `this` refers to mocha test suite
fn.apply(this, [self.$element.isolateScope()]);
}]));
},
beforeCompile: function(fn) {
var self = this;
// Run before compile step by passing in the
// outer scope, allowing for modifications
// prior to compiling
self.withScope(fn);
this.registerCompile();
},
afterCompile: function(fn) {
var self = this;
var $outerScope;
// Make sure compile step gets setup first
if (!this._compileRegistered) {
this.registerCompile();
}
// Then pre-apply the function with the outer scope
self.withScope(function($scope) {
// `this` refers to mocha test suite
$outerScope = $scope;
});
// Finally, have it called by the isolate scope
// hook, which will pass in both the outer
// scope (since it was pre-applied) and the
// isolate scope (if one exists)
//
self.withIsolateScope(function($scope) {
// `this` refers to mocha test suite
fn.apply(this, [$outerScope, $scope]);
});
},
registerCompile: function(deps) {
var self = this;
// Only setup compile step once
if (this._compileRegistered) {
return;
}
beforeEach("compile directive element",
window.inject(['$compile', '$httpBackend', '$rootScope', function($compile, $httpBackend, $rootScope) {
if (!self.$scope) {
self.$scope = $rootScope.$new();
}
self.$element = $compile(self.element)(self.$scope);
$(self.$element).appendTo('body');
self.$scope.$digest();
// $httpBackend.flush();
}]));
afterEach("cleanup directive element", function() {
$(self.$element).trigger('$destroy');
self.$element.remove();
delete self.$scope;
});
this._compileRegistered = true;
},
withController: function(fn) {
var self = this;
beforeEach(function() {
self._ensureCompiled();
fn(self.$element.controller(self.name));
});
},
use: function(elem) {
this.element = angular.element(elem);
},
provideTemplate: function(url, template) {
var $scope = this.$scope;
beforeEach("mock template endpoint", window.inject(['$httpBackend', function($httpBackend) {
$httpBackend
.whenGET(url)
.respond(template);
}]));
},
_ensureCompiled: function() {
if (typeof this.$element === 'undefined') {
throw "Can only call withController after registerPostHooks on directive test";
}
}
};
}
function ModuleDescriptor(name, deps) {
var moduleTests = [];
var testModule =
Object.create(TestModule(name, deps));
var proto =
{ mockProvider: function(name, value) {
testModule.mockProvider(name, value);
return this;
},
testService: function(name, test) {
testModule.describe(name, function() {
var testService = Object.create(TestService(name));
testModule.mockProvider('Rest', testService.restStub);
testModule.mockProvider('$cookieStore', { get: angular.noop });
testModule.registerPreHooks();
beforeEach("$q", window.inject(['$q', function($q) {
testService.restStub.$q = $q;
}]));
test.apply(null, [testService, testService.restStub]);
});
},
testDirective: function(name, test) {
testModule.describe(name, function(deps) {
var directiveDeps = _.clone(deps);
var testDirective =
Object.create(TestDirective(name));
// Hand in testDirective object & injected
// dependencies to the test as separate arguments
//
var args = [testDirective].concat(_.values(directiveDeps));
var testObj =
// Using Function#bind to create a new function
// with the arguments pre-applied (go search
// the web for "partial application" to know more)
//
{ run: test.bind(null, testDirective, args),
name: name
};
testModule.registerPreHooks();
// testDirective.registerCompile();
testObj.run();
// testDirective.registerPostHooks();
});
}
};
return proto;
}
export function describeModule(name) {
var descriptor = null
descriptor = Object.create(ModuleDescriptor(name));
return descriptor;
};

View File

@@ -1,4 +0,0 @@
module.exports =
function exportGlobal(varName, value) {
global[varName] = global.window[varName] = value;
};

View File

@@ -1,26 +0,0 @@
/* jshint node: true */
(function() {
var isNode = typeof window === 'undefined';
if (!isNode) {
window.expect = chai.expect;
return;
}
require('./setup/jsdom');
require('./setup/mocha');
require('./setup/jquery');
require('./setup/angular');
require('./setup/angular-mocks');
require('./setup/angular-templates');
require('./setup/sinon');
require('./setup/chai');
require('./setup/chai-plugins');
require('./setup/d3');
require('./setup/nv');
require('./setup/lodash');
require('./setup/local-storage');
require('./setup/moment');
})();

View File

@@ -1,5 +0,0 @@
var exportGlobal = require('../export-global');
require('angular-mocks/angular-mocks');
exportGlobal('inject', window.inject);

View File

@@ -1,2 +0,0 @@
angular.module('templates', []);
require('../../../../templates');

View File

@@ -1,5 +0,0 @@
var exportGlobal = require('../export-global');
require('angular/angular');
exportGlobal('angular', window.angular);

View File

@@ -1,8 +0,0 @@
var sinonChai = require('sinon-chai');
var chaiAsPromised = require('chai-as-promised');
var chaiThings = require('chai-things');
chai.use(sinonChai);
chai.use(chaiAsPromised);
chai.use(chaiThings);

View File

@@ -1,5 +0,0 @@
var exportGlobal = require('../export-global');
var chai = require('chai');
exportGlobal('chai', chai);
exportGlobal('expect', chai.expect);

View File

@@ -1,6 +0,0 @@
var exportGlobal = require('../export-global');
var d3 = require('d3');
exportGlobal('d3', d3);

View File

@@ -1,7 +0,0 @@
var exportGlobal = require('../export-global');
var jquery = require('jquery');
exportGlobal('$', jquery);
exportGlobal('jQuery', jquery);

View File

@@ -1,6 +0,0 @@
var jsdom = require('jsdom').jsdom;
var document = jsdom('tower');
var window = document.parentWindow;
global.document = document;
global.window = window;

View File

@@ -1,7 +0,0 @@
var exportGlobal = require('../export-global');
var LocalStorage = require('node-localstorage').LocalStorage;
exportGlobal('localStorage',
new LocalStorage('./scratch'));

View File

@@ -1,4 +0,0 @@
var exportGlobal = require('../export-global');
var lodash = require('lodash');
exportGlobal('_', lodash);

View File

@@ -1,7 +0,0 @@
var exportGlobal = require('../export-global');
var mocha = require('mocha');
exportGlobal('mocha', mocha);
exportGlobal('beforeEach', beforeEach);
exportGlobal('afterEach', afterEach);

View File

@@ -1,5 +0,0 @@
var exportGlobal = require('../export-global');
var moment = require('moment');
exportGlobal('moment', moment);

View File

@@ -1,6 +0,0 @@
var exportGlobal = require('../export-global');
var nv = require('nvd3');
exportGlobal('nv', nv);

View File

@@ -1,4 +0,0 @@
var exportGlobal = require('../export-global');
var sinon = require('sinon');
exportGlobal('sinon', sinon);

View File

@@ -1,71 +0,0 @@
function assertUrlDeferred(url, obj) {
if (angular.isUndefined(obj[url]) ||
angular.isUndefined(obj[url].then) &&
angular.isUndefined(obj[url].promise.then)) {
var urls = [];
for (var key in obj) {
if (/\//.test(key)) {
urls.push(key);
}
}
var registered = urls.map(function(url) {
return "\t\"" + url + "\"";
}).join("\n");
throw "Could not find a thenable registered for url \"" + url + "\". Registered URLs include:\n\n" + registered + "\n\nPerhaps you typo'd the URL?\n"
}
}
function RestStub() {
}
RestStub.prototype =
{ setUrl: function(url) {
this[url] = this.$q.defer();
this.currentUrl = url;
},
reset: function() {
delete this.deferred;
},
get: function() {
// allow a single deferred on this in case we don't need URL
this.deferred = this[this.currentUrl];
return this.deferred.promise;
},
destroy: function() {
this.deferred = this.deferred || {};
this.deferred.destroy = this[this.currentUrl];
return this.deferred.destroy.promise;
},
succeedAt: function(url, value) {
assertUrlDeferred(url, this);
this[url].resolve(value);
},
succeedOn: function(method, value) {
this.deferred[method] = value;
},
succeed: function(value) {
this.deferred.resolve(value);
},
failAt: function(url, value) {
assertUrlDeferred(url, this);
this[url].reject(value);
},
fail: function(value) {
this.deferred.reject(value);
},
flush: function() {
window.setTimeout(function() {
inject(['$rootScope', function($rootScope) {
$rootScope.$apply();
}]);
}, 10);
}
};
export default RestStub;

View File

@@ -1,590 +0,0 @@
/* jshint node: true */
import '../../support/node';
import compareFacts from '../../../src/system-tracking/compare-facts/flat';
// This makes this test runnable in node OR karma. The sheer
// number of times I had to run this test made the karma
// workflow just too dang slow for me. Maybe this can
// be a pattern going forward? Not sure...
//
// (function(global) {
// var chai = global.chai || require('chai');
// if (typeof window === 'undefined') {
// var chaiThings = global.chaiThings || require('chai-things');
// chai.use(chaiThings);
// }
// _ = global._ || require('lodash');
// expect = global.expect || chai.expect;
// global.expect = expect;
// global._ = _;
// })(typeof window === 'undefined' ? global : window);
describe('CompareFacts.Flat', function() {
function options(overrides) {
return _.merge({}, defaultOptions, overrides);
}
var defaultTemplate =
{ hasTemplate: function() { return false; }
};
var defaultOptions =
{ factTemplate: defaultTemplate,
nameKey: 'name'
};
it('returns empty array with empty basis facts', function() {
var result = compareFacts({ facts: [] }, { facts: [] }, defaultOptions);
expect(result).to.deep.equal([]);
});
it('returns empty array when no differences', function() {
var result = compareFacts(
{ facts:
[{ 'name': 'foo',
'value': 'bar'
}]
},
{ facts:
[{ 'name': 'foo',
'value': 'bar'
}]
}, options({ nameKey: 'name',
compareKey: ['value'],
}));
expect(result).to.deep.equal([]);
});
it('returns empty array with multiple compare keys and no differences', function() {
var result = compareFacts(
{ facts:
[{ 'name': 'foo',
'value': 'bar'
}]
},
{ facts:
[{ 'name': 'foo',
'value': 'bar'
}]
}, options({ compareKey: ['name', 'value']
}));
expect(result).to.deep.equal([]);
});
context('when both collections contain facts', function() {
it('includes each compare key value when a compareKey differs', function() {
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz',
'extra': 'doo'
}]
}, options({ compareKey: ['value', 'extra'] }));
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
containsValueArray: false,
nestingLevel: 0,
facts:
[{ keyName: 'value',
value1: 'bar',
value2: 'baz',
isDivergent: true
},
{ keyName: 'extra',
value1: 'doo',
value2: 'doo',
isDivergent: false
}]
}]);
});
it('ignores compare keys with no values in fact', function() {
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz',
'extra': 'doo'
}]
}, options({ compareKey: ['value', 'extra', 'blah'] }));
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
containsValueArray: false,
nestingLevel: 0,
facts:
[{ keyName: 'value',
value1: 'bar',
value2: 'baz',
isDivergent: true
},
{ keyName: 'extra',
value1: 'doo',
value2: 'doo',
isDivergent: false
}]
}]);
});
it('allows mapping key names with keyNameMap parameter', function() {
var keyNameMap =
{ 'extra': 'blah'
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz',
'extra': 'doo'
}]
}, options({ compareKey: ['value', 'extra', 'blah'],
keyNameMap: keyNameMap
}));
expect(result[0].facts).to.include.something.that.deep.equals(
{ keyName: 'blah',
value1: 'doo',
value2: 'doo',
isDivergent: false
});
});
it('allows flattening values with factTemplate parameter', function() {
var factTemplate =
{ hasTemplate:
function() {
return true;
},
render: function(fact) {
return 'value: ' + fact.value;
}
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz',
'extra': 'doo'
}]
}, options({ compareKey: ['value'],
factTemplate: factTemplate
}));
expect(result[0].facts).to.deep.equal(
{ keyName: 'foo',
value1: 'value: bar',
value2: 'value: baz'
});
});
it('allows formatting values with factTemplate parameter', function() {
var values = ['value1', 'value2'];
var factTemplate =
{ 'value':
{ hasTemplate: function() {
return true;
},
render: function() {
return values.shift();
}
},
'extra': true
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz',
'extra': 'doo'
}]
}, options({ compareKey: ['value'],
factTemplate: factTemplate
}));
expect(result[0].facts).to.include.something.that.deep.equals(
{ keyName: 'value',
value1: 'value1',
value2: 'value2',
isDivergent: true
},
{ keyName: 'extra',
value1: 'doo',
value2: 'doo',
isDivergent: false
});
});
it('compares values using the formatted values, not the raw ones', function() {
var values = ['value1', 'value2'];
var factTemplate =
{ 'extra':
{ render: function() {
return values.shift();
}
}
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
}, options({ factTemplate: factTemplate,
compareKey: ['extra']
}));
expect(result.length).to.be.greaterThan(0);
expect(result[0].facts).to.include.something.that.deep.equals(
{ keyName: 'extra',
value1: 'value1',
value2: 'value2',
isDivergent: true
});
});
});
context('when value for nameKey is present in one collection but not the other', function() {
function factData(leftFacts) {
var facts = [{ position: 'left',
facts: leftFacts
},
{ position: 'right',
facts: []
}];
return facts;
}
it('keeps missing values as undefined', function() {
var facts = factData([{ 'name': 'foo',
'value': 'bar'
}]);
var result = compareFacts(facts[0], facts[1],
options({ compareKey: ['value']
}));
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
containsValueArray: false,
nestingLevel: 0,
facts:
[{ keyName: 'value',
value1: 'bar',
value2: undefined,
isDivergent: true
}]
}]);
});
it('still keeps missing values as undefined when using a template', function() {
var factTemplate =
{ hasTemplate:
function() {
return true;
},
render:
function(fact) {
return fact.value;
}
};
var facts = factData([{ 'name': 'foo',
'value': 'bar'
}]);
var result = compareFacts(facts[0], facts[1],
options({ compareKey: ['value'],
factTemplate: factTemplate
}));
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
containsValueArray: false,
nestingLevel: 0,
facts:
{ keyName: 'foo',
value1: 'bar',
value2: undefined
}
}]);
});
it('includes given compare keys from basisFacts', function() {
var facts = factData([{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]);
var result = compareFacts(facts[0], facts[1],
options({ compareKey: ['value', 'extra']
}));
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
containsValueArray: false,
nestingLevel: 0,
facts:
[{ keyName: 'value',
value1: 'bar',
value2: undefined,
isDivergent: true
},
{ keyName: 'extra',
value1: 'doo',
value2: undefined,
isDivergent: true
}]
}]);
});
});
describe('when value for nameKey exists multiple times in a single collection', function() {
context('with differences between any of the values', function() {
it('includes rendered values as array for value properties', function() {
var factTemplate =
{ hasTemplate:
function() {
return true;
},
render: function(fact) {
return fact.version;
}
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'some-package',
'version': 'abcd'
},
{ 'name': 'some-package',
'version': 'efgh'
}]
},
{ position: 'right',
facts:
[{ 'name': 'some-package',
'version': 'abcd'
},
{ 'name': 'some-package',
'version': 'ijkl'
}]
}, options({ compareKey: ['value'],
factTemplate: factTemplate,
supportsValueArray: true
}));
expect(result[0].containsValueArray).to.equal(true);
expect(result[0].facts).to.deep.equal(
{ keyName: 'some-package',
value1: ['abcd', 'efgh'],
value2: ['abcd', 'ijkl']
});
});
});
context('with no differences between any of the values', function() {
it('does not include the property at all', function() {
var expectation;
var factTemplate =
{ hasTemplate:
function() {
return true;
},
render: function(fact) {
return fact.version;
}
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'some-package',
'version': 'abcd'
},
{ 'name': 'some-package',
'version': 'efgh'
}]
},
{ position: 'right',
facts:
[{ 'name': 'some-package',
'version': 'abcd'
},
{ 'name': 'some-package',
'version': 'efgh'
}]
}, options({ compareKey: ['value'],
factTemplate: factTemplate,
supportsValueArray: true
}));
// Use assignment to avoid jshint warning
expectation = expect(result).to.be.empty;
});
it('is insensitive to the order of the facts', function() {
var expectation;
var factTemplate =
{ hasTemplate:
function() {
return true;
},
render: function(fact) {
return fact.version;
}
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'some-package',
'version': 'efgh'
},
{ 'name': 'some-package',
'version': 'abcd'
}]
},
{ position: 'right',
facts:
[{ 'name': 'some-package',
'version': 'abcd'
},
{ 'name': 'some-package',
'version': 'efgh'
}]
}, options({ compareKey: ['value'],
factTemplate: factTemplate,
supportsValueArray: true
}));
// Use assignment to avoid jshint warning
expectation = expect(result).to.be.empty;
});
});
});
context('with factTemplate', function() {
var factData;
beforeEach(function() {
factData = [{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz'
}]
}];
});
it('renders the template with each provided fact', function() {
var renderCalledWith = [];
var factTemplate =
{ render: function(fact) {
renderCalledWith.push(fact);
},
hasTemplate: function() { return true; },
template: ""
};
compareFacts(factData[0], factData[1],
options({ compareKey: ['value'],
factTemplate: factTemplate
}));
expect(renderCalledWith).to.include(factData[0].facts[0]);
expect(renderCalledWith).to.include(factData[1].facts[0]);
});
});
});

View File

@@ -1,153 +0,0 @@
/* jshint node: true */
import '../../support/node';
import compareFacts from '../../../src/system-tracking/compare-facts/nested';
describe('CompareFacts.Nested', function() {
it('returns empty array with no fact data', function() {
var result = compareFacts({ facts: [] }, { facts: [] });
expect(result).to.deep.equal([]);
});
it('returns empty array when no differences', function() {
var result = compareFacts(
{ facts:
{ 'testing_facts':
{ 'foo': 'bar'
}
}
},
{ facts:
{ 'testing_facts':
{ 'foo': 'bar'
}
}
});
expect(result).to.deep.equal([]);
});
context('when only left set has data', function() {
it('returns values with data for value1 and "absent" for value2', function() {
var result = compareFacts(
{ position: 'left',
facts:
{ 'testing_facts':
{ 'foo': 'bar'
}
}
},
{ position: 'right',
facts:
{}
});
expect(result[0].facts).to.contain
.an.item
.with.property('value1', 'bar');
expect(result[0].facts).to.contain
.an.item
.with.property('value2', 'absent');
});
});
context('when only right set has data', function() {
it('returns values with data for value2 and "absent" for value1', function() {
var result = compareFacts(
{ position: 'left',
facts:
{}
},
{ position: 'right',
facts:
{ 'testing_facts':
{ 'foo': 'bar'
}
}
});
expect(result).not.to.be.empty;
expect(result[0].facts).to.contain
.an.item
.with.property('value1', 'absent');
expect(result[0].facts).to.contain
.an.item
.with.property('value2', 'bar');
});
});
context('when both sets have fact data and differences exist', function() {
it('does not consider false values "absent"', function() {
var result = compareFacts(
{ position: 'left',
facts:
{ 'testing_facts':
{ 'foo': false
}
}
},
{ position: 'right',
facts:
{ 'testing_facts':
{ 'foo': true
}
}
});
expect(result[0].facts).to.contain
.an.item
.with.property('value1', false);
expect(result[0].facts).to.contain
.an.item
.with.property('value2', true);
});
it('uses "absent" for both values when neither has data', function() {
var result = compareFacts(
{ position: 'left',
facts:
{ 'testing_facts':
{ 'foo': 'baz',
'blah': null
}
}
},
{ position: 'right',
facts:
{ 'testing_facts':
{ 'foo': 'bar',
'blah': null
}
}
});
expect(result[0].facts).to.contain
.an.item
.with.property('value1', 'absent');
expect(result[0].facts).to.contain
.an.item
.with.property('value2', 'absent');
});
});
});

View File

@@ -1,77 +0,0 @@
import '../support/node';
import systemTracking from '../../src/system-tracking/data-services/main';
import {describeModule} from '../support/describe-module';
import moment from '../../src/shared/moment/moment';
describeModule(systemTracking.name)
.testService('factScanDataService', function(test, restStub) {
var service;
test.withService(function(_service) {
service = _service;
});
it('returns list of versions with search parameters', function() {
var version = { result: 'test' };
var host_id = 1;
var module = 'packages';
var start = moment('2015-05-05');
var end = moment('2015-05-06');
var result = {
data: {
results: [version]
}
};
var actual, expected;
var searchParams =
{ hostId: host_id,
dateRange:
{ from: start,
to: end
},
endDate: end,
moduleName: module
};
actual = service.getVersion(searchParams);
expected = _.clone(searchParams);
expected.versions = [version];
restStub.succeed(result);
restStub.flush();
return expect(actual).to.eventually.deep.equal(expected);
});
it('returns list of facts', function() {
var facts = [{}],
version = {
"module" : "package",
"timestamp": '2015-05-07T14:57:37',
"related" : {
"fact_view" : "/hosts/1/fact_versions/?module=packages&from=2015-05-05T00:00:00-04:00&to=2015-05-06T00:00:00-04:00"
}
},
result = {
data: {
fact: facts
}
};
var actual = service.getFacts(version)
.then(function(response) {
return response.fact;
});
restStub.succeedAt(version.related.fact_view, result);
restStub.flush();
return expect(actual).to.eventually.equal(facts);
});
});