More TS unit tests

This commit is contained in:
Matthew Ross 2018-03-22 15:04:58 -04:00
parent c39ff51238
commit 705fe0e407
11 changed files with 433 additions and 880 deletions

View File

@ -156,11 +156,11 @@ Because I like seeing the numbers.
Language | Files | Blank | Comment | Code
-------------|--------:|---------:|--------:|---------:
TypeScript | 64 | 880 | 88 | 4029
TypeScript | 64 | 884 | 88 | 4053
PHP | 19 | 624 | 27 | 1997
HTML | 19 | 150 | 1 | 1419
SASS | 14 | 269 | 12 | 1215
__SUM:__ | __114__ | __1923__ | __128__ | __8660__
__SUM:__ | __116__ | __1927__ | __128__ | __8684__
Command: `cloc --exclude-dir=vendor --exclude-ext=json src/`
@ -168,9 +168,9 @@ Command: `cloc --exclude-dir=vendor --exclude-ext=json src/`
Language | Files | Blank | Comment | Code
-------------|-------:|---------:|--------:|---------:
TypeScript | 5 | 37 | 0 | 207
TypeScript | 8 | 152 | 0 | 581
PHP | 11 | 742 | 16 | 2205
__SUM:__ | __16__ | __779__ | __16__ | __2412__
__SUM:__ | __19__ | __894__ | __16__ | __2786__
Command: `cloc --exclude-ext=xml test/`

View File

@ -45,9 +45,8 @@ export class BoardDisplay implements OnInit, OnDestroy, AfterContentInit {
constructor(public title: Title,
private router: Router,
private active: ActivatedRoute,
private auth: AuthService,
private boardService: BoardService,
public auth: AuthService,
public boardService: BoardService,
private menuService: ContextMenuService,
private notes: NotificationsService,
private stringsService: StringsService,

View File

@ -1,6 +1,6 @@
<h3 [class.near-limit]="columnData.hasTaskLimit() &&
<h3 [class.near-limit]="columnData && columnData.hasTaskLimit() &&
columnData.task_limit - columnData.tasks.length === 0"
[class.limit-reached]="columnData.hasTaskLimit() &&
[class.limit-reached]="columnData && columnData.hasTaskLimit() &&
columnData.task_limit - columnData.tasks.length < 0">
<span class="icon icon-minus-squared-alt"
[title]="strings['boards_collapseAllTasks']"
@ -11,14 +11,14 @@
*ngIf="collapseTasks"
(click)="toggleTaskCollapse()"></span>
{{ columnData.name }}
{{ columnData ? columnData.name : '' }}
<span class="count" *ngIf="columnData.hasTaskLimit()">
<span class="count" *ngIf="columnData && columnData.hasTaskLimit()">
{{ columnData.tasks.length + ' / ' + columnData.task_limit }}
</span>
<span class="badge" [title]="strings['boards_tasksInColumn']">
{{ columnData.tasks && columnData.tasks.length || 0 }}
{{ columnData && columnData.tasks && columnData.tasks.length || 0 }}
</span>
<span class="icon icon-angle-double-up"
@ -27,7 +27,7 @@
[title]="strings['boards_collapseColumn']" (click)="toggleCollapsed()"></span>
<span class="count-editor"
*ngIf="activeUser.isAnyAdmin()">
*ngIf="activeUser && activeUser.isAnyAdmin()">
<i class="icon icon-hashtag"
[title]="strings['boards_editTaskLimit']"
(click)="beginLimitEdit()"></i>
@ -72,7 +72,7 @@
</button>
</div>
<div class="tasks"
<div class="tasks" *ngIf="columnData"
[dragula]="'tasks-bag'" [dragulaModel]="columnData.tasks">
<tb-task class="task-container" [id]="task.id"
*ngFor="let task of columnData.tasks"
@ -88,9 +88,9 @@
<tb-context-menu [menu-items]="contextMenuItems"></tb-context-menu>
<tb-modal *ngIf="activeBoard"
<tb-modal *ngIf="activeBoard && columnData"
modal-title="{{ strings['boards_viewTask'] }} - {{ viewModalProps.title }}"
modal-id="{{ MODAL_VIEW_ID + columnData.id }}"
modal-id="{{ MODAL_VIEW_ID + (columnData ? columnData.id : '') }}"
wide="true"
class="view-modal">
<div *ngIf="viewModalProps.points">
@ -138,7 +138,7 @@
<div class="quick-actions">
<button class="flat"
(click)="this.modal.close(MODAL_VIEW_ID + columnData.id);
(click)="this.modal.close(MODAL_VIEW_ID + (columnData ? columnData.id : ''));
showModal(viewModalProps.id)">
{{ strings['boards_editTask'] }}
</button>
@ -197,7 +197,7 @@
[title]="strings['boards_taskRemoveComment']"
(click)="commentToRemove=comment;
modal.open(MODAL_CONFIRM_COMMENT_ID +
columnData.id)"></i>
(columnData ? columnData.id : ''))"></i>
</div>
</div>
</div>
@ -237,11 +237,11 @@
</div>
</tb-modal>
<tb-modal *ngIf="activeBoard"
<tb-modal *ngIf="activeBoard && columnData"
modal-title="{{ modalProps.id === 0
? strings['boards_addTask']
: strings['boards_editTask'] }}"
modal-id="{{ MODAL_ID + columnData.id }}">
modal-id="{{ MODAL_ID + (columnData ? columnData.id : '') }}">
<label>
{{ strings['boards_taskTitle'] }}
<input #focusMe type="text" name="title"
@ -312,32 +312,32 @@
<i class="icon icon-floppy"></i>
{{ strings['boards_saveTask'] }}
</button>
<button class="flat" (click)="modal.close(MODAL_ID + columnData.id)">
<button class="flat" (click)="modal.close(MODAL_ID + (columnData ? columnData.id : ''))">
{{ strings['cancel'] }}
</button>
</div>
</tb-modal>
<tb-modal modal-title="{{ strings['boards_confirmRemoveTask'] }}" blocking="true"
modal-id="{{ MODAL_CONFIRM_ID + columnData.id }}">
modal-id="{{ MODAL_CONFIRM_ID + (columnData ? columnData.id : '') }}">
<div class="center">
{{ strings['boards_confirmWarning'] }}<br>
{{ strings['boards_confirmContinue'] }}
</div>
<div class="buttons">
<button class="flat"
(click)="modal.close(MODAL_CONFIRM_ID + columnData.id);removeTask()">
(click)="modal.close(MODAL_CONFIRM_ID + (columnData ? columnData.id : ''));removeTask()">
{{ strings['yes'] }}
</button>
<button #defaultAction #focusMe
(click)="modal.close(MODAL_CONFIRM_ID + columnData.id)">
(click)="modal.close(MODAL_CONFIRM_ID + (columnData ? columnData.id : ''))">
{{ strings['no'] }}
</button>
</div>
</tb-modal>
<tb-modal modal-title="{{ strings['boards_confirmRemoveComment'] }}" blocking="true"
modal-id="{{ MODAL_CONFIRM_COMMENT_ID + columnData.id }}">
modal-id="{{ MODAL_CONFIRM_COMMENT_ID + (columnData ? columnData.id : '') }}">
<div class="center">
{{ strings['boards_confirmWarningComment'] }}<br>
{{ strings['boards_confirmContinue'] }}
@ -345,11 +345,11 @@
<div class="buttons">
<button class="flat"
(click)="modal.close(MODAL_CONFIRM_COMMENT_ID
+ columnData.id);removeComment()">
+ (columnData ? columnData.id : ''));removeComment()">
{{ strings['yes'] }}
</button>
<button #defaultAction #focusMe
(click)="modal.close(MODAL_CONFIRM_COMMENT_ID + columnData.id)">
(click)="modal.close(MODAL_CONFIRM_COMMENT_ID + (columnData ? columnData.id : ''))">
{{ strings['no'] }}
</button>
</div>

View File

@ -4,6 +4,7 @@ import {
EventEmitter,
Input,
OnInit,
OnDestroy,
Output
} from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@ -36,14 +37,12 @@ import { BoardService } from '../board.service';
selector: 'tb-column',
templateUrl: './column.component.html'
})
export class ColumnDisplay implements OnInit {
private templateElement: any;
export class ColumnDisplay implements OnInit, OnDestroy {
private saving: boolean;
private showLimitEditor: boolean;
private isOverdue: boolean;
private isNearlyDue: boolean;
private userOptions: UserOptions;
private tasks: Array<Task>;
private MODAL_ID: string;
@ -60,7 +59,10 @@ export class ColumnDisplay implements OnInit {
private newComment: string;
private fileUpload: any;
private subs = [];
public templateElement: any;
public userOptions: UserOptions;
public strings: any;
public collapseTasks: boolean;
public activeUser: User;
@ -98,7 +100,7 @@ export class ColumnDisplay implements OnInit {
this.modalProps = new Task();
this.viewModalProps = new Task();
stringsService.stringsChanged.subscribe(newStrings => {
let sub = stringsService.stringsChanged.subscribe(newStrings => {
this.strings = newStrings;
this.contextMenuItems = [
@ -106,12 +108,18 @@ export class ColumnDisplay implements OnInit {
this.getShowModalFunction())
];
});
this.subs.push(sub);
boardService.activeBoardChanged.subscribe((board: Board) => {
sub = boardService.activeBoardChanged.subscribe((board: Board) => {
this.activeBoard = board;
});
this.subs.push(sub);
sub = auth.userChanged.subscribe((user: User) => {
if (user === null) {
return;
}
auth.userChanged.subscribe((user: User) => {
this.activeUser = new User(+user.default_board_id,
user.email,
+user.id,
@ -124,15 +132,20 @@ export class ColumnDisplay implements OnInit {
this.userOptions = auth.userOptions;
this.showActivity = this.activeUser.isAnyAdmin();
});
this.subs.push(sub);
}
ngOnInit() {
this.templateElement.classList.remove('double');
if (this.userOptions.multiple_tasks_per_row) {
if (this.userOptions && this.userOptions.multiple_tasks_per_row) {
this.templateElement.classList.add('double');
}
if (this.activeUser === undefined) {
return;
}
let isCollapsed = false;
this.activeUser.collapsed.forEach(id => {
@ -149,6 +162,10 @@ export class ColumnDisplay implements OnInit {
this.taskLimit = this.columnData.task_limit;
}
ngOnDestroy() {
this.subs.forEach(sub => (sub.unsubscribe()));
}
sortTasks() {
switch (this.sortOption) {
case 'pos':

View File

@ -1,124 +0,0 @@
/* global expect RxJs TitleMock RouterMock ActivatedRouteMock AuthServiceMock BoardServiceMock StringsServiceMock */
var path = '../../../build/board/',
BoardDisplay = require(path + 'board.component.js').BoardDisplay;
describe('BoardDisplay', () => {
var board,
title,
router,
dragula = {
find: () => {},
setOptions: () => {},
dropModel: RxJs.Observable.of([
null, {id: 1},
{ parentNode: { id: 1} },
{ parentNode: { id: 1} }
])
};
beforeEach(() => {
title = new TitleMock();
router = new RouterMock();
board = new BoardDisplay(title, router, ActivatedRouteMock,
AuthServiceMock, BoardServiceMock,
null, null, StringsServiceMock, dragula);
});
it('sets the title when constructed', () => {
expect(title.getTitle()).to.equal('TaskBoard - Kanban App');
});
it('implements ngOnOnit', () => {
board.boardNavId = '0';
board.ngOnInit();
expect(board.boardNavId).to.equal('0');
board.boardNavId = null;
board.ngOnInit();
expect(board.boardNavId).to.equal(null);
board.activeUser = { default_board_id: '2' };
board.ngOnInit();
expect(board.boardNavId).to.equal('2');
expect(router.path).to.equal('/boards/2');
});
it('implements ngAfterContentInit', () => {
board.activeBoard = { columns: [{ id: 1, tasks: [{ id: 0 }] }] };
board.ngAfterContentInit();
});
it('has a function to check for boards', () => {
expect(board.noBoards()).to.equal(false);
board.loading = false;
board.boards = [];
expect(board.noBoards()).to.equal(true);
});
it('has a function to navigate to a board', () => {
board.boardNavId = null;
board.goToBoard();
board.boardNavId = 1;
board.goToBoard();
expect(router.path).to.equal('/boards/1');
});
it('has a function to toggle display of filtered tasks', () => {
board.hideFiltered = true;
board.activeBoard = {
columns: [{ tasks: [{ id: 1 }] }]
};
board.toggleFiltered();
expect(board.activeBoard.columns[0].tasks[0].hideFiltered)
.to.equal(true);
});
it('has a function to filter tasks', () => {
board.activeBoard = {
columns: [
{ tasks: [{ id: 1, assignees: [], categories: [] }] }
]
};
board.userFilter = -1;
board.categoryFilter = -1;
board.filterTasks();
expect(board.activeBoard.columns[0].tasks[0].filtered)
.to.equal(false);
board.userFilter = 1;
board.categoryFilter = 1;
board.activeBoard.columns[0].tasks[0].assignees = [{ id: 1 }];
board.activeBoard.columns[0].tasks[0].categories = [{ id: 1 }];
board.filterTasks();
expect(board.activeBoard.columns[0].tasks[0].filtered)
.to.equal(false);
board.activeBoard.columns[0].tasks[0].assignees = [{ id: 2 }];
board.activeBoard.columns[0].tasks[0].categories = [{ id: 2 }];
board.filterTasks();
expect(board.activeBoard.columns[0].tasks[0].filtered)
.to.equal(true);
});
it('has a function to update the active board', () => {
board.boardNavId = 1;
board.boards = [{ id: 1, name: 'test' }];
board.updateActiveBoard();
expect(board.pageName).to.equal('test');
});
});

View File

@ -1,4 +1,4 @@
import { async, TestBed, ComponentFixture } from '@angular/core/testing'
import { TestBed, ComponentFixture } from '@angular/core/testing'
import { RouterTestingModule } from '@angular/router/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { FormsModule } from '@angular/forms';
@ -26,60 +26,13 @@ import { BoardDisplay } from '../../../src/app/board/board.component';
import { BoardService } from '../../../src/app/board/board.service';
import { ColumnDisplay } from '../../../src/app/board/column/column.component';
import { TaskDisplay } from '../../../src/app/board/task/task.component';
class RouterMock {
public url = {
indexOf: str => TestBed.get(Location).path().indexOf(str)
}
navigate(arr) {
TestBed.get(Location).go(arr[0]);
}
}
class DragulaMock {
public opts;
public dropModel = new BehaviorSubject([
{},
{ id: '1' },
{ parentNode: { id: '1' } },
{ parentNode: { id: '1' } }
]);
find () {
return {};
}
destroy () {}
setOptions (name, opts) {
this.opts = opts;
}
}
class BoardServiceMock {
public activeBoardChanged = new BehaviorSubject({ id: 0, name: 'Test', columns: [] });
getBoards () {
return new BehaviorSubject({
data: [{}, [{ id: 1, name: 'Test' }]]
});
}
updateActiveBoard (board) {
this.activeBoardChanged.next(board);
}
updateColumn (col) {
return new BehaviorSubject({});
}
}
import { RouterMock, BoardServiceMock, DragulaMock } from '../mocks';
describe('BoardDisplay', () => {
let component: BoardDisplay,
fixture: ComponentFixture<BoardDisplay>;
beforeEach(async(() => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
@ -115,13 +68,13 @@ describe('BoardDisplay', () => {
}
]
}).compileComponents();
}));
});
beforeEach(() => {
fixture = TestBed.createComponent(BoardDisplay);
component = fixture.componentInstance;
fixture.detectChanges();
})
});
it('sets the title when constructed', () => {
expect(component.title.getTitle()).toEqual('TaskBoard - Test');
@ -219,6 +172,9 @@ describe('BoardDisplay', () => {
it('has a function to check for boards', () => {
expect(component.noBoards).toEqual(jasmine.any(Function));
component.loading = true;
expect(component.noBoards()).toEqual(false);
component.loading = false;
component.boards = [];
@ -228,10 +184,18 @@ describe('BoardDisplay', () => {
expect(component.noBoards()).toEqual(false);
})
it('updates the boards list from a service', () => {
component.boards = <any>[];
it('updates the active board from a service', () => {
component.boardService.updateActiveBoard(null);
component.boardService.updateActiveBoard(<any>{});
expect(component.activeBoard).toEqual(jasmine.any(Object));
});
it('updates the active user from a service', () => {
component.auth.updateUser(<any>{ security_level: 1 });
expect(component.activeUser).toEqual(jasmine.any(Object));
})
});

View File

@ -0,0 +1,220 @@
import { TestBed, getTestBed } from '@angular/core/testing';
import {
HttpClientTestingModule,
HttpTestingController
} from '@angular/common/http/testing';
import { BoardService } from '../../../src/app/board/board.service';
describe('BoardService', () => {
let injector: TestBed;
let service: BoardService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [BoardService]
});
injector = getTestBed();
service = injector.get(BoardService);
httpMock = injector.get(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
})
it('should be created', () => {
expect(service).toBeTruthy();
});
it('lets the active board get updated', () => {
let changed = false;
service.activeBoardChanged.subscribe(() => (changed = true));
service.updateActiveBoard(<any>{});
expect(changed).toEqual(true);
});
it('gets all boards', () => {
service.getBoards().subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/boards', 'GET');
});
it('handles errors when getting all boards', () => {
service.getBoards().subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/boards', 'GET', true);
});
it('toggles the collapsed state of a column', () => {
service.toggleCollapsed(1, 1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/users/1/cols', 'POST');
});
it('handles error when toggling collapse', () => {
service.toggleCollapsed(1, 1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/users/1/cols', 'POST', true);
});
it('updates a board', () => {
service.updateBoard(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/boards/1', 'POST');
});
it('handles errors on board update', () => {
service.updateBoard(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/boards/1', 'POST', true);
});
it('updates a column', () => {
service.updateColumn(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/columns/1', 'POST');
});
it('handles errors on column update', () => {
service.updateColumn(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/columns/1', 'POST', true);
});
it('adds a task', () => {
service.addTask(<any>{}).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/tasks', 'POST');
});
it('handles errors on task add', () => {
service.addTask(<any>{}).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/tasks', 'POST', true);
});
it('updates a task', () => {
service.updateTask(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/tasks/1', 'POST');
});
it('handles errors on task update', () => {
service.updateTask(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/tasks/1', 'POST', true);
});
it('removes a task', () => {
service.removeTask(1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/tasks/1', 'DELETE');
});
it('handles errors on task removal', () => {
service.removeTask(1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/tasks/1', 'DELETE', true);
});
it('gets task activity', () => {
service.getTaskActivity(1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/activity/task/1', 'GET');
});
it('handles errors on get task activity', () => {
service.getTaskActivity(1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/activity/task/1', 'GET', true);
});
it('updates a comment', () => {
service.updateComment(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/comments/1', 'POST');
});
it('handles errors on comment update', () => {
service.updateComment(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/comments/1', 'POST', true);
});
it('removes a comment', () => {
service.removeComment(1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/comments/1', 'DELETE');
});
it('handles errors on comment removal', () => {
service.removeComment(1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/comments/1', 'DELETE', true);
});
it('refreshes the API token', () => {
service.refreshToken();
testCall('api/refresh', 'POST');
});
const testCall = (url, method, isError = false) => {
const req = httpMock.expectOne(url);
expect(req.request.method).toEqual(method);
if (isError) {
req.flush({ alerts: [{}] }, { status: 500, statusText: '' });
} else {
req.flush({ data: [] });
}
}
});

View File

@ -1,172 +0,0 @@
/* global expect ElementRefMock AuthServiceMock NotificationsServiceMock StringsServiceMock BoardServiceMock ModalServiceMock */
var path = '../../../../build/board/column/',
ColumnDisplay = require(path + 'column.component.js').ColumnDisplay;
describe('ColumnDisplay', () => {
var column,
modalService;
beforeEach(() => {
modalService = new ModalServiceMock();
column = new ColumnDisplay(ElementRefMock, AuthServiceMock,
new NotificationsServiceMock(),
modalService, StringsServiceMock,
BoardServiceMock);
});
it('implements ngOnInit', () => {
column.columnData = { task_limit: 3, id: 1, tasks: [] };
column.activeUser = { collapsed: [1] };
column.userOptions = { multiple_tasks_per_row: true };
column.ngOnInit();
expect(column.taskLimit).to.equal(3);
});
it('has a function to sort tasks', () => {
column.columnData = {
tasks: [{
position: 1,
due_date: '1/1/2017',
points: 5
}, {
position: 2,
due_date: '1/1/2016',
points: 8
}, {
position: 3,
due_date: '1/1/2018',
points: 13
}]
};
column.sortOption = 'pos';
column.sortTasks();
expect(column.columnData.tasks[0].position).to.equal(1);
column.sortOption = 'due';
column.sortTasks();
expect(column.columnData.tasks[0].due_date).to.equal('1/1/2016');
column.sortOption = 'pnt';
column.sortTasks();
expect(column.columnData.tasks[0].points).to.equal(13);
});
it('has a function to toggle collapsed state', () => {
column.activeUser = { id: 1 };
column.columnData = { id: 1 };
column.toggleCollapsed();
expect(column.activeUser.collapsed[0]).to.equal(1);
});
it('has a function to toggle task collapsed state', () => {
column.collapseTasks = false;
column.toggleTaskCollapse();
expect(column.collapseTasks).to.equal(true);
});
it('has a function to update task color by category', () => {
column.modalProps = {};
column.updateTaskColorByCategory([{ default_task_color: 'test' }]);
expect(column.modalProps.color).to.equal('test');
});
it('has a function to validate a task', () => {
var test = column.validateTask({ title: '' });
expect(test).to.equal(false);
test = column.validateTask({ title: 'test' });
expect(test).to.equal(true);
});
it('has a functions to add, update, and remove a task', () => {
column.columnData = { id: 1 };
column.modalProps = { title: 'test' };
column.addTask();
column.updateTask();
column.removeTask();
});
it('has a function to load a column task limit editor', () => {
column.columnData = { task_limit: 3 };
column.beginLimitEdit();
expect(column.taskLimit).to.equal(3);
expect(column.showLimitEditor).to.equal(true);
});
it('has a function to close the task limit editor', () => {
column.showLimitEditor = true;
column.cancelLimitChanges();
expect(column.showLimitEditor).to.equal(false);
});
it('has a function to save task limit changes', () => {
column.columnData = { task_limit: 1 };
column.taskLimit = 3;
column.saveLimitChanges();
expect(column.columnData.task_limit).to.equal(3);
expect(column.showLimitEditor).to.equal(false);
});
it('has a function to update boards for child components', done => {
column.onUpdateBoards = {
emit: () => { done(); }
};
column.callBoardUpdate();
});
it('has a function to get a remove task function', () => {
var func = column.getRemoveTaskFunction(1);
column.columnData = { id: 1 };
expect(func).to.be.a('function');
func();
expect(column.taskToRemove).to.equal(1);
});
it('has a function to get a show modal function', () => {
var func = column.getShowModalFunction();
column.columnData = { id: 1 };
expect(func).to.be.a('function');
func();
});
it('has a function to handle quick add', () => {
column.columnData = { id: 1 };
column.quickAddClicked({ stopPropagation: () => {} });
column.quickAdd = { title: 'test' };
column.quickAddClicked({ stopPropagation: () => {} });
});
it('has a function to show modals', () => {
column.columnData = {
tasks: [{
id: 1, title: 'test', description: '', color: 'red',
due_date: '', points: 3, position: 1, column_id: 1,
comments: [], attachments: [], assignees: [{ id: 1 }],
categories: [{ id: 1 }]
}]
};
column.activeBoard = { users: [{ id: 1 }], categories: [{ id: 1 }] };
column.showModal(1);
});
});

View File

@ -0,0 +1,92 @@
import { TestBed, ComponentFixture } from '@angular/core/testing'
import { RouterTestingModule } from '@angular/router/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ElementRef } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { DragulaService } from 'ng2-dragula/ng2-dragula';
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
import { ColumnDisplay } from '../../../../src/app/board/column/column.component';
import { TaskDisplay } from '../../../../src/app/board/task/task.component';
import {
AuthService,
StringsService,
Constants,
ContextMenuService,
ModalService,
NotificationsService
} from '../../../../src/app/shared/services';
import { BoardService } from '../../../../src/app/board/board.service';
import { SharedModule } from '../../../../src/app/shared/shared.module';
describe('ColumnDisplay', () => {
let component: ColumnDisplay,
fixture: ComponentFixture<ColumnDisplay>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
FormsModule,
RouterTestingModule,
DragulaModule,
SharedModule
],
declarations: [
ColumnDisplay,
TaskDisplay
],
providers: [
DragulaService,
AuthService,
NotificationsService,
ModalService,
StringsService,
BoardService
]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ColumnDisplay);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('can be constructed', () => {
expect(component).toBeTruthy();
});
it('implements OnInit', () => {
component.userOptions = <any>{ multiple_tasks_per_row: true };
component.columnData = <any>{ id: 1, task_limit: 3, tasks: [] };
component.activeUser = <any>{ collapsed: [1] };
component.ngOnInit();
expect(component.templateElement.classList.contains('collapsed')).toEqual(true);
});
it('sorts tasks', () => {
component.columnData = <any>{ tasks:[
{ position: 2, due_date: '1/1/2018', points: 1 },
{ position: 1, due_date: '1/1/2019', points: 3 }
] };
component.sortOption = 'pos';
component.sortTasks();
expect(component.columnData.tasks[0].position).toEqual(1);
component.sortOption = 'due';
component.sortTasks();
expect(component.columnData.tasks[0].due_date).toEqual('1/1/2018');
component.sortOption = 'pnt';
component.sortTasks();
expect(component.columnData.tasks[0].points).toEqual(3);
});
});

View File

@ -1,496 +0,0 @@
/* global RxJs */
var MockBrowser = require('mock-browser').mocks.MockBrowser,
mockBrowser = new MockBrowser(),
chai = require('chai'),
users = [
{
id: '1',
default_board_id: '0',
username: 'tester',
security_level: '2',
user_option_id: '0',
board_access: []
},
{
id: '2',
default_board_id: '0',
username: 'test',
security_level: '3',
user_option_id: '0',
board_access: []
}
],
boards = [
{
id: 1,
name: 'testing',
is_active: true,
columns: [{
id: 1,
name: 'Column 1',
position: 0,
board_id: 1,
tasks: []
}],
categories: [{
id: 1,
name: 'Category 1'
}],
issue_trackers: [],
users: [ users[1] ]
},
{
id: 2,
name: 'test',
is_active: false,
columns: [{
id: 2,
name: 'Column 1',
position: 0,
board_id: 2,
tasks: []
}],
categories: [],
issue_trackers: [],
users
}
],
actions = [
{
id: 1,
trigger: 1,
source_id: 1,
type: 1,
change_to: 'test',
board_id: 1
},
{
id: 2,
trigger: 2,
source_id: 2,
type: 2,
change_to: 'testing',
board_id: 2
}
];
global.window = mockBrowser.getWindow();
global.document = mockBrowser.getDocument();
global.navigator = mockBrowser.getNavigator();
global.localStorage = mockBrowser.getLocalStorage();
require('reflect-metadata');
global.window.Reflect = Reflect;
global.RxJs = require('rxjs/Rx');
global.expect = chai.expect;
global.ElementRefMock = {
nativeElement: {
parentElement: {
oncontextmenu: () => {}
},
classList: {
add: () => {},
remove: () => {},
toggle: () => {}
},
firstElementChild: {
style: {},
getBoundingClientRect: () => {
return {
width: 10,
height: 10
};
}
}
}
};
global.Chartist = {
Pie(id, data, opts) {
this.sum = function() { return 100; };
},
Line(id, data, opts) {
this.plugins = {
tooltip: () => {}
};
}
};
global.ConstantsMock = {
VERSION: 'TEST'
};
global.TitleMock = function() {
var title = '';
return {
getTitle: () => {
return title;
},
setTitle: text => {
title = text;
}
};
};
global.RouterMock = function() {
return {
path: 'test',
url: 'test',
navigate(arr) {
this.path = arr[0];
}
};
};
global.ActivatedRouteMock = {
params: RxJs.Observable.of({})
};
global.AuthServiceMock = {
userOptions: {
show_animations: false
},
userChanged: RxJs.Observable.of(users[0]),
updateUser: user => {
},
login: () => {
return RxJs.Observable.of({
alerts: [ 'Logged in' ],
status: 'success'
});
},
logout: () => {
return RxJs.Observable.of({
alerts: [ 'Logged out' ]
});
},
authenticate: () => {
return RxJs.Observable.of(true);
}
};
global.NotificationsServiceMock = function() {
var notes = new RxJs.Subject();
return {
noteAdded: notes.asObservable(),
add: note => {
notes.next(note);
}
};
};
global.ResponseMock = function(endpoint) {
return {
json: () => {
return {
alerts: [],
data: [ 'jwt', 'true', 'true' ],
status: 'success',
endpoint
};
}
};
};
global.ModalServiceMock = function() {
var closed = new RxJs.Subject(),
opened = new RxJs.Subject(),
register = new RxJs.Subject();
return {
closeCalled: closed.asObservable(),
openCalled: opened.asObservable(),
registerCalled: register.asObservable(),
open: id => {
opened.next(id);
},
close: () => {
closed.next(true);
},
registerModal: () => {
register.next(true);
}
};
};
global.ContextMenuServiceMock = function() {
var register = new RxJs.Subject(),
closeAll = new RxJs.Subject();
return {
registerCalled: register.asObservable(),
closeAllCalled: closeAll.asObservable(),
registerMenu: () => {
register.next(true);
},
closeAllMenus: () => {
closeAll.next(true);
}
};
};
global.StringsServiceMock = {
stringsChanged: {
subscribe(callback) {
callback({
settings: 'Settings'
});
}
},
loadStrings() {}
};
global.SettingsServiceMock = function() {
var userList = new RxJs.BehaviorSubject(users),
boardList = new RxJs.BehaviorSubject(boards),
actionList = new RxJs.BehaviorSubject(actions);
return {
usersChanged: userList.asObservable(),
boardsChanged: boardList.asObservable(),
actionsChanged: actionList.asObservable(),
updateUsers: users => {
userList.next(users);
},
getUsers: () => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [ null, users ]
});
},
updateBoards: boards => {
boardList.next(boards);
},
getBoards: () => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [ null, boards ]
});
},
updateActions: actions => {
actionList.next(actions);
},
getActions: () => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [ null, actions ]
});
}
};
};
global.UserAdminServiceMock = function() {
var userList = users.slice();
return {
addUser: user => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
userList.concat(user)
]
});
},
editUser: user => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
JSON.stringify(userList[1]),
userList
]
});
},
removeUser: userId => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
userList.slice(1)
]
});
}
};
};
global.BoardAdminServiceMock = function() {
return {
addBoard: board => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
boards.concat(board)
]
});
},
editBoard: board => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
boards
]
});
},
removeBoard: boardId => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
boards.slice(1)
]
});
}
};
};
global.AutoActionsServiceMock = function() {
return {
addAction: action => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
actions.concat(action)
]
});
},
removeAction: boardId => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: [
null,
actions.slice(1)
]
});
}
};
};
global.UserSettingsServiceMock = {
changeUserOptions: opts => {
return RxJs.Observable.of({
alerts: []
});
},
changeDefaultBoard: boardId => {
return RxJs.Observable.of({
alerts: [{ type: 'success', text: '' }],
data: [ '', '{}' ]
});
},
changeUsername: newName => {
return RxJs.Observable.of({
alerts: [{ type: 'success', text: '' }]
});
},
changePassword: newPass => {
return RxJs.Observable.of({
alerts: [{ type: 'success', text: '' }]
});
},
changeEmail: newEmail => {
return RxJs.Observable.of({
alerts: [{ type: 'success', text: '' }]
});
}
};
global.BoardServiceMock = {
getBoards: () => {
return RxJs.Observable.of({
data: [ '', [{
id: 1, name: 'test', is_active: '1',
ownColumn: [], ownCategory: [],
ownAutoAction: [], ownIssuetracker: [],
sharedUser: []
}] ]
});
},
updateColumn: () => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: ['', [{
id: 1, name: 'test', position: 1,
board_id: 1, task_limit: 3, ownTask: []
}]]
});
},
toggleCollapsed: () => {
return RxJs.Observable.of({ data: [ '', [1]] });
},
addTask: () => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: ['', '', [{ ownColumn: [{}] }] ]
});
},
updateTask: () => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: ['', '', [{}]]
});
},
removeTask: () => {
return RxJs.Observable.of({
status: 'success',
alerts: [],
data: ['', [{}]]
});
},
activeBoardChanged: RxJs.Observable.of({ name: 'Kanban App', columns: [] }),
updateActiveBoard: () => {},
refreshToken: () => {}
};
global.HttpMock = {
post: (url, data) => {
var response = new global.ResponseMock(url);
return RxJs.Observable.of(response);
},
get: url => {
var response = new global.ResponseMock(url);
return RxJs.Observable.of(response);
},
delete: url => {
var response = new global.ResponseMock(url);
return RxJs.Observable.of(response);
}
};
global.SanitizerMock = {
bypassSecurityTrustHtml: html => {
return html;
},
bypassSecurityTrustStyle: css => {
return css;
}
};

53
test/app/mocks.ts Normal file
View File

@ -0,0 +1,53 @@
import { TestBed } from '@angular/core/testing'
import { Location } from '@angular/common';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
export class RouterMock {
public url = {
indexOf: str => TestBed.get(Location).path().indexOf(str)
}
navigate(arr) {
TestBed.get(Location).go(arr[0]);
}
}
export class DragulaMock {
public opts;
public dropModel = new BehaviorSubject([
{},
{ id: '1' },
{ parentNode: { id: '1' } },
{ parentNode: { id: '1' } }
]);
find () {
return {};
}
destroy () {}
setOptions (name, opts) {
this.opts = opts;
}
}
export class BoardServiceMock {
public activeBoardChanged = new BehaviorSubject({ id: 0, name: 'Test', columns: [] });
getBoards () {
return new BehaviorSubject({
data: [{}, [{ id: 1, name: 'Test', is_active: '1' }]]
});
}
updateActiveBoard (board) {
this.activeBoardChanged.next(board);
}
updateColumn (col) {
return new BehaviorSubject({});
}
}