diff --git a/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts b/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts new file mode 100644 index 0000000000..57cbb1ed40 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts @@ -0,0 +1,320 @@ +/*! + * @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 { it, describe, expect, beforeEach } from '@angular/core/testing'; +import { Http, RequestOptionsArgs, Response, ResponseOptions } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; +import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core'; + +import { FormService } from './form.service'; +import { FormValues } from './../components/widgets/core/index'; + +describe('FormService', () => { + + let http: Http; + let responseBody: any; + let formService: FormService; + let authService: AlfrescoAuthenticationService; + let settingsService: AlfrescoSettingsService; + + let createResponse = (url, body): Observable => { + return Observable.create(observer => { + let response = new Response(new ResponseOptions({ + url: url, + body: body + })); + observer.next(response); + observer.complete(); + }); + }; + + beforeEach(() => { + + http = { + get(url: string, options?: RequestOptionsArgs): Observable { + return createResponse(url, responseBody); + }, + post(url: string, body: any, options?: RequestOptionsArgs): Observable { + return createResponse(url, responseBody); + } + }; + + settingsService = new AlfrescoSettingsService(); + settingsService.setProviders([]); + + authService = new AlfrescoAuthenticationService(settingsService, null); + formService = new FormService(http, authService, settingsService); + }); + + it('should resolve host address via settings service', () => { + const url = ''; + settingsService.bpmHost = url; + expect(formService.getHostAddress()).toBe(url); + }); + + it('should fetch and parse process definitions', (done) => { + spyOn(http, 'get').and.callThrough(); + + responseBody = { + data: [ + { id: '1' }, + { id: '2' } + ] + }; + + formService.getProcessDefinitions().subscribe(result => { + expect(http.get).toHaveBeenCalled(); + + let args: any[] = (http).get.calls.argsFor(0); + expect(args[0].endsWith('/process-definitions')).toBeTruthy(); + + expect(result).toEqual(responseBody.data); + done(); + }); + }); + + it('should fetch and parse tasks', (done) => { + spyOn(http, 'post').and.callThrough(); + + responseBody = { + data: [ + { id: '1' }, + { id: '2' } + ] + }; + + formService.getTasks().subscribe(result => { + expect(http.post).toHaveBeenCalled(); + + let args: any[] = (http).post.calls.argsFor(0); + expect(args[0].endsWith('/tasks/query')).toBeTruthy(); + + expect(result).toEqual(responseBody.data); + done(); + }); + }); + + it('should fetch and parse the task by id', (done) => { + spyOn(http, 'get').and.callThrough(); + + responseBody = { + id: '1' + }; + + formService.getTask('1').subscribe(result => { + expect(http.get).toHaveBeenCalled(); + + let args: any[] = (http).get.calls.argsFor(0); + expect(args[0].endsWith('/tasks/1')).toBeTruthy(); + + expect(result).toEqual(responseBody); + done(); + }); + }); + + it('should save task form', (done) => { + spyOn(http, 'post').and.callThrough(); + + let values = { + field1: 'one', + field2: 'two' + }; + + formService.saveTaskForm('1', values).subscribe(() => { + expect(http.post).toHaveBeenCalled(); + + let args: any[] = (http).post.calls.argsFor(0); + expect(args[0].endsWith('/task-forms/1/save-form')).toBeTruthy(); + expect(args[1]).toEqual(JSON.stringify({ values: values })); + + done(); + }); + }); + + it('should complete task form', (done) => { + spyOn(http, 'post').and.callThrough(); + + let values = { + field1: 'one', + field2: 'two' + }; + + formService.completeTaskForm('1', values).subscribe(() => { + expect(http.post).toHaveBeenCalled(); + + let args: any[] = (http).post.calls.argsFor(0); + expect(args[0].endsWith('/task-forms/1')).toBeTruthy(); + expect(args[1]).toEqual(JSON.stringify({ values: values })); + + done(); + }); + }); + + it('should complete task form with a specific outcome', (done) => { + spyOn(http, 'post').and.callThrough(); + + let values = { + field1: 'one', + field2: 'two' + }; + + formService.completeTaskForm('1', values, 'custom').subscribe(() => { + expect(http.post).toHaveBeenCalled(); + + let args: any[] = (http).post.calls.argsFor(0); + expect(args[0].endsWith('/task-forms/1')).toBeTruthy(); + expect(args[1]).toEqual(JSON.stringify({ values: values, outcome: 'custom' })); + + done(); + }); + }); + + it('should get task form by id', (done) => { + spyOn(http, 'get').and.callThrough(); + + responseBody = { id: '1' }; + + formService.getTaskForm('1').subscribe(result => { + expect(http.get).toHaveBeenCalled(); + + let args: any[] = (http).get.calls.argsFor(0); + expect(args[0].endsWith('/task-forms/1')).toBeTruthy(); + + expect(result).toEqual(responseBody); + done(); + }); + }); + + it('should get form definition by id', (done) => { + spyOn(http, 'get').and.callThrough(); + + responseBody = { id: '1' }; + + formService.getFormDefinitionById('1').subscribe(result => { + expect(http.get).toHaveBeenCalled(); + + let args: any[] = (http).get.calls.argsFor(0); + expect(args[0].endsWith('/form-models/1')).toBeTruthy(); + + expect(result).toEqual(responseBody); + done(); + }); + }); + + it('should get form definition id by name', (done) => { + spyOn(http, 'get').and.callThrough(); + + const formName = 'form1'; + const formId = 1; + responseBody = { + data: [ + { id: formId } + ] + }; + + formService.getFormDefinitionByName(formName).subscribe(result => { + expect(http.get).toHaveBeenCalled(); + + let args: any[] = (http).get.calls.argsFor(0); + expect(args[0].endsWith(`models?filter=myReusableForms&filterText=${formName}&modelType=2`)).toBeTruthy(); + + expect(result).toEqual(formId); + done(); + }); + }); + + it('should not get form id from response', () => { + let response = new Response(new ResponseOptions({ body: null })); + expect(formService.getFormId(response)).toBeNull(); + + response = new Response(new ResponseOptions({ body: {} })); + expect(formService.getFormId(response)).toBeNull(); + + response = new Response(new ResponseOptions({ body: { data: null } })); + expect(formService.getFormId(response)).toBeNull(); + + response = new Response(new ResponseOptions({ body: { data: [] } })); + expect(formService.getFormId(response)).toBeNull(); + + expect(formService.getFormId(null)).toBeNull(); + }); + + it('should convert response to json object', () => { + let data = { id: 1 }; + let response = new Response(new ResponseOptions({ body: data })); + expect(formService.toJson(response)).toEqual(data); + }); + + it('should fallback to empty json object', () => { + let response = new Response(new ResponseOptions({ body: null })); + expect(formService.toJson(response)).toEqual({}); + + expect(formService.toJson(null)).toEqual({}); + }); + + it('should convert response to json array', () => { + let payload = { + data: [ + { id: 1 } + ] + }; + + let response = new Response(new ResponseOptions({ body: JSON.stringify(payload) })); + expect(formService.toJsonArray(response)).toEqual(payload.data); + }); + + it('should fallback to empty json array', () => { + expect(formService.toJsonArray(null)).toEqual([]); + + let response = new Response(new ResponseOptions({ body: {} })); + expect(formService.toJsonArray(response)).toEqual([]); + + response = new Response(new ResponseOptions({ body: { data: null } })); + expect(formService.toJsonArray(response)).toEqual([]); + }); + + it('should handle error with generic message', () => { + spyOn(console, 'error').and.stub(); + + formService.handleError(null); + expect(console.error).toHaveBeenCalledWith(FormService.UNKNOWN_ERROR_MESSAGE); + }); + + it('should handle error with error message', () => { + spyOn(console, 'error').and.stub(); + + const message = ''; + formService.handleError({ message: message }); + + expect(console.error).toHaveBeenCalledWith(message); + }); + + it('should handle error with detailed message', () => { + spyOn(console, 'error').and.stub(); + formService.handleError({ + status: '400', + statusText: 'Bad request' + }); + expect(console.error).toHaveBeenCalledWith('400 - Bad request'); + }); + + it('should handle error with generic message', () => { + spyOn(console, 'error').and.stub(); + formService.handleError({}); + expect(console.error).toHaveBeenCalledWith(FormService.GENERIC_ERROR_MESSAGE); + }); +}); diff --git a/ng2-components/ng2-activiti-form/src/services/form.service.ts b/ng2-components/ng2-activiti-form/src/services/form.service.ts index 305caa4b3b..dc8092ece2 100644 --- a/ng2-components/ng2-activiti-form/src/services/form.service.ts +++ b/ng2-components/ng2-activiti-form/src/services/form.service.ts @@ -25,13 +25,20 @@ import { AlfrescoSettingsService } from 'ng2-alfresco-core'; @Injectable() export class FormService { + static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error'; + static GENERIC_ERROR_MESSAGE: string = 'Server error'; + constructor(private http: Http, private authService: AlfrescoAuthenticationService, private alfrescoSettingsService: AlfrescoSettingsService) { } + getHostAddress(): string { + return this.alfrescoSettingsService.bpmHost; + } + getProcessDefinitions(): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}/activiti-app/api/enterprise/process-definitions`; + let url = `${this.getHostAddress()}/activiti-app/api/enterprise/process-definitions`; let options = this.getRequestOptions(); return this.http .get(url, options) @@ -40,7 +47,7 @@ export class FormService { } getTasks(): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}/activiti-app/api/enterprise/tasks/query`; + let url = `${this.getHostAddress()}/activiti-app/api/enterprise/tasks/query`; let body = JSON.stringify({}); let options = this.getRequestOptions(); @@ -51,7 +58,7 @@ export class FormService { } getTask(id: string): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}/activiti-app/api/enterprise/tasks/${id}`; + let url = `${this.getHostAddress()}/activiti-app/api/enterprise/tasks/${id}`; let options = this.getRequestOptions(); return this.http @@ -61,10 +68,8 @@ export class FormService { } saveTaskForm(id: string, formValues: FormValues): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}/activiti-app/api/enterprise/task-forms/${id}/save-form`; - let body = JSON.stringify({ - values: formValues - }); + let url = `${this.getHostAddress()}/activiti-app/api/enterprise/task-forms/${id}/save-form`; + let body = JSON.stringify({ values: formValues }); let options = this.getRequestOptions(); return this.http @@ -80,8 +85,8 @@ export class FormService { * @returns {any} */ completeTaskForm(id: string, formValues: FormValues, outcome?: string): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}/activiti-app/api/enterprise/task-forms/${id}`; - let data: any = {values: formValues}; + let url = `${this.getHostAddress()}/activiti-app/api/enterprise/task-forms/${id}`; + let data: any = { values: formValues }; if (outcome) { data.outcome = outcome; } @@ -94,7 +99,7 @@ export class FormService { } getTaskForm(id: string): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}/activiti-app/api/enterprise/task-forms/${id}`; + let url = `${this.getHostAddress()}/activiti-app/api/enterprise/task-forms/${id}`; let options = this.getRequestOptions(); return this.http @@ -104,7 +109,7 @@ export class FormService { } getFormDefinitionById(id: string): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}/activiti-app/app/rest/form-models/${id}`; + let url = `${this.getHostAddress()}/activiti-app/app/rest/form-models/${id}`; let options = this.getRequestOptions(); return this.http @@ -113,9 +118,13 @@ export class FormService { .catch(this.handleError); } + /** + * Returns form definition ID by a given name. + * @param name + * @returns {Promise|Promise} + */ getFormDefinitionByName(name: string): Observable { - let url = `${this.alfrescoSettingsService.bpmHost}` + - `/activiti-app/app/rest/models?filter=myReusableForms&filterText=${name}&modelType=2`; + let url = `${this.getHostAddress()}/activiti-app/app/rest/models?filter=myReusableForms&filterText=${name}&modelType=2`; let options = this.getRequestOptions(); return this.http @@ -137,27 +146,42 @@ export class FormService { return new RequestOptions({headers: headers}); } - private getFormId(res: Response) { - let body = res.json(); - return body.data[0].id || {}; + getFormId(res: Response) { + let result = null; + + if (res) { + let body = res.json(); + if (body && body.data && body.data.length > 0) { + result = body.data[0].id; + } + } + + return result; } - private toJson(res: Response) { - let body = res.json(); - return body || {}; + toJson(res: Response) { + if (res) { + let body = res.json(); + return body || {}; + } + return {}; } - private toJsonArray(res: Response) { - let body = res.json(); - return body.data || []; + toJsonArray(res: Response) { + if (res) { + let body = res.json(); + return body.data || []; + } + return []; } - private handleError(error: any) { - // In a real world app, we might use a remote logging infrastructure - // We'd also dig deeper into the error to get a better message - let errMsg = (error.message) ? error.message : - error.status ? `${error.status} - ${error.statusText}` : 'Server error'; - console.error(errMsg); // log to console instead + handleError(error: any): Observable { + let errMsg = FormService.UNKNOWN_ERROR_MESSAGE; + if (error) { + errMsg = (error.message) ? error.message : + error.status ? `${error.status} - ${error.statusText}` : FormService.GENERIC_ERROR_MESSAGE; + } + console.error(errMsg); return Observable.throw(errMsg); } diff --git a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts index 25cec2f692..cb66572d1a 100644 --- a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts +++ b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts @@ -35,13 +35,15 @@ export class AlfrescoAuthenticationService extends AlfrescoAuthenticationBase { /** * Constructor - * @param alfrescoSetting + * @param settingsService * @param http */ - constructor(alfrescoSetting: AlfrescoSettingsService, + constructor(settingsService: AlfrescoSettingsService, http: Http) { - super(alfrescoSetting, http); - this.createProviderInstance(alfrescoSetting.getProviders()); + super(settingsService, http); + if (settingsService) { + this.createProviderInstance(settingsService.getProviders()); + } } /**