UNPKG

angular-gantt

Version:

Gantt chart component for AngularJS

464 lines (409 loc) 14.9 kB
// tslint:disable:no-unused-expression import angular, {ICompileService, IRootScopeService, ITimeoutService} from 'angular' import 'angular-mocks' import {expect} from 'chai' import jQuery from 'jquery' describe('Plugins', function () { // Load the module with MainController beforeEach( angular.mock.module('gantt', 'gantt.labels', 'gantt.sortable', 'gantt.movable', 'gantt.drawtask', 'gantt.tooltips', 'gantt.bounds', 'gantt.progress', 'gantt.table', 'gantt.tree', 'gantt.groups' ) ) let Gantt let $rootScope: IRootScopeService let $compile: ICompileService let $timeout: ITimeoutService let mockData = [ // Order is optional. If not specified it will be assigned automatically { name: 'Milestones', height: '3em', sortable: false, drawTask: false, classes: 'gantt-row-milestone', color: '#45607D', tasks: [ // Dates can be specified as string, timestamp or javascript date object. The data attribute can be used to attach a custom object { name: 'Kickoff', color: '#93C47D', from: '2013-10-07T09:00:00', to: '2013-10-07T10:00:00', data: 'Can contain any custom data or object' }, { name: 'Concept approval', color: '#93C47D', from: new Date(2013, 9, 18, 18, 0, 0), to: new Date(2013, 9, 18, 18, 0, 0), est: new Date(2013, 9, 16, 7, 0, 0), lct: new Date(2013, 9, 19, 0, 0, 0) }, { name: 'Development finished', color: '#93C47D', from: new Date(2013, 10, 15, 18, 0, 0), to: new Date(2013, 10, 15, 18, 0, 0) }, { name: 'Shop is running', color: '#93C47D', from: new Date(2013, 10, 22, 12, 0, 0), to: new Date(2013, 10, 22, 12, 0, 0) }, { name: 'Go-live', color: '#93C47D', from: new Date(2013, 10, 29, 16, 0, 0), to: new Date(2013, 10, 29, 16, 0, 0) } ], data: 'Can contain any custom data or object' }, { name: 'Status meetings', tasks: [ {name: 'Demo #1', color: '#9FC5F8', from: new Date(2013, 9, 25, 15, 0, 0), to: new Date(2013, 9, 25, 18, 30, 0)}, {name: 'Demo #2', color: '#9FC5F8', from: new Date(2013, 10, 1, 15, 0, 0), to: new Date(2013, 10, 1, 18, 0, 0)}, {name: 'Demo #3', color: '#9FC5F8', from: new Date(2013, 10, 8, 15, 0, 0), to: new Date(2013, 10, 8, 18, 0, 0)}, {name: 'Demo #4', color: '#9FC5F8', from: new Date(2013, 10, 15, 15, 0, 0), to: new Date(2013, 10, 15, 18, 0, 0)}, {name: 'Demo #5', color: '#9FC5F8', from: new Date(2013, 10, 24, 9, 0, 0), to: new Date(2013, 10, 24, 10, 0, 0)} ] }, { name: 'Kickoff', movable: {allowResizing: false}, tasks: [ { name: 'Day 1', color: '#9FC5F8', from: new Date(2013, 9, 7, 9, 0, 0), to: new Date(2013, 9, 7, 17, 0, 0), progress: {percent: 100, color: '#3C8CF8'}, movable: false }, { name: 'Day 2', color: '#9FC5F8', from: new Date(2013, 9, 8, 9, 0, 0), to: new Date(2013, 9, 8, 17, 0, 0), progress: {percent: 100, color: '#3C8CF8'} }, { name: 'Day 3', color: '#9FC5F8', from: new Date(2013, 9, 9, 8, 30, 0), to: new Date(2013, 9, 9, 12, 0, 0), progress: {percent: 100, color: '#3C8CF8'} } ] }, { name: 'Create concept', tasks: [ { name: 'Create concept', content: '<i class="fa fa-cog"></i> {{task.model.name}}', color: '#F1C232', from: new Date(2013, 9, 10, 8, 0, 0), to: new Date(2013, 9, 16, 18, 0, 0), est: new Date(2013, 9, 8, 8, 0, 0), lct: new Date(2013, 9, 18, 20, 0, 0), progress: 100 } ] }, { name: 'Finalize concept', tasks: [ { name: 'Finalize concept', color: '#F1C232', from: new Date(2013, 9, 17, 8, 0, 0), to: new Date(2013, 9, 18, 18, 0, 0), progress: 100 } ] }, { id: 'development', name: 'Development', children: ['Sprint 1', 'Sprint 2', 'Sprint 3', 'Sprint 4'], content: '<i class="fa fa-file-code-o"></i> {{row.model.name}}' }, { name: 'Sprint 1', tooltips: false, tasks: [ { name: 'Product list view', color: '#F1C232', from: new Date(2013, 9, 21, 8, 0, 0), to: new Date(2013, 9, 25, 15, 0, 0), progress: 25 } ] }, { name: 'Sprint 2', tasks: [ { name: 'Order basket', color: '#F1C232', from: new Date(2013, 9, 28, 8, 0, 0), to: new Date(2013, 10, 1, 15, 0, 0) } ] }, { name: 'Sprint 3', tasks: [ {name: 'Checkout', color: '#F1C232', from: new Date(2013, 10, 4, 8, 0, 0), to: new Date(2013, 10, 8, 15, 0, 0)} ] }, { name: 'Sprint 4', tasks: [ { name: 'Login & Signup & Admin Views', color: '#F1C232', from: new Date(2013, 10, 11, 8, 0, 0), to: new Date(2013, 10, 15, 15, 0, 0) } ] }, {name: 'Hosting', content: '<i class="fa fa-server"></i> {{row.model.name}}'}, { name: 'Setup', tasks: [ {name: 'HW', color: '#F1C232', from: new Date(2013, 10, 18, 8, 0, 0), to: new Date(2013, 10, 18, 12, 0, 0)} ] }, { name: 'Config', tasks: [ { name: 'SW / DNS/ Backups', color: '#F1C232', from: new Date(2013, 10, 18, 12, 0, 0), to: new Date(2013, 10, 21, 18, 0, 0) } ] }, {name: 'Server', parent: 'Hosting', children: ['Setup', 'Config']}, { name: 'Deployment', parent: 'Hosting', tasks: [ { name: 'Depl. & Final testing', color: '#F1C232', from: new Date(2013, 10, 21, 8, 0, 0), to: new Date(2013, 10, 22, 12, 0, 0), 'classes': 'gantt-task-deployment' } ] }, { name: 'Workshop', tasks: [ { name: 'On-side education', color: '#F1C232', from: new Date(2013, 10, 24, 9, 0, 0), to: new Date(2013, 10, 25, 15, 0, 0) } ] }, { name: 'Content', tasks: [ { name: 'Supervise content creation', color: '#F1C232', from: new Date(2013, 10, 26, 9, 0, 0), to: new Date(2013, 10, 29, 16, 0, 0) } ] }, { name: 'Documentation', tasks: [ { name: 'Technical/User documentation', color: '#F1C232', from: new Date(2013, 10, 26, 8, 0, 0), to: new Date(2013, 10, 28, 18, 0, 0) } ] } ] beforeEach(inject(['$rootScope', '$compile', '$timeout', 'Gantt', function ($tRootScope: IRootScopeService, $tCompile: ICompileService, $tTimeout: ITimeoutService, tGantt) { Gantt = tGantt $rootScope = $tRootScope $compile = $tCompile $timeout = $tTimeout }])) describe('every plugins', function () { it('should load without error', function () { let $scope = $rootScope.$new() $compile('<div gantt api="api">' + '<gantt-labels></gantt-labels>' + '<gantt-tree></gantt-tree>' + '<gantt-table></gantt-table>' + '<gantt-groups></gantt-groups>' + '<gantt-tooltips></gantt-tooltips>' + '<gantt-bounds></gantt-bounds>' + '<gantt-progress></gantt-progress>' + '<gantt-sortable></gantt-sortable>' + '<gantt-movable></gantt-movable>' + '<gantt-draw-task></gantt-draw-task>' + '</div>')($scope) $scope.$digest() $timeout.flush() } ) it('should destroy scope without error', function () { let $scope = $rootScope.$new() $scope.data = angular.copy(mockData) $compile('<div gantt api="api">' + '<gantt-labels></gantt-labels>' + '<gantt-tree></gantt-tree>' + '<gantt-table></gantt-table>' + '<gantt-groups></gantt-groups>' + '<gantt-tooltips></gantt-tooltips>' + '<gantt-bounds></gantt-bounds>' + '<gantt-progress></gantt-progress>' + '<gantt-sortable></gantt-sortable>' + '<gantt-movable></gantt-movable>' + '<gantt-draw-task></gantt-draw-task>' + '</div>')($scope) $scope.$digest() $timeout.flush() $scope.$destroy() } ) }) let checkLabels = function (data, ganttElement, contentNotSupported?) { let rowLabelsElements = jQuery(ganttElement).find('.gantt-row-label').not('.gantt-row-label-header').find('.gantt-label-text') expect(rowLabelsElements.length).to.be.eq(data.length) angular.forEach(rowLabelsElements, function (rowLabelElement, i) { rowLabelElement = jQuery(rowLabelElement) let rowModel = data[i] let rowText = rowLabelElement.text().trim() if (contentNotSupported || rowModel.content === undefined) { expect(rowText).to.be.eq(rowModel.name) } else { let rowHtmlModel = rowModel.content rowHtmlModel = rowHtmlModel.replace('{{row.model.name}}', rowModel.name) let expectedRowText = rowHtmlModel.replace(/<(?:.|\n)*?>/gm, '').trim() // Strip HTML expect(rowText).to.be.eq(expectedRowText) } if (rowModel.classes) { let rowClasses = rowModel.classes if (!angular.isArray(rowClasses)) { rowClasses = [rowClasses] } angular.forEach(rowClasses, function (rowClass) { expect(rowLabelElement.parents().hasClass(rowClass)).to.be.ok }) } }) } describe('labels', function () { it('should display labels', function () { let $scope = $rootScope.$new() $scope.data = angular.copy(mockData) let ganttElement = $compile('<div gantt data="data"><gantt-labels></gantt-labels></div>')($scope) $scope.$digest() $timeout.flush() checkLabels($scope.data, ganttElement, true) } ) }) describe('table', function () { it('should display labels', function () { let $scope = $rootScope.$new() $scope.data = angular.copy(mockData) let ganttElement = $compile('<div gantt data="data"><gantt-table></gantt-table></div>')($scope) $scope.$digest() $timeout.flush() checkLabels($scope.data, ganttElement) } ) }) describe('tree', function () { it('should display labels', function () { let $scope = $rootScope.$new() $scope.data = angular.copy(mockData) let ganttElement = $compile('<div gantt data="data"><gantt-tree></gantt-tree></div>')($scope) $scope.$digest() $timeout.flush() // Set the data in tree view ordering let orderedData = $scope.data.slice() let indices = {} angular.forEach($scope.data, function (rowModel, i) { if (rowModel.name) { indices[rowModel.name] = i } }) /*jshint sub:true */ let configRow = orderedData[indices['Config']] let setupRow = orderedData[indices['Setup']] let serverRow = orderedData[indices['Server']] orderedData[indices['Setup']] = serverRow orderedData[indices['Config']] = setupRow orderedData[indices['Server']] = configRow /*jshint sub:false */ checkLabels(orderedData, ganttElement) } ) it('should contain nodes that can expand and collapse', function () { let $scope = $rootScope.$new() $scope.data = angular.copy(mockData) let ganttApi let ready = false $scope.api = function (api) { ganttApi = api ganttApi.core.on.ready($scope, function () { ready = true }) } let ganttElement = $compile('<div gantt api="api" data="data">' + '<gantt-tree></gantt-tree>' + '</div>')($scope) $scope.$digest() $timeout.flush() expect(ganttApi).to.be.not.undefined expect(ready).to.be.ok expect(ganttApi.tree.isCollapsed(undefined)).to.be.undefined // All rows should be expanded on init angular.forEach(ganttApi.gantt.rowsManager.rows, function (row) { expect(ganttApi.tree.isCollapsed(row)).to.be.not.ok }) // Collapse all rows ganttApi.tree.collapseAll() $scope.$digest() // Development row should be collapsed expect(ganttApi.tree.isCollapsed('development')).to.be.ok // All rows should be collapsed angular.forEach(ganttApi.gantt.rowsManager.rows, function (row) { expect(ganttApi.tree.isCollapsed(row)).to.be.ok }) // Expand all rows ganttApi.tree.expandAll() $scope.$digest() // All rows should be expanded angular.forEach(ganttApi.gantt.rowsManager.rows, function (row) { expect(ganttApi.tree.isCollapsed(row)).to.be.not.ok }) // GanttTreeNodeController let treeNodeElement = jQuery(ganttElement).find('[ng-controller="GanttTreeNodeController"]').first() let ganttTreeNodeController = angular.element(treeNodeElement[0]).scope() // First row name should be "Milestones" expect(ganttTreeNodeController.getValue()).to.be.eq('Milestones') // Collapsing should be disabled - no child rows expect(ganttTreeNodeController.isCollapseDisabled()).to.be.ok // Should get row content correctly. If undefined and if defined expect(ganttTreeNodeController.getRowContent()).to.be.eq('{{row.model.name}}') // Test row let testRow = ganttApi.gantt.rowsManager.rows[0] // Test undefined collapsed testRow._collapsed = undefined expect(ganttApi.tree.isCollapsed(testRow)).to.be.not.ok // Set custom content testRow.model.content = '> {{row.model.name}}' expect(ganttTreeNodeController.getRowContent()).to.be.eq('> {{row.model.name}}') // GanttTreeController let treeElement = jQuery(ganttElement).find('[ng-controller="GanttTreeController"]') let ganttTreeController = angular.element(treeElement).scope() // Get default header expect(ganttTreeController.getHeader()).to.be.eq('Name') // Get default header content expect(ganttTreeController.getHeaderContent()).to.be.eq('{{getHeader()}}') } ) } ) })