Merge pull request #901 from Alfresco/dev-denys--activiti-form-tests

Unit tests for Activiti Form component
This commit is contained in:
Will Abson 2016-10-14 16:03:43 +01:00 committed by GitHub
commit ad6da9a657
27 changed files with 1655 additions and 109 deletions

View File

@ -33,6 +33,9 @@ module.exports = function (config) {
{pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false},
'node_modules/alfresco-js-api/dist/alfresco-js-api.js',
'node_modules/moment/min/moment.min.js',
'node_modules/md-date-time-picker/dist/js/mdDateTimePicker.min.js',
'node_modules/md-date-time-picker/dist/js/draggabilly.pkgd.min.js',
{pattern: 'node_modules/ng2-translate/**/*.js', included: false, watched: false},
{pattern: 'node_modules/ng2-translate/**/*.js.map', included: false, watched: false},

View File

@ -21,6 +21,7 @@ import { ActivitiForm } from './activiti-form.component';
import { FormModel, FormOutcomeModel, FormFieldModel, FormOutcomeEvent } from './widgets/index';
import { FormService } from './../services/form.service';
import { WidgetVisibilityService } from './../services/widget-visibility.service';
import { NodeService } from './../services/node.service';
describe('ActivitiForm', () => {
@ -28,6 +29,7 @@ describe('ActivitiForm', () => {
let formService: FormService;
let formComponent: ActivitiForm;
let visibilityService: WidgetVisibilityService;
let nodeService: NodeService;
beforeEach(() => {
componentHandler = jasmine.createSpyObj('componentHandler', [
@ -39,7 +41,8 @@ describe('ActivitiForm', () => {
window['componentHandler'] = componentHandler;
formService = new FormService(null, null);
formComponent = new ActivitiForm(formService, visibilityService, null, null);
nodeService = new NodeService(null);
formComponent = new ActivitiForm(formService, visibilityService, null, nodeService);
});
it('should upgrade MDL content on view checked', () => {
@ -633,4 +636,84 @@ describe('ActivitiForm', () => {
expect(visibilityService.refreshVisibility).toHaveBeenCalledWith(field.form);
});
it('should load form for ecm node', () => {
let metadata = {};
spyOn(nodeService, 'getNodeMetadata').and.returnValue(
Observable.create(observer => {
observer.next({ metadata: metadata });
observer.complete();
})
);
spyOn(formComponent, 'loadFormFromActiviti').and.stub();
const nodeId = '<id>';
formComponent.nodeId = nodeId;
formComponent.ngOnInit();
expect(nodeService.getNodeMetadata).toHaveBeenCalledWith(nodeId);
expect(formComponent.loadFormFromActiviti).toHaveBeenCalled();
expect(formComponent.data).toBe(metadata);
});
it('should disable outcome buttons for readonly form', () => {
let formModel = new FormModel();
formModel.readOnly = true;
formComponent.form = formModel;
let outcome = new FormOutcomeModel(new FormModel(), {
id: ActivitiForm.CUSTOM_OUTCOME_ID,
name: 'Custom'
});
expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeFalsy();
});
it('should require outcome to eval button state', () => {
formComponent.form = new FormModel();
expect(formComponent.isOutcomeButtonEnabled(null)).toBeFalsy();
});
it('should always enable save outcome for writeable form', () => {
let formModel = new FormModel();
let field = new FormFieldModel(formModel, {
type: 'text',
value: null,
required: true
});
formComponent.form = formModel;
formModel.onFormFieldChanged(field);
expect(formModel.isValid).toBeFalsy();
let outcome = new FormOutcomeModel(new FormModel(), {
id: ActivitiForm.SAVE_OUTCOME_ID,
name: FormOutcomeModel.SAVE_ACTION
});
formComponent.readOnly = true;
expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeTruthy();
});
it('should disable oucome buttons for invalid form', () => {
let formModel = new FormModel();
let field = new FormFieldModel(formModel, {
type: 'text',
value: null,
required: true
});
formComponent.form = formModel;
formModel.onFormFieldChanged(field);
expect(formModel.isValid).toBeFalsy();
let outcome = new FormOutcomeModel(new FormModel(), {
id: ActivitiForm.CUSTOM_OUTCOME_ID,
name: 'Custom'
});
expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeFalsy();
});
});

View File

@ -194,7 +194,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
ngOnInit() {
if (this.nodeId) {
this.loadActivitiFormForEcmNode();
this.loadFormForEcmNode();
} else {
this.loadForm();
}
@ -418,7 +418,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
}
}
private loadActivitiFormForEcmNode(): void {
private loadFormForEcmNode(): void {
this.nodeService.getNodeMetadata(this.nodeId).subscribe(data => {
this.data = data.metadata;
this.loadFormFromActiviti(data.nodeType);
@ -426,7 +426,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
this.handleError);
}
public loadFormFromActiviti(nodeType: string): any {
loadFormFromActiviti(nodeType: string): any {
this.formService.searchFrom(nodeType).subscribe(
form => {
if (!form) {

View File

@ -0,0 +1,45 @@
/*!
* @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 { AmountWidget } from './amount.widget';
import { FormFieldModel } from './../core/form-field.model';
describe('AmountWidget', () => {
let widget: AmountWidget;
beforeEach(() => {
widget = new AmountWidget(null);
});
it('should setup currentcy from field', () => {
const currency = 'UAH';
widget.field = new FormFieldModel(null, {
currency: currency
});
widget.ngOnInit();
expect(widget.currency).toBe(currency);
});
it('should setup default currency', () => {
widget.field = null;
widget.ngOnInit();
expect(widget.currency).toBe(AmountWidget.DEFAULT_CURRENCY);
});
});

View File

@ -26,7 +26,9 @@ import { TextFieldWidgetComponent } from './../textfield-widget.component';
})
export class AmountWidget extends TextFieldWidgetComponent implements OnInit {
currency: string = '$';
static DEFAULT_CURRENCY: string = '$';
currency: string = AmountWidget.DEFAULT_CURRENCY;
constructor(elementRef: ElementRef) {
super(elementRef);

View File

@ -0,0 +1,293 @@
/*!
* @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 { Observable } from 'rxjs/Rx';
import { AttachWidget } from './attach.widget';
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
import { FormFieldModel } from './../core/form-field.model';
import { FormFieldTypes } from '../core/form-field-types';
import { ExternalContent } from '../core/external-content';
import { ExternalContentLink } from '../core/external-content-link';
describe('AttachWidget', () => {
let widget: AttachWidget;
let contentService: ActivitiAlfrescoContentService;
let dialogPolyfill: any;
beforeEach(() => {
contentService = new ActivitiAlfrescoContentService(null);
widget = new AttachWidget(contentService);
dialogPolyfill = {
registerDialog(obj: any) {
obj.showModal = function () {};
}
};
window['dialogPolyfill'] = dialogPolyfill;
});
it('should require field value to check file', () => {
widget.hasFile = false;
widget.field = null;
widget.ngOnInit();
expect(widget.hasFile).toBeFalsy();
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
value: null
});
widget.ngOnInit();
expect(widget.hasFile).toBeFalsy();
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
value: [{ name: 'file' }]
});
widget.ngOnInit();
expect(widget.hasFile).toBeTruthy();
});
it('should setup with form field', () => {
let nodes = [{}];
spyOn(contentService, 'getAlfrescoNodes').and.returnValue(
Observable.create(observer => {
observer.next(nodes);
observer.complete();
})
);
let config = {
siteId: '<id>',
site: '<site>',
pathId: '<pathId>',
accountId: '<accountId>'
};
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
params: {
fileSource: {
selectedFolder: config
}
}
});
widget.ngOnInit();
expect(widget.selectedFolderSiteId).toBe(config.siteId);
expect(widget.selectedFolderSiteName).toBe(config.site);
expect(widget.selectedFolderPathId).toBe(config.pathId);
expect(widget.selectedFolderAccountId).toBe(config.accountId);
expect(widget.selectedFolderNodes).toEqual(nodes);
});
it('should link file on select', () => {
let link = <ExternalContentLink> {};
spyOn(contentService, 'linkAlfrescoNode').and.returnValue(
Observable.create(observer => {
observer.next(link);
observer.complete();
})
);
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD
});
widget.ngOnInit();
let node = <ExternalContent> {};
widget.selectFile(node, null);
expect(contentService.linkAlfrescoNode).toHaveBeenCalled();
expect(widget.selectedFile).toBe(node);
expect(widget.field.value).toEqual([link]);
expect(widget.field.json.value).toEqual([link]);
});
it('should reset', () => {
widget.hasFile = true;
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
value: [{ name: 'filename' }]
});
widget.reset();
expect(widget.hasFile).toBeFalsy();
expect(widget.field.value).toBeNull();
expect(widget.field.json.value).toBeNull();
});
it('should close dialog on cancel', () => {
let closed = false;
widget.dialog = {
nativeElement: {
close: function() {
closed = true;
}
}
};
widget.cancel();
expect(closed).toBeTruthy();
});
it('should show modal dialog', () => {
spyOn(contentService, 'getAlfrescoNodes').and.returnValue(
Observable.create(observer => {
observer.next([]);
observer.complete();
})
);
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
params: {
fileSource: {
selectedFolder: {}
}
}
});
let modalShown = false;
widget.dialog = {
nativeElement: {
showModal: function() {
modalShown = true;
}
}
};
widget.showDialog();
expect(modalShown).toBeTruthy();
});
it('should select folder and load nodes', () => {
let nodes = [{}];
spyOn(contentService, 'getAlfrescoNodes').and.returnValue(
Observable.create(observer => {
observer.next(nodes);
observer.complete();
})
);
let node = <ExternalContent> { id: '<id>' };
widget.selectFolder(node, null);
expect(widget.selectedFolderPathId).toBe(node.id);
expect(widget.selectedFolderNodes).toEqual(nodes);
});
it('should get linked file name via local variable', () => {
widget.fileName = '<fileName>';
widget.selectedFile = null;
widget.field = null;
expect(widget.getLinkedFileName()).toBe(widget.fileName);
});
it('should get linked file name via selected file', () => {
widget.fileName = null;
widget.selectedFile = <ExternalContent> { title: '<title>' };
widget.field = null;
expect(widget.getLinkedFileName()).toBe(widget.selectedFile.title);
});
it('should get linked file name via form field', () => {
widget.fileName = null;
widget.selectedFile = null;
let name = '<file>';
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
value: [{ name: name }]
});
expect(widget.getLinkedFileName()).toBe(name);
});
it('should require form field to setup file browser', () => {
widget.field = null;
widget.setupFileBrowser();
expect(widget.selectedFolderPathId).toBeUndefined();
expect(widget.selectedFolderAccountId).toBeUndefined();
const pathId = '<pathId>';
const accountId = '<accountId>';
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
params: {
fileSource: {
selectedFolder: {
pathId: pathId,
accountId: accountId
}
}
}
});
widget.setupFileBrowser();
expect(widget.selectedFolderPathId).toBe(pathId);
expect(widget.selectedFolderAccountId).toBe(accountId);
});
it('should get external content nodes', () => {
let nodes = [{}];
spyOn(contentService, 'getAlfrescoNodes').and.returnValue(
Observable.create(observer => {
observer.next(nodes);
observer.complete();
})
);
const accountId = '<accountId>';
const pathId = '<pathId>';
widget.selectedFolderAccountId = accountId;
widget.selectedFolderPathId = pathId;
widget.getExternalContentNodes();
expect(contentService.getAlfrescoNodes).toHaveBeenCalledWith(accountId, pathId);
expect(widget.selectedFolderNodes).toEqual(nodes);
});
it('should handle error', () => {
let error = 'error';
spyOn(contentService, 'getAlfrescoNodes').and.returnValue(
Observable.throw(error)
);
spyOn(console, 'log').and.stub();
widget.getExternalContentNodes();
expect(console.log).toHaveBeenCalledWith(error);
});
it('should register dialog via polyfill', () => {
widget.dialog = {
nativeElement: {}
};
spyOn(dialogPolyfill, 'registerDialog').and.callThrough();
spyOn(widget, 'setupFileBrowser').and.stub();
spyOn(widget, 'getExternalContentNodes').and.stub();
widget.showDialog();
expect(dialogPolyfill.registerDialog).toHaveBeenCalledWith(widget.dialog.nativeElement);
});
it('should require configured dialog to show modal', () => {
widget.dialog = null;
spyOn(widget, 'setupFileBrowser').and.stub();
spyOn(widget, 'getExternalContentNodes').and.stub();
expect(widget.showDialog()).toBeFalsy();
});
});

View File

@ -53,24 +53,30 @@ export class AttachWidget extends WidgetComponent implements OnInit {
}
ngOnInit() {
if (this.field &&
this.field.value) {
this.hasFile = true;
}
if (this.field &&
this.field.params &&
this.field.params.fileSource &&
this.field.params.fileSource.selectedFolder) {
this.selectedFolderSiteId = this.field.params.fileSource.selectedFolder.siteId;
this.selectedFolderSiteName = this.field.params.fileSource.selectedFolder.site;
this.setupFileBrowser();
this.getExternalContentNodes();
if (this.field) {
if (this.field.value) {
this.hasFile = true;
}
let params = this.field.params;
if (params &&
params.fileSource &&
params.fileSource.selectedFolder) {
this.selectedFolderSiteId = params.fileSource.selectedFolder.siteId;
this.selectedFolderSiteName = params.fileSource.selectedFolder.site;
this.setupFileBrowser();
this.getExternalContentNodes();
}
}
}
private setupFileBrowser() {
this.selectedFolderPathId = this.field.params.fileSource.selectedFolder.pathId;
this.selectedFolderAccountId = this.field.params.fileSource.selectedFolder.accountId;
setupFileBrowser() {
if (this.field) {
let params = this.field.params;
this.selectedFolderPathId = params.fileSource.selectedFolder.pathId;
this.selectedFolderAccountId = params.fileSource.selectedFolder.accountId;
}
}
getLinkedFileName(): string {
@ -80,7 +86,8 @@ export class AttachWidget extends WidgetComponent implements OnInit {
this.selectedFile.title) {
result = this.selectedFile.title;
}
if (this.field.value &&
if (this.field &&
this.field.value &&
this.field.value.length > 0 &&
this.field.value[0].name) {
result = this.field.value[0].name;
@ -89,14 +96,12 @@ export class AttachWidget extends WidgetComponent implements OnInit {
return result;
}
private getExternalContentNodes() {
getExternalContentNodes() {
this.contentService.getAlfrescoNodes(this.selectedFolderAccountId, this.selectedFolderPathId)
.subscribe(
(nodes) => {
this.selectedFolderNodes = nodes;
},
error => console.error(error));
nodes => this.selectedFolderNodes = nodes,
error => this.handleError(error)
);
}
selectFile(node: ExternalContent, $event: any) {
@ -116,17 +121,19 @@ export class AttachWidget extends WidgetComponent implements OnInit {
this.getExternalContentNodes();
}
public showDialog() {
showDialog(): boolean {
this.setupFileBrowser();
this.getExternalContentNodes();
if (!this.dialog.nativeElement.showModal) {
dialogPolyfill.registerDialog(this.dialog.nativeElement);
}
if (this.dialog) {
if (!this.dialog.nativeElement.showModal) {
dialogPolyfill.registerDialog(this.dialog.nativeElement);
}
this.dialog.nativeElement.showModal();
return true;
}
return false;
}
private closeDialog() {
@ -135,7 +142,7 @@ export class AttachWidget extends WidgetComponent implements OnInit {
}
}
public cancel() {
cancel() {
this.closeDialog();
}

View File

@ -210,7 +210,7 @@ export class FormFieldModel extends FormWidgetModel {
*/
if (json.type === FormFieldTypes.DATE) {
if (value) {
let d = moment(value.split('T')[0]);
let d = moment(value.split('T')[0], 'YYYY-M-D');
if (d.isValid()) {
value = d.format('D-M-YYYY');
}

View File

@ -0,0 +1,146 @@
/*!
* @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 { ElementRef } from '@angular/core';
import { DateWidget } from './date.widget';
import { FormFieldModel } from './../core/form-field.model';
describe('DateWidget', () => {
let widget: DateWidget;
let nativeElement: any;
let elementRef: ElementRef;
beforeEach(() => {
nativeElement = {
querySelector: function () {
return null;
}
};
elementRef = new ElementRef(nativeElement);
widget = new DateWidget(elementRef);
});
it('should setup basic date picker settings on init ', () => {
expect(widget.datePicker).toBeUndefined();
widget.ngOnInit();
expect(widget.datePicker).toBeDefined();
});
it('should setup min value for date picker', () => {
let minValue = '13-03-1982';
widget.field = new FormFieldModel(null, {
minValue: minValue
});
widget.ngOnInit();
let expected = moment(minValue, widget.DATE_FORMAT);
expect(widget.datePicker._past.isSame(expected)).toBeTruthy();
});
it('should setup max value for date picker', () => {
let maxValue = '31-03-1982';
widget.field = new FormFieldModel(null, {
maxValue: maxValue
});
widget.ngOnInit();
let expected = moment(maxValue, widget.DATE_FORMAT);
expect(widget.datePicker._future.isSame(expected)).toBeTruthy();
});
it('should setup default time value for date picker', () => {
let dateValue = '13-03-1982';
widget.field = new FormFieldModel(null, {
type: 'date',
value: '1982-03-13'
});
widget.ngOnInit();
let expected = moment(dateValue, widget.DATE_FORMAT);
expect(widget.datePicker.time.isSame(expected)).toBeTruthy();
});
it('should setup trigger element', () => {
let el = {};
spyOn(nativeElement, 'querySelector').and.returnValue(el);
widget.ngOnInit();
expect(widget.datePicker.trigger).toBe(el);
});
it('should not setup trigger element', () => {
let w = new DateWidget(null);
w.ngOnInit();
expect(w.datePicker.trigger).toBeFalsy();
});
it('should eval visibility on date changed', () => {
spyOn(widget, 'checkVisibility').and.callThrough();
let field = new FormFieldModel(null);
widget.field = field;
widget.onDateChanged();
expect(widget.checkVisibility).toHaveBeenCalledWith(field);
});
it('should update picker value on input date changed', () => {
widget.field = new FormFieldModel(null, {
type: 'date',
value: '13-03-1982'
});
widget.ngOnInit();
widget.field.value = '31-03-1982';
widget.onDateChanged();
let expected = moment('31-03-1982', widget.DATE_FORMAT);
expect(widget.datePicker.time.isSame(expected)).toBeTruthy();
});
it('should update field value on date selected', () => {
widget.field = new FormFieldModel(null, { type: 'date' });
widget.ngOnInit();
let date = '13-3-1982';
widget.datePicker.time = moment(date, widget.DATE_FORMAT);
widget.onDateSelected();
expect(widget.field.value).toBe(date);
});
it('should update material textfield on date selected', () => {
spyOn(widget, 'setupMaterialTextField').and.callThrough();
widget.field = new FormFieldModel(null, { type: 'date' });
widget.ngOnInit();
widget.datePicker.time = moment();
widget.onDateSelected();
expect(widget.setupMaterialTextField).toHaveBeenCalled();
});
it('should not update material textfield on date selected', () => {
let w = new DateWidget(null);
spyOn(w, 'setupMaterialTextField').and.callThrough();
w.field = new FormFieldModel(null, { type: 'date' });
w.ngOnInit();
w.datePicker.time = moment();
w.onDateSelected();
expect(w.setupMaterialTextField).not.toHaveBeenCalled();
});
});

View File

@ -26,7 +26,7 @@ import { TextFieldWidgetComponent } from './../textfield-widget.component';
})
export class DateWidget extends TextFieldWidgetComponent implements OnInit {
private dateFormat: string = 'D-M-YYYY';
DATE_FORMAT: string = 'D-M-YYYY';
datePicker: any;
@ -44,41 +44,37 @@ export class DateWidget extends TextFieldWidgetComponent implements OnInit {
if (this.field) {
if (this.field.minValue) {
let min = moment(this.field.minValue, this.dateFormat);
if (min.isValid()) {
settings.past = min;
}
settings.past = moment(this.field.minValue, this.DATE_FORMAT);
}
if (this.field.maxValue) {
let max = moment(this.field.maxValue, this.dateFormat);
if (max.isValid()) {
settings.future = max;
}
settings.future = moment(this.field.maxValue, this.DATE_FORMAT);
}
if (this.field.value) {
settings.time = moment(this.field.value, this.dateFormat);
settings.init = moment(this.field.value, this.DATE_FORMAT);
}
}
this.datePicker = new mdDateTimePicker.default(settings);
this.datePicker.trigger = this.elementRef.nativeElement.querySelector('#dateInput');
if (this.elementRef) {
this.datePicker.trigger = this.elementRef.nativeElement.querySelector('#dateInput');
}
}
onDateChanged() {
if (this.field.value) {
this.datePicker.time = moment(this.field.value, this.dateFormat);
this.datePicker.time = moment(this.field.value, this.DATE_FORMAT);
}
this.checkVisibility(this.field);
}
onDateSelected() {
this.field.value = this.datePicker.time.format('DD-MM-YYYY');
let el = this.elementRef.nativeElement;
let container = el.querySelector('.mdl-textfield');
if (container) {
container.MaterialTextfield.change(this.field.value.toString());
let newValue = this.datePicker.time.format(this.DATE_FORMAT);
this.field.value = newValue;
if (this.elementRef) {
this.setupMaterialTextField(this.elementRef, componentHandler, newValue);
}
}

View File

@ -0,0 +1,542 @@
/*!
* @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 { Observable } from 'rxjs/Rx';
import { DisplayValueWidget } from './display-value.widget';
import { FormService } from '../../../services/form.service';
import { FormFieldModel } from './../core/form-field.model';
import { FormFieldTypes } from '../core/form-field-types';
import { FormModel } from '../core/form.model';
describe('DisplayValueWidget', () => {
let widget: DisplayValueWidget;
let formService: FormService;
beforeEach(() => {
formService = new FormService(null, null);
widget = new DisplayValueWidget(formService);
});
it('should require field to setup default value', () => {
widget.field = null;
widget.ngOnInit();
expect(widget.value).toBeUndefined();
});
it('should take field value on init', () => {
let value = '<value>';
widget.field = new FormFieldModel(null, { value: value });
widget.field.params = null;
widget.ngOnInit();
expect(widget.value).toBe(value);
});
it('should setup [BOOLEAN] field', () => {
expect(widget.value).toBeUndefined();
// test TRUE value
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: 'true',
params: {
field: {
type: FormFieldTypes.BOOLEAN
}
}
});
widget.ngOnInit();
expect(widget.value).toBeTruthy();
// test FALSE value
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: 'false',
params: {
field: {
type: FormFieldTypes.BOOLEAN
}
}
});
widget.ngOnInit();
expect(widget.value).toBeFalsy();
});
it ('should setup [FUNCTIONAL-GROUP] field', () => {
let groupName: '<group>';
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: {
name: groupName
},
params: {
field: {
type: FormFieldTypes.FUNCTIONAL_GROUP
}
}
});
widget.ngOnInit();
expect(widget.value).toBe(groupName);
});
it('should not setup [FUNCTIONAL-GROUP] field when missing value', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
params: {
field: {
type: FormFieldTypes.FUNCTIONAL_GROUP
}
}
});
widget.ngOnInit();
expect(widget.value).toBeNull();
});
it('should setup [PEOPLE] field', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: {
firstName: 'John',
lastName: 'Doe'
},
params: {
field: {
type: FormFieldTypes.PEOPLE
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('John Doe');
});
it('should not setup [PEOPLE] field whem missing value', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
params: {
field: {
type: FormFieldTypes.PEOPLE
}
}
});
widget.ngOnInit();
expect(widget.value).toBeUndefined();
});
it('should setup [UPLOAD] field', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: [
{ name: 'file1' }
],
params: {
field: {
type: FormFieldTypes.UPLOAD
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('file1');
});
it('should not setup [UPLOAD] field when missing value', () => {
widget.field = new FormFieldModel(null, {
value: null,
params: {
field: {
type: FormFieldTypes.UPLOAD
}
}
});
widget.ngOnInit();
expect(widget.value).toBeNull();
});
it('should not setup [UPLOAD] field when empty value', () => {
widget.field = new FormFieldModel(null, {
value: [],
params: {
field: {
type: FormFieldTypes.UPLOAD
}
}
});
widget.ngOnInit();
expect(widget.value).toBeNull();
});
it('should setup [TYPEAHEAD] field', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
params: {
field: {
type: FormFieldTypes.TYPEAHEAD
}
}
});
spyOn(widget, 'loadRestFieldValue').and.stub();
widget.ngOnInit();
expect(widget.loadRestFieldValue).toHaveBeenCalled();
});
it('should setup [DROPDOWN] field with REST config', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
params: {
field: {
type: FormFieldTypes.DROPDOWN
}
}
});
spyOn(widget, 'loadRestFieldValue').and.stub();
widget.ngOnInit();
expect(widget.loadRestFieldValue).toHaveBeenCalled();
});
it('should setup [RADIO_BUTTONS] field', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: null,
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
spyOn(widget, 'loadRadioButtonValue').and.stub();
widget.ngOnInit();
expect(widget.loadRadioButtonValue).toHaveBeenCalled();
});
it('should setup [RADIO_BUTTONS] value by options', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: null,
value: '2',
options: [
{ id: '1', name: 'option 1' },
{ id: '2', name: 'option 2' }
],
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('option 2');
});
it('should not setup [RADIO_BUTTONS] value with missing option', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: null,
value: '100',
options: [
{ id: '1', name: 'option 1' },
{ id: '2', name: 'option 2' }
],
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('100');
});
it('should not setup [RADIO_BUTTONS] when missing options', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: null,
value: '100',
options: null,
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
widget.field.options = null;
widget.ngOnInit();
expect(widget.value).toBe('100');
});
it('should setup [RADIO_BUTTONS] field with REST config', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: '<url>',
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
spyOn(widget, 'loadRestFieldValue').and.stub();
widget.ngOnInit();
expect(widget.loadRestFieldValue).toHaveBeenCalled();
});
it('should setup rest field values with REST options', () => {
spyOn(formService, 'getRestFieldValues').and.returnValue(
Observable.create(observer => {
observer.next([
{ id: '1', name: 'option 1' },
{ id: '2', name: 'option 2' }
]);
observer.complete();
})
);
let form = new FormModel({ taskId: '<id>' });
widget.field = new FormFieldModel(form, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: '<url>',
value: '2',
options: [
{ id: '1', name: 'option 1' },
{ id: '2', name: 'option 2' }
],
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
widget.ngOnInit();
expect(formService.getRestFieldValues).toHaveBeenCalled();
expect(widget.value).toBe('option 2');
});
it('should not setup rest field values with missing REST option', () => {
spyOn(formService, 'getRestFieldValues').and.returnValue(
Observable.create(observer => {
observer.next([
{ id: '1', name: 'option 1' },
{ id: '2', name: 'option 2' }
]);
observer.complete();
})
);
let form = new FormModel({ taskId: '<id>' });
widget.field = new FormFieldModel(form, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: '<url>',
value: '100',
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
widget.ngOnInit();
expect(formService.getRestFieldValues).toHaveBeenCalled();
expect(widget.value).toBe('100');
});
it('should not setup rest field values with no REST response', () => {
spyOn(formService, 'getRestFieldValues').and.returnValue(
Observable.create(observer => {
observer.next(null);
observer.complete();
})
);
let form = new FormModel({ taskId: '<id>' });
widget.field = new FormFieldModel(form, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: '<url>',
value: '100',
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
widget.ngOnInit();
expect(formService.getRestFieldValues).toHaveBeenCalled();
expect(widget.value).toBe('100');
});
it('should handle rest error', () => {
const error = 'ERROR';
spyOn(formService, 'getRestFieldValues').and.returnValue(
Observable.throw(error)
);
spyOn(console, 'log').and.stub();
let form = new FormModel({ taskId: '<id>' });
widget.field = new FormFieldModel(form, {
type: FormFieldTypes.DISPLAY_VALUE,
restUrl: '<url>',
value: '100',
params: {
field: {
type: FormFieldTypes.RADIO_BUTTONS
}
}
});
widget.ngOnInit();
expect(formService.getRestFieldValues).toHaveBeenCalled();
expect(console.log).toHaveBeenCalledWith(error);
expect(widget.value).toBe('100');
});
it('should setup [DATE] field with valid date', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: '1982-03-13T00:00:00.000Z',
params: {
field: {
type: FormFieldTypes.DATE
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('13-3-1982');
});
it('should setup [DATE] field with invalid date', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: '<invalid value>',
params: {
field: {
type: FormFieldTypes.DATE
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('<invalid value>');
});
it('should not setup [DATE] field when missing value', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
params: {
field: {
type: FormFieldTypes.DATE
}
}
});
widget.ngOnInit();
expect(widget.value).toBeUndefined();
});
it('should setup [AMOUNT] field with default currency', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: 11,
params: {
field: {
type: FormFieldTypes.AMOUNT
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('$ 11');
});
it('should setup [AMOUNT] field with custom currency', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: 12.6,
currency: 'UAH',
params: {
field: {
type: FormFieldTypes.AMOUNT
}
}
});
widget.ngOnInit();
expect(widget.value).toBe('UAH 12.6');
});
it('should not setup [AMOUNT] field when missing value', () => {
widget.field = new FormFieldModel(null, {
params: {
field: {
type: FormFieldTypes.AMOUNT
}
}
});
widget.ngOnInit();
expect(widget.value).toBeUndefined();
});
it('should setup [HYPERLINK] field', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
hyperlinkUrl: 'www.some-url.com',
displayText: 'Custom URL',
params: {
field: {
type: FormFieldTypes.HYPERLINK
}
}
});
widget.ngOnInit();
expect(widget.linkUrl).toBe(`http://${widget.field.hyperlinkUrl}`);
expect(widget.linkText).toBe(widget.field.displayText);
});
it('should take default value for unknown field type', () => {
const value = '<value>';
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: value,
params: {
field: {
type: '<unknown type>'
}
}
});
widget.ngOnInit();
expect(widget.value).toBe(value);
});
it('should take default value when missing params', () => {
const value = '<value>';
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: value
});
widget.ngOnInit();
expect(widget.value).toBe(value);
});
it('should take default value when missing enclosed field type', () => {
const value = '<value>';
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
value: value,
params: {
field: {
}
}
});
widget.ngOnInit();
expect(widget.value).toBe(value);
});
});

View File

@ -53,6 +53,8 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
case FormFieldTypes.FUNCTIONAL_GROUP:
if (this.field.value) {
this.value = this.field.value.name;
} else {
this.value = null;
}
break;
case FormFieldTypes.PEOPLE:
@ -66,6 +68,8 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
let files = this.field.value || [];
if (files.length > 0) {
this.value = decodeURI(files[0].name);
} else {
this.value = null;
}
break;
case FormFieldTypes.TYPEAHEAD:
@ -83,7 +87,7 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
break;
case FormFieldTypes.DATE:
if (this.value) {
let d = moment(this.value.split('T')[0]);
let d = moment(this.value.split('T')[0], 'YYYY-M-D');
if (d.isValid()) {
this.value = d.format('D-M-YYYY');
}
@ -96,10 +100,8 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
}
break;
case FormFieldTypes.HYPERLINK:
if (this.value) {
this.linkUrl = this.getHyperlinkUrl(this.field);
this.linkText = this.getHyperlinkText(this.field);
}
this.linkUrl = this.getHyperlinkUrl(this.field);
this.linkText = this.getHyperlinkText(this.field);
break;
default:
this.value = this.field.value;

View File

@ -20,6 +20,7 @@ import { FormService } from '../../../services/form.service';
import { DropdownWidget } from './dropdown.widget';
import { FormModel } from './../core/form.model';
import { FormFieldModel } from './../core/form-field.model';
import { FormFieldOption } from './../core/form-field-option';
describe('DropdownWidget', () => {
@ -32,6 +33,18 @@ describe('DropdownWidget', () => {
widget.field = new FormFieldModel(new FormModel());
});
it('should require field with restUrl', () => {
spyOn(formService, 'getRestFieldValues').and.stub();
widget.field = null;
widget.ngOnInit();
expect(formService.getRestFieldValues).not.toHaveBeenCalled();
widget.field = new FormFieldModel(null, { restUrl: null });
widget.ngOnInit();
expect(formService.getRestFieldValues).not.toHaveBeenCalled();
});
it('should request field values from service', () => {
const taskId = '<form-id>';
const fieldId = '<field-id>';
@ -45,10 +58,12 @@ describe('DropdownWidget', () => {
restUrl: '<url>'
});
spyOn(formService, 'getRestFieldValues').and.returnValue(Observable.create(observer => {
observer.next(null);
observer.complete();
}));
spyOn(formService, 'getRestFieldValues').and.returnValue(
Observable.create(observer => {
observer.next(null);
observer.complete();
})
);
widget.ngOnInit();
expect(formService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId);
});
@ -58,4 +73,29 @@ describe('DropdownWidget', () => {
widget.handleError('Err');
expect(console.error).toHaveBeenCalledWith('Err');
});
it('should preserve empty option when loading fields', () => {
let restFieldValue: FormFieldOption = <FormFieldOption> { id: '1', name: 'Option1' };
spyOn(formService, 'getRestFieldValues').and.returnValue(
Observable.create(observer => {
observer.next([restFieldValue]);
observer.complete();
})
);
let form = new FormModel({ taskId: '<id>' });
let emptyOption: FormFieldOption = <FormFieldOption> { id: 'empty', name: 'Empty' };
widget.field = new FormFieldModel(form, {
id: '<id>',
restUrl: '/some/url/address',
hasEmptyValue: true,
options: [emptyOption]
});
widget.ngOnInit();
expect(formService.getRestFieldValues).toHaveBeenCalled();
expect(widget.field.options.length).toBe(2);
expect(widget.field.options[0]).toBe(emptyOption);
expect(widget.field.options[1]).toBe(restFieldValue);
});
});

View File

@ -15,6 +15,7 @@
* limitations under the License.
*/
import { ElementRef } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { FunctionalGroupWidget } from './functional-group.widget';
import { FormService } from '../../../services/form.service';
@ -24,12 +25,20 @@ import { GroupModel } from '../core/group.model';
describe('FunctionalGroupWidget', () => {
let componentHandler;
let formService: FormService;
let elementRef: ElementRef;
let widget: FunctionalGroupWidget;
beforeEach(() => {
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
formService = new FormService(null, null);
widget = new FunctionalGroupWidget(formService, null);
elementRef = new ElementRef(null);
widget = new FunctionalGroupWidget(formService, elementRef);
widget.field = new FormFieldModel(new FormModel());
});
@ -39,7 +48,7 @@ describe('FunctionalGroupWidget', () => {
spyOn(formService, 'getWorkflowGroups').and.returnValue(
Observable.create(observer => {
observer.next([]);
observer.next(null);
observer.complete();
})
);
@ -219,4 +228,37 @@ describe('FunctionalGroupWidget', () => {
expect(formService.getWorkflowGroups).not.toHaveBeenCalled();
expect(widget.popupVisible).toBeFalsy();
});
it('should setup mdl textfield on view init', () => {
spyOn(widget, 'setupMaterialComponents').and.callThrough();
spyOn(widget, 'setupMaterialTextField').and.callThrough();
widget.value = '<value>';
widget.ngAfterViewInit();
expect(widget.setupMaterialComponents).toHaveBeenCalledWith(componentHandler);
expect(widget.setupMaterialTextField).toHaveBeenCalled();
});
it('should require component handler to setup textfield', () => {
expect(widget.setupMaterialComponents(null)).toBeFalsy();
});
it('should require element reference to setup textfield', () => {
let w = new FunctionalGroupWidget(formService, null);
w.value = '<value>';
expect(w.setupMaterialComponents(componentHandler)).toBeFalsy();
w = new FunctionalGroupWidget(formService, elementRef);
w.value = '<value>';
expect(w.setupMaterialComponents(componentHandler)).toBeTruthy();
});
it('should require value to setup textfield', () => {
widget.value = '<value>';
expect(widget.setupMaterialComponents(componentHandler)).toBeTruthy();
widget.value = null;
expect(widget.setupMaterialComponents(componentHandler)).toBeFalsy();
});
});

View File

@ -109,16 +109,12 @@ export class FunctionalGroupWidget extends WidgetComponent implements OnInit {
}
setupMaterialComponents(handler: any): boolean {
// workaround for MDL issues with dynamic components
super.setupMaterialComponents(handler);
if (handler) {
handler.upgradeAllRegistered();
if (this.elementRef && this.value) {
let container = this.elementRef.nativeElement.querySelector('.mdl-textfield');
if (container) {
container.MaterialTextfield.change(this.value);
}
this.setupMaterialTextField(this.elementRef, handler, this.value);
return true;
}
return true;
}
return false;
}

View File

@ -0,0 +1,31 @@
/*!
* @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 { MultilineTextWidget } from './multiline-text.widget';
describe('MultilineTextWidget', () => {
let widget: MultilineTextWidget;
beforeEach(() => {
widget = new MultilineTextWidget(null);
});
it('should exist', () => {
expect(widget).toBeDefined();
});
});

View File

@ -0,0 +1,31 @@
/*!
* @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 { NumberWidget } from './number.widget';
describe('NumberWidget', () => {
let widget: NumberWidget;
beforeEach(() => {
widget = new NumberWidget(null);
});
it('should exist', () => {
expect(widget).toBeDefined();
});
});

View File

@ -15,6 +15,7 @@
* limitations under the License.
*/
import { ElementRef } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { PeopleWidget } from './people.widget';
import { FormService } from '../../../services/form.service';
@ -24,12 +25,20 @@ import { GroupUserModel } from '../core/group-user.model';
describe('PeopleWidget', () => {
let componentHandler;
let elementRef: ElementRef;
let formService: FormService;
let widget: PeopleWidget;
beforeEach(() => {
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
formService = new FormService(null, null);
widget = new PeopleWidget(formService, null);
elementRef = new ElementRef(null);
widget = new PeopleWidget(formService, elementRef);
widget.field = new FormFieldModel(new FormModel());
});
@ -45,6 +54,16 @@ describe('PeopleWidget', () => {
expect(widget.getDisplayName(model)).toBe('John Doe');
});
it('should skip first name for display name', () => {
let model = new GroupUserModel({ firstName: null, lastName: 'Doe' });
expect(widget.getDisplayName(model)).toBe('Doe');
});
it('should skip last name for display name', () => {
let model = new GroupUserModel({ firstName: 'John', lastName: null });
expect(widget.getDisplayName(model)).toBe('John');
});
it('should flush value on blur', (done) => {
spyOn(widget, 'flushValue').and.stub();
widget.onBlur();
@ -61,10 +80,12 @@ describe('PeopleWidget', () => {
lastName: 'Doe'
});
spyOn(formService, 'getWorkflowUsers').and.returnValue(Observable.create(observer => {
observer.next([]);
observer.complete();
}));
spyOn(formService, 'getWorkflowUsers').and.returnValue(
Observable.create(observer => {
observer.next(null);
observer.complete();
})
);
widget.ngOnInit();
expect(widget.value).toBe('John Doe');
@ -103,10 +124,12 @@ describe('PeopleWidget', () => {
it('should fetch users by search term', () => {
let users = [{}, {}];
spyOn(formService, 'getWorkflowUsers').and.returnValue(Observable.create(observer => {
observer.next(users);
observer.complete();
}));
spyOn(formService, 'getWorkflowUsers').and.returnValue(
Observable.create(observer => {
observer.next(users);
observer.complete();
})
);
widget.value = 'user1';
widget.onKeyUp(null);
@ -118,10 +141,12 @@ describe('PeopleWidget', () => {
it('should fetch users by search term and group id', () => {
let users = [{}, {}];
spyOn(formService, 'getWorkflowUsers').and.returnValue(Observable.create(observer => {
observer.next(users);
observer.complete();
}));
spyOn(formService, 'getWorkflowUsers').and.returnValue(
Observable.create(observer => {
observer.next(users);
observer.complete();
})
);
widget.value = 'user1';
widget.groupId = '1001';
@ -133,10 +158,12 @@ describe('PeopleWidget', () => {
});
it('should fetch users and show no popup', () => {
spyOn(formService, 'getWorkflowUsers').and.returnValue(Observable.create(observer => {
observer.next(null);
observer.complete();
}));
spyOn(formService, 'getWorkflowUsers').and.returnValue(
Observable.create(observer => {
observer.next(null);
observer.complete();
})
);
widget.value = 'user1';
widget.onKeyUp(null);
@ -209,4 +236,37 @@ describe('PeopleWidget', () => {
expect(widget.value).toBeNull();
expect(widget.field.value).toBeNull();
});
it('should setup mdl textfield on view init', () => {
spyOn(widget, 'setupMaterialComponents').and.callThrough();
spyOn(widget, 'setupMaterialTextField').and.callThrough();
widget.value = '<value>';
widget.ngAfterViewInit();
expect(widget.setupMaterialComponents).toHaveBeenCalledWith(componentHandler);
expect(widget.setupMaterialTextField).toHaveBeenCalled();
});
it('should require component handler to setup textfield', () => {
expect(widget.setupMaterialComponents(null)).toBeFalsy();
});
it('should require element reference to setup textfield', () => {
let w = new PeopleWidget(formService, null);
w.value = '<value>';
expect(w.setupMaterialComponents(componentHandler)).toBeFalsy();
w = new PeopleWidget(formService, elementRef);
w.value = '<value>';
expect(w.setupMaterialComponents(componentHandler)).toBeTruthy();
});
it('should require value to setup textfield', () => {
widget.value = '<value>';
expect(widget.setupMaterialComponents(componentHandler)).toBeTruthy();
widget.value = null;
expect(widget.setupMaterialComponents(componentHandler)).toBeFalsy();
});
});

View File

@ -122,16 +122,12 @@ export class PeopleWidget extends WidgetComponent implements OnInit {
}
setupMaterialComponents(handler: any): boolean {
// workaround for MDL issues with dynamic components
super.setupMaterialComponents(handler);
if (handler) {
handler.upgradeAllRegistered();
if (this.elementRef && this.value) {
let container = this.elementRef.nativeElement.querySelector('.mdl-textfield');
if (container) {
container.MaterialTextfield.change(this.value);
}
this.setupMaterialTextField(this.elementRef, handler, this.value);
return true;
}
return true;
}
return false;
}

View File

@ -17,6 +17,7 @@
import { TabsWidget } from './tabs.widget';
import { TabModel } from './../core/tab.model';
import { FormFieldModel } from './../core/form-field.model';
describe('TabsWidget', () => {
@ -56,4 +57,13 @@ describe('TabsWidget', () => {
expect(widget.setupMaterialComponents()).toBeFalsy();
});
it('should emit tab changed event', (done) => {
let field = new FormFieldModel(null);
widget.formTabChanged.subscribe(tab => {
expect(tab).toBe(field);
done();
});
widget.tabChanged(field);
});
});

View File

@ -0,0 +1,68 @@
/*!
* @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 { ElementRef } from '@angular/core';
import { TextWidget } from './text.widget';
import { FormFieldModel } from './../core/form-field.model';
import { FormFieldTypes } from '../core/form-field-types';
describe('TextWidget', () => {
let widget: TextWidget;
let elementRef: ElementRef;
let componentHandler;
beforeEach(() => {
elementRef = new ElementRef(null);
widget = new TextWidget(elementRef);
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
});
it('should upgrade material textfield', () => {
spyOn(widget, 'setupMaterialTextField').and.stub();
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.TEXT,
value: '<text>'
});
widget.ngAfterViewInit();
expect(widget.setupMaterialTextField).toHaveBeenCalled();
});
it('should require mdl component handler to setup textfield', () => {
expect(widget.setupMaterialComponents(null)).toBeFalsy();
});
it('should require element reference to setup textfield', () => {
widget = new TextWidget(null);
expect(widget.setupMaterialComponents(componentHandler)).toBeFalsy();
});
it('should require field value to setup textfield', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.TEXT,
value: null
});
expect(widget.setupMaterialComponents(componentHandler)).toBeFalsy();
});
});

View File

@ -27,19 +27,13 @@ export abstract class TextFieldWidgetComponent extends WidgetComponent {
this.elementRef = elementRef;
}
// Overrides base implementation
setupMaterialComponents(handler: any): boolean {
super.setupMaterialComponents(handler);
// workaround for MDL issues with dynamic components
if (handler) {
handler.upgradeAllRegistered();
if (this.elementRef && this.hasValue()) {
let el = this.elementRef.nativeElement;
let container = el.querySelector('.mdl-textfield');
if (container) {
container.MaterialTextfield.change(this.field.value.toString());
}
return this.setupMaterialTextField(this.elementRef, handler, this.field.value.toString());
}
return true;
}
return false;
}

View File

@ -3,7 +3,7 @@
<label class="upload-widget__label" [attr.for]="field.id">{{field.name}}</label>
<div>
<i *ngIf="hasFile" class="material-icons upload-widget__icon">attachment</i>
<span *ngIf="hasFile" class="upload-widget__file">{{getUploadedFileName()}}</span>
<span *ngIf="hasFile" class="upload-widget__file">{{displayText}}</span>
<input *ngIf="!hasFile"
#file
type="file"

View File

@ -0,0 +1,84 @@
/*!
* @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 { UploadWidget } from './upload.widget';
import { AlfrescoSettingsService, AlfrescoAuthenticationService, AlfrescoApiService } from 'ng2-alfresco-core';
import { FormFieldModel } from './../core/form-field.model';
import { FormFieldTypes } from '../core/form-field-types';
describe('UploadWidget', () => {
let widget: UploadWidget;
let settingsService: AlfrescoSettingsService;
let authService: AlfrescoAuthenticationService;
beforeEach(() => {
settingsService = new AlfrescoSettingsService();
authService = new AlfrescoAuthenticationService(settingsService, new AlfrescoApiService());
widget = new UploadWidget(settingsService, authService);
});
it('should setup with field data', () => {
const fileName = 'hello world';
const encodedFileName = encodeURI(fileName);
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
value: [
{ name: encodedFileName }
]
});
widget.ngOnInit();
expect(widget.hasFile).toBeTruthy();
expect(widget.fileName).toBe(encodeURI(fileName));
expect(widget.displayText).toBe(fileName);
});
it('should require form field to setup', () => {
widget.field = null;
widget.ngOnInit();
expect(widget.hasFile).toBeFalsy();
expect(widget.fileName).toBeUndefined();
expect(widget.displayText).toBeUndefined();
});
it('should reset local properties', () => {
widget.hasFile = true;
widget.fileName = '<fileName>';
widget.displayText = '<displayText>';
widget.reset();
expect(widget.hasFile).toBeFalsy();
expect(widget.fileName).toBeNull();
expect(widget.displayText).toBeNull();
});
it('should reset field value', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.UPLOAD,
value: [
{ name: 'filename' }
]
});
widget.reset();
expect(widget.field.value).toBeNull();
expect(widget.field.json.value).toBeNull();
});
});

View File

@ -29,6 +29,7 @@ export class UploadWidget extends WidgetComponent implements OnInit {
hasFile: boolean;
fileName: string;
displayText: string;
constructor(private settingsService: AlfrescoSettingsService,
private authService: AlfrescoAuthenticationService) {
@ -42,18 +43,19 @@ export class UploadWidget extends WidgetComponent implements OnInit {
this.hasFile = true;
let file = this.field.value[0];
this.fileName = file.name;
this.displayText = decodeURI(file.name);
}
}
getUploadedFileName(): string {
return decodeURI(this.fileName);
}
reset() {
this.field.value = null;
this.field.json.value = null;
this.hasFile = false;
this.fileName = null;
this.displayText = null;
if (this.field) {
this.field.value = null;
this.field.json.value = null;
}
}
onFileChanged(event: any) {
@ -64,6 +66,7 @@ export class UploadWidget extends WidgetComponent implements OnInit {
this.hasFile = true;
this.fileName = encodeURI(file.name);
this.displayText = file.name;
let formData: FormData = new FormData();
formData.append('file', file, this.fileName);

View File

@ -15,6 +15,7 @@
* limitations under the License.
*/
import { ElementRef } from '@angular/core';
import { WidgetComponent } from './widget.component';
import { FormFieldModel } from './core/form-field.model';
import { FormModel } from './core/form.model';
@ -80,4 +81,53 @@ describe('WidgetComponent', () => {
component.checkVisibility(fakeField);
});
it('should eval isRequired state of the field', () => {
let widget = new WidgetComponent();
expect(widget.isRequired()).toBeFalsy();
widget.field = new FormFieldModel(null);
expect(widget.isRequired()).toBeFalsy();
widget.field = new FormFieldModel(null, { required: false });
expect(widget.isRequired()).toBeFalsy();
widget.field = new FormFieldModel(null, { required: true });
expect(widget.isRequired()).toBeTruthy();
});
it('should require element reference to setup textfield', () => {
let widget = new WidgetComponent();
expect(widget.setupMaterialTextField(null, {}, 'value')).toBeFalsy();
});
it('should require component handler to setup textfield', () => {
let elementRef = new ElementRef(null);
let widget = new WidgetComponent();
expect(widget.setupMaterialTextField(elementRef, null, 'value')).toBeFalsy();
});
it('should require field value to setup textfield', () => {
let elementRef = new ElementRef(null);
let widget = new WidgetComponent();
expect(widget.setupMaterialTextField(elementRef, {}, null)).toBeFalsy();
});
it('should setup textfield', () => {
let changeCalled = false;
let elementRef = new ElementRef({
querySelector: function () {
return {
MaterialTextfield: {
change: function() {
changeCalled = true;
}
}
};
}
});
let widget = new WidgetComponent();
expect(widget.setupMaterialTextField(elementRef, {}, 'value')).toBeTruthy();
expect(changeCalled).toBeTruthy();
});
});

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Input, AfterViewInit, Output, EventEmitter } from '@angular/core';
import { Input, AfterViewInit, Output, EventEmitter, ElementRef } from '@angular/core';
import { FormFieldModel } from './core/index';
/**
@ -36,6 +36,8 @@ export class WidgetComponent implements AfterViewInit {
return this.field ? true : false;
}
// Note for developers:
// returns <any> object to be able binding it to the <element reguired="required"> attribute
isRequired(): any {
if (this.field && this.field.required) {
return true;
@ -63,6 +65,20 @@ export class WidgetComponent implements AfterViewInit {
return false;
}
setupMaterialTextField(elementRef: ElementRef, handler: any, value: string): boolean {
if (elementRef && handler) {
let el = elementRef.nativeElement;
if (el) {
let container = el.querySelector('.mdl-textfield');
if (container) {
container.MaterialTextfield.change(value);
return true;
}
}
}
return false;
}
checkVisibility(field: FormFieldModel) {
this.fieldChanged.emit(field);
}
@ -85,4 +101,10 @@ export class WidgetComponent implements AfterViewInit {
return null;
}
protected handleError(error: any) {
if (error) {
console.log(error);
}
}
}