diff --git a/.gitignore b/.gitignore index bb1e6b97bc..cf779d87af 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,8 @@ npm-debug.log coverage.xml htmlcov pep8.txt +scratch +testem.log # Mac OS X *.DS_Store diff --git a/Makefile b/Makefile index f3ae843b39..5f245be131 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ SITELIB=$(shell $(PYTHON) -c "from distutils.sysconfig import get_python_lib; pr OFFICIAL ?= no PACKER ?= packer GRUNT ?= $(shell [ -t 0 ] && echo "grunt" || echo "grunt --no-color") +TESTEM ?= ./node_modules/.bin/testem BROCCOLI ?= ./node_modules/.bin/broccoli NODE ?= node @@ -293,8 +294,8 @@ reports/ui_code: node_modules clean-ui Brocfile.js bower.json Gruntfile.js $(BROCCOLI) build reports/ui_code -- --no-concat --no-tests --no-styles --no-sourcemaps # Run UI unit tests -test_ui: node_modules minjs_ci Gruntfile.js - $(GRUNT) karma:ci +test_ui: node_modules minjs_ci + $(TESTEM) ci --file testem.yml -R xunit # Run API unit tests across multiple Python/Django versions with Tox. test_tox: diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 41f795e625..e8f65b5a6d 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -38,6 +38,7 @@ import mainMenu from 'tower/main-menu/main'; import browserData from 'tower/browser-data/main'; import dashboard from 'tower/dashboard/main'; import moment from 'tower/shared/moment/main'; +import templateUrl from 'tower/shared/template-url/main'; import {JobDetailController} from 'tower/controllers/JobDetail'; import {JobStdoutController} from 'tower/controllers/JobStdout'; @@ -84,6 +85,7 @@ var tower = angular.module('Tower', [ mainMenu.name, dashboard.name, moment.name, + templateUrl.name, 'AuthService', 'Utilities', 'LicenseHelper', diff --git a/awx/ui/static/js/dashboard/counts/dashboard-counts.directive.js b/awx/ui/static/js/dashboard/counts/dashboard-counts.directive.js index ac0f201237..3dafe1f13e 100644 --- a/awx/ui/static/js/dashboard/counts/dashboard-counts.directive.js +++ b/awx/ui/static/js/dashboard/counts/dashboard-counts.directive.js @@ -1,14 +1,14 @@ /* jshint unused: vars */ export default - [ '$rootScope', - function() { + [ 'templateUrl', + function(templateUrl) { return { restrict: 'E', scope: { data: '=' }, replace: false, - templateUrl: '/static/js/dashboard/counts/dashboard-counts.partial.html', + templateUrl: templateUrl('dashboard/counts/dashboard-counts'), link: function(scope, element, attrs) { scope.$watch("data", function(data) { if (data && data.hosts) { diff --git a/awx/ui/static/js/dashboard/dashboard.directive.js b/awx/ui/static/js/dashboard/dashboard.directive.js index c330aeb137..243a423a67 100644 --- a/awx/ui/static/js/dashboard/dashboard.directive.js +++ b/awx/ui/static/js/dashboard/dashboard.directive.js @@ -1,11 +1,11 @@ /* jshint unused: vars */ export default - [ '$rootScope', - function() { + [ 'templateUrl', + function(templateUrl) { return { restrict: 'E', scope: true, - templateUrl: '/static/js/dashboard/dashboard.partial.html', + templateUrl: templateUrl('dashboard/dashboard'), link: function(scope, element, attrs) { } }; diff --git a/awx/ui/static/js/dashboard/graphs/dashboard-graphs.directive.js b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.directive.js index b27418a94c..ce0052e132 100644 --- a/awx/ui/static/js/dashboard/graphs/dashboard-graphs.directive.js +++ b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.directive.js @@ -1,11 +1,11 @@ /* jshint unused: vars */ export default - [ '$rootScope', - function() { + [ 'templateUrl', + function(templateUrl) { return { restrict: 'E', scope: true, - templateUrl: '/static/js/dashboard/graphs/dashboard-graphs.partial.html', + templateUrl: templateUrl('dashboard/graphs/dashboard-graphs'), link: function(scope, element, attrs) { function clearGraphs() { scope.jobStatusSelected = false; diff --git a/awx/ui/static/js/dashboard/graphs/host-status/host-status-graph.directive.js b/awx/ui/static/js/dashboard/graphs/host-status/host-status-graph.directive.js index 8fb44090b8..9ec11d5d46 100644 --- a/awx/ui/static/js/dashboard/graphs/host-status/host-status-graph.directive.js +++ b/awx/ui/static/js/dashboard/graphs/host-status/host-status-graph.directive.js @@ -8,14 +8,15 @@ [ '$compile', '$window', 'adjustGraphSize', + 'templateUrl', HostStatusGraph, ]; -function HostStatusGraph($compile, $window, adjustGraphSize) { +function HostStatusGraph($compile, $window, adjustGraphSize, templateUrl) { return { restrict: 'E', link: link, - templateUrl: '/static/js/dashboard/graphs/host-status/host_status_graph.partial.html' + templateUrl: templateUrl('dashboard/graphs/host-status/host_status_graph') }; function link(scope, element, attr) { diff --git a/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.directive.js b/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.directive.js index 1d233ab42f..e6c3af0095 100644 --- a/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.directive.js +++ b/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.directive.js @@ -12,16 +12,17 @@ 'Wait', 'adjustGraphSize', 'jobStatusGraphData', + 'templateUrl', JobStatusGraph ]; -function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustGraphSize, graphDataService) { +function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustGraphSize, graphDataService, templateUrl) { return { restrict: 'E', scope: { data: '=' }, - templateUrl: '/static/js/dashboard/graphs/job-status/job_status_graph.partial.html', + templateUrl: templateUrl('dashboard/graphs/job-status/job_status_graph'), link: link }; diff --git a/awx/ui/static/js/dashboard/graphs/job-status/main.js b/awx/ui/static/js/dashboard/graphs/job-status/main.js index 5758354a28..9c122acf3b 100644 --- a/awx/ui/static/js/dashboard/graphs/job-status/main.js +++ b/awx/ui/static/js/dashboard/graphs/job-status/main.js @@ -1,8 +1,8 @@ import JobStatusGraphDirective from 'tower/dashboard/graphs/job-status/job-status-graph.directive'; import JobStatusGraphService from 'tower/dashboard/graphs/job-status/job-status-graph.service'; import DashboardGraphHelpers from 'tower/dashboard/graphs/graph-helpers/main'; -import ApiLoader from 'tower/shared/api-loader'; +import templateUrl from 'tower/shared/template-url/main'; -export default angular.module('JobStatusGraph', [DashboardGraphHelpers.name, ApiLoader.name]) +export default angular.module('JobStatusGraph', [DashboardGraphHelpers.name, templateUrl.name]) .directive('jobStatusGraph', JobStatusGraphDirective) .service('jobStatusGraphData', JobStatusGraphService); diff --git a/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.directive.js b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.directive.js index 6dc6f20afb..19ba322888 100644 --- a/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.directive.js +++ b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.directive.js @@ -1,14 +1,15 @@ /* jshint unused: vars */ export default [ "PlaybookRun", - function JobTemplatesList(PlaybookRun) { + 'templateUrl', + function JobTemplatesList(PlaybookRun, templateUrl) { return { restrict: 'E', link: link, scope: { data: '=' }, - templateUrl: '/static/js/dashboard/lists/job-templates/job-templates-list.partial.html' + templateUrl: templateUrl('dashboard/lists/job-templates/job-templates-list') }; function link(scope, element, attr) { diff --git a/awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js index 31a433db1a..f0c9d742e2 100644 --- a/awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js +++ b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js @@ -1,43 +1,44 @@ /* jshint unused: vars */ export default - ['moment', - function JobsList(moment) { - return { - restrict: 'E', - link: link, - scope: { - data: '=' - }, - templateUrl: '/static/js/dashboard/lists/jobs/jobs-list.partial.html' - }; - - function link(scope, element, attr) { - scope.$watch("data", function(data) { - if (data) { - if (data.length > 0) { - createList(data); - scope.noJobs = false; - } else { - scope.noJobs = true; - } - } - }); - - function createList(list) { - // detailsUrl, status, name, time - scope.jobs = _.map(list, function(job){ - return { - detailsUrl: job.url.replace("api/v1", "#"), - status: job.status, - name: job.name, - time: moment(job.finished).fromNow() - }; }); - - scope.snapRows = (list.length < 4); - } - - scope.isSuccessful = function (status) { - return (status === "successful"); + [ 'moment', + 'templateUrl', + function JobsList(moment, templateUrl) { + return { + restrict: 'E', + link: link, + scope: { + data: '=' + }, + templateUrl: templateUrl('dashboard/lists/jobs/jobs-list') }; - } + + function link(scope, element, attr) { + scope.$watch("data", function(data) { + if (data) { + if (data.length > 0) { + createList(data); + scope.noJobs = false; + } else { + scope.noJobs = true; + } + } + }); + + function createList(list) { + // detailsUrl, status, name, time + scope.jobs = _.map(list, function(job){ + return { + detailsUrl: job.url.replace("api/v1", "#"), + status: job.status, + name: job.name, + time: moment(job.finished).fromNow() + }; }); + + scope.snapRows = (list.length < 4); + } + + scope.isSuccessful = function (status) { + return (status === "successful"); + }; + } }]; diff --git a/awx/ui/static/js/main-menu/default-menu.directive.js b/awx/ui/static/js/main-menu/default-menu.directive.js index 792009307e..59e7039be5 100644 --- a/awx/ui/static/js/main-menu/default-menu.directive.js +++ b/awx/ui/static/js/main-menu/default-menu.directive.js @@ -1,15 +1,18 @@ -export default function() { - return { - restrict: 'E', - templateUrl: '/static/js/main-menu/menu-default.partial.html', - link: function(scope, element) { - var contents = element.contents(); - contents.unwrap(); +export default + [ 'templateUrl', + function(templateUrl) { + return { + restrict: 'E', + templateUrl: templateUrl('main-menu/menu-default'), + link: function(scope, element) { + var contents = element.contents(); + contents.unwrap(); - scope.$on('$destroy', function() { - contents.remove(); - $(".MenuItem--socketStatus").remove(); - }); + scope.$on('$destroy', function() { + contents.remove(); + $(".MenuItem--socketStatus").remove(); + }); + } + }; } - }; -} + ]; diff --git a/awx/ui/static/js/main-menu/main-menu.directive.js b/awx/ui/static/js/main-menu/main-menu.directive.js index 4e2eafee22..ad139cd24e 100644 --- a/awx/ui/static/js/main-menu/main-menu.directive.js +++ b/awx/ui/static/js/main-menu/main-menu.directive.js @@ -1,45 +1,48 @@ /* jshint unused: vars */ -export default function() { - return { - restrict: 'E', - controllerAs: 'mainMenu', - templateUrl: '/static/js/main-menu/main-menu.partial.html', - controller: ['$scope', function($scope) { - this.open = function() { - $scope.isOpen = true; - }; +export default + [ 'templateUrl', + function(templateUrl) { + return { + restrict: 'E', + controllerAs: 'mainMenu', + templateUrl: templateUrl('main-menu/main-menu'), + controller: ['$scope', function($scope) { + this.open = function() { + $scope.isOpen = true; + }; - this.close = function() { - $scope.isOpen = false; - }; + this.close = function() { + $scope.isOpen = false; + }; - this.toggle = function() { - $scope.isOpen = !$scope.isOpen; - }; + this.toggle = function() { + $scope.isOpen = !$scope.isOpen; + }; - $scope.isOpen = false; - }], - scope: { - menuStyle: '&menuStyle', - currentUser: '=' - }, - link: function(scope, element, attrs) { - scope.menuStyleClassName = 'blah'; - scope.$watch(function() { - return scope.$eval(scope.menuStyle); - }, function(newValue) { - scope.menuStyleClassName = 'MainMenu--' + newValue; - }); - scope.$watch('isOpen', function(isOpen) { - if (isOpen) { - element.find('.MainMenu').addClass("Menu--open"); - element.find('menu-toggle-button').addClass("MenuToggle--open"); - } else { - element.find('.MainMenu').removeClass("Menu--open"); - element.find('menu-toggle-button').removeClass("MenuToggle--open"); + $scope.isOpen = false; + }], + scope: { + menuStyle: '&menuStyle', + currentUser: '=' + }, + link: function(scope, element, attrs) { + scope.menuStyleClassName = 'blah'; + scope.$watch(function() { + return scope.$eval(scope.menuStyle); + }, function(newValue) { + scope.menuStyleClassName = 'MainMenu--' + newValue; + }); + scope.$watch('isOpen', function(isOpen) { + if (isOpen) { + element.find('.MainMenu').addClass("Menu--open"); + element.find('menu-toggle-button').addClass("MenuToggle--open"); + } else { + element.find('.MainMenu').removeClass("Menu--open"); + element.find('menu-toggle-button').removeClass("MenuToggle--open"); + } + }); } - }); + }; } - }; -} + ]; diff --git a/awx/ui/static/js/main-menu/menu-toggle.directive.js b/awx/ui/static/js/main-menu/menu-toggle.directive.js index df399bbce9..6459f3e09b 100644 --- a/awx/ui/static/js/main-menu/menu-toggle.directive.js +++ b/awx/ui/static/js/main-menu/menu-toggle.directive.js @@ -1,27 +1,30 @@ /* jshint unused: vars */ -export default function() { - return { - templateUrl: '/static/js/main-menu/menu-toggle.partial.html', - restrict: 'E', - require: '^^mainMenu', - scope: { - width: '@', - height: '@', - barHeight: '@' - }, - link: function(scope, element, attrs, mainMenuController) { - scope.$on('$destroy', function() { - element.off('click'); - }); +export default + [ 'templateUrl', + function(templateUrl) { + return { + templateUrl: templateUrl('main-menu/menu-toggle'), + restrict: 'E', + require: '^^mainMenu', + scope: { + width: '@', + height: '@', + barHeight: '@' + }, + link: function(scope, element, attrs, mainMenuController) { + scope.$on('$destroy', function() { + element.off('click'); + }); - element.on("click", function(e) { - e.preventDefault(); - e.stopPropagation(); - scope.$apply(function() { - mainMenuController.toggle(); - }); - }); + element.on("click", function(e) { + e.preventDefault(); + e.stopPropagation(); + scope.$apply(function() { + mainMenuController.toggle(); + }); + }); + } + }; } - }; -} + ]; diff --git a/awx/ui/static/js/main-menu/portal-menu.directive.js b/awx/ui/static/js/main-menu/portal-menu.directive.js index e7aeceb0e6..cd4c7b588d 100644 --- a/awx/ui/static/js/main-menu/portal-menu.directive.js +++ b/awx/ui/static/js/main-menu/portal-menu.directive.js @@ -1,15 +1,18 @@ -export default function() { - return { - restrict: 'E', - templateUrl: '/static/js/main-menu/menu-portal.partial.html', - link: function(scope, element) { - var contents = element.contents(); - contents.unwrap(); +export default + [ 'templateUrl', + function(templateUrl) { + return { + restrict: 'E', + templateUrl: templateUrl('main-menu/menu-portal'), + link: function(scope, element) { + var contents = element.contents(); + contents.unwrap(); - scope.$on('$destroy', function() { - contents.remove(); - $(".MenuItem--socketStatus").remove(); - }); + scope.$on('$destroy', function() { + contents.remove(); + $(".MenuItem--socketStatus").remove(); + }); + } + }; } - }; -} + ]; diff --git a/awx/ui/static/js/main-menu/web-socket-status.directive.js b/awx/ui/static/js/main-menu/web-socket-status.directive.js index 4f847e72f7..e7cdb5a0df 100644 --- a/awx/ui/static/js/main-menu/web-socket-status.directive.js +++ b/awx/ui/static/js/main-menu/web-socket-status.directive.js @@ -1,18 +1,22 @@ /* jshint unused: vars */ -export default ['$rootScope', function($rootScope) { - return { - restrict: 'E', - templateUrl: '/static/js/main-menu/web-socket-status.partial.html', - link: function(scope, element, attrs) { - scope.socketHelp = $rootScope.socketHelp; - scope.socketTip = $rootScope.socketTip; - $rootScope.$watch('socketStatus', function(newStatus) { - scope.socketStatus = newStatus; - }); - $rootScope.$watch('socketTip', function(newTip) { - scope.socketTip = newTip; - }); +export default + [ '$rootScope', + 'templateUrl', + function($rootScope, templateUrl) { + return { + restrict: 'E', + templateUrl: templateUrl('main-menu/web-socket-status'), + link: function(scope, element, attrs) { + scope.socketHelp = $rootScope.socketHelp; + scope.socketTip = $rootScope.socketTip; + $rootScope.$watch('socketStatus', function(newStatus) { + scope.socketStatus = newStatus; + }); + $rootScope.$watch('socketTip', function(newTip) { + scope.socketTip = newTip; + }); + } + }; } - }; -}]; + ]; diff --git a/awx/ui/static/js/shared/breadcrumbs/breadcrumbs.directive.js b/awx/ui/static/js/shared/breadcrumbs/breadcrumbs.directive.js index ae1f3fd85c..0d613d0a91 100644 --- a/awx/ui/static/js/shared/breadcrumbs/breadcrumbs.directive.js +++ b/awx/ui/static/js/shared/breadcrumbs/breadcrumbs.directive.js @@ -9,30 +9,33 @@ import controller from './breadcrumbs.controller'; import 'tower/shared/generator-helpers'; -export default function() { +export default + [ 'templateUrl', + function(templateUrl) { - return { - restrict: 'E', - controller: controller, - transclude: true, - templateUrl: '/static/js/shared/breadcrumbs/breadcrumbs.partial.html', - scope: { - }, - link: function(scope, element, attrs, controller) { - // make breadcrumbs hidden until the current - // breadcrumb has a title; this avoids - // ugly rendering when an object's title - // is fetched via ajax - // - controller.setHidden(); + return { + restrict: 'E', + controller: controller, + transclude: true, + templateUrl: templateUrl('shared/breadcrumbs/breadcrumbs'), + scope: { + }, + link: function(scope, element, attrs, controller) { + // make breadcrumbs hidden until the current + // breadcrumb has a title; this avoids + // ugly rendering when an object's title + // is fetched via ajax + // + controller.setHidden(); - scope.$watch('isHidden', function(value) { - if (value) { - element.hide(); - } else { - element.show(); + scope.$watch('isHidden', function(value) { + if (value) { + element.hide(); + } else { + element.show(); + } + }); } - }); + }; } - }; -} + ]; diff --git a/awx/ui/static/js/shared/icon/icon.directive.js b/awx/ui/static/js/shared/icon/icon.directive.js index b0735704fb..d4da46b5a6 100644 --- a/awx/ui/static/js/shared/icon/icon.directive.js +++ b/awx/ui/static/js/shared/icon/icon.directive.js @@ -1,29 +1,32 @@ -export default function() { - return { - restrict: 'E', - templateUrl: '/static/js/shared/icon/icon.partial.html', - scope: { - }, - link: function(scope, element, attrs) { - var svg = $('svg', element); - var iconPath = '#' + attrs.name; +export default + [ 'templateUrl', + function(templateUrl) { + return { + restrict: 'E', + templateUrl: templateUrl('shared/icon/icon'), + scope: { + }, + link: function(scope, element, attrs) { + var svg = $('svg', element); + var iconPath = '#' + attrs.name; - // Make a copy of the tag to insert its contents into this - // element's svg tag - var content = $(iconPath).clone(); + // Make a copy of the tag to insert its contents into this + // element's svg tag + var content = $(iconPath).clone(); - // Copy classes & viewBox off the so that we preserve any styling - // when we copy the item inline - var classes = $(iconPath).attr('class'); + // Copy classes & viewBox off the so that we preserve any styling + // when we copy the item inline + var classes = $(iconPath).attr('class'); - // viewBox needs to be access via native - // javascript's setAttribute function - var viewBox = $(iconPath)[0].getAttribute('viewBox'); + // viewBox needs to be access via native + // javascript's setAttribute function + var viewBox = $(iconPath)[0].getAttribute('viewBox'); - svg[0].setAttribute('viewBox', viewBox); - svg.attr('class', classes) - .html(content.contents()); + svg[0].setAttribute('viewBox', viewBox); + svg.attr('class', classes) + .html(content.contents()); + } + }; } - }; -} + ]; diff --git a/awx/ui/static/js/shared/moment/moment.js b/awx/ui/static/js/shared/moment/moment.js index 9d7ba7cc91..50e8c2341f 100644 --- a/awx/ui/static/js/shared/moment/moment.js +++ b/awx/ui/static/js/shared/moment/moment.js @@ -7,9 +7,9 @@ function moment() { // lists the user's preferred languages, the first in the array // being the user's top choice. navigator.languages is currently // comptabile with chrome>v32, ffox>32, but not IE/Safari - var lang = navigator.languages ? - navigator.languages[0] : - (navigator.language || navigator.userLanguage); + var lang = window.navigator.languages ? + window.navigator.languages[0] : + (window.navigator.language || window.navigator.userLanguage); originalMoment.locale(lang); return originalMoment.apply(this, arguments); diff --git a/awx/ui/static/js/shared/multi-select-list/main.js b/awx/ui/static/js/shared/multi-select-list/main.js index 089fc7cd7b..7679b5e9d4 100644 --- a/awx/ui/static/js/shared/multi-select-list/main.js +++ b/awx/ui/static/js/shared/multi-select-list/main.js @@ -7,9 +7,10 @@ import multiSelect from './multi-select-list.directive'; import selectAll from './select-all.directive'; import selectListItem from './select-list-item.directive'; +import templateUrl from 'tower/shared/template-url/main'; export default - angular.module('multiSelectList', []) + angular.module('multiSelectList', [templateUrl.name]) .directive('multiSelectList', multiSelect) .directive('selectAll', selectAll) .directive('selectListItem', selectListItem); diff --git a/awx/ui/static/js/shared/multi-select-list/select-all.directive.js b/awx/ui/static/js/shared/multi-select-list/select-all.directive.js index 251fd6a008..4470f05e79 100644 --- a/awx/ui/static/js/shared/multi-select-list/select-all.directive.js +++ b/awx/ui/static/js/shared/multi-select-list/select-all.directive.js @@ -129,12 +129,10 @@ // // => // '/static/js/shared/multi-select-list/select-all.html // -function template(base) { - return '/static/js/' + base + '.partial.html'; -} export default - [ function() { + [ 'templateUrl', + function(templateUrl) { return { require: '^multiSelectList', restrict: 'E', @@ -145,7 +143,7 @@ export default extendedLabel: '&', isSelectionEmpty: '=selectionsEmpty' }, - templateUrl: template('shared/multi-select-list/select-all'), + templateUrl: templateUrl('shared/multi-select-list/select-all'), link: function(scope, element, attrs, controller) { scope.label = scope.label || 'All'; diff --git a/awx/ui/static/js/shared/template-url/main.js b/awx/ui/static/js/shared/template-url/main.js new file mode 100644 index 0000000000..8c1c64185e --- /dev/null +++ b/awx/ui/static/js/shared/template-url/main.js @@ -0,0 +1,6 @@ +import templateUrl from './template-url.factory'; + +export default + angular.module('templateUrl', []) + .factory('templateUrl', templateUrl); + diff --git a/awx/ui/static/js/shared/template-url/template-url.factory.js b/awx/ui/static/js/shared/template-url/template-url.factory.js new file mode 100644 index 0000000000..c3fb17fd68 --- /dev/null +++ b/awx/ui/static/js/shared/template-url/template-url.factory.js @@ -0,0 +1,20 @@ +function templateUrl($sce, path, isTrusted) { + isTrusted = isTrusted !== false; // defaults to true, can be passed in as false + var parts = ['', 'static', 'js']; + parts.push(path); + + var url = parts.join('/') + '.partial.html'; + + if (isTrusted) { + url = $sce.trustAsResourceUrl(url); + } + + return url; +} + +export default + [ '$sce', + function($sce) { + return _.partial(templateUrl, $sce); + } + ]; diff --git a/awx/ui/static/js/system-tracking/data-services/main.js b/awx/ui/static/js/system-tracking/data-services/main.js index cf72087b27..f76af4cc10 100644 --- a/awx/ui/static/js/system-tracking/data-services/main.js +++ b/awx/ui/static/js/system-tracking/data-services/main.js @@ -2,9 +2,10 @@ import factScanDataService from './fact-scan-data.service'; import getDataForComparison from './get-data-for-comparison.factory'; import getModuleOptions from './get-module-options.factory'; import resolveEmptyVersions from './resolve-empty-versions.factory'; +import shared from 'tower/shared/main'; export default - angular.module('systemTracking.dataServices', []) + angular.module('systemTracking.dataServices', [shared.name]) .factory('getModuleOptions', getModuleOptions) .factory('getDataForComparison', getDataForComparison) .factory('resolveEmptyVersions', resolveEmptyVersions) diff --git a/awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js b/awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js index 167ef8688b..211705768f 100644 --- a/awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js +++ b/awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js @@ -8,7 +8,8 @@ export default [ 'moment', - function(moment) { + 'templateUrl', + function(moment, templateUrl) { return { restrict: 'E', scope: { @@ -17,7 +18,7 @@ export default autoUpdate: '=?', inputClass: '&' }, - templateUrl: '/static/js/system-tracking/date-picker/date-picker.partial.html', + templateUrl: templateUrl('system-tracking/date-picker/date-picker'), link: function(scope, element, attrs) { // We need to make sure this _never_ recurses, which sometimes happens diff --git a/awx/ui/static/js/system-tracking/fact-data-table/fact-data-table.directive.js b/awx/ui/static/js/system-tracking/fact-data-table/fact-data-table.directive.js index 21f157d3ff..1c99f546a0 100644 --- a/awx/ui/static/js/system-tracking/fact-data-table/fact-data-table.directive.js +++ b/awx/ui/static/js/system-tracking/fact-data-table/fact-data-table.directive.js @@ -1,9 +1,10 @@ /* jshint unused: vars */ export default - [ function() { + [ 'templateUrl', + function(templateUrl) { return { restrict: 'E', - templateUrl: '/static/js/system-tracking/fact-data-table/fact-data-table.partial.html', + templateUrl: templateUrl('system-tracking/fact-data-table/fact-data-table'), scope: { leftHostname: '=', rightHostname: '=', diff --git a/awx/ui/static/lib/loader.js/loader.js b/awx/ui/static/lib/loader.js/loader.js index 0c9559c39b..4f3f7f6e38 100644 --- a/awx/ui/static/lib/loader.js/loader.js +++ b/awx/ui/static/lib/loader.js/loader.js @@ -55,7 +55,11 @@ var define, requireModule, require, requirejs; } if (!registry[name]) { - throw new Error('Could not find module ' + name); + name = name + '/index'; + + if (!registry[name]) { + throw new Error('Could not find module ' + name); + } } var mod = registry[name]; diff --git a/awx/ui/tests/.jshintrc b/awx/ui/tests/.jshintrc new file mode 100644 index 0000000000..f34bd39c9c --- /dev/null +++ b/awx/ui/tests/.jshintrc @@ -0,0 +1,5 @@ +{ + "expr": true, + "esnext": true, + "node": true +} diff --git a/awx/ui/tests/unit/directives/job-status-graph-test.js b/awx/ui/tests/directives/job-status-graph-test.js similarity index 89% rename from awx/ui/tests/unit/directives/job-status-graph-test.js rename to awx/ui/tests/directives/job-status-graph-test.js index a7bdc72970..f0c49d1ef0 100644 --- a/awx/ui/tests/unit/directives/job-status-graph-test.js +++ b/awx/ui/tests/directives/job-status-graph-test.js @@ -1,11 +1,20 @@ -import Tower from 'tower/app'; -import {describeModule} from 'tests/unit/describe-module'; -import JobStatusGraph from 'tower/dashboard/graphs/job-status/main' +/* jshint node: true */ + +import '../support/node'; + +import {describeModule} from '../support/describe-module'; +import 'tower/shared/Utilities'; +import 'tower/shared/RestServices'; +import JobStatusGraph from 'tower/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) { diff --git a/awx/ui/tests/e2e/CheckLicense.js b/awx/ui/tests/e2e/CheckLicense.js deleted file mode 100644 index f2e148c1dc..0000000000 --- a/awx/ui/tests/e2e/CheckLicense.js +++ /dev/null @@ -1,30 +0,0 @@ -/********************************** - * Copyright (c) 2015 Ansible, Inc. - * - * CheckLicense.js - * - * Tests the CheckLicense service- helpers/CheckLicense.js - * - */ - - /* global describe, it, expect, by, browser, element, beforeEach */ - - -describe('E2E:CheckLicense', function() { - beforeEach(function() { - browser.get('http://localhost:8013'); - }); - - it('should present login dialog', function() { - var labels = element.all(by.css('#login-modal .modal-body label')); - expect(labels.get(0).getText()).toMatch(/Username/); - }); - - it('should login', function() { - element(by.model('login_username')).sendKeys('admin'); - element(by.model('login_password')).sendKeys('password01!'); - element(by.id('login-button')).click(); - var user = element(by.css('#account-menu [ng-bind="current_user.username"]')); - expect(user.getText()).toMatch(/admin/); - }); -}); \ No newline at end of file diff --git a/awx/ui/tests/unit/features/features.controller-test.js b/awx/ui/tests/features/features.controller-test.js similarity index 83% rename from awx/ui/tests/unit/features/features.controller-test.js rename to awx/ui/tests/features/features.controller-test.js index ac131334a1..08c159a881 100644 --- a/awx/ui/tests/unit/features/features.controller-test.js +++ b/awx/ui/tests/features/features.controller-test.js @@ -1,8 +1,10 @@ +import '../support/node'; + import featuresController from 'tower/shared/features/features.controller'; describe('featuresController', function() { - it('checks if a feature is enabled', inject(['$rootScope', function($rootScope) { + it('checks if a feature is enabled', window.inject(['$rootScope', function($rootScope) { var actual; $rootScope.features = { diff --git a/awx/ui/tests/unit/features/features.service-test.js b/awx/ui/tests/features/features.service-test.js similarity index 90% rename from awx/ui/tests/unit/features/features.service-test.js rename to awx/ui/tests/features/features.service-test.js index 26804f3254..320ed0fd46 100644 --- a/awx/ui/tests/unit/features/features.service-test.js +++ b/awx/ui/tests/features/features.service-test.js @@ -1,5 +1,7 @@ +import '../support/node'; + import features from 'tower/shared/features/main'; -import {describeModule} from '../describe-module'; +import {describeModule} from '../support/describe-module'; //test that it returns features, as well as test that it is returned in rootScope @@ -31,7 +33,7 @@ describeModule(features.name) }); - it('caches in rootScope', inject(['$rootScope', + it('caches in rootScope', window.inject(['$rootScope', function($rootScope){ var features = {}, result = { diff --git a/awx/ui/tests/unit/job-templates/delete-job-template.service-test.js b/awx/ui/tests/job-templates/delete-job-template.service-test.js similarity index 86% rename from awx/ui/tests/unit/job-templates/delete-job-template.service-test.js rename to awx/ui/tests/job-templates/delete-job-template.service-test.js index f1fcb871fc..5766287f51 100644 --- a/awx/ui/tests/unit/job-templates/delete-job-template.service-test.js +++ b/awx/ui/tests/job-templates/delete-job-template.service-test.js @@ -1,5 +1,7 @@ +import '../support/node'; + import jobTemplates from 'tower/job-templates/main'; -import {describeModule} from '../describe-module'; +import {describeModule} from '../support/describe-module'; describeModule(jobTemplates.name) .testService('deleteJobTemplate', function(test, restStub) { diff --git a/awx/ui/tests/karma-unit.conf b/awx/ui/tests/karma-unit.conf deleted file mode 100644 index eae72dd9e0..0000000000 --- a/awx/ui/tests/karma-unit.conf +++ /dev/null @@ -1,22 +0,0 @@ -// Karma configuration -// Generated on Mon Aug 04 2014 21:17:04 GMT-0400 (EDT) - -var sharedConfig = require('./karma-shared.conf'); - -module.exports = function(config) { - var conf = sharedConfig(); - - // list of files / patterns to load in the browser - conf.files = conf.files.concat([ - '../static/lib/angular-mocks/angular-mocks.js', - '../../../node_modules/ng-midway-tester/src/ngMidwayTester.js', - './unit/*', - './unit/**/*' - ]); - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - conf.logLevel = config.LOG_INFO, - - config.set(conf); -}; diff --git a/awx/ui/tests/karma.conf.js b/awx/ui/tests/karma.conf.js deleted file mode 100644 index a6f42aa4a6..0000000000 --- a/awx/ui/tests/karma.conf.js +++ /dev/null @@ -1,88 +0,0 @@ -// Karma configuration -// Generated on Mon Aug 04 2014 21:17:04 GMT-0400 (EDT) - -var path = require('path'); - -module.exports = function(config) { - config.set({ - - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - - autoWatchBatchDelay: 2000, - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - - frameworks: - [ 'mocha', - 'chai', - 'sinon-chai', - 'chai-as-promised', - 'chai-things' - ], - - preprocessors: - { '../dist/**/*.html': ['ng-html2js'] - }, - - // list of files / patterns to load in the browser - files: [ - '../tests/phantomjs-polyfill.js', - '../dist/tower.concat.js', - '../static/lib/angular-mocks/angular-mocks.js', - '../static/lib/ember-cli-test-loader/test-loader.js', - '../dist/tests/**/*.js', - '../tests/unit.js', - '../dist/partials/**/*.html', - '../dist/js/**/*.html' - ], - - ngHtml2JsPreprocessor: { - stripPrefix: path.join(process.cwd(), 'awx/ui/dist'), - prependPrefix: '/static', - moduleName: 'templates' - }, - - - // list of files to exclude - exclude: [ - '../static/js/awx.min.js' - ], - - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['dots', 'progress'], - - client: { - mocha: { - ui: 'bdd' - } - }, - - - // web server port - port: 9876, - - - // enable / disable colors in the output (reporters and logs) - colors: true, - - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Chrome'], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false - - }); -}; diff --git a/awx/ui/tests/unit/multi-select-list/multi-select-list.controller-test.js b/awx/ui/tests/multi-select-list/multi-select-list.controller-test.js similarity index 100% rename from awx/ui/tests/unit/multi-select-list/multi-select-list.controller-test.js rename to awx/ui/tests/multi-select-list/multi-select-list.controller-test.js diff --git a/awx/ui/tests/unit/multi-select-list/multi-select-list.directive-test.js b/awx/ui/tests/multi-select-list/multi-select-list.directive-test.js similarity index 96% rename from awx/ui/tests/unit/multi-select-list/multi-select-list.directive-test.js rename to awx/ui/tests/multi-select-list/multi-select-list.directive-test.js index ed4f872c2b..5af5770cb2 100644 --- a/awx/ui/tests/unit/multi-select-list/multi-select-list.directive-test.js +++ b/awx/ui/tests/multi-select-list/multi-select-list.directive-test.js @@ -1,4 +1,6 @@ -import {describeModule} from 'tests/unit/describe-module'; +import '../support/node'; + +import {describeModule} from '../support/describe-module'; import mod from 'tower/shared/multi-select-list/main'; describeModule(mod.name) @@ -18,9 +20,9 @@ describeModule(mod.name) }); it('works as an attribute on elements', function() { - inject(['$compile', function($compile) { + window.inject(['$compile', function($compile) { var node = $compile('
')($scope); - var classes = Array.prototype.slice.apply(node[0].classList) + var classes = Array.prototype.slice.apply(node.attr('class').split(' ')); expect(classes).to.contain('ng-scope'); }]); }); diff --git a/awx/ui/tests/unit/multi-select-list/select-all.directive-test.js b/awx/ui/tests/multi-select-list/select-all.directive-test.js similarity index 92% rename from awx/ui/tests/unit/multi-select-list/select-all.directive-test.js rename to awx/ui/tests/multi-select-list/select-all.directive-test.js index 31f06c25e3..8bdf295111 100644 --- a/awx/ui/tests/unit/multi-select-list/select-all.directive-test.js +++ b/awx/ui/tests/multi-select-list/select-all.directive-test.js @@ -1,4 +1,7 @@ -import {describeModule} from 'tests/unit/describe-module'; +import '../support/node'; + +import {describeModule} from '../support/describe-module'; +import mod from 'tower/shared/multi-select-list/main'; var mockController = { selectAll: sinon.spy(), @@ -7,7 +10,7 @@ var mockController = { deselectAllExtended: sinon.spy() }; -describeModule('multiSelectList') +describeModule(mod.name) .testDirective('selectAll', function(directive) { var $scope; @@ -36,7 +39,7 @@ describeModule('multiSelectList') }); it('works as an element tag', function() { - var classes = Array.prototype.slice.apply(directive.$element[0].classList); + var classes = directive.$element.attr('class').split(' '); expect(classes).to.contain('ng-scope'); }); @@ -91,4 +94,4 @@ describeModule('multiSelectList') }); - }); +}); diff --git a/awx/ui/tests/phantomjs-polyfill.js b/awx/ui/tests/phantomjs-polyfill.js deleted file mode 100644 index 46c4204283..0000000000 --- a/awx/ui/tests/phantomjs-polyfill.js +++ /dev/null @@ -1,28 +0,0 @@ -// Phantom.js is missing the standard Function.prototype.bind -// function. See https://code.google.com/p/phantomjs/issues/detail?id=522 -// for more details. -// -if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} diff --git a/awx/ui/tests/protractor-e2e.conf b/awx/ui/tests/protractor-e2e.conf deleted file mode 100644 index c4df53799e..0000000000 --- a/awx/ui/tests/protractor-e2e.conf +++ /dev/null @@ -1,4 +0,0 @@ -exports.config = { - seleniumAddress: 'http://localhost:4444/wd/hub', - specs: ['e2e/*.js'] -} diff --git a/awx/ui/tests/unit/services/job-status-graph-data-test.js b/awx/ui/tests/services/job-status-graph-data-test.js similarity index 96% rename from awx/ui/tests/unit/services/job-status-graph-data-test.js rename to awx/ui/tests/services/job-status-graph-data-test.js index 74d4919bf6..e810b7e708 100644 --- a/awx/ui/tests/unit/services/job-status-graph-data-test.js +++ b/awx/ui/tests/services/job-status-graph-data-test.js @@ -1,5 +1,7 @@ -import {describeModule} from 'tests/unit/describe-module'; -import JobStatusGraph from 'tower/dashboard/graphs/job-status/main' +import '../support/node'; + +import {describeModule} from '../support/describe-module'; +import JobStatusGraph from 'tower/dashboard/graphs/job-status/main'; var processErrors = sinon.spy(); diff --git a/awx/ui/tests/unit/shared/lodash-as-promised_test.js b/awx/ui/tests/shared/lodash-as-promised-test.js similarity index 97% rename from awx/ui/tests/unit/shared/lodash-as-promised_test.js rename to awx/ui/tests/shared/lodash-as-promised-test.js index d0d86a4f44..80105306bc 100644 --- a/awx/ui/tests/unit/shared/lodash-as-promised_test.js +++ b/awx/ui/tests/shared/lodash-as-promised-test.js @@ -1,3 +1,5 @@ +import '../support/node'; + import 'tower/shared/main'; describe('LodashAsPromised', function() { @@ -17,7 +19,7 @@ describe('LodashAsPromised', function() { return memo + value; } - beforeEach(module('shared')); + beforeEach(window.module('shared')); beforeEach(inject(['lodashAsPromised', '$q', function(_lodash, _$q) { _ = _lodash; diff --git a/awx/ui/tests/unit.js b/awx/ui/tests/support/browser/index.js similarity index 100% rename from awx/ui/tests/unit.js rename to awx/ui/tests/support/browser/index.js diff --git a/awx/ui/tests/unit/describe-module.js b/awx/ui/tests/support/describe-module.js similarity index 84% rename from awx/ui/tests/unit/describe-module.js rename to awx/ui/tests/support/describe-module.js index b230edb136..5a0ec240f3 100644 --- a/awx/ui/tests/unit/describe-module.js +++ b/awx/ui/tests/support/describe-module.js @@ -1,4 +1,4 @@ -import RestStub from 'tests/unit/rest-stub'; +import RestStub from './rest-stub'; var $provide; @@ -7,7 +7,7 @@ function wrapInjected(dslFn) { // })); return function(fn) { dslFn.apply(this, - [inject( + [window.inject( [ '$injector', function($injector) { var $compile = $injector.get('$compile'); @@ -28,18 +28,19 @@ function TestModule(name, deps) { registerPreHooks: function() { var self = this; - beforeEach("tower module", module('Tower')); - beforeEach(name + " module", module(name)); - beforeEach("templates module", module('templates')); - beforeEach("mock app setup", module(['$provide', function(_provide_) { + // 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]); @@ -47,12 +48,12 @@ function TestModule(name, deps) { }])); - wrapInjected(beforeEach)(function($httpBackend) { + // wrapInjected(beforeEach)(function($httpBackend) { - $httpBackend - .expectGET('/static/js/local_config.js') - .respond({}); - }); + // $httpBackend + // .expectGET('/static/js/local_config.js') + // .respond({}); + // }); }, mockProvider: function(name, value) { this.mockedProviders[name] = value; @@ -64,7 +65,7 @@ function TestModule(name, deps) { }); }, registerPostHooks: function() { - afterEach(inject(['$httpBackend', function($httpBackend) { + afterEach(window.inject(['$httpBackend', function($httpBackend) { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }])); @@ -81,7 +82,7 @@ function TestService(name) { return { withService: function(fn) { - beforeEach(name + " service", inject([name, function() { + beforeEach(name + " service", window.inject([name, function() { var service = arguments[0]; fn(service); }])); @@ -104,7 +105,7 @@ function TestDirective(name, deps) { // by the test withScope: function(fn) { var self = this; - beforeEach("capture outer $scope", inject(['$rootScope', function($rootScope) { + 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]); @@ -112,7 +113,7 @@ function TestDirective(name, deps) { }, withIsolateScope: function(fn) { var self = this; - beforeEach("capture isolate scope", inject(['$rootScope', function($rootScope) { + beforeEach("capture isolate scope", window.inject(['$rootScope', function($rootScope) { // `this` refers to mocha test suite fn.apply(this, [self.$element.isolateScope()]); }])); @@ -165,7 +166,7 @@ function TestDirective(name, deps) { } beforeEach("compile directive element", - inject(['$compile', '$httpBackend', '$rootScope', function($compile, $httpBackend, $rootScope) { + window.inject(['$compile', '$httpBackend', '$rootScope', function($compile, $httpBackend, $rootScope) { if (!self.$scope) { self.$scope = $rootScope.$new(); @@ -176,13 +177,14 @@ function TestDirective(name, deps) { self.$scope.$digest(); - $httpBackend.flush(); + // $httpBackend.flush(); }])); afterEach("cleanup directive element", function() { - self.$element.trigger('$destroy'); + $(self.$element).trigger('$destroy'); self.$element.remove(); + delete self.$scope; }); this._compileRegistered = true; @@ -200,7 +202,7 @@ function TestDirective(name, deps) { }, provideTemplate: function(url, template) { var $scope = this.$scope; - beforeEach("mock template endpoint", inject(['$httpBackend', function($httpBackend) { + beforeEach("mock template endpoint", window.inject(['$httpBackend', function($httpBackend) { $httpBackend .whenGET(url) .respond(template); @@ -233,7 +235,7 @@ function ModuleDescriptor(name, deps) { testModule.mockProvider('$cookieStore', { get: angular.noop }); testModule.registerPreHooks(); - beforeEach("$q", inject(['$q', function($q) { + beforeEach("$q", window.inject(['$q', function($q) { testService.restStub.$q = $q; }])); diff --git a/awx/ui/tests/support/node/export-global.js b/awx/ui/tests/support/node/export-global.js new file mode 100644 index 0000000000..c1fccb23a1 --- /dev/null +++ b/awx/ui/tests/support/node/export-global.js @@ -0,0 +1,4 @@ +module.exports = + function exportGlobal(varName, value) { + global[varName] = global.window[varName] = value; + }; diff --git a/awx/ui/tests/support/node/index.js b/awx/ui/tests/support/node/index.js new file mode 100644 index 0000000000..91ef218cf6 --- /dev/null +++ b/awx/ui/tests/support/node/index.js @@ -0,0 +1,26 @@ +/* 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'); + +})(); diff --git a/awx/ui/tests/support/node/setup/angular-mocks.js b/awx/ui/tests/support/node/setup/angular-mocks.js new file mode 100644 index 0000000000..fbf1a88ac4 --- /dev/null +++ b/awx/ui/tests/support/node/setup/angular-mocks.js @@ -0,0 +1,5 @@ +var exportGlobal = require('../export-global'); +require('angular-mocks/angular-mocks'); + +exportGlobal('inject', window.inject); + diff --git a/awx/ui/tests/support/node/setup/angular-templates.js b/awx/ui/tests/support/node/setup/angular-templates.js new file mode 100644 index 0000000000..75837d0ad8 --- /dev/null +++ b/awx/ui/tests/support/node/setup/angular-templates.js @@ -0,0 +1,2 @@ +angular.module('templates', []); +require('../../../../templates'); diff --git a/awx/ui/tests/support/node/setup/angular.js b/awx/ui/tests/support/node/setup/angular.js new file mode 100644 index 0000000000..90749a49bc --- /dev/null +++ b/awx/ui/tests/support/node/setup/angular.js @@ -0,0 +1,5 @@ +var exportGlobal = require('../export-global'); +require('angular/angular'); + +exportGlobal('angular', window.angular); + diff --git a/awx/ui/tests/support/node/setup/chai-plugins.js b/awx/ui/tests/support/node/setup/chai-plugins.js new file mode 100644 index 0000000000..dde64dd10c --- /dev/null +++ b/awx/ui/tests/support/node/setup/chai-plugins.js @@ -0,0 +1,8 @@ +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); + diff --git a/awx/ui/tests/support/node/setup/chai.js b/awx/ui/tests/support/node/setup/chai.js new file mode 100644 index 0000000000..570b230185 --- /dev/null +++ b/awx/ui/tests/support/node/setup/chai.js @@ -0,0 +1,5 @@ +var exportGlobal = require('../export-global'); +var chai = require('chai'); + +exportGlobal('chai', chai); +exportGlobal('expect', chai.expect); diff --git a/awx/ui/tests/support/node/setup/d3.js b/awx/ui/tests/support/node/setup/d3.js new file mode 100644 index 0000000000..ec8f384ccb --- /dev/null +++ b/awx/ui/tests/support/node/setup/d3.js @@ -0,0 +1,6 @@ +var exportGlobal = require('../export-global'); +var d3 = require('d3'); + +exportGlobal('d3', d3); + + diff --git a/awx/ui/tests/support/node/setup/jquery.js b/awx/ui/tests/support/node/setup/jquery.js new file mode 100644 index 0000000000..d10af4298c --- /dev/null +++ b/awx/ui/tests/support/node/setup/jquery.js @@ -0,0 +1,7 @@ +var exportGlobal = require('../export-global'); +var jquery = require('jquery'); + +exportGlobal('$', jquery); +exportGlobal('jQuery', jquery); + + diff --git a/awx/ui/tests/support/node/setup/jsdom.js b/awx/ui/tests/support/node/setup/jsdom.js new file mode 100644 index 0000000000..5a5a7b68e5 --- /dev/null +++ b/awx/ui/tests/support/node/setup/jsdom.js @@ -0,0 +1,6 @@ +var jsdom = require('jsdom').jsdom; +var document = jsdom('tower'); +var window = document.parentWindow; + +global.document = document; +global.window = window; diff --git a/awx/ui/tests/support/node/setup/local-storage.js b/awx/ui/tests/support/node/setup/local-storage.js new file mode 100644 index 0000000000..fff3ab7861 --- /dev/null +++ b/awx/ui/tests/support/node/setup/local-storage.js @@ -0,0 +1,7 @@ +var exportGlobal = require('../export-global'); +var LocalStorage = require('node-localstorage').LocalStorage; + +exportGlobal('localStorage', + new LocalStorage('./scratch')); + + diff --git a/awx/ui/tests/support/node/setup/lodash.js b/awx/ui/tests/support/node/setup/lodash.js new file mode 100644 index 0000000000..8af57a2da5 --- /dev/null +++ b/awx/ui/tests/support/node/setup/lodash.js @@ -0,0 +1,4 @@ +var exportGlobal = require('../export-global'); +var lodash = require('lodash'); + +exportGlobal('_', lodash); diff --git a/awx/ui/tests/support/node/setup/mocha.js b/awx/ui/tests/support/node/setup/mocha.js new file mode 100644 index 0000000000..b7d366a4b7 --- /dev/null +++ b/awx/ui/tests/support/node/setup/mocha.js @@ -0,0 +1,7 @@ +var exportGlobal = require('../export-global'); +var mocha = require('mocha'); + +exportGlobal('mocha', mocha); +exportGlobal('beforeEach', beforeEach); +exportGlobal('afterEach', afterEach); + diff --git a/awx/ui/tests/support/node/setup/moment.js b/awx/ui/tests/support/node/setup/moment.js new file mode 100644 index 0000000000..28822e411c --- /dev/null +++ b/awx/ui/tests/support/node/setup/moment.js @@ -0,0 +1,5 @@ +var exportGlobal = require('../export-global'); +var moment = require('moment'); + +exportGlobal('moment', moment); + diff --git a/awx/ui/tests/support/node/setup/nv.js b/awx/ui/tests/support/node/setup/nv.js new file mode 100644 index 0000000000..733b7dbad6 --- /dev/null +++ b/awx/ui/tests/support/node/setup/nv.js @@ -0,0 +1,6 @@ +var exportGlobal = require('../export-global'); +var nv = require('nvd3'); + +exportGlobal('nv', nv); + + diff --git a/awx/ui/tests/support/node/setup/sinon.js b/awx/ui/tests/support/node/setup/sinon.js new file mode 100644 index 0000000000..bfaf5cacec --- /dev/null +++ b/awx/ui/tests/support/node/setup/sinon.js @@ -0,0 +1,4 @@ +var exportGlobal = require('../export-global'); +var sinon = require('sinon'); + +exportGlobal('sinon', sinon); diff --git a/awx/ui/tests/unit/rest-stub.js b/awx/ui/tests/support/rest-stub.js similarity index 98% rename from awx/ui/tests/unit/rest-stub.js rename to awx/ui/tests/support/rest-stub.js index c714096a6a..ad8789bca4 100644 --- a/awx/ui/tests/unit/rest-stub.js +++ b/awx/ui/tests/support/rest-stub.js @@ -63,7 +63,7 @@ RestStub.prototype = inject(['$rootScope', function($rootScope) { $rootScope.$apply(); }]); - }, 1000); + }, 10); } }; diff --git a/awx/ui/tests/unit/system-tracking/compare-facts/flat-test.js b/awx/ui/tests/system-tracking/compare-facts/flat-test.js similarity index 97% rename from awx/ui/tests/unit/system-tracking/compare-facts/flat-test.js rename to awx/ui/tests/system-tracking/compare-facts/flat-test.js index bd72cb774a..c277a19641 100644 --- a/awx/ui/tests/unit/system-tracking/compare-facts/flat-test.js +++ b/awx/ui/tests/system-tracking/compare-facts/flat-test.js @@ -1,33 +1,32 @@ -import compareFacts from 'tower/system-tracking/compare-facts/flat'; - /* jshint node: true */ -/* globals -expect, -_ */ -var _, expect; +import '../../support/node'; + +import compareFacts from 'tower/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'); +// (function(global) { +// var chai = global.chai || require('chai'); - if (typeof window === 'undefined') { - var chaiThings = global.chaiThings || require('chai-things'); - chai.use(chaiThings); - } +// if (typeof window === 'undefined') { +// var chaiThings = global.chaiThings || require('chai-things'); +// chai.use(chaiThings); +// } - _ = global._ || require('lodash'); - expect = global.expect || chai.expect; +// _ = global._ || require('lodash'); +// expect = global.expect || chai.expect; - global.expect = expect; +// global.expect = expect; - global._ = _; +// global._ = _; -})(typeof window === 'undefined' ? global : window); +// })(typeof window === 'undefined' ? global : window); describe('CompareFacts.Flat', function() { diff --git a/awx/ui/tests/unit/system-tracking/compare-facts/nested-test.js b/awx/ui/tests/system-tracking/compare-facts/nested-test.js similarity index 88% rename from awx/ui/tests/unit/system-tracking/compare-facts/nested-test.js rename to awx/ui/tests/system-tracking/compare-facts/nested-test.js index 4014650901..a7ff98452b 100644 --- a/awx/ui/tests/unit/system-tracking/compare-facts/nested-test.js +++ b/awx/ui/tests/system-tracking/compare-facts/nested-test.js @@ -1,34 +1,8 @@ -import compareFacts from 'tower/system-tracking/compare-facts/nested'; - /* jshint node: true */ -/* globals -expect, -_ */ -var _, expect; - -// 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); +import '../../support/node'; +import compareFacts from 'tower/system-tracking/compare-facts/nested'; describe('CompareFacts.Nested', function() { diff --git a/awx/ui/tests/unit/system-tracking/single-host-data.service-test.js b/awx/ui/tests/system-tracking/single-host-data.service-test.js similarity index 93% rename from awx/ui/tests/unit/system-tracking/single-host-data.service-test.js rename to awx/ui/tests/system-tracking/single-host-data.service-test.js index 7579f71743..f9da3c2770 100644 --- a/awx/ui/tests/unit/system-tracking/single-host-data.service-test.js +++ b/awx/ui/tests/system-tracking/single-host-data.service-test.js @@ -1,5 +1,7 @@ -import systemTracking from 'tower/system-tracking/main'; -import {describeModule} from '../describe-module'; +import '../support/node'; + +import systemTracking from 'tower/system-tracking/data-services/main'; +import {describeModule} from '../support/describe-module'; import moment from 'tower/shared/moment/moment'; describeModule(systemTracking.name) diff --git a/testem.yml b/testem.yml new file mode 100644 index 0000000000..913cd51282 --- /dev/null +++ b/testem.yml @@ -0,0 +1,30 @@ +--- +framework: mocha +cwd: awx/ui/ +port: 7358 +src_files: + - static/js/**/*.js + - static/lib/**/*.js + - tests/**/*.js +serve_files: + - dist/tower.concat.js + - dist/tests/**/*.js + - dist/tests/unit.js +unsafe_file_serving: true +test_page: tests.html +disable_watching: true +routes: + /awx/ui/dist: /static + /tests.html: ../../packaging/grunt/testem.mustache + /test-loader.js: static/lib/ember-cli-test-loader/test-loader.js + /vendor: ../../node_modules + /angular-mocks.js: dist/lib/angular-mocks/angular-mocks.js + /templates.js: dist/node-tests/templates.js +reporter: xunit +launch_in_dev: + - Mocha +launch_in_ci: + - PhantomJS +launchers: + Mocha: + command: npm test