#572 unit tests for form renderer

This commit is contained in:
Denys Vuika 2016-08-15 16:53:02 +01:00
parent 070323585d
commit 42cfdd093d
11 changed files with 671 additions and 16 deletions

View File

@ -0,0 +1,42 @@
/*!
* @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 } from '@angular/core/testing';
import { ContainerColumnModel } from './container-column.model';
import { FormFieldModel } from './form-field.model';
describe('ContainerColumnModel', () => {
it('should have max size by default', () => {
let column = new ContainerColumnModel();
expect(column.size).toBe(12);
});
it('should check fields', () => {
let column = new ContainerColumnModel();
column.fields = null;
expect(column.hasFields()).toBeFalsy();
column.fields = [];
expect(column.hasFields()).toBeFalsy();
column.fields = [new FormFieldModel(null, null)];
expect(column.hasFields()).toBeTruthy();
});
});

View File

@ -0,0 +1,140 @@
/*!
* @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 } from '@angular/core/testing';
import { ContainerModel } from './container.model';
import { FormModel } from './form.model';
import { FormFieldTypes } from './form-field-types';
describe('ContainerModel', () => {
it('should store the form reference', () => {
let form = new FormModel();
let model = new ContainerModel(form);
expect(model.form).toBe(form);
});
it('should store original json', () => {
let json = {};
let model = new ContainerModel(null, json);
expect(model.json).toBe(json);
});
it('should have 1 column layout by default', () => {
let container = new ContainerModel(null, null);
expect(container.numberOfColumns).toBe(1);
});
it('should be expanded by default', () => {
let container = new ContainerModel(null, null);
expect(container.isExpanded).toBeTruthy();
});
it('should setup with json config', () => {
let json = {
fieldType: '<type>',
id: '<id>',
name: '<name>',
type: '<type>',
tab: '<tab>',
numberOfColumns: 2,
params: {}
};
let container = new ContainerModel(null, json);
Object.keys(json).forEach(key => {
expect(container[key]).toEqual(json[key]);
});
});
it('should wrap fields into columns on setup', () => {
let form = new FormModel();
let json = {
fieldType: '<type>',
id: '<id>',
name: '<name>',
type: '<type>',
tab: '<tab>',
numberOfColumns: 3,
params: {},
fields: {
'1': [
{ id: 'field-1' },
{ id: 'field-3' }
],
'2': [
{ id: 'field-2' }
],
'3': null
}
};
let container = new ContainerModel(form, json);
expect(container.columns.length).toBe(3);
let col1 = container.columns[0];
expect(col1.fields.length).toBe(2);
expect(col1.fields[0].id).toBe('field-1');
expect(col1.fields[1].id).toBe('field-3');
let col2 = container.columns[1];
expect(col2.fields.length).toBe(1);
expect(col2.fields[0].id).toBe('field-2');
let col3 = container.columns[2];
expect(col3.fields.length).toBe(0);
});
it('should allow collapsing only when of a group type', () => {
let container = new ContainerModel(new FormModel(), {
type: FormFieldTypes.CONTAINER,
params: {
allowCollapse: true
}
});
expect(container.isCollapsible()).toBeFalsy();
container.type = FormFieldTypes.GROUP;
expect(container.isCollapsible()).toBeTruthy();
});
it('should allow collapsing only when explicitly defined in params', () => {
let container = new ContainerModel(new FormModel(), {
type: FormFieldTypes.GROUP,
params: {}
});
expect(container.isCollapsible()).toBeFalsy();
container = new ContainerModel(new FormModel(), {
type: FormFieldTypes.GROUP,
params: {
allowCollapse: true
}
});
expect(container.isCollapsible()).toBeTruthy();
});
it('should be collapsed by default', () => {
let container = new ContainerModel(new FormModel(), {
type: FormFieldTypes.GROUP,
params: {
allowCollapse: true,
collapseByDefault: true
}
});
expect(container.isCollapsedByDefault()).toBeTruthy();
});
});

View File

@ -83,11 +83,13 @@ export class ContainerModel extends FormWidgetModel {
this.columns.push(col);
}
Object.keys(json.fields).map(key => {
let fields = (json.fields[key] || []).map(f => new FormFieldModel(form, f));
let col = this.columns[parseInt(key, 10) - 1];
col.fields = fields;
});
if (json.fields) {
Object.keys(json.fields).map(key => {
let fields = (json.fields[key] || []).map(f => new FormFieldModel(form, f));
let col = this.columns[parseInt(key, 10) - 1];
col.fields = fields;
});
}
this.isExpanded = !this.isCollapsedByDefault();
}

View File

@ -29,4 +29,8 @@ export class FormFieldTypes {
FormFieldTypes.DISPLAY_VALUE,
FormFieldTypes.READONLY_TEXT
];
static isReadOnlyType(type: string) {
return FormFieldTypes.READONLY_TYPES.indexOf(type) > -1;
}
}

View File

@ -0,0 +1,243 @@
/*!
* @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 } from '@angular/core/testing';
import { FormFieldModel } from './form-field.model';
import { FormFieldTypes } from './form-field-types';
import { FormModel } from './form.model';
describe('FormFieldModel', () => {
it('should store the form reference', () => {
let form = new FormModel();
let model = new FormFieldModel(form);
expect(model.form).toBe(form);
});
it('should store original json', () => {
let json = {};
let model = new FormFieldModel(new FormModel(), json);
expect(model.json).toBe(json);
});
it('should setup with json config', () => {
let json = {
fieldType: '<fieldType>',
id: '<id>',
name: '<name>',
type: '<type>',
required: true,
readOnly: true,
overrideId: true,
tab: '<tab>',
restUrl: '<rest-url>',
restResponsePath: '<rest-path>',
restIdProperty: '<rest-id>',
restLabelProperty: '<rest-label>',
colspan: 1,
options: [],
hasEmptyValue: true,
className: '<class>',
optionType: '<type>',
params: {},
hyperlinkUrl: '<url>',
displayText: '<text>',
value: '<value>'
};
let field = new FormFieldModel(new FormModel(), json);
Object.keys(json).forEach(key => {
expect(field[key]).toBe(json[key]);
});
});
it('should setup empty options collection', () => {
let field = new FormFieldModel(new FormModel(), null);
expect(field.options).toBeDefined();
expect(field.options.length).toBe(0);
field = new FormFieldModel(new FormModel(), { options: null });
expect(field.options).toBeDefined();
expect(field.options.length).toBe(0);
});
it('should setup empty params', () => {
let field = new FormFieldModel(new FormModel(), null);
expect(field.params).toEqual({});
field = new FormFieldModel(new FormModel(), { params: null });
expect(field.params).toEqual({});
});
it('should update form on every value change', () => {
let form = new FormModel();
let field = new FormFieldModel(form, { id: 'field1' });
let value = 10;
spyOn(field, 'updateForm').and.callThrough();
field.value = value;
expect(field.value).toBe(value);
expect(field.updateForm).toHaveBeenCalled();
expect(form.values['field1']).toBe(value);
});
it('should get form readonly state', () => {
let form = new FormModel();
let field = new FormFieldModel(form, null);
expect(field.readOnly).toBeFalsy();
form.readOnly = true;
expect(field.readOnly).toBeTruthy();
});
it('should take own readonly state if form is writable', () => {
let form = new FormModel();
let field = new FormFieldModel(form, { readOnly: true });
expect(form.readOnly).toBeFalsy();
expect(field.readOnly).toBeTruthy();
});
it('should parse and convert empty dropdown value', () => {
let field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN,
value: ''
});
expect(field.value).toBe('empty');
});
it('should parse and leave dropdown value as is', () => {
let field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.DROPDOWN,
options: [],
value: 'deferred'
});
expect(field.value).toBe('deferred');
});
it('should parse and resolve radio button value', () => {
let field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.RADIO_BUTTONS,
options: [
{ id: 'opt1', value: 'Option 1' },
{ id: 'opt2', value: 'Option 2' }
],
value: 'opt2'
});
expect(field.value).toBe('opt2');
});
it('should parse and fall back to first radio button value', () => {
let field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.RADIO_BUTTONS,
options: [
{ id: 'opt1', value: 'Option 1' },
{ id: 'opt2', value: 'Option 2' }
],
value: 'opt3'
});
expect(field.value).toBe('opt1');
});
it('should parse and leave radio button value as is', () => {
let field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.RADIO_BUTTONS,
options: [],
value: 'deferred-radio'
});
expect(field.value).toBe('deferred-radio');
});
it('should update form with empty dropdown value', () => {
let form = new FormModel();
let field = new FormFieldModel(form, {
id: 'dropdown-1',
type: FormFieldTypes.DROPDOWN
});
field.value = 'empty';
expect(form.values['dropdown-1']).toEqual({});
field.value = '';
expect(form.values['dropdown-1']).toEqual({});
});
it('should update form with dropdown value', () => {
let form = new FormModel();
let field = new FormFieldModel(form, {
id: 'dropdown-2',
type: FormFieldTypes.DROPDOWN,
options: [
{ id: 'opt1', value: 'Option 1' },
{ id: 'opt2', value: 'Option 2' }
]
});
field.value = 'opt2';
expect(form.values['dropdown-2']).toEqual(field.options[1]);
});
it('should update form with radio button value', () => {
let form = new FormModel();
let field = new FormFieldModel(form, {
id: 'radio-1',
type: FormFieldTypes.RADIO_BUTTONS,
options: [
{ id: 'opt1', value: 'Option 1' },
{ id: 'opt2', value: 'Option 2' }
]
});
field.value = 'opt2';
expect(form.values['radio-1']).toEqual(field.options[1]);
});
it('should update form with the first radio button value', () => {
let form = new FormModel();
let field = new FormFieldModel(form, {
id: 'radio-2',
type: FormFieldTypes.RADIO_BUTTONS,
options: [
{ id: 'opt1', value: 'Option 1' },
{ id: 'opt2', value: 'Option 2' }
]
});
field.value = 'missing';
expect(form.values['radio-2']).toEqual(field.options[0]);
});
it('should not update form with display-only field value', () => {
let form = new FormModel();
FormFieldTypes.READONLY_TYPES.forEach(typeName => {
let field = new FormFieldModel(form, {
id: typeName,
type: typeName
});
field.value = '<some value>';
expect(form.values[field.id]).toBeUndefined();
});
});
});

View File

@ -92,11 +92,7 @@ export class FormFieldModel extends FormWidgetModel {
}
}
static isReadOnlyType(type: string) {
return FormFieldTypes.READONLY_TYPES.indexOf(type) > -1;
}
private parseValue(json: any): any {
parseValue(json: any): any {
let value = json.value;
/*
@ -151,10 +147,10 @@ export class FormFieldModel extends FormWidgetModel {
if (entry.length > 0) {
this.form.values[this.id] = entry[0];
} else if (this.options.length > 0) {
this.form.values[this.id] = this.options[0].id;
this.form.values[this.id] = this.options[0];
}
} else {
if (!FormFieldModel.isReadOnlyType(this.type)) {
if (!FormFieldTypes.isReadOnlyType(this.type)) {
this.form.values[this.id] = this.value;
}
}

View File

@ -0,0 +1,46 @@
/*!
* @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 } from '@angular/core/testing';
import { FormModel } from './form.model';
import { FormOutcomeModel } from './form-outcome.model';
describe('FormOutcomeModel', () => {
it('should setup with json config', () => {
let json = {
id: '<id>',
name: '<name>'
};
let model = new FormOutcomeModel(null, json);
expect(model.id).toBe(json.id);
expect(model.name).toBe(json.name);
});
it('should store the form reference', () => {
let form = new FormModel();
let model = new FormOutcomeModel(form);
expect(model.form).toBe(form);
});
it('should store original json', () => {
let json = {};
let model = new FormOutcomeModel(null, json);
expect(model.json).toBe(json);
});
});

View File

@ -0,0 +1,36 @@
/*!
* @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 } from '@angular/core/testing';
import { FormModel } from './form.model';
import { FormWidgetModel } from './form-widget.model';
describe('FormWidgetModel', () => {
it('should store the form reference', () => {
let form = new FormModel();
let model = new FormWidgetModel(form, null);
expect(model.form).toBe(form);
});
it('should store original json', () => {
let json = {};
let model = new FormWidgetModel(null, json);
expect(model.json).toBe(json);
});
});

View File

@ -0,0 +1,62 @@
/*!
* @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 } from '@angular/core/testing';
import { FormModel } from './form.model';
describe('FormModel', () => {
it('should store original json', () => {
let json = {};
let form = new FormModel(json);
expect(form.json).toBe(json);
});
it('should setup properties with json', () => {
let json = {
id: '<id>',
name: '<name>',
taskId: '<task-id>',
taskName: '<task-name>'
};
let form = new FormModel(json);
Object.keys(json).forEach(key => {
expect(form[key]).toEqual(form[key]);
});
});
it('should take form name when task name is missing', () => {
let json = {
id: '<id>',
name: '<name>'
};
let form = new FormModel(json);
expect(form.taskName).toBe(json.name);
});
it('should use fallback value for task name', () => {
let form = new FormModel({});
expect(form.taskName).toBe(FormModel.UNSET_TASK_NAME);
});
it('should set readonly state from params', () => {
let form = new FormModel({}, null, null, true);
expect(form.readOnly).toBeTruthy();
});
});

View File

@ -23,12 +23,12 @@ import { FormOutcomeModel } from './form-outcome.model';
export class FormModel {
private UNSET_TASK_NAME: string = 'Nameless task';
static UNSET_TASK_NAME: string = 'Nameless task';
private _id: string;
private _name: string;
private _taskId: string;
private _taskName: string = this.UNSET_TASK_NAME;
private _taskName: string = FormModel.UNSET_TASK_NAME;
get id(): string {
return this._id;
@ -79,7 +79,7 @@ export class FormModel {
this._id = json.id;
this._name = json.name;
this._taskId = json.taskId;
this._taskName = json.taskName || json.name || this.UNSET_TASK_NAME;
this._taskName = json.taskName || json.name || FormModel.UNSET_TASK_NAME;
let tabCache: FormWidgetModelCache<TabModel> = {};
@ -89,7 +89,7 @@ export class FormModel {
return model;
});
this.fields = (json.fields || json.formDefinition.fields || []).map(obj => new ContainerModel(this, obj));
this.fields = this.parseContainerFields(json);
if (data) {
this.loadData(data);
@ -127,6 +127,20 @@ export class FormModel {
}
}
private parseContainerFields(json: any): ContainerModel[] {
let fields = [];
if (json) {
if (json.fields) {
fields = json.fields;
} else if (json.formDefinition && json.formDefinition.fields) {
fields = json.formDefinition.fields;
}
}
return fields.map(obj => new ContainerModel(this, obj));
}
// Loads external data and overrides field values
// Typically used when form definition and form data coming from different sources
private loadData(data: any) {

View File

@ -0,0 +1,70 @@
/*!
* @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 } from '@angular/core/testing';
import { FormModel } from './form.model';
import { TabModel } from './tab.model';
import { ContainerModel } from './container.model';
describe('TabModel', () => {
it('should setup with json config', () => {
let json = {
id: '<id>',
title: '<title>',
visibilityCondition: '<condition>'
};
let model = new TabModel(null, json);
expect(model.id).toBe(json.id);
expect(model.title).toBe(json.title);
expect(model.visibilityCondition).toBe(json.visibilityCondition);
});
it('should not setup with json config', () => {
let model = new TabModel(null, null);
expect(model.id).toBeUndefined();
expect(model.title).toBeUndefined();
expect(model.visibilityCondition).toBeUndefined();
});
it('should evaluate content based on fields', () => {
let model = new TabModel(null, null);
model.fields = null;
expect(model.hasContent()).toBeFalsy();
model.fields = [];
expect(model.hasContent()).toBeFalsy();
model.fields = [new ContainerModel(null, null)];
expect(model.hasContent()).toBeTruthy();
});
it('should store the form reference', () => {
let form = new FormModel();
let model = new TabModel(form);
expect(model.form).toBe(form);
});
it('should store original json', () => {
let json = {};
let model = new TabModel(null, json);
expect(model.json).toBe(json);
});
});