From e7c663877896f386dc1ebb92599ffd2e2acf1560 Mon Sep 17 00:00:00 2001 From: Will Abson Date: Thu, 10 Nov 2016 13:57:00 +0000 Subject: [PATCH] New tests for tasklist component Refs #1025 --- .../src/assets/activiti-apps.mock.ts | 51 +++++ .../src/assets/task-details.component.mock.ts | 20 ++ .../activiti-apps.component.spec.ts | 166 +++++++++++++++ .../src/components/activiti-apps.component.ts | 18 +- .../activiti-comments.component.html | 12 +- .../activiti-comments.component.spec.ts | 191 ++++++++++++++++++ .../components/activiti-comments.component.ts | 47 +++-- .../activiti-task-header.component.html | 15 +- .../activiti-task-header.component.spec.ts | 108 ++++++++++ .../activiti-task-header.component.ts | 6 +- .../no-task-detail-template.component.spec.ts | 38 ++++ .../ng2-activiti-tasklist/src/i18n/en.json | 16 +- 12 files changed, 646 insertions(+), 42 deletions(-) create mode 100644 ng2-components/ng2-activiti-tasklist/src/assets/activiti-apps.mock.ts create mode 100644 ng2-components/ng2-activiti-tasklist/src/assets/task-details.component.mock.ts create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.spec.ts create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.spec.ts create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts diff --git a/ng2-components/ng2-activiti-tasklist/src/assets/activiti-apps.mock.ts b/ng2-components/ng2-activiti-tasklist/src/assets/activiti-apps.mock.ts new file mode 100644 index 0000000000..99da6cd062 --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/assets/activiti-apps.mock.ts @@ -0,0 +1,51 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AppDefinitionRepresentationModel } from '../models/filter.model'; + +export var deployedApps = [new AppDefinitionRepresentationModel({ + id: '1', + name: 'App1', + icon: 'icon1', + deploymentId: '1' +}), new AppDefinitionRepresentationModel({ + id: '2', + name: 'App2', + icon: 'icon2', + deploymentId: '2' +}), new AppDefinitionRepresentationModel({ + id: '3', + name: 'App3', + icon: 'icon3', + deploymentId: '3' +})]; +export var nonDeployedApps = [new AppDefinitionRepresentationModel({ + id: '1', + name: '1', + icon: 'icon1' +}), new AppDefinitionRepresentationModel({ + id: '1', + name: '2', + icon: 'icon2' +}), new AppDefinitionRepresentationModel({ + id: '1', + name: '3', + icon: 'icon3' +})]; +export var defaultApp = [new AppDefinitionRepresentationModel({ + defaultAppId: 'tasks' +})]; diff --git a/ng2-components/ng2-activiti-tasklist/src/assets/task-details.component.mock.ts b/ng2-components/ng2-activiti-tasklist/src/assets/task-details.component.mock.ts new file mode 100644 index 0000000000..cb96238dcf --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/assets/task-details.component.mock.ts @@ -0,0 +1,20 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export var mockTaskDetailsComponent = { + noTaskDetailsTemplateComponent: null +}; diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.spec.ts new file mode 100644 index 0000000000..a7649b665a --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.spec.ts @@ -0,0 +1,166 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DebugElement } from '@angular/core'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { Observable } from 'rxjs/Rx'; + +import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; + +import { ActivitiApps } from './activiti-apps.component'; +import { ActivitiTaskListService } from './../services/activiti-tasklist.service'; +import { TranslationMock } from './../assets/translation.service.mock'; +import { defaultApp, deployedApps, nonDeployedApps } from './../assets/activiti-apps.mock'; + +describe('ActivitiApps', () => { + + let componentHandler: any; + let component: ActivitiApps; + let fixture: ComponentFixture; + let debugElement: DebugElement; + let service: ActivitiTaskListService; + let getAppsSpy: jasmine.Spy; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule + ], + declarations: [ + ActivitiApps + ], + providers: [ + { provide: AlfrescoTranslationService, useClass: TranslationMock }, + ActivitiTaskListService + ] + }).compileComponents(); + })); + + beforeEach(() => { + + fixture = TestBed.createComponent(ActivitiApps); + component = fixture.componentInstance; + debugElement = fixture.debugElement; + service = fixture.debugElement.injector.get(ActivitiTaskListService); + + getAppsSpy = spyOn(service, 'getDeployedApplications').and.returnValue(Observable.of()); + + componentHandler = jasmine.createSpyObj('componentHandler', [ + 'upgradeAllRegistered', + 'upgradeElement' + ]); + window['componentHandler'] = componentHandler; + }); + + it('should load apps on init', () => { + fixture.detectChanges(); + expect(getAppsSpy).toHaveBeenCalled(); + }); + + it('should emit an error when an error occurs loading apps', () => { + let emitSpy = spyOn(component.error, 'emit'); + getAppsSpy.and.returnValue(Observable.throw({})); + fixture.detectChanges(); + expect(emitSpy).toHaveBeenCalled(); + }); + + describe('layout', () => { + + it('should display a grid by default', () => { + fixture.detectChanges(); + expect(component.isGrid()).toBe(true); + expect(component.isList()).toBe(false); + }); + + it('should display a grid when configured to', () => { + component.layoutType = ActivitiApps.LAYOUT_GRID; + fixture.detectChanges(); + expect(component.isGrid()).toBe(true); + expect(component.isList()).toBe(false); + }); + + it('should display a list when configured to', () => { + component.layoutType = ActivitiApps.LAYOUT_LIST; + fixture.detectChanges(); + expect(component.isGrid()).toBe(false); + expect(component.isList()).toBe(true); + }); + + it('should throw an exception on init if unknown type configured', () => { + component.layoutType = 'unknown'; + expect(component.ngOnInit).toThrowError(); + }); + }); + + describe('display apps', () => { + + it('should display all deployed apps', () => { + getAppsSpy.and.returnValue(Observable.of(deployedApps)); + fixture.detectChanges(); + expect(debugElement.queryAll(By.css('h1')).length).toBe(3); + }); + + it('should not display undeployed apps', () => { + getAppsSpy.and.returnValue(Observable.of(nonDeployedApps)); + fixture.detectChanges(); + expect(debugElement.queryAll(By.css('h1')).length).toBe(0); + }); + + it('should display default app', () => { + getAppsSpy.and.returnValue(Observable.of(defaultApp)); + fixture.detectChanges(); + expect(debugElement.queryAll(By.css('h1')).length).toBe(1); + }); + + }); + + describe('select apps', () => { + + beforeEach(() => { + getAppsSpy.and.returnValue(Observable.of(deployedApps)); + fixture.detectChanges(); + }); + + it('should initially have no app selected', () => { + let selectedEls = debugElement.queryAll(By.css('.selectedIcon')); + expect(selectedEls.length).toBe(0); + }); + + it('should emit a click event when app selected', () => { + spyOn(component.appClick, 'emit'); + component.selectApp(deployedApps[1]); + expect(component.appClick.emit).toHaveBeenCalledWith(deployedApps[1]); + }); + + it('should have one app shown as selected after app selected', () => { + component.selectApp(deployedApps[1]); + fixture.detectChanges(); + let selectedEls = debugElement.queryAll(By.css('.selectedIcon')); + expect(selectedEls.length).toBe(1); + }); + + it('should have the correct app shown as selected after app selected', () => { + component.selectApp(deployedApps[1]); + fixture.detectChanges(); + let appEls = debugElement.queryAll(By.css('.mdl-grid > div')); + expect(appEls[1].query(By.css('.selectedIcon'))).not.toBeNull(); + }); + + }); + +}); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.ts index 44e44cdf3f..a0db97ca53 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-apps.component.ts @@ -16,7 +16,7 @@ */ import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core'; -import { AlfrescoTranslationService, AlfrescoAuthenticationService } from 'ng2-alfresco-core'; +import { AlfrescoTranslationService } from 'ng2-alfresco-core'; import { ActivitiTaskListService } from './../services/activiti-tasklist.service'; import { AppDefinitionRepresentationModel } from '../models/filter.model'; import { IconModel } from '../models/icon.model'; @@ -48,6 +48,9 @@ export class ActivitiApps implements OnInit { @Output() appClick: EventEmitter = new EventEmitter(); + @Output() + error: EventEmitter = new EventEmitter(); + private appsObserver: Observer; apps$: Observable; @@ -59,11 +62,10 @@ export class ActivitiApps implements OnInit { /** * Constructor - * @param auth - * @param translate + * @param translate Translate service + * @param activitiTaskList Task service */ - constructor(private auth: AlfrescoAuthenticationService, - private translate: AlfrescoTranslationService, + constructor(private translate: AlfrescoTranslationService, private activitiTaskList: ActivitiTaskListService) { if (translate) { @@ -85,8 +87,8 @@ export class ActivitiApps implements OnInit { this.load(); } - public load(name?: string) { - this.activitiTaskList.getDeployedApplications(name).subscribe( + private load() { + this.activitiTaskList.getDeployedApplications().subscribe( (res) => { res.forEach((app: AppDefinitionRepresentationModel) => { if (app.defaultAppId === ActivitiApps.DEFAULT_TASKS_APP) { @@ -100,7 +102,7 @@ export class ActivitiApps implements OnInit { }); }, (err) => { - console.log(err); + this.error.emit(err); } ); } diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.html b/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.html index 26d71179d4..3194483e2a 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.html +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.html @@ -2,7 +2,7 @@ [attr.data-badge]="comments?.length">{{ 'TASK_DETAILS.LABELS.COMMENTS' |translate }}
add
- Add a comment + {{ 'TASK_DETAILS.COMMENTS.ADD' | translate }}
-
+
{{ 'TASK_DETAILS.COMMENTS.NONE' | translate }}
-

New comment

+

{{ 'TASK_DETAILS.COMMENTS.DIALOG.TITLE' | translate }}

- +
- - + +
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.spec.ts new file mode 100644 index 0000000000..0802e0d4fd --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.spec.ts @@ -0,0 +1,191 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SimpleChange } from '@angular/core'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { Observable } from 'rxjs/Rx'; + +import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; +import { ActivitiFormModule } from 'ng2-activiti-form'; + +import { ActivitiComments } from './activiti-comments.component'; +import { ActivitiTaskListService } from './../services/activiti-tasklist.service'; +import { TranslationMock } from './../assets/translation.service.mock'; + +describe('ActivitiTaskDetails', () => { + + let componentHandler: any; + let service: ActivitiTaskListService; + let component: ActivitiComments; + let fixture: ComponentFixture; + let getCommentsSpy: jasmine.Spy; + let addCommentSpy: jasmine.Spy; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule, + ActivitiFormModule + ], + declarations: [ + ActivitiComments + ], + providers: [ + { provide: AlfrescoTranslationService, useClass: TranslationMock }, + ActivitiTaskListService + ] + }).compileComponents(); + })); + + beforeEach(() => { + + fixture = TestBed.createComponent(ActivitiComments); + component = fixture.componentInstance; + service = fixture.debugElement.injector.get(ActivitiTaskListService); + + getCommentsSpy = spyOn(service, 'getTaskComments').and.returnValue(Observable.of([{ + message: 'Test1' + }, { + message: 'Test2' + }, { + message: 'Test3' + }])); + addCommentSpy = spyOn(service, 'addTaskComment').and.returnValue(Observable.of({id: 123, message: 'Test'})); + + componentHandler = jasmine.createSpyObj('componentHandler', [ + 'upgradeAllRegistered', + 'upgradeElement' + ]); + window['componentHandler'] = componentHandler; + }); + + it('should load comments when taskId specified', () => { + component.taskId = '123'; + fixture.detectChanges(); + expect(getCommentsSpy).toHaveBeenCalled(); + }); + + it('should emit an error when an error occurs loading comments', () => { + let emitSpy = spyOn(component.error, 'emit'); + getCommentsSpy.and.returnValue(Observable.throw({})); + component.taskId = '123'; + fixture.detectChanges(); + expect(emitSpy).toHaveBeenCalled(); + }); + + it('should not comments when no taskId is specified', () => { + fixture.detectChanges(); + expect(getCommentsSpy).not.toHaveBeenCalled(); + }); + + it('should display comments when the task has comments', async(() => { + component.taskId = '123'; + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.debugElement.queryAll(By.css('ul.mdl-list li')).length).toBe(3); + }); + })); + + it('should not display comments when the task has no comments', async(() => { + component.taskId = '123'; + getCommentsSpy.and.returnValue(Observable.of([])); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.debugElement.queryAll(By.css('ul.mdl-list li')).length).toBe(0); + }); + })); + + describe('change detection', () => { + + let change = new SimpleChange('123', '456'); + let nullChange = new SimpleChange('123', null); + + beforeEach(async(() => { + component.taskId = '123'; + fixture.detectChanges(); + fixture.whenStable().then(() => { + getCommentsSpy.calls.reset(); + }); + })); + + it('should fetch new comments when taskId changed', () => { + component.ngOnChanges({ 'taskId': change }); + expect(getCommentsSpy).toHaveBeenCalledWith('456'); + }); + + it('should NOT fetch new comments when empty changeset made', () => { + component.ngOnChanges({}); + expect(getCommentsSpy).not.toHaveBeenCalled(); + }); + + it('should NOT fetch new comments when taskId changed to null', () => { + component.ngOnChanges({ 'taskId': nullChange }); + expect(getCommentsSpy).not.toHaveBeenCalled(); + }); + + it('should set a placeholder message when taskId changed to null', () => { + component.ngOnChanges({ 'taskId': nullChange }); + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('[data-automation-id="comments-none"]'))).not.toBeNull(); + }); + }); + + describe('Add comment', () => { + + beforeEach(async(() => { + component.taskId = '123'; + fixture.detectChanges(); + fixture.whenStable(); + })); + + it('should display a dialog to the user when the Add button clicked', () => { + let dialogEl = fixture.debugElement.query(By.css('.mdl-dialog')).nativeElement; + let showSpy: jasmine.Spy = spyOn(dialogEl, 'showModal'); + component.showDialog(); + expect(showSpy).toHaveBeenCalled(); + }); + + it('should call service to add a comment', () => { + component.showDialog(); + component.message = 'Test comment'; + component.add(); + expect(addCommentSpy).toHaveBeenCalledWith('123', 'Test comment'); + }); + + it('should emit an error when an error occurs adding the comment', () => { + let emitSpy = spyOn(component.error, 'emit'); + addCommentSpy.and.returnValue(Observable.throw({})); + component.showDialog(); + component.message = 'Test comment'; + component.add(); + expect(emitSpy).toHaveBeenCalled(); + }); + + it('should close add dialog when close button clicked', () => { + let dialogEl = fixture.debugElement.query(By.css('.mdl-dialog')).nativeElement; + let closeSpy: jasmine.Spy = spyOn(dialogEl, 'close'); + component.showDialog(); + component.cancel(); + expect(closeSpy).toHaveBeenCalled(); + }); + + }); + +}); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.ts index 10f5a7b1a4..767cdb00ec 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-comments.component.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { Component, Input, OnInit, ViewChild, OnChanges, SimpleChanges } from '@angular/core'; -import { AlfrescoTranslationService, AlfrescoAuthenticationService } from 'ng2-alfresco-core'; +import { Component, Input, Output, OnInit, ViewChild, OnChanges, SimpleChanges, EventEmitter } from '@angular/core'; +import { AlfrescoTranslationService } from 'ng2-alfresco-core'; import { ActivitiTaskListService } from './../services/activiti-tasklist.service'; import { Comment } from '../models/comment.model'; import { Observer, Observable } from 'rxjs/Rx'; @@ -36,6 +36,9 @@ export class ActivitiComments implements OnInit, OnChanges { @Input() readOnly: boolean = false; + @Output() + error: EventEmitter = new EventEmitter(); + @ViewChild('dialog') dialog: any; @@ -48,11 +51,10 @@ export class ActivitiComments implements OnInit, OnChanges { /** * Constructor - * @param auth - * @param translate + * @param translate Translation service + * @param activitiTaskList Task service */ - constructor(private auth: AlfrescoAuthenticationService, - private translate: AlfrescoTranslationService, + constructor(private translate: AlfrescoTranslationService, private activitiTaskList: ActivitiTaskListService) { if (translate) { @@ -60,25 +62,28 @@ export class ActivitiComments implements OnInit, OnChanges { } this.comment$ = new Observable(observer => this.commentObserver = observer).share(); - } ngOnInit() { this.comment$.subscribe((comment: Comment) => { this.comments.push(comment); }); + this.getTaskComments(this.taskId); } ngOnChanges(changes: SimpleChanges) { let taskId = changes['taskId']; - if (taskId && taskId.currentValue) { - this.getTaskComments(taskId.currentValue); - return; + if (taskId) { + if (taskId.currentValue) { + this.getTaskComments(taskId.currentValue); + } else { + this.resetComments(); + } } } - public getTaskComments(taskId: string) { - this.comments = []; + private getTaskComments(taskId: string) { + this.resetComments(); if (taskId) { this.activitiTaskList.getTaskComments(taskId).subscribe( (res: Comment[]) => { @@ -87,21 +92,23 @@ export class ActivitiComments implements OnInit, OnChanges { }); }, (err) => { - console.log(err); + this.error.emit(err); } ); } else { - this.comments = []; + this.resetComments(); } } + private resetComments() { + this.comments = []; + } + public showDialog() { - if (this.dialog) { - if (!this.dialog.nativeElement.showModal) { - dialogPolyfill.registerDialog(this.dialog.nativeElement); - } - this.dialog.nativeElement.showModal(); + if (!this.dialog.nativeElement.showModal) { + dialogPolyfill.registerDialog(this.dialog.nativeElement); } + this.dialog.nativeElement.showModal(); } public add() { @@ -111,7 +118,7 @@ export class ActivitiComments implements OnInit, OnChanges { this.message = ''; }, (err) => { - console.log(err); + this.error.emit(err); } ); this.cancel(); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html index cb971824a8..9cb0f62abd 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html @@ -1,16 +1,19 @@
-
+
{{ 'TASK_DETAILS.LABELS.ASSIGNEE' | translate }}: - {{taskDetails.assignee.lastName }} + {{ taskDetails.assignee.firstName }} {{ taskDetails.assignee.lastName }} + {{ 'TASK_DETAILS.ASSIGNEE.NONE' | translate }}
-
+
{{ 'TASK_DETAILS.LABELS.DUE' | translate }}: - {{taskDetails?.dueDate ? taskDetails.dueDate : ('TASK_DETAILS.DUE.NONE' |translate) }} + {{ taskDetails.dueDate }} + {{ 'TASK_DETAILS.DUE.NONE' |translate }}
-
+
{{ 'TASK_DETAILS.LABELS.FORM' | translate }}: - {{formName}} + {{ formName }} + {{ 'TASK_DETAILS.FORM.NONE' | translate }}
diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts new file mode 100644 index 0000000000..ebb1263b7e --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts @@ -0,0 +1,108 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; + +import { ActivitiTaskHeader } from './activiti-task-header.component'; +import { TranslationMock } from './../assets/translation.service.mock'; +import { taskDetailsMock } from './../assets/task-details.mock'; +import { TaskDetailsModel } from '../models/task-details.model'; + +describe('ActivitiTaskHeader', () => { + + let componentHandler: any; + let component: ActivitiTaskHeader; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule + ], + declarations: [ + ActivitiTaskHeader + ], + providers: [ + { provide: AlfrescoTranslationService, useClass: TranslationMock } + ] + }).compileComponents(); + })); + + beforeEach(() => { + + fixture = TestBed.createComponent(ActivitiTaskHeader); + component = fixture.componentInstance; + + component.taskDetails = new TaskDetailsModel(taskDetailsMock); + + componentHandler = jasmine.createSpyObj('componentHandler', [ + 'upgradeAllRegistered', + 'upgradeElement' + ]); + window['componentHandler'] = componentHandler; + }); + + it('should render empty component if no form details provided', () => { + component.taskDetails = undefined; + fixture.detectChanges(); + expect(fixture.debugElement.children.length).toBe(0); + }); + + it('should display assignee', () => { + fixture.detectChanges(); + let formNameEl = fixture.debugElement.query(By.css('[data-automation-id="header-assignee"] .activiti-task-header__value')); + expect(formNameEl.nativeElement.innerText).toBe('Wilbur Adams'); + }); + + it('should display placeholder if no assignee', () => { + component.taskDetails.assignee = null; + fixture.detectChanges(); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-assignee"] .activiti-task-header__value')); + expect(valueEl.nativeElement.innerText).toBe('TASK_DETAILS.ASSIGNEE.NONE'); + }); + + it('should display due date', () => { + component.taskDetails.dueDate = '2016-11-03T15:25:42.749+0000'; + fixture.detectChanges(); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-due-date"] .activiti-task-header__value')); + expect(valueEl.nativeElement.innerText).toBe('2016-11-03T15:25:42.749+0000'); + }); + + it('should display placeholder if no due date', () => { + component.taskDetails.dueDate = null; + fixture.detectChanges(); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-due-date"] .activiti-task-header__value')); + expect(valueEl.nativeElement.innerText).toBe('TASK_DETAILS.DUE.NONE'); + }); + + it('should display form name', () => { + component.formName = 'test form'; + fixture.detectChanges(); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-form-name"] .activiti-task-header__value')); + expect(valueEl.nativeElement.innerText).toBe('test form'); + }); + + it('should not display form name if no form name provided', () => { + fixture.detectChanges(); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-form-name"] .activiti-task-header__value')); + expect(valueEl).toBeNull(); + }); + +}); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts index 9d0d1a0ce0..a94f244aa1 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts @@ -28,7 +28,7 @@ import { TaskDetailsModel } from '../models/task-details.model'; export class ActivitiTaskHeader { @Input() - formName: string = 'No form'; + formName: string = null; @Input() taskDetails: TaskDetailsModel; @@ -38,4 +38,8 @@ export class ActivitiTaskHeader { translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src'); } } + + public hasAssignee(): boolean { + return (this.taskDetails && this.taskDetails.assignee) ? true : false; + } } diff --git a/ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts new file mode 100644 index 0000000000..5bf34e0165 --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts @@ -0,0 +1,38 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NoTaskDetailsTemplateComponent } from './no-task-detail-template.component'; +import { ActivitiTaskDetails } from './activiti-task-details.component'; + +describe('NoTaskDetailsTemplateComponent', () => { + + let component: NoTaskDetailsTemplateComponent; + let detailsComponent: ActivitiTaskDetails; + + beforeEach(() => { + detailsComponent = new ActivitiTaskDetails(null, null, null, null); + component = new NoTaskDetailsTemplateComponent(detailsComponent); + }); + + it('should set "no task details" template on task details component', () => { + let testTemplate = 'blah blah'; + component.template = testTemplate; + component.ngAfterContentInit(); + expect(detailsComponent.noTaskDetailsTemplateComponent).toBe(testTemplate); + }); + +}); diff --git a/ng2-components/ng2-activiti-tasklist/src/i18n/en.json b/ng2-components/ng2-activiti-tasklist/src/i18n/en.json index 96642c6c57..2b662dfe4d 100644 --- a/ng2-components/ng2-activiti-tasklist/src/i18n/en.json +++ b/ng2-components/ng2-activiti-tasklist/src/i18n/en.json @@ -25,11 +25,25 @@ "DUE": { "NONE": "No due date." }, + "ASSIGNEE": { + "NONE": "No assignee." + }, "PEOPLE": { "NONE": "No people involved." }, "COMMENTS": { - "NONE": "No comments." + "NONE": "No comments.", + "ADD": "Add a comment", + "DIALOG": { + "TITLE": "New comment", + "LABELS": { + "MESSAGE": "Message" + }, + "BUTTON": { + "ADD": "Add Comment", + "CANCEL": "Cancel" + } + } }, "CHECKLIST": { "NONE": "No checklist."