diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dropdown/dropdown.widget.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dropdown/dropdown.widget.spec.ts new file mode 100644 index 0000000000..2fdaf83374 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dropdown/dropdown.widget.spec.ts @@ -0,0 +1,212 @@ +/*! + * @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 { DropdownWidget } from './dropdown.widget'; +import { FormModel } from './../core/form.model'; +import { FormFieldModel } from './../core/form-field.model'; + +describe('DropdownWidget', () => { + + let http: Http; + let widget: DropdownWidget; + + beforeEach(() => { + http = { + get(url: string, options?: RequestOptionsArgs): Observable { + return null; + } + }; + widget = new DropdownWidget(http); + }); + + it('should fetch and parse REST data on init', () => { + + let data = [ + { uid: '1', text: 'One' }, + { uid: '2', text: 'Two' } + ]; + + spyOn(http, 'get').and.callFake((url) => { + return Observable.create(observer => { + let options = new ResponseOptions({ + body: data, + url: url + }); + let response = new Response(options); + observer.next(response); + observer.complete(); + }); + }); + + let field = new FormFieldModel(new FormModel(), { + optionType: 'rest', + restUrl: 'http://
', + restIdProperty: 'uid', + restLabelProperty: 'text' + }); + + widget.field = field; + widget.ngOnInit(); + + + expect((http.get).calls.argsFor(0)).toEqual([field.restUrl]); + expect(field.options.length).toBe(2); + + expect(field.options[0].id).toBe(data[0].uid); + expect(field.options[0].name).toBe(data[0].text); + + expect(field.options[1].id).toBe(data[1].uid); + expect(field.options[1].name).toBe(data[1].text); + }); + + it('should require REST settings to fetch data', () => { + let form = new FormModel(); + spyOn(http, 'get').and.stub(); + + // 1) Null field + widget.field = null; + widget.ngOnInit(); + expect(http.get).not.toHaveBeenCalled(); + + // 2) Missing [optionType] + widget.field = new FormFieldModel(form, { + optionType: null, + restUrl: 'http://
', + restIdProperty: 'uid', + restLabelProperty: 'text' + }); + widget.ngOnInit(); + expect(http.get).not.toHaveBeenCalled(); + + // 3) Missing [restUrl] + widget.field = new FormFieldModel(form, { + optionType: 'rest', + restUrl: null, + restIdProperty: 'uid', + restLabelProperty: 'text' + }); + widget.ngOnInit(); + expect(http.get).not.toHaveBeenCalled(); + + // 4) Missing [restIdProperty] + widget.field = new FormFieldModel(form, { + optionType: 'rest', + restUrl: 'http://
', + restIdProperty: null, + restLabelProperty: 'text' + }); + widget.ngOnInit(); + expect(http.get).not.toHaveBeenCalled(); + + // 4) Missing [restLabelProperty] + widget.field = new FormFieldModel(form, { + optionType: 'rest', + restUrl: 'http://
', + restIdProperty: null, + restLabelProperty: null + }); + widget.ngOnInit(); + expect(http.get).not.toHaveBeenCalled(); + }); + + it('should parse only array response', () => { + expect(widget.loadFromJson([])).toBeFalsy(); + + widget.field = new FormFieldModel(new FormModel()); + expect(widget.loadFromJson([])).toBeTruthy(); + + expect(widget.loadFromJson(null)).toBeFalsy(); + expect(widget.loadFromJson({})).toBeFalsy(); + }); + + it('should bind to nested properties', () => { + let data = [ + { uid: { value: 1 }, name: { fullName: 'John Doe' } } + ]; + + spyOn(http, 'get').and.callFake((url) => { + return Observable.create(observer => { + let options = new ResponseOptions({ + body: data, + url: url + }); + let response = new Response(options); + observer.next(response); + observer.complete(); + }); + }); + + let field = new FormFieldModel(new FormModel(), { + optionType: 'rest', + restUrl: 'http://
', + restIdProperty: 'uid.value', + restLabelProperty: 'name.fullName' + }); + + widget.field = field; + widget.ngOnInit(); + + expect(field.options.length).toBe(1); + expect(field.options[0].id).toBe(data[0].uid.value.toString()); + expect(field.options[0].name).toBe(data[0].name.fullName); + }); + + it('should update form upon loading REST data', () => { + let field = new FormFieldModel(new FormModel()); + widget.field = field; + + spyOn(field, 'updateForm').and.stub(); + + expect(widget.loadFromJson([])).toBeTruthy(); + expect(field.updateForm).toHaveBeenCalled(); + }); + + it('should handle error with generic message', () => { + spyOn(console, 'error').and.stub(); + + widget.handleError(null); + expect(console.error).toHaveBeenCalledWith(DropdownWidget.UNKNOWN_ERROR_MESSAGE); + }); + + it('should handle error with error message', () => { + spyOn(console, 'error').and.stub(); + + const message = ''; + widget.handleError({ message: message }); + + expect(console.error).toHaveBeenCalledWith(message); + }); + + it('should handle error with detailed message', () => { + spyOn(console, 'error').and.stub(); + widget.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(); + widget.handleError({}); + expect(console.error).toHaveBeenCalledWith(DropdownWidget.GENERIC_ERROR_MESSAGE); + }); + +}); diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dropdown/dropdown.widget.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dropdown/dropdown.widget.ts index c5d61526e5..5e47fd41b9 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dropdown/dropdown.widget.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dropdown/dropdown.widget.ts @@ -16,7 +16,6 @@ */ import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs/Rx'; import { Http } from '@angular/http'; import { ObjectUtils } from 'ng2-alfresco-core'; import { WidgetComponent } from './../widget.component'; @@ -32,6 +31,9 @@ declare var componentHandler; }) export class DropdownWidget extends WidgetComponent implements OnInit { + static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error'; + static GENERIC_ERROR_MESSAGE: string = 'Server error'; + constructor(private http: Http) { super(); } @@ -51,13 +53,12 @@ export class DropdownWidget extends WidgetComponent implements OnInit { }, this.handleError ); - } } // TODO: support 'restResponsePath' - private loadFromJson(json: any) { - if (json instanceof Array) { + loadFromJson(json: any): boolean { + if (this.field && json && json instanceof Array) { let options = json.map(obj => { return { id: ObjectUtils.getValue(obj, this.field.restIdProperty).toString(), @@ -66,16 +67,19 @@ export class DropdownWidget extends WidgetComponent implements OnInit { }); this.field.options = options; this.field.updateForm(); + return true; } + return false; } - 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 - return Observable.throw(errMsg); + + handleError(error: any) { + let errMsg = DropdownWidget.UNKNOWN_ERROR_MESSAGE; + if (error) { + errMsg = (error.message) ? error.message : + error.status ? `${error.status} - ${error.statusText}` : DropdownWidget.GENERIC_ERROR_MESSAGE; + } + console.error(errMsg); } } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/hyperlink/hyperlink.widget.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/hyperlink/hyperlink.widget.spec.ts new file mode 100644 index 0000000000..9b6be175ae --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/hyperlink/hyperlink.widget.spec.ts @@ -0,0 +1,97 @@ +/*! + * @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 { HyperlinkWidget } from './hyperlink.widget'; +import { FormModel } from './../core/form.model'; +import { FormFieldModel } from './../core/form-field.model'; + +describe('HyperlinkWidget', () => { + + let widget: HyperlinkWidget; + + beforeEach(() => { + widget = new HyperlinkWidget(); + }); + + it('should get link text from field display text', () => { + const text = 'hello world'; + + widget.field = new FormFieldModel(new FormModel(), { + displayText: text + }); + + expect(widget.linkText).toBe(text); + }); + + it('should get link text from field url', () => { + const url = 'http://
'; + + widget.field = new FormFieldModel(new FormModel(), { + displayText: null, + hyperlinkUrl: url + }); + + expect(widget.linkText).toBe(url); + }); + + it('should require field to get link text', () => { + widget.field = null; + expect(widget.linkText).toBeNull(); + }); + + it('should not return link text', () => { + widget.field = new FormFieldModel(new FormModel(), { + displayText: null, + hyperlinkUrl: null + }); + + expect(widget.linkText).toBeNull(); + }); + + it('should return default url for missing field', () => { + widget.field = null; + expect(widget.linkUrl).toBe(HyperlinkWidget.DEFAULT_URL); + }); + + it('should return default url for missing field property', () => { + widget.field = new FormFieldModel(new FormModel(), { + hyperlinkUrl: null + }); + + expect(widget.linkUrl).toBe(HyperlinkWidget.DEFAULT_URL); + }); + + it('should prepend url with scheme', () => { + const url = 'www.alfresco.com'; + widget.field = new FormFieldModel(new FormModel(), { + hyperlinkUrl: url + }); + + expect(widget.linkUrl).toBe(`${HyperlinkWidget.DEFAULT_URL_SCHEME}${url}`); + }); + + it('should not prepend url with scheme', () => { + const url = 'https://'; + widget.field = new FormFieldModel(new FormModel(), { + hyperlinkUrl: url + }); + + expect(widget.linkUrl).toBe(url); + }); + +}); diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/hyperlink/hyperlink.widget.ts b/ng2-components/ng2-activiti-form/src/components/widgets/hyperlink/hyperlink.widget.ts index 5f7139efed..dd9c7e3fd2 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/hyperlink/hyperlink.widget.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/hyperlink/hyperlink.widget.ts @@ -29,21 +29,27 @@ declare var componentHandler; }) export class HyperlinkWidget extends WidgetComponent { + static DEFAULT_URL: string = '#'; + static DEFAULT_URL_SCHEME: string = 'http://'; + get linkUrl(): string { - let url = '#'; + let url = HyperlinkWidget.DEFAULT_URL; if (this.field && this.field.hyperlinkUrl) { url = this.field.hyperlinkUrl; if (!/^https?:\/\//i.test(url)) { - url = 'http://' + url; + url = HyperlinkWidget.DEFAULT_URL_SCHEME + url; } } return url; } - get linkText() { - return this.field.displayText || this.field.hyperlinkUrl; + get linkText(): string { + if (this.field) { + return this.field.displayText || this.field.hyperlinkUrl; + } + return null; } } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.spec.ts new file mode 100644 index 0000000000..2ffc23f974 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.spec.ts @@ -0,0 +1,60 @@ +/*! + * @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 { TabsWidget } from './tabs.widget'; +import { TabModel } from './../core/tab.model'; + +describe('TabsWidget', () => { + + let componentHandler; + let widget: TabsWidget; + + beforeEach(() => { + widget = new TabsWidget(); + + componentHandler = jasmine.createSpyObj('componentHandler', [ + 'upgradeAllRegistered' + ]); + + window['componentHandler'] = componentHandler; + }); + + it('should check tabs', () => { + widget.tabs = null; + expect(widget.hasTabs()).toBeFalsy(); + + widget.tabs = []; + expect(widget.hasTabs()).toBeFalsy(); + + widget.tabs = [new TabModel(null)]; + expect(widget.hasTabs()).toBeTruthy(); + }); + + it('should upgrade MDL content on view init', () => { + widget.ngAfterViewInit(); + expect(componentHandler.upgradeAllRegistered).toHaveBeenCalled(); + }); + + it('should setup MDL content only if component handler available', () => { + expect(widget.setupMaterialComponents()).toBeTruthy(); + + window['componentHandler'] = null; + expect(widget.setupMaterialComponents()).toBeFalsy(); + }); + +}); diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.ts b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.ts index acd9536b84..8c4d9de949 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.ts @@ -39,9 +39,15 @@ export class TabsWidget implements AfterViewInit { } ngAfterViewInit() { + this.setupMaterialComponents(); + } + + setupMaterialComponents(): boolean { // workaround for MDL issues with dynamic components if (componentHandler) { componentHandler.upgradeAllRegistered(); + return true; } + return false; } }