mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
parent
ea1953771b
commit
08ba048c89
@ -0,0 +1,192 @@
|
||||
/*!
|
||||
* @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 taskDetailsMock = {
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': {'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': null,
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'processDefinitionDescription': null,
|
||||
'processDefinitionKey': 'TranslationProcess',
|
||||
'processDefinitionCategory': 'http://www.activiti.org/processdef',
|
||||
'processDefinitionVersion': 2,
|
||||
'processDefinitionDeploymentId': '5',
|
||||
'formKey': '4',
|
||||
'processInstanceStartUserId': '1001',
|
||||
'initiatorCanCompleteTask': false,
|
||||
'adhocTaskCanBeReassigned': false,
|
||||
'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
|
||||
'executionId': '86',
|
||||
'involvedPeople': [],
|
||||
'memberOfCandidateUsers': false,
|
||||
'managerOfCandidateGroup': false,
|
||||
'memberOfCandidateGroup': false
|
||||
};
|
||||
|
||||
export var taskFormMock = {
|
||||
'id': 4,
|
||||
'name': 'Translation request',
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'processDefinitionKey': 'TranslationProcess',
|
||||
'taskId': '91',
|
||||
'taskName': 'Request translation',
|
||||
'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
|
||||
'tabs': [],
|
||||
'fields': [{
|
||||
'fieldType': 'ContainerRepresentation',
|
||||
'id': '1478093984155',
|
||||
'name': 'Label',
|
||||
'type': 'container',
|
||||
'value': null,
|
||||
'required': false,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': null,
|
||||
'options': null,
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'dateDisplayFormat': null,
|
||||
'layout': null,
|
||||
'sizeX': 2,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'numberOfColumns': 2,
|
||||
'fields': {
|
||||
'1': [{
|
||||
'fieldType': 'AttachFileFieldRepresentation',
|
||||
'id': 'originalcontent',
|
||||
'name': 'Original content',
|
||||
'type': 'upload',
|
||||
'value': [],
|
||||
'required': true,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': null,
|
||||
'options': null,
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'params': {
|
||||
},
|
||||
'dateDisplayFormat': null,
|
||||
'layout': {'row': -1, 'column': -1, 'colspan': 1},
|
||||
'sizeX': 1,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'metaDataColumnDefinitions': []
|
||||
}],
|
||||
'2': [{
|
||||
'fieldType': 'RestFieldRepresentation',
|
||||
'id': 'language',
|
||||
'name': 'Language',
|
||||
'type': 'dropdown',
|
||||
'value': 'Choose one...',
|
||||
'required': true,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': true,
|
||||
'options': [{'id': 'empty', 'name': 'Choose one...'}, {'id': 'fr', 'name': 'French'}, {
|
||||
'id': 'de',
|
||||
'name': 'German'
|
||||
}, {'id': 'es', 'name': 'Spanish'}],
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'params': {'existingColspan': 1, 'maxColspan': 1},
|
||||
'dateDisplayFormat': null,
|
||||
'layout': {'row': -1, 'column': -1, 'colspan': 1},
|
||||
'sizeX': 1,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'endpoint': null,
|
||||
'requestHeaders': null
|
||||
}]
|
||||
}
|
||||
}],
|
||||
'outcomes': [],
|
||||
'javascriptEvents': [],
|
||||
'className': '',
|
||||
'style': '',
|
||||
'customFieldTemplates': {},
|
||||
'metadata': {},
|
||||
'variables': [],
|
||||
'gridsterForm': false,
|
||||
'globalDateFormat': 'D-M-YYYY'
|
||||
};
|
||||
|
||||
export var tasksMock = {
|
||||
data: [
|
||||
taskDetailsMock
|
||||
]
|
||||
};
|
||||
|
||||
export var noDataMock = {
|
||||
data: []
|
||||
};
|
@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div *ngIf="taskDetails">
|
||||
<h2 class="mdl-card__title-text">{{taskDetails.name}}</h2>
|
||||
<activiti-task-header [taskDetails]="taskDetails" [formName]="taskFormName" #activitiheader></activiti-task-header>
|
||||
<activiti-task-header [taskDetails]="taskDetails" [formName]="taskFormName"></activiti-task-header>
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<activiti-people [people]="taskPeople" [readOnly]="readOnlyForm"
|
||||
@ -34,7 +34,7 @@
|
||||
(formCompleted)='onFormCompleted($event)'
|
||||
(formLoaded)='onFormLoaded($event)'
|
||||
(onError)='onFormError($event)'
|
||||
(executeOutcome)='onExecuteFormOutcome($event)'
|
||||
(executeOutcome)='onFormExecuteOutcome($event)'
|
||||
#activitiForm>
|
||||
</activiti-form>
|
||||
<button type="button" class="mdl-button" *ngIf="!hasFormKey() && isTaskActive()" (click)="onComplete()">
|
||||
|
@ -0,0 +1,249 @@
|
||||
/*!
|
||||
* @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 { NO_ERRORS_SCHEMA, 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, FormModel, FormOutcomeEvent, FormOutcomeModel, FormService } from 'ng2-activiti-form';
|
||||
|
||||
import { ActivitiTaskDetails } from './activiti-task-details.component';
|
||||
import { ActivitiTaskListService } from './../services/activiti-tasklist.service';
|
||||
import { ActivitiPeopleService } from './../services/activiti-people.service';
|
||||
import { TranslationMock } from './../assets/translation.service.mock';
|
||||
import { taskDetailsMock, taskFormMock, tasksMock, noDataMock } from './../assets/task-details.mock';
|
||||
|
||||
describe('ActivitiTaskDetails', () => {
|
||||
|
||||
let componentHandler: any;
|
||||
let service: ActivitiTaskListService;
|
||||
let formService: FormService;
|
||||
let component: ActivitiTaskDetails;
|
||||
let fixture: ComponentFixture<ActivitiTaskDetails>;
|
||||
let getTaskDetailsSpy: jasmine.Spy;
|
||||
let getFormSpy: jasmine.Spy;
|
||||
let getTasksSpy: jasmine.Spy;
|
||||
let completeTaskSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule,
|
||||
ActivitiFormModule
|
||||
],
|
||||
declarations: [
|
||||
ActivitiTaskDetails
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
|
||||
ActivitiTaskListService,
|
||||
ActivitiPeopleService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ActivitiTaskDetails);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ActivitiTaskListService);
|
||||
formService = fixture.debugElement.injector.get(FormService);
|
||||
|
||||
getTaskDetailsSpy = spyOn(service, 'getTaskDetails').and.returnValue(Observable.of(taskDetailsMock));
|
||||
getFormSpy = spyOn(formService, 'getTaskForm').and.returnValue(Observable.of(taskFormMock));
|
||||
getTasksSpy = spyOn(service, 'getTasks').and.returnValue(Observable.of(tasksMock));
|
||||
completeTaskSpy = spyOn(service, 'completeTask').and.returnValue(Observable.of({}));
|
||||
spyOn(service, 'getTaskComments').and.returnValue(Observable.of(noDataMock));
|
||||
spyOn(service, 'getTaskChecklist').and.returnValue(Observable.of(noDataMock));
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should load task details when taskId specified', () => {
|
||||
component.taskId = '123';
|
||||
fixture.detectChanges();
|
||||
expect(getTaskDetailsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not load task details when no taskId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getTaskDetailsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set a placeholder message when taskId not initialised', () => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerText).toBe('TASK_DETAILS.MESSAGES.NONE');
|
||||
});
|
||||
|
||||
it('should display a form when the task has an associated form', async(() => {
|
||||
component.taskId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('activiti-form'))).not.toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not display a form when the task does not have an associated form', async((done) => {
|
||||
component.taskId = '123';
|
||||
taskDetailsMock.formKey = undefined;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('activiti-form'))).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
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(() => {
|
||||
getTaskDetailsSpy.calls.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fetch new task details when taskId changed', () => {
|
||||
component.ngOnChanges({ 'taskId': change });
|
||||
expect(getTaskDetailsSpy).toHaveBeenCalledWith('456');
|
||||
});
|
||||
|
||||
it('should NOT fetch new task details when empty changeset made', () => {
|
||||
component.ngOnChanges({});
|
||||
expect(getTaskDetailsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT fetch new task details when taskId changed to null', () => {
|
||||
component.ngOnChanges({ 'taskId': nullChange });
|
||||
expect(getTaskDetailsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set a placeholder message when taskId changed to null', () => {
|
||||
component.ngOnChanges({ 'taskId': nullChange });
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerText).toBe('TASK_DETAILS.MESSAGES.NONE');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form events', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.taskId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable();
|
||||
}));
|
||||
|
||||
it('should emit a save event when form saved', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.formSaved, 'emit');
|
||||
component.onFormSaved(new FormModel());
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit a outcome execution event when form outcome executed', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.executeOutcome, 'emit');
|
||||
component.onFormExecuteOutcome(new FormOutcomeEvent(new FormOutcomeModel(new FormModel())));
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit a complete event when form completed', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.formCompleted, 'emit');
|
||||
component.onFormCompleted(new FormModel());
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load next task when form completed', () => {
|
||||
component.onComplete();
|
||||
expect(getTasksSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should show placeholder message if there is no next task', () => {
|
||||
getTasksSpy.and.returnValue(Observable.of(noDataMock));
|
||||
component.onComplete();
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerText).toBe('TASK_DETAILS.MESSAGES.NONE');
|
||||
});
|
||||
|
||||
it('should emit an error event if an error occurs fetching the next task', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.onError, 'emit');
|
||||
getTasksSpy.and.returnValue(Observable.throw({}));
|
||||
component.onComplete();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT load next task when form completed if showNextTask is false', () => {
|
||||
component.showNextTask = false;
|
||||
component.onComplete();
|
||||
expect(getTasksSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call service to complete task when complete button clicked', () => {
|
||||
component.onComplete();
|
||||
expect(completeTaskSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit a complete event when complete button clicked and task completed', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.formCompleted, 'emit');
|
||||
component.onComplete();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call service to load next task when complete button clicked', () => {
|
||||
component.onComplete();
|
||||
expect(getTasksSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit a load event when form loaded', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.formLoaded, 'emit');
|
||||
component.onFormLoaded(new FormModel());
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit an error event when form error occurs', () => {
|
||||
let emitSpy: jasmine.Spy = spyOn(component.onError, 'emit');
|
||||
component.onFormError({});
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display a dialog to the user when a form error occurs', () => {
|
||||
let dialogEl = fixture.debugElement.query(By.css('.error-dialog')).nativeElement;
|
||||
let showSpy: jasmine.Spy = spyOn(dialogEl, 'showModal');
|
||||
component.onFormError({});
|
||||
expect(showSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close error dialog when close button clicked', () => {
|
||||
let dialogEl = fixture.debugElement.query(By.css('.error-dialog')).nativeElement;
|
||||
let closeSpy: jasmine.Spy = spyOn(dialogEl, 'close');
|
||||
component.onFormError({});
|
||||
component.closeErrorDialog();
|
||||
expect(closeSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -85,8 +85,10 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param auth Authentication service
|
||||
* @param translate Translation service
|
||||
* @param activitiForm Form service
|
||||
* @param activitiTaskList Task service
|
||||
*/
|
||||
constructor(private auth: AlfrescoAuthenticationService,
|
||||
private translate: AlfrescoTranslationService,
|
||||
@ -117,9 +119,9 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the task detail to undefined
|
||||
* Reset the task details
|
||||
*/
|
||||
reset() {
|
||||
private reset() {
|
||||
this.taskDetails = null;
|
||||
}
|
||||
|
||||
@ -141,7 +143,7 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
|
||||
* Load the activiti task details
|
||||
* @param taskId
|
||||
*/
|
||||
loadDetails(taskId: string) {
|
||||
private loadDetails(taskId: string) {
|
||||
this.taskPeople = [];
|
||||
this.taskFormName = null;
|
||||
if (taskId) {
|
||||
@ -157,10 +159,7 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
|
||||
this.taskPeople.push(new User(user));
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.reset();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +168,7 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
|
||||
* @param processInstanceId
|
||||
* @param processDefinitionId
|
||||
*/
|
||||
loadNextTask(processInstanceId: string, processDefinitionId: string) {
|
||||
private loadNextTask(processInstanceId: string, processDefinitionId: string) {
|
||||
let requestNode = new TaskQueryRequestRepresentationModel(
|
||||
{
|
||||
processInstanceId: processInstanceId,
|
||||
@ -190,11 +189,11 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the activiti task
|
||||
* Complete button clicked
|
||||
*/
|
||||
onComplete() {
|
||||
this.activitiTaskList.completeTask(this.taskId).subscribe(
|
||||
(res) => this.formCompleted.emit(null)
|
||||
(res) => this.onFormCompleted(null)
|
||||
);
|
||||
}
|
||||
|
||||
@ -222,7 +221,7 @@ export class ActivitiTaskDetails implements OnInit, OnChanges {
|
||||
this.onError.emit(error);
|
||||
}
|
||||
|
||||
onExecuteFormOutcome(event: FormOutcomeEvent) {
|
||||
onFormExecuteOutcome(event: FormOutcomeEvent) {
|
||||
this.executeOutcome.emit(event);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user