From 318edcb9a1ddb9c932648da9bb036ad5c1f4ef1d Mon Sep 17 00:00:00 2001 From: James Scharett Date: Fri, 25 May 2018 13:02:17 -0400 Subject: [PATCH 01/18] Abstract Widget Created Abstract widget and started migrating widget to use it --- .../abstract-widget.component.ts | 29 +++++++++++++++++++ .../widget-library/add-reference.component.ts | 17 ++++------- .../src/widget-library/button.component.ts | 26 ++++------------- .../src/widget-library/checkbox.component.ts | 24 +++++---------- .../widget-library/checkboxes.component.ts | 23 +++++---------- src/lib/src/widget-library/file.component.ts | 28 ++++-------------- .../src/widget-library/hidden.component.ts | 23 ++++----------- src/lib/src/widget-library/index.ts | 2 ++ src/lib/src/widget-library/input.component.ts | 27 ++++------------- .../src/widget-library/message.component.ts | 16 ++++------ src/lib/src/widget-library/none.component.ts | 16 ++++++---- .../src/widget-library/number.component.ts | 27 +++++------------ .../src/widget-library/one-of.component.ts | 27 ++++------------- .../src/widget-library/radios.component.ts | 24 ++++----------- src/lib/src/widget-library/root.component.ts | 17 +++++------ 15 files changed, 115 insertions(+), 211 deletions(-) create mode 100644 src/lib/src/widget-library/abstract-widget.component.ts diff --git a/src/lib/src/widget-library/abstract-widget.component.ts b/src/lib/src/widget-library/abstract-widget.component.ts new file mode 100644 index 00000000..45df5210 --- /dev/null +++ b/src/lib/src/widget-library/abstract-widget.component.ts @@ -0,0 +1,29 @@ +import { Input, OnInit } from '@angular/core'; +import { AbstractControl } from '@angular/forms'; + +import { JsonSchemaFormService } from '../json-schema-form.service'; + +export abstract class AbstractWidget implements OnInit { + boundControl = false; + controlDisabled = false; + controlName: string; + controlValue: any; + formControl: AbstractControl; + options: any; + + @Input() layoutNode: any; + @Input() layoutIndex: Array; + @Input() dataIndex: Array; + + + constructor(protected jsf: JsonSchemaFormService) {} + + ngOnInit() { + this.jsf.initializeControl(this); + this.options = this.layoutNode.options || {}; + } + + updateValue(event) { + this.jsf.updateValue(this, event.target.value); + } +} diff --git a/src/lib/src/widget-library/add-reference.component.ts b/src/lib/src/widget-library/add-reference.component.ts index 2c17c2cd..f2f12a40 100755 --- a/src/lib/src/widget-library/add-reference.component.ts +++ b/src/lib/src/widget-library/add-reference.component.ts @@ -1,7 +1,8 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'add-reference-widget', @@ -15,21 +16,13 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; `, changeDetection: ChangeDetectionStrategy.Default, }) -export class AddReferenceComponent implements OnInit { - options: any; +export class AddReferenceComponent extends AbstractWidget { itemCount: number; previousLayoutIndex: number[]; previousDataIndex: number[]; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.options = this.layoutNode.options || {}; + constructor(jsf: JsonSchemaFormService) { + super(jsf); } get showAddButton(): boolean { diff --git a/src/lib/src/widget-library/button.component.ts b/src/lib/src/widget-library/button.component.ts index e52d8450..c775b931 100755 --- a/src/lib/src/widget-library/button.component.ts +++ b/src/lib/src/widget-library/button.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'button-widget', @@ -23,31 +23,17 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; `, }) -export class ButtonComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; +export class ButtonComponent extends AbstractWidget { - constructor( - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + constructor(jsf: JsonSchemaFormService) { + super(jsf); } updateValue(event) { if (typeof this.options.onClick === 'function') { this.options.onClick(event); } else { - this.jsf.updateValue(this, event.target.value); + super.updateValue(event); } } } diff --git a/src/lib/src/widget-library/checkbox.component.ts b/src/lib/src/widget-library/checkbox.component.ts index 27e06c3c..4563583e 100755 --- a/src/lib/src/widget-library/checkbox.component.ts +++ b/src/lib/src/widget-library/checkbox.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'checkbox-widget', @@ -37,26 +37,16 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; [innerHTML]="options?.title"> `, }) -export class CheckboxComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; +export class CheckboxComponent extends AbstractWidget implements OnInit { trueValue: any = true; falseValue: any = false; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + super.ngOnInit(); if (this.controlValue === null || this.controlValue === undefined) { this.controlValue = this.options.title; } diff --git a/src/lib/src/widget-library/checkboxes.component.ts b/src/lib/src/widget-library/checkboxes.component.ts index cc3069db..fc3f6599 100755 --- a/src/lib/src/widget-library/checkboxes.component.ts +++ b/src/lib/src/widget-library/checkboxes.component.ts @@ -1,8 +1,9 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { FormArray, AbstractControl } from '@angular/forms'; import { JsonSchemaFormService, TitleMapItem } from '../json-schema-form.service'; import { buildTitleMap } from '../shared'; +import { AbstractWidget } from '.'; @Component({ selector: 'checkboxes-widget', @@ -56,29 +57,19 @@ import { buildTitleMap } from '../shared'; `, }) -export class CheckboxesComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; +export class CheckboxesComponent extends AbstractWidget implements OnInit { layoutOrientation: string; formArray: AbstractControl; checkboxList: TitleMapItem[] = []; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { - this.options = this.layoutNode.options || {}; this.layoutOrientation = (this.layoutNode.type === 'checkboxes-inline' || this.layoutNode.type === 'checkboxbuttons') ? 'horizontal' : 'vertical'; - this.jsf.initializeControl(this); + super.ngOnInit(); this.checkboxList = buildTitleMap( this.options.titleMap || this.options.enumNames, this.options.enum, true ); diff --git a/src/lib/src/widget-library/file.component.ts b/src/lib/src/widget-library/file.component.ts index 8eb9f57a..6be0978f 100755 --- a/src/lib/src/widget-library/file.component.ts +++ b/src/lib/src/widget-library/file.component.ts @@ -1,35 +1,19 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; + // TODO: Add this control @Component({ selector: 'file-widget', template: ``, }) -export class FileComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - - constructor( - private jsf: JsonSchemaFormService - ) { } +export class FileComponent extends AbstractWidget { - ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + constructor(jsf: JsonSchemaFormService) { + super(jsf); } - updateValue(event) { - this.jsf.updateValue(this, event.target.value); - } } diff --git a/src/lib/src/widget-library/hidden.component.ts b/src/lib/src/widget-library/hidden.component.ts index db9d9809..803752e5 100755 --- a/src/lib/src/widget-library/hidden.component.ts +++ b/src/lib/src/widget-library/hidden.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'hidden-widget', @@ -18,21 +18,10 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; type="hidden" [value]="controlValue">`, }) -export class HiddenComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; +export class HiddenComponent extends AbstractWidget { - constructor( - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.jsf.initializeControl(this); + constructor(jsf: JsonSchemaFormService) { + super(jsf); } + } diff --git a/src/lib/src/widget-library/index.ts b/src/lib/src/widget-library/index.ts index 1e370d32..572299eb 100755 --- a/src/lib/src/widget-library/index.ts +++ b/src/lib/src/widget-library/index.ts @@ -1,3 +1,4 @@ +import { AbstractWidget } from './abstract-widget.component'; import { AddReferenceComponent } from './add-reference.component'; import { OneOfComponent } from './one-of.component'; import { ButtonComponent } from './button.component'; @@ -30,6 +31,7 @@ export const BASIC_WIDGETS = [ TemplateComponent, TextareaComponent ]; +export { AbstractWidget } from './abstract-widget.component'; export { AddReferenceComponent } from './add-reference.component'; export { OneOfComponent } from './one-of.component'; export { ButtonComponent } from './button.component'; diff --git a/src/lib/src/widget-library/input.component.ts b/src/lib/src/widget-library/input.component.ts index 29ded3da..146421a9 100755 --- a/src/lib/src/widget-library/input.component.ts +++ b/src/lib/src/widget-library/input.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'input-widget', @@ -48,28 +48,11 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; `, }) -export class InputComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: string; - controlDisabled = false; - boundControl = false; - options: any; +export class InputComponent extends AbstractWidget { autoCompleteList: string[] = []; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + constructor(jsf: JsonSchemaFormService) { + super(jsf); } - updateValue(event) { - this.jsf.updateValue(this, event.target.value); - } } diff --git a/src/lib/src/widget-library/message.component.ts b/src/lib/src/widget-library/message.component.ts index 1e6bff6e..7d257ef4 100755 --- a/src/lib/src/widget-library/message.component.ts +++ b/src/lib/src/widget-library/message.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'message-widget', @@ -10,16 +10,12 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; [class]="options?.labelHtmlClass || ''" [innerHTML]="message">`, }) -export class MessageComponent implements OnInit { - options: any; +export class MessageComponent extends AbstractWidget implements OnInit { message: string = null; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { this.options = this.layoutNode.options || {}; diff --git a/src/lib/src/widget-library/none.component.ts b/src/lib/src/widget-library/none.component.ts index f0c64794..af14c2a4 100755 --- a/src/lib/src/widget-library/none.component.ts +++ b/src/lib/src/widget-library/none.component.ts @@ -1,12 +1,16 @@ -import { Component, Input } from '@angular/core'; -import { FormGroup } from '@angular/forms'; +import { Component } from '@angular/core'; + +import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'none-widget', template: ``, }) -export class NoneComponent { - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; +export class NoneComponent extends AbstractWidget { + + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } + } diff --git a/src/lib/src/widget-library/number.component.ts b/src/lib/src/widget-library/number.component.ts index 5fe6162f..a6d7a766 100755 --- a/src/lib/src/widget-library/number.component.ts +++ b/src/lib/src/widget-library/number.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'number-widget', @@ -47,32 +47,19 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; `, }) -export class NumberComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; +export class NumberComponent extends AbstractWidget implements OnInit { allowNegative = true; allowDecimal = true; allowExponents = false; lastValidNumber = ''; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + super.ngOnInit(); if (this.layoutNode.dataType === 'integer') { this.allowDecimal = false; } } - updateValue(event) { - this.jsf.updateValue(this, event.target.value); - } } diff --git a/src/lib/src/widget-library/one-of.component.ts b/src/lib/src/widget-library/one-of.component.ts index 23384a98..6465140d 100644 --- a/src/lib/src/widget-library/one-of.component.ts +++ b/src/lib/src/widget-library/one-of.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; // TODO: Add this control @@ -9,27 +9,10 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; selector: 'one-of-widget', template: ``, }) -export class OneOfComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; +export class OneOfComponent extends AbstractWidget { - constructor( - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + constructor(jsf: JsonSchemaFormService) { + super(jsf); } - updateValue(event) { - this.jsf.updateValue(this, event.target.value); - } } diff --git a/src/lib/src/widget-library/radios.component.ts b/src/lib/src/widget-library/radios.component.ts index 2b904d30..eed71af1 100755 --- a/src/lib/src/widget-library/radios.component.ts +++ b/src/lib/src/widget-library/radios.component.ts @@ -3,6 +3,7 @@ import { AbstractControl } from '@angular/forms'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap } from '../shared'; +import { AbstractWidget } from '.'; @Component({ selector: 'radios-widget', @@ -63,25 +64,16 @@ import { buildTitleMap } from '../shared'; `, }) -export class RadiosComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; +export class RadiosComponent extends AbstractWidget implements OnInit { layoutOrientation = 'vertical'; radiosList: any[] = []; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { - this.options = this.layoutNode.options || {}; + super.ngOnInit(); if (this.layoutNode.type === 'radios-inline' || this.layoutNode.type === 'radiobuttons' ) { @@ -91,10 +83,6 @@ export class RadiosComponent implements OnInit { this.options.titleMap || this.options.enumNames, this.options.enum, true ); - this.jsf.initializeControl(this); } - updateValue(event) { - this.jsf.updateValue(this, event.target.value); - } } diff --git a/src/lib/src/widget-library/root.component.ts b/src/lib/src/widget-library/root.component.ts index 9f110404..1f52f2c1 100755 --- a/src/lib/src/widget-library/root.component.ts +++ b/src/lib/src/widget-library/root.component.ts @@ -1,7 +1,8 @@ -import { Component, Input, Host } from '@angular/core'; +import { Component, Input, Host, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { hasValue, JsonPointer } from '../shared'; +import { AbstractWidget } from '.'; @Component({ selector: 'root-widget', @@ -47,17 +48,15 @@ import { hasValue, JsonPointer } from '../shared'; } `], }) -export class RootComponent { - options: any; - @Input() dataIndex: number[]; - @Input() layoutIndex: number[]; - @Input() layout: any[]; +export class RootComponent extends AbstractWidget implements OnInit { @Input() isOrderable: boolean; @Input() isFlexItem = false; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } + + ngOnInit() {} isDraggable(node: any): boolean { return node.arrayItem && node.type !== '$ref' && From 61b16d87f552a8e7798c3f59ab9212c05a209b65 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Fri, 25 May 2018 18:02:18 -0400 Subject: [PATCH 02/18] Abstract widget Refactored remaining widgets to use AbstractWidget --- .../src/widget-library/section.component.ts | 18 ++++------ .../select-framework.component.ts | 34 ++++--------------- .../widget-library/select-widget.component.ts | 34 ++++--------------- .../src/widget-library/select.component.ts | 25 ++++---------- .../src/widget-library/submit.component.ts | 24 ++++--------- src/lib/src/widget-library/tab.component.ts | 15 ++++---- src/lib/src/widget-library/tabs.component.ts | 15 ++++---- .../src/widget-library/template.component.ts | 31 +++++++++-------- .../src/widget-library/textarea.component.ts | 27 +++------------ 9 files changed, 66 insertions(+), 157 deletions(-) diff --git a/src/lib/src/widget-library/section.component.ts b/src/lib/src/widget-library/section.component.ts index fb160db4..2d457a09 100755 --- a/src/lib/src/widget-library/section.component.ts +++ b/src/lib/src/widget-library/section.component.ts @@ -1,7 +1,8 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { toTitleCase } from '../shared'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'section-widget', @@ -73,25 +74,20 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; .expanded > legend:before, .expanded > label:before { content: '▼'; padding-right: .2em; } `], }) -export class SectionComponent implements OnInit { - options: any; +export class SectionComponent extends AbstractWidget implements OnInit { expanded = true; containerType: string; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } get sectionTitle() { return this.options.notitle ? null : this.jsf.setItemTitle(this); } ngOnInit() { - this.jsf.initializeControl(this); - this.options = this.layoutNode.options || {}; + super.ngOnInit(); this.expanded = typeof this.options.expanded === 'boolean' ? this.options.expanded : !this.options.expandable; switch (this.layoutNode.type) { diff --git a/src/lib/src/widget-library/select-framework.component.ts b/src/lib/src/widget-library/select-framework.component.ts index 78898305..aa1dbee6 100755 --- a/src/lib/src/widget-library/select-framework.component.ts +++ b/src/lib/src/widget-library/select-framework.component.ts @@ -1,45 +1,23 @@ -import { - Component, ComponentFactoryResolver, ComponentRef, Input, - OnChanges, OnInit, ViewChild, ViewContainerRef -} from '@angular/core'; +import { Component, ComponentFactoryResolver } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { TemplateComponent } from '.'; @Component({ selector: 'select-framework-widget', template: `
`, }) -export class SelectFrameworkComponent implements OnChanges, OnInit { - newComponent: ComponentRef = null; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - @ViewChild('widgetContainer', { read: ViewContainerRef }) - widgetContainer: ViewContainerRef; +export class SelectFrameworkComponent extends TemplateComponent { - constructor( - private componentFactory: ComponentFactoryResolver, - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.updateComponent(); - } - - ngOnChanges() { - this.updateComponent(); + constructor(jsf: JsonSchemaFormService, componentFactory: ComponentFactoryResolver) { + super(jsf, componentFactory); } - updateComponent() { + protected createComponent() { if (!this.newComponent && this.jsf.framework) { this.newComponent = this.widgetContainer.createComponent( this.componentFactory.resolveComponentFactory(this.jsf.framework) ); } - if (this.newComponent) { - for (let input of ['layoutNode', 'layoutIndex', 'dataIndex']) { - this.newComponent.instance[input] = this[input]; - } - } } } diff --git a/src/lib/src/widget-library/select-widget.component.ts b/src/lib/src/widget-library/select-widget.component.ts index 86dfdf9e..ec471832 100755 --- a/src/lib/src/widget-library/select-widget.component.ts +++ b/src/lib/src/widget-library/select-widget.component.ts @@ -1,45 +1,23 @@ -import { - Component, ComponentFactoryResolver, ComponentRef, Input, - OnChanges, OnInit, ViewChild, ViewContainerRef -} from '@angular/core'; +import { Component, ComponentFactoryResolver } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { TemplateComponent } from '.'; @Component({ selector: 'select-widget-widget', template: `
`, }) -export class SelectWidgetComponent implements OnChanges, OnInit { - newComponent: ComponentRef = null; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - @ViewChild('widgetContainer', { read: ViewContainerRef }) - widgetContainer: ViewContainerRef; +export class SelectWidgetComponent extends TemplateComponent { - constructor( - private componentFactory: ComponentFactoryResolver, - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.updateComponent(); - } - - ngOnChanges() { - this.updateComponent(); + constructor(jsf: JsonSchemaFormService, componentFactory: ComponentFactoryResolver) { + super(jsf, componentFactory); } - updateComponent() { + protected createComponent() { if (!this.newComponent && (this.layoutNode || {}).widget) { this.newComponent = this.widgetContainer.createComponent( this.componentFactory.resolveComponentFactory(this.layoutNode.widget) ); } - if (this.newComponent) { - for (let input of ['layoutNode', 'layoutIndex', 'dataIndex']) { - this.newComponent.instance[input] = this[input]; - } - } } } diff --git a/src/lib/src/widget-library/select.component.ts b/src/lib/src/widget-library/select.component.ts index 2c9fae72..b7e5c2ca 100755 --- a/src/lib/src/widget-library/select.component.ts +++ b/src/lib/src/widget-library/select.component.ts @@ -3,6 +3,8 @@ import { AbstractControl } from '@angular/forms'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap, isArray } from '../shared'; +import { AbstractWidget } from '.'; +import { AbstractWidget } from '.'; @Component({ selector: 'select-widget', @@ -63,33 +65,20 @@ import { buildTitleMap, isArray } from '../shared'; `, }) -export class SelectComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; +export class SelectComponent extends AAbstractWidget implements OnInit { selectList: any[] = []; isArray = isArray; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { - this.options = this.layoutNode.options || {}; + super.ngOnInit(); this.selectList = buildTitleMap( this.options.titleMap || this.options.enumNames, this.options.enum, !!this.options.required, !!this.options.flatList ); - this.jsf.initializeControl(this); } - updateValue(event) { - this.jsf.updateValue(this, event.target.value); - } } diff --git a/src/lib/src/widget-library/submit.component.ts b/src/lib/src/widget-library/submit.component.ts index 629177ad..a8c10544 100755 --- a/src/lib/src/widget-library/submit.component.ts +++ b/src/lib/src/widget-library/submit.component.ts @@ -1,8 +1,8 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { hasOwn } from '../shared/utility.functions'; +import { AbstractWidget } from '.'; @Component({ selector: 'submit-widget', @@ -22,24 +22,14 @@ import { hasOwn } from '../shared/utility.functions'; (click)="updateValue($event)"> `, }) -export class SubmitComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; +export class SubmitComponent extends AbstractWidget implements OnInit { - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + super.ngOnInit(); if (hasOwn(this.options, 'disabled')) { this.controlDisabled = this.options.disabled; } else if (this.jsf.formOptions.disableInvalidSubmit) { diff --git a/src/lib/src/widget-library/tab.component.ts b/src/lib/src/widget-library/tab.component.ts index 99a162fe..d7f32c73 100755 --- a/src/lib/src/widget-library/tab.component.ts +++ b/src/lib/src/widget-library/tab.component.ts @@ -1,6 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'tab-widget', @@ -12,15 +13,11 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; [layout]="layoutNode.items"> `, }) -export class TabComponent implements OnInit { - options: any; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; +export class TabComponent extends AbstractWidget implements OnInit { - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { this.options = this.layoutNode.options || {}; diff --git a/src/lib/src/widget-library/tabs.component.ts b/src/lib/src/widget-library/tabs.component.ts index f0497842..0d2c15d5 100755 --- a/src/lib/src/widget-library/tabs.component.ts +++ b/src/lib/src/widget-library/tabs.component.ts @@ -1,6 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'tabs-widget', @@ -35,18 +36,14 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; `, styles: [` a { cursor: pointer; } `], }) -export class TabsComponent implements OnInit { - options: any; +export class TabsComponent extends AbstractWidget implements OnInit { itemCount: number; selectedItem = 0; showAddTab = true; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; - constructor( - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService) { + super(jsf); + } ngOnInit() { this.options = this.layoutNode.options || {}; diff --git a/src/lib/src/widget-library/template.component.ts b/src/lib/src/widget-library/template.component.ts index e48eae17..16e762f7 100755 --- a/src/lib/src/widget-library/template.component.ts +++ b/src/lib/src/widget-library/template.component.ts @@ -1,26 +1,23 @@ import { - Component, ComponentFactoryResolver, ComponentRef, Input, + Component, ComponentFactoryResolver, ComponentRef, OnChanges, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'template-widget', template: `
`, }) -export class TemplateComponent implements OnInit, OnChanges { +export class TemplateComponent extends AbstractWidget implements OnInit, OnChanges { newComponent: ComponentRef = null; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; @ViewChild('widgetContainer', { read: ViewContainerRef }) widgetContainer: ViewContainerRef; - constructor( - private componentFactory: ComponentFactoryResolver, - private jsf: JsonSchemaFormService - ) { } + constructor(jsf: JsonSchemaFormService, protected componentFactory: ComponentFactoryResolver) { + super(jsf); + } ngOnInit() { this.updateComponent(); @@ -30,16 +27,20 @@ export class TemplateComponent implements OnInit, OnChanges { this.updateComponent(); } - updateComponent() { - if (!this.newComponent && this.layoutNode.options.template) { - this.newComponent = this.widgetContainer.createComponent( - this.componentFactory.resolveComponentFactory(this.layoutNode.options.template) - ); - } + protected updateComponent() { + this.createComponent(); if (this.newComponent) { for (let input of ['layoutNode', 'layoutIndex', 'dataIndex']) { this.newComponent.instance[input] = this[input]; } } } + + protected createComponent(): void { + if (!this.newComponent && this.layoutNode.options.template) { + this.newComponent = this.widgetContainer.createComponent( + this.componentFactory.resolveComponentFactory(this.layoutNode.options.template) + ); + } + } } diff --git a/src/lib/src/widget-library/textarea.component.ts b/src/lib/src/widget-library/textarea.component.ts index d6c7c045..3627a901 100755 --- a/src/lib/src/widget-library/textarea.component.ts +++ b/src/lib/src/widget-library/textarea.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; +import { AbstractWidget } from '.'; @Component({ selector: 'textarea-widget', @@ -41,27 +41,10 @@ import { JsonSchemaFormService } from '../json-schema-form.service'; (input)="updateValue($event)">{{controlValue}} `, }) -export class TextareaComponent implements OnInit { - formControl: AbstractControl; - controlName: string; - controlValue: any; - controlDisabled = false; - boundControl = false; - options: any; - @Input() layoutNode: any; - @Input() layoutIndex: number[]; - @Input() dataIndex: number[]; +export class TextareaComponent extends AbstractWidget { - constructor( - private jsf: JsonSchemaFormService - ) { } - - ngOnInit() { - this.options = this.layoutNode.options || {}; - this.jsf.initializeControl(this); + constructor(jsf: JsonSchemaFormService) { + super(jsf); } - updateValue(event) { - this.jsf.updateValue(this, event.target.value); - } } From c41c0380b69dfb0d7ff6ea4d6fae052ffdd91391 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Sat, 26 May 2018 01:48:29 -0400 Subject: [PATCH 03/18] Clean up from previous commits --- src/lib/src/widget-library/radios.component.ts | 3 +-- src/lib/src/widget-library/select.component.ts | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/lib/src/widget-library/radios.component.ts b/src/lib/src/widget-library/radios.component.ts index eed71af1..66e7d8be 100755 --- a/src/lib/src/widget-library/radios.component.ts +++ b/src/lib/src/widget-library/radios.component.ts @@ -1,5 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap } from '../shared'; diff --git a/src/lib/src/widget-library/select.component.ts b/src/lib/src/widget-library/select.component.ts index b7e5c2ca..b94a3c88 100755 --- a/src/lib/src/widget-library/select.component.ts +++ b/src/lib/src/widget-library/select.component.ts @@ -1,10 +1,8 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl } from '@angular/forms'; +import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap, isArray } from '../shared'; import { AbstractWidget } from '.'; -import { AbstractWidget } from '.'; @Component({ selector: 'select-widget', @@ -65,7 +63,7 @@ import { AbstractWidget } from '.'; `, }) -export class SelectComponent extends AAbstractWidget implements OnInit { +export class SelectComponent extends AbstractWidget implements OnInit { selectList: any[] = []; isArray = isArray; From 86498c781e68ff81120ef350b7592f3527a27bc5 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Sat, 26 May 2018 22:00:19 -0400 Subject: [PATCH 04/18] Fixed test runner for demp --- karma.conf.js | 34 ++++++++ package-lock.json | 166 ++++++++++++++++++++++++++---------- package.json | 9 +- src/demo/tsconfig.spec.json | 9 ++ 4 files changed, 170 insertions(+), 48 deletions(-) create mode 100644 karma.conf.js create mode 100644 src/demo/tsconfig.spec.json diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000..472105a0 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,34 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular/cli'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('karma-mocha-reporter'), + require('@angular/cli/plugins/karma') + ], + client:{ + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + reports: [ 'html', 'lcovonly' ], + fixWebpackSourcePaths: true + }, + angularCli: { + environment: 'dev' + }, + reporters: ['mocha'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['ChromeHeadless'], + singleRun: false + }); +}; diff --git a/package-lock.json b/package-lock.json index 85623f0b..211cd08d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2471,6 +2471,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-versions": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.2.1.tgz", + "integrity": "sha512-2y2nHcopMG/NAyk6vWXlLs86XeM9sik4jmx1tKIgzMi9/RQ2eo758RGpxQO3ErihHmg0RlQITPqgz73y6s7quA==", + "dev": true + }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -5710,7 +5716,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "dev": true, "requires": { "fs.realpath": "1.0.0", @@ -6976,22 +6982,46 @@ "dev": true }, "istanbul-api": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.2.1.tgz", - "integrity": "sha512-oFCwXvd65amgaPCzqrR+a2XjanS1MvpXN6l/MlMUTv6uiA1NOgGX+I0uyq8Lg3GDxsxPsaP1049krz3hIJ5+KA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.1.tgz", + "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==", "dev": true, "requires": { "async": "2.6.0", + "compare-versions": "3.2.1", "fileset": "2.0.3", - "istanbul-lib-coverage": "1.1.1", - "istanbul-lib-hook": "1.1.0", - "istanbul-lib-instrument": "1.9.1", - "istanbul-lib-report": "1.1.2", - "istanbul-lib-source-maps": "1.2.2", - "istanbul-reports": "1.1.3", + "istanbul-lib-coverage": "1.2.0", + "istanbul-lib-hook": "1.2.0", + "istanbul-lib-instrument": "1.10.1", + "istanbul-lib-report": "1.1.4", + "istanbul-lib-source-maps": "1.2.4", + "istanbul-reports": "1.3.0", "js-yaml": "3.7.0", "mkdirp": "0.5.1", "once": "1.4.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", + "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", + "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", + "dev": true, + "requires": { + "babel-generator": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.2.0", + "semver": "5.4.1" + } + } } }, "istanbul-instrumenter-loader": { @@ -7013,9 +7043,9 @@ "dev": true }, "istanbul-lib-hook": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", - "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.0.tgz", + "integrity": "sha512-p3En6/oGkFQV55Up8ZPC2oLxvgSxD8CzA0yBrhRZSh3pfv3OFj9aSGVC0yoerAi/O4u7jUVnOGVX1eVFM+0tmQ==", "dev": true, "requires": { "append-transform": "0.4.0" @@ -7037,25 +7067,33 @@ } }, "istanbul-lib-report": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.2.tgz", - "integrity": "sha512-UTv4VGx+HZivJQwAo1wnRwe1KTvFpfi/NYwN7DcsrdzMXwpRT/Yb6r4SBPoHWj4VuQPakR32g4PUUeyKkdDkBA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz", + "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==", "dev": true, "requires": { - "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-coverage": "1.2.0", "mkdirp": "0.5.1", "path-parse": "1.0.5", "supports-color": "3.2.3" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", + "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", + "dev": true + } } }, "istanbul-lib-source-maps": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.2.tgz", - "integrity": "sha512-8BfdqSfEdtip7/wo1RnrvLpHVEd8zMZEDmOFEnpC6dg0vXflHt9nvoAyQUzig2uMSXfF2OBEYBV3CVjIL9JvaQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.4.tgz", + "integrity": "sha512-UzuK0g1wyQijiaYQxj/CdNycFhAd2TLtO2obKQMTZrZ1jzEMRY3rvpASEKkaxbRR6brvdovfA03znPa/pXcejg==", "dev": true, "requires": { "debug": "3.1.0", - "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-coverage": "1.2.0", "mkdirp": "0.5.1", "rimraf": "2.6.2", "source-map": "0.5.7" @@ -7069,13 +7107,19 @@ "requires": { "ms": "2.0.0" } + }, + "istanbul-lib-coverage": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", + "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", + "dev": true } } }, "istanbul-reports": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.3.tgz", - "integrity": "sha512-ZEelkHh8hrZNI5xDaKwPMFwDsUf5wIEI2bXAFGp1e6deR2mnEKBPhLJEgr4ZBt8Gi6Mj38E/C8kcy9XLggVO2Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.3.0.tgz", + "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==", "dev": true, "requires": { "handlebars": "4.0.11" @@ -7101,15 +7145,15 @@ } }, "jasmine-core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.9.1.tgz", - "integrity": "sha1-trvB2OZSUNVvWIhGFwXr7uuI8i8=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.1.0.tgz", + "integrity": "sha1-pHheE11d9lAk38kiSVPfWFvSdmw=", "dev": true }, "jasmine-spec-reporter": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", - "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "integrity": "sha1-HWMq7ANBZwrTJPkrqEtLMrNeniI=", "dev": true, "requires": { "colors": "1.1.2" @@ -7327,7 +7371,7 @@ "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", "dev": true, "requires": { "fs-access": "1.0.1", @@ -7344,12 +7388,12 @@ } }, "karma-coverage-istanbul-reporter": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.0.tgz", - "integrity": "sha512-A+ssrpqSLICkT5M9TqLjLiZ+erIuEMjUCMccF7/qpDYS+fG0+S7F5+LREJDCsvKavNX2Mb/SAD8kbWJZf/OW3Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.1.tgz", + "integrity": "sha512-UcgrHkFehI5+ivMouD8NH/UOHiX4oCAtwaANylzPFdcAuD52fnCUuelacq2gh8tZ4ydhU3+xiXofSq7j5Ehygw==", "dev": true, "requires": { - "istanbul-api": "1.2.1", + "istanbul-api": "1.3.1", "minimatch": "3.0.4" } }, @@ -7360,12 +7404,37 @@ "dev": true }, "karma-jasmine-html-reporter": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", - "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.1.0.tgz", + "integrity": "sha512-uhNED+4B1axgptXkM8cCa3kztpQqsPrOxhfbjr4FdunNexnU6+cF2bfiIeGfsFMhphVyOMKy/S9LFaOFj8VXRA==", + "dev": true + }, + "karma-mocha-reporter": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", + "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=", "dev": true, "requires": { - "karma-jasmine": "1.1.1" + "chalk": "2.1.0", + "log-symbols": "2.2.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } } }, "karma-source-map-support": { @@ -7633,6 +7702,15 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "2.1.0" + } + }, "log4js": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.5.1.tgz", @@ -11576,7 +11654,7 @@ "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", "dev": true, "requires": { "glob": "7.1.2" @@ -11601,7 +11679,7 @@ "rollup-plugin-commonjs": { "version": "8.2.6", "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-8.2.6.tgz", - "integrity": "sha512-qK0+uhktmnAgZkHkqFuajNmPw93fjrO7+CysDaxWE5jrUR9XSlSvuao5ZJP+XizxA8weakhgYYBtbVz9SGBpjA==", + "integrity": "sha1-J+W5Bp/5QAW7AeAbtGoeSHN4Rnc=", "dev": true, "requires": { "acorn": "5.2.1", @@ -11614,7 +11692,7 @@ "acorn": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", - "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", + "integrity": "sha1-MXrHghgmwixwLWYYmrg1lnXxNdc=", "dev": true } } @@ -13409,7 +13487,7 @@ "typedoc": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.9.0.tgz", - "integrity": "sha512-numP0CtcUK4I1Vssw6E1N/FjyJWpWqhLT4Zb7Gw3i7ca3ElnYh6z41Y/tcUhMsMYn6L8b67E/Fu4XYYKkNaLbA==", + "integrity": "sha1-FZv/fHeEzluR2G8+TMiSjmIECVc=", "dev": true, "requires": { "@types/fs-extra": "4.0.0", @@ -14746,9 +14824,9 @@ "dev": true }, "zone.js": { - "version": "0.8.20", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.20.tgz", - "integrity": "sha512-FXlA37ErSXCMy5RNBcGFgCI/Zivqzr0D19GuvDxhcYIJc7xkFp6c29DKyODJu0Zo+EMyur/WPPgcBh1EHjB9jA==", + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.26.tgz", + "integrity": "sha512-W9Nj+UmBJG251wkCacIkETgra4QgBo/vgoEkb4a2uoLzpQG7qF9nzwoLXWU5xj3Fg2mxGvEDh47mg24vXccYjA==", "dev": true } } diff --git a/package.json b/package.json index 8fe8aedd..00150337 100755 --- a/package.json +++ b/package.json @@ -95,14 +95,15 @@ "core-js": "^2.5.3", "glob": "^7.1.2", "hammerjs": "2.x", - "jasmine-core": "^2.9.1", + "jasmine-core": "^3.1.0", "jasmine-spec-reporter": "^4.2.1", "karma": "^2.0.0", "karma-chrome-launcher": "^2.2.0", "karma-cli": "^1.0.1", - "karma-coverage-istanbul-reporter": "^1.4.0", + "karma-coverage-istanbul-reporter": "^2.0.1", "karma-jasmine": "^1.1.1", - "karma-jasmine-html-reporter": "^0.2.2", + "karma-jasmine-html-reporter": "^1.1.0", + "karma-mocha-reporter": "^2.2.5", "protractor": "^5.2.2", "rimraf": "^2.6.2", "rollup": "^0.55.0", @@ -115,6 +116,6 @@ "tslint": "^5.9.1", "typedoc": "^0.9.0", "typescript": "~2.6.2", - "zone.js": "^0.8.20" + "zone.js": "^0.8.21" } } diff --git a/src/demo/tsconfig.spec.json b/src/demo/tsconfig.spec.json new file mode 100644 index 00000000..f1bcaf32 --- /dev/null +++ b/src/demo/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": "", + "module": "commonjs", + "declaration": false, + "emitDecoratorMetadata": true + } +} From b11be28da831a0b265acfe092c7d9ed8082ef937 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Tue, 29 May 2018 09:38:31 -0400 Subject: [PATCH 05/18] Tests Reworked scripts to get tests running in both demo and lib apps --- .angular-cli.json | 9 +++ package.json | 4 +- src/demo/app/demo.component.spec.ts | 7 +++ src/lib/polyfills.ts | 69 ++++++++++++++++++++++ src/lib/src/framework-library/index.ts | 2 +- src/lib/src/widget-library/widgets.spec.ts | 7 +++ src/lib/test.ts | 32 ++++++++++ 7 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/demo/app/demo.component.spec.ts create mode 100644 src/lib/polyfills.ts create mode 100644 src/lib/src/widget-library/widgets.spec.ts create mode 100644 src/lib/test.ts diff --git a/.angular-cli.json b/.angular-cli.json index 9f282127..cd710ad1 100755 --- a/.angular-cli.json +++ b/.angular-cli.json @@ -5,6 +5,7 @@ }, "apps": [ { + "name": "demo", "root": "src/demo", "outDir": "dist/demo", "assets": [ "assets", "favicon.ico" ], @@ -22,6 +23,14 @@ "dev": "environments/environment.ts", "prod": "environments/environment.prod.ts" } + }, { + "name": "lib", + "root": "src/lib", + "polyfills": "polyfills.ts", + "main": "index.ts", + "test": "test.ts", + "tsconfig": "tsconfig.app.json", + "testTsconfig": "tsconfig.spec.json" } ], "e2e": { diff --git a/package.json b/package.json index 00150337..05765a49 100755 --- a/package.json +++ b/package.json @@ -40,7 +40,9 @@ "ng": "ng", "serve": "ng serve", "start": "ng serve", - "test": "ng test", + "test": "ng test --app lib --sr && ng test --app demo --sr", + "test:lib": "ng test --app lib", + "test:demo": "ng test --app demo", "lint": "ng lint", "docs": "typedoc src/lib/src/", "clean": "rimraf out-ngc dist/*", diff --git a/src/demo/app/demo.component.spec.ts b/src/demo/app/demo.component.spec.ts new file mode 100644 index 00000000..07452a05 --- /dev/null +++ b/src/demo/app/demo.component.spec.ts @@ -0,0 +1,7 @@ +describe('democompoennt', () => { + describe('test', () => { + it('should run', () => { + expect(true).toBeTruthy(); + }); + }); +}); diff --git a/src/lib/polyfills.ts b/src/lib/polyfills.ts new file mode 100644 index 00000000..f8cffb12 --- /dev/null +++ b/src/lib/polyfills.ts @@ -0,0 +1,69 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +import 'core-js/es6/string'; +// import 'core-js/es6/date'; +import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/set'; +import 'core-js/es7/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following to support `@angular/animation`. */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + + +/** Evergreen browsers require these. **/ +import 'core-js/es6/reflect'; +import 'core-js/es7/reflect'; + + +/** ALL Firefox browsers require the following to support `@angular/animation`. **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + + + +/*************************************************************************************************** + * Zone JS is required by Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +/** + * Date, currency, decimal and percent pipes. + * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 + */ +// import 'intl'; // Run `npm install --save intl`. diff --git a/src/lib/src/framework-library/index.ts b/src/lib/src/framework-library/index.ts index a3d1de71..0c27f5e9 100644 --- a/src/lib/src/framework-library/index.ts +++ b/src/lib/src/framework-library/index.ts @@ -1,5 +1,5 @@ export { FrameworkLibraryService } from './framework-library.service'; -export { FrameworkLibraryModule } from './framework-library.module'; +// export { FrameworkLibraryModule } from './framework-library.module'; export { NoFramework } from './no-framework/no.framework'; export { NoFrameworkModule } from './no-framework/no-framework.module'; diff --git a/src/lib/src/widget-library/widgets.spec.ts b/src/lib/src/widget-library/widgets.spec.ts new file mode 100644 index 00000000..41aa7078 --- /dev/null +++ b/src/lib/src/widget-library/widgets.spec.ts @@ -0,0 +1,7 @@ +describe('widgets', () => { + describe('test', () => { + it('should run', () => { + expect(true).toBeTruthy(); + }); + }); +}); diff --git a/src/lib/test.ts b/src/lib/test.ts new file mode 100644 index 00000000..9bf72267 --- /dev/null +++ b/src/lib/test.ts @@ -0,0 +1,32 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/jasmine-patch'; +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. +declare var __karma__: any; +declare var require: any; + +// Prevent Karma from running prematurely. +__karma__.loaded = function () {}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); +// Finally, start Karma to run the tests. +__karma__.start(); From ed0ab57ec10efab0cf18a3336a3e5e4d308d52ac Mon Sep 17 00:00:00 2001 From: James Scharett Date: Tue, 29 May 2018 11:50:42 -0400 Subject: [PATCH 06/18] Test compilation Fixed compilation issue caused by referring to the barrel roles. Updated the ts config options --- ...ct-widget.component.ts => abstract-widget.ts} | 1 - .../widget-library/add-reference.component.ts | 16 +++++++--------- src/lib/src/widget-library/button.component.ts | 2 +- src/lib/src/widget-library/checkbox.component.ts | 2 +- .../src/widget-library/checkboxes.component.ts | 2 +- src/lib/src/widget-library/file.component.ts | 2 +- src/lib/src/widget-library/hidden.component.ts | 2 +- src/lib/src/widget-library/index.ts | 4 ++-- src/lib/src/widget-library/input.component.ts | 2 +- src/lib/src/widget-library/message.component.ts | 2 +- src/lib/src/widget-library/none.component.ts | 2 +- src/lib/src/widget-library/number.component.ts | 2 +- src/lib/src/widget-library/one-of.component.ts | 2 +- src/lib/src/widget-library/radios.component.ts | 2 +- src/lib/src/widget-library/root.component.ts | 2 +- src/lib/src/widget-library/section.component.ts | 2 +- .../widget-library/select-framework.component.ts | 2 +- .../widget-library/select-widget.component.ts | 2 +- src/lib/src/widget-library/select.component.ts | 2 +- src/lib/src/widget-library/submit.component.ts | 2 +- src/lib/src/widget-library/tab.component.ts | 2 +- src/lib/src/widget-library/tabs.component.ts | 2 +- src/lib/src/widget-library/template.component.ts | 2 +- src/lib/src/widget-library/textarea.component.ts | 2 +- src/lib/tsconfig.spec.json | 13 +++++++++---- tsconfig.json | 16 ++++++++-------- 26 files changed, 47 insertions(+), 45 deletions(-) rename src/lib/src/widget-library/{abstract-widget.component.ts => abstract-widget.ts} (99%) diff --git a/src/lib/src/widget-library/abstract-widget.component.ts b/src/lib/src/widget-library/abstract-widget.ts similarity index 99% rename from src/lib/src/widget-library/abstract-widget.component.ts rename to src/lib/src/widget-library/abstract-widget.ts index 45df5210..6db94b66 100644 --- a/src/lib/src/widget-library/abstract-widget.component.ts +++ b/src/lib/src/widget-library/abstract-widget.ts @@ -15,7 +15,6 @@ export abstract class AbstractWidget implements OnInit { @Input() layoutIndex: Array; @Input() dataIndex: Array; - constructor(protected jsf: JsonSchemaFormService) {} ngOnInit() { diff --git a/src/lib/src/widget-library/add-reference.component.ts b/src/lib/src/widget-library/add-reference.component.ts index f2f12a40..e62a6c0d 100755 --- a/src/lib/src/widget-library/add-reference.component.ts +++ b/src/lib/src/widget-library/add-reference.component.ts @@ -1,8 +1,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FormGroup } from '@angular/forms'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'add-reference-widget', @@ -13,8 +12,7 @@ import { AbstractWidget } from '.'; (click)="addItem($event)"> - `, - changeDetection: ChangeDetectionStrategy.Default, + ` }) export class AddReferenceComponent extends AbstractWidget { itemCount: number; @@ -30,11 +28,6 @@ export class AddReferenceComponent extends AbstractWidget { this.layoutIndex[this.layoutIndex.length - 1] < this.options.maxItems; } - addItem(event) { - event.preventDefault(); - this.jsf.addItem(this); - } - get buttonText(): string { const parent: any = { dataIndex: this.dataIndex.slice(0, -1), @@ -44,4 +37,9 @@ export class AddReferenceComponent extends AbstractWidget { return parent.layoutNode.add || this.jsf.setArrayItemTitle(parent, this.layoutNode, this.itemCount); } + + addItem(event) { + event.preventDefault(); + this.jsf.addItem(this); + } } diff --git a/src/lib/src/widget-library/button.component.ts b/src/lib/src/widget-library/button.component.ts index c775b931..c5fac65c 100755 --- a/src/lib/src/widget-library/button.component.ts +++ b/src/lib/src/widget-library/button.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'button-widget', diff --git a/src/lib/src/widget-library/checkbox.component.ts b/src/lib/src/widget-library/checkbox.component.ts index 4563583e..3c886ecb 100755 --- a/src/lib/src/widget-library/checkbox.component.ts +++ b/src/lib/src/widget-library/checkbox.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'checkbox-widget', diff --git a/src/lib/src/widget-library/checkboxes.component.ts b/src/lib/src/widget-library/checkboxes.component.ts index fc3f6599..b73a8172 100755 --- a/src/lib/src/widget-library/checkboxes.component.ts +++ b/src/lib/src/widget-library/checkboxes.component.ts @@ -3,7 +3,7 @@ import { FormArray, AbstractControl } from '@angular/forms'; import { JsonSchemaFormService, TitleMapItem } from '../json-schema-form.service'; import { buildTitleMap } from '../shared'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'checkboxes-widget', diff --git a/src/lib/src/widget-library/file.component.ts b/src/lib/src/widget-library/file.component.ts index 6be0978f..c4b283e4 100755 --- a/src/lib/src/widget-library/file.component.ts +++ b/src/lib/src/widget-library/file.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; // TODO: Add this control diff --git a/src/lib/src/widget-library/hidden.component.ts b/src/lib/src/widget-library/hidden.component.ts index 803752e5..5ff11e1b 100755 --- a/src/lib/src/widget-library/hidden.component.ts +++ b/src/lib/src/widget-library/hidden.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'hidden-widget', diff --git a/src/lib/src/widget-library/index.ts b/src/lib/src/widget-library/index.ts index 572299eb..f13bfe62 100755 --- a/src/lib/src/widget-library/index.ts +++ b/src/lib/src/widget-library/index.ts @@ -1,4 +1,4 @@ -import { AbstractWidget } from './abstract-widget.component'; +import { AbstractWidget } from './abstract-widget'; import { AddReferenceComponent } from './add-reference.component'; import { OneOfComponent } from './one-of.component'; import { ButtonComponent } from './button.component'; @@ -31,7 +31,7 @@ export const BASIC_WIDGETS = [ TemplateComponent, TextareaComponent ]; -export { AbstractWidget } from './abstract-widget.component'; +export { AbstractWidget } from './abstract-widget'; export { AddReferenceComponent } from './add-reference.component'; export { OneOfComponent } from './one-of.component'; export { ButtonComponent } from './button.component'; diff --git a/src/lib/src/widget-library/input.component.ts b/src/lib/src/widget-library/input.component.ts index 146421a9..ae04b300 100755 --- a/src/lib/src/widget-library/input.component.ts +++ b/src/lib/src/widget-library/input.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'input-widget', diff --git a/src/lib/src/widget-library/message.component.ts b/src/lib/src/widget-library/message.component.ts index 7d257ef4..8ad239e7 100755 --- a/src/lib/src/widget-library/message.component.ts +++ b/src/lib/src/widget-library/message.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'message-widget', diff --git a/src/lib/src/widget-library/none.component.ts b/src/lib/src/widget-library/none.component.ts index af14c2a4..dffc3b3e 100755 --- a/src/lib/src/widget-library/none.component.ts +++ b/src/lib/src/widget-library/none.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'none-widget', diff --git a/src/lib/src/widget-library/number.component.ts b/src/lib/src/widget-library/number.component.ts index a6d7a766..f7628b91 100755 --- a/src/lib/src/widget-library/number.component.ts +++ b/src/lib/src/widget-library/number.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'number-widget', diff --git a/src/lib/src/widget-library/one-of.component.ts b/src/lib/src/widget-library/one-of.component.ts index 6465140d..86c370c1 100644 --- a/src/lib/src/widget-library/one-of.component.ts +++ b/src/lib/src/widget-library/one-of.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; // TODO: Add this control diff --git a/src/lib/src/widget-library/radios.component.ts b/src/lib/src/widget-library/radios.component.ts index 66e7d8be..494f2cb8 100755 --- a/src/lib/src/widget-library/radios.component.ts +++ b/src/lib/src/widget-library/radios.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap } from '../shared'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'radios-widget', diff --git a/src/lib/src/widget-library/root.component.ts b/src/lib/src/widget-library/root.component.ts index 1f52f2c1..e818502f 100755 --- a/src/lib/src/widget-library/root.component.ts +++ b/src/lib/src/widget-library/root.component.ts @@ -2,7 +2,7 @@ import { Component, Input, Host, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { hasValue, JsonPointer } from '../shared'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'root-widget', diff --git a/src/lib/src/widget-library/section.component.ts b/src/lib/src/widget-library/section.component.ts index 2d457a09..b82c66f6 100755 --- a/src/lib/src/widget-library/section.component.ts +++ b/src/lib/src/widget-library/section.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { toTitleCase } from '../shared'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'section-widget', diff --git a/src/lib/src/widget-library/select-framework.component.ts b/src/lib/src/widget-library/select-framework.component.ts index aa1dbee6..068bd406 100755 --- a/src/lib/src/widget-library/select-framework.component.ts +++ b/src/lib/src/widget-library/select-framework.component.ts @@ -1,7 +1,7 @@ import { Component, ComponentFactoryResolver } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { TemplateComponent } from '.'; +import { TemplateComponent } from './template.component'; @Component({ selector: 'select-framework-widget', diff --git a/src/lib/src/widget-library/select-widget.component.ts b/src/lib/src/widget-library/select-widget.component.ts index ec471832..d44a0753 100755 --- a/src/lib/src/widget-library/select-widget.component.ts +++ b/src/lib/src/widget-library/select-widget.component.ts @@ -1,7 +1,7 @@ import { Component, ComponentFactoryResolver } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { TemplateComponent } from '.'; +import { TemplateComponent } from './template.component'; @Component({ selector: 'select-widget-widget', diff --git a/src/lib/src/widget-library/select.component.ts b/src/lib/src/widget-library/select.component.ts index b94a3c88..ac41fdc8 100755 --- a/src/lib/src/widget-library/select.component.ts +++ b/src/lib/src/widget-library/select.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap, isArray } from '../shared'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'select-widget', diff --git a/src/lib/src/widget-library/submit.component.ts b/src/lib/src/widget-library/submit.component.ts index a8c10544..104f48fd 100755 --- a/src/lib/src/widget-library/submit.component.ts +++ b/src/lib/src/widget-library/submit.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { hasOwn } from '../shared/utility.functions'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'submit-widget', diff --git a/src/lib/src/widget-library/tab.component.ts b/src/lib/src/widget-library/tab.component.ts index d7f32c73..13c3c1c9 100755 --- a/src/lib/src/widget-library/tab.component.ts +++ b/src/lib/src/widget-library/tab.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'tab-widget', diff --git a/src/lib/src/widget-library/tabs.component.ts b/src/lib/src/widget-library/tabs.component.ts index 0d2c15d5..03b7d12a 100755 --- a/src/lib/src/widget-library/tabs.component.ts +++ b/src/lib/src/widget-library/tabs.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'tabs-widget', diff --git a/src/lib/src/widget-library/template.component.ts b/src/lib/src/widget-library/template.component.ts index 16e762f7..7fa16238 100755 --- a/src/lib/src/widget-library/template.component.ts +++ b/src/lib/src/widget-library/template.component.ts @@ -4,7 +4,7 @@ import { } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'template-widget', diff --git a/src/lib/src/widget-library/textarea.component.ts b/src/lib/src/widget-library/textarea.component.ts index 3627a901..7d3c6dcf 100755 --- a/src/lib/src/widget-library/textarea.component.ts +++ b/src/lib/src/widget-library/textarea.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from '.'; +import { AbstractWidget } from './abstract-widget'; @Component({ selector: 'textarea-widget', diff --git a/src/lib/tsconfig.spec.json b/src/lib/tsconfig.spec.json index f1bcaf32..03a6bffe 100755 --- a/src/lib/tsconfig.spec.json +++ b/src/lib/tsconfig.spec.json @@ -1,9 +1,14 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "baseUrl": "", - "module": "commonjs", + "baseUrl": "./", + "module": "es2015", "declaration": false, - "emitDecoratorMetadata": true - } + "types": ["jasmine", "node"] + }, + "files": ["test.ts"], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] } diff --git a/tsconfig.json b/tsconfig.json index f0cd7b1d..896289e8 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,18 @@ { "compilerOptions": { - "target": "es5", - "module": "es2015", - "moduleResolution": "node", - "sourceMap": true, - "inlineSources": true, "declaration": true, + "emitDecoratorMetadata": true, "experimentalDecorators": true, + "inlineSources": true, + "lib": [ "es2015", "dom", "es7" ], + "module": "es2015", + "moduleResolution": "node", "removeComments": true, - "suppressImplicitAnyIndexErrors": true, "skipLibCheck": true, + "sourceMap": true, "stripInternal": true, - "lib": [ "es2015", "dom", "es7" ], - "emitDecoratorMetadata": true + "suppressImplicitAnyIndexErrors": true, + "target": "es5" }, "atom": { "rewriteTsconfig": false From b8811fb16a72aaf30e04ccf37857f81061f44a22 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Tue, 29 May 2018 14:05:15 -0400 Subject: [PATCH 07/18] Tests for a few widgets --- .../src/widget-library/checkbox.component.ts | 8 +- src/lib/src/widget-library/widgets.spec.ts | 227 +++++++++++++++++- 2 files changed, 228 insertions(+), 7 deletions(-) diff --git a/src/lib/src/widget-library/checkbox.component.ts b/src/lib/src/widget-library/checkbox.component.ts index 3c886ecb..960659a4 100755 --- a/src/lib/src/widget-library/checkbox.component.ts +++ b/src/lib/src/widget-library/checkbox.component.ts @@ -45,6 +45,10 @@ export class CheckboxComponent extends AbstractWidget implements OnInit { super(jsf); } + get isChecked() { + return this.jsf.getFormControlValue(this) === this.trueValue; + } + ngOnInit() { super.ngOnInit(); if (this.controlValue === null || this.controlValue === undefined) { @@ -56,8 +60,4 @@ export class CheckboxComponent extends AbstractWidget implements OnInit { event.preventDefault(); this.jsf.updateValue(this, event.target.checked ? this.trueValue : this.falseValue); } - - get isChecked() { - return this.jsf.getFormControlValue(this) === this.trueValue; - } } diff --git a/src/lib/src/widget-library/widgets.spec.ts b/src/lib/src/widget-library/widgets.spec.ts index 41aa7078..32f73600 100644 --- a/src/lib/src/widget-library/widgets.spec.ts +++ b/src/lib/src/widget-library/widgets.spec.ts @@ -1,7 +1,228 @@ +import { NO_ERRORS_SCHEMA, Component } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { JsonSchemaFormService } from '../..'; + +import { AbstractWidget } from './abstract-widget'; +import { AddReferenceComponent } from './add-reference.component'; +import { ButtonComponent } from './button.component'; +import { CheckboxComponent } from './checkbox.component'; +import { CheckboxesComponent } from './checkboxes.component'; + describe('widgets', () => { - describe('test', () => { - it('should run', () => { - expect(true).toBeTruthy(); + let fixture: ComponentFixture; + let mockFormService: JsonSchemaFormService; + + function setupCompoent(clazz: new (...args: any[]) => A, onBeforeInit: Function = (comp: A) => {}): A { + fixture = TestBed.createComponent(clazz); + + const component = fixture.componentInstance; + component.layoutNode = {}; + component.layoutIndex = [0]; + component.dataIndex = []; + + if (!onBeforeInit(component)) { + fixture.detectChanges(); + } + + return component; + } + + beforeEach(async(() => { + mockFormService = jasmine.createSpyObj('JsonSchemaFormService', { + addItem: undefined, + getFormControl: null, + getFormControlValue: null, + getParentNode: {}, + initializeControl: undefined, + setArrayItemTitle: '', + updateArrayCheckboxList: undefined, + updateValue: undefined + }); + (mockFormService.initializeControl).and.callFake((comp) => { + comp.options = comp.layoutNode.options; + }); + + TestBed.configureTestingModule({ + declarations: [ + AddReferenceComponent, + ButtonComponent, + CheckboxComponent, + CheckboxesComponent + ], + providers: [{ + provide: JsonSchemaFormService, + useValue: mockFormService + }], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .compileComponents(); + })); + + describe('AddReferenceComponent', () => { + let component: AddReferenceComponent; + + beforeEach(() => { + component = setupCompoent(AddReferenceComponent, (comp) => { + comp.layoutNode.options = {maxItems: 3}; + }); + }); + + it('should show Add button', () => { + component.layoutNode.arrayItem = false; + expect(component.showAddButton).toBeTruthy(); + + component.layoutNode.arrayItem = true; + component.layoutIndex = [0, 1, 2]; + expect(component.showAddButton).toBeTruthy(); + }); + + it('should hide Add button', () => { + component.layoutNode.arrayItem = true; + component.layoutIndex = [0, 1, 2, 3, 4]; + expect(component.showAddButton).toBeFalsy(); + }); + + it('should return button text from parent', () => { + (mockFormService.getParentNode).and.returnValue({add: 'test'}); + expect(component.buttonText).toEqual('test'); + expect(mockFormService.setArrayItemTitle).not.toHaveBeenCalled(); + }); + + it('should call jsf to get button text', () => { + component.itemCount = 2; + (mockFormService.setArrayItemTitle).and.returnValue('test'); + expect(component.buttonText).toEqual('test'); + expect(mockFormService.setArrayItemTitle).toHaveBeenCalledWith({ + dataIndex: [], + layoutIndex: [], + layoutNode: {} + }, component.layoutNode, component.itemCount); + }); + + it('should call serve to add item', () => { + component.addItem(jasmine.createSpyObj('event', ['preventDefault'])); + + expect(mockFormService.addItem).toHaveBeenCalledWith(component); + }); + }); + + describe('ButtonComponent', () => { + let component: ButtonComponent; + + beforeEach(() => { + component = setupCompoent(ButtonComponent); + }); + + it('should use the default update method when no click handler', () => { + component.updateValue({target: {value: null}}); + expect(mockFormService.updateValue).toHaveBeenCalledWith(component, null); + }); + + it('should use click handler from options', () => { + component.options.onClick = jasmine.createSpy('onclick'); + component.updateValue({target: {value: null}}); + expect(mockFormService.updateValue).not.toHaveBeenCalled(); + expect(component.options.onClick).toHaveBeenCalledWith({target: {value: null}}); + }); + }); + + describe('CheckboxComponent', () => { + let component: CheckboxComponent; + + beforeEach(() => { + component = setupCompoent(CheckboxComponent, (comp) => { + comp.controlValue = true; + }); + }); + + it('should return true for checked', () => { + (mockFormService.getFormControlValue).and.returnValue(true); + expect(component.isChecked).toBeTruthy(); + }); + + it('should return false for checked', () => { + (mockFormService.getFormControlValue).and.returnValue(false); + expect(component.isChecked).toBeFalsy(); + }); + + it('should call jsf to update value', () => { + component.updateValue({target: {checked: true}, preventDefault: jasmine.createSpy('0')}); + expect(mockFormService.updateValue).toHaveBeenCalledWith(component, true); + + component.updateValue({target: {}, preventDefault: jasmine.createSpy('1')}); + expect(mockFormService.updateValue).toHaveBeenCalledWith(component, false); + }); + }); + + describe('CheckboxesComponent', () => { + let component: CheckboxesComponent; + + beforeEach(() => { + component = setupCompoent(CheckboxesComponent, (comp) => { + comp.controlValue = true; + comp.layoutNode.options = {titleMap: [ + {value: 'check1', name: 'Test1'}, + {value: 'check2', name: 'Test2'} + ]}; + + return true; + }); + (mockFormService.getFormControl).and.returnValue({value: ['check1']}); + }); + + it('should have vertical orietation by default', () => { + fixture.detectChanges(); + expect(component.layoutOrientation).toEqual('vertical'); + }); + + it('should set orientation to horizontal', () => { + component.layoutNode.type = 'checkboxes-inline'; + fixture.detectChanges(); + expect(component.layoutOrientation).toEqual('horizontal'); + }); + + it('should initialize valeus in titleMap list', () => { + component.boundControl = true; + fixture.detectChanges(); + expect(component.checkboxList).toEqual([{ + name: 'Test1', + value: 'check1', + checked: true + }, { + name: 'Test2', + value: 'check2', + checked: false + }]); + }); + + it('should update value in titleMap list', () => { + component.boundControl = true; + fixture.detectChanges(); + component.updateValue({target: {value: 'check2', checked: true}}); + expect(component.checkboxList).toEqual([{ + name: 'Test1', + value: 'check1', + checked: true + }, { + name: 'Test2', + value: 'check2', + checked: true + }]); + }); + + it('should not call service to update control', () => { + fixture.detectChanges(); + component.boundControl = false; + component.updateValue({target: {}}); + expect(mockFormService.updateArrayCheckboxList).not.toHaveBeenCalled(); + }); + + it('should call service to update bound control', () => { + fixture.detectChanges(); + component.boundControl = true; + component.updateValue({target: {}}); + expect(mockFormService.updateArrayCheckboxList).toHaveBeenCalledWith(component, component.checkboxList); }); }); }); From 5fb3f464f7fe4a503add383adf2a8a4da4520809 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Tue, 29 May 2018 15:55:32 -0400 Subject: [PATCH 08/18] More widget tests --- src/lib/src/widget-library/widgets.spec.ts | 173 +++++++++++++++++++-- 1 file changed, 164 insertions(+), 9 deletions(-) diff --git a/src/lib/src/widget-library/widgets.spec.ts b/src/lib/src/widget-library/widgets.spec.ts index 32f73600..1dcd7ebe 100644 --- a/src/lib/src/widget-library/widgets.spec.ts +++ b/src/lib/src/widget-library/widgets.spec.ts @@ -1,19 +1,48 @@ -import { NO_ERRORS_SCHEMA, Component } from '@angular/core'; +import { NO_ERRORS_SCHEMA, Component, NgModule, Injectable } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { JsonSchemaFormService } from '../..'; +import { JsonSchemaFormService, Framework } from '../..'; import { AbstractWidget } from './abstract-widget'; import { AddReferenceComponent } from './add-reference.component'; import { ButtonComponent } from './button.component'; import { CheckboxComponent } from './checkbox.component'; import { CheckboxesComponent } from './checkboxes.component'; +import { MessageComponent } from './message.component'; +import { RadiosComponent } from './radios.component'; +import { SelectFrameworkComponent } from './select-framework.component'; +import { SelectWidgetComponent } from './select-widget.component'; +import { SelectComponent } from './select.component'; +import { TemplateComponent } from './template.component'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'test-component', + template: '
Hello World
' +}) +class TestComponent {} + +@Injectable() +class TestFramework extends Framework { + name = 'TestFramework'; + framework = TestComponent; +}; + +@NgModule({ + imports: [ CommonModule ], + declarations: [ TestComponent, MessageComponent ], + entryComponents: [ TestComponent, MessageComponent ], + providers: [ + { provide: Framework, useClass: TestFramework, multi: true } + ] +}) +class TestModule {} describe('widgets', () => { let fixture: ComponentFixture; let mockFormService: JsonSchemaFormService; - function setupCompoent
(clazz: new (...args: any[]) => A, onBeforeInit: Function = (comp: A) => {}): A { + function setupComponent(clazz: new (...args: any[]) => A, onBeforeInit: Function = (comp: A) => {}): A { fixture = TestBed.createComponent(clazz); const component = fixture.componentInstance; @@ -44,11 +73,17 @@ describe('widgets', () => { }); TestBed.configureTestingModule({ + imports: [ TestModule ], declarations: [ AddReferenceComponent, ButtonComponent, CheckboxComponent, - CheckboxesComponent + CheckboxesComponent, + RadiosComponent, + SelectFrameworkComponent, + SelectWidgetComponent, + SelectComponent, + TemplateComponent ], providers: [{ provide: JsonSchemaFormService, @@ -63,7 +98,7 @@ describe('widgets', () => { let component: AddReferenceComponent; beforeEach(() => { - component = setupCompoent(AddReferenceComponent, (comp) => { + component = setupComponent(AddReferenceComponent, (comp) => { comp.layoutNode.options = {maxItems: 3}; }); }); @@ -111,7 +146,7 @@ describe('widgets', () => { let component: ButtonComponent; beforeEach(() => { - component = setupCompoent(ButtonComponent); + component = setupComponent(ButtonComponent); }); it('should use the default update method when no click handler', () => { @@ -131,7 +166,7 @@ describe('widgets', () => { let component: CheckboxComponent; beforeEach(() => { - component = setupCompoent(CheckboxComponent, (comp) => { + component = setupComponent(CheckboxComponent, (comp) => { comp.controlValue = true; }); }); @@ -159,7 +194,7 @@ describe('widgets', () => { let component: CheckboxesComponent; beforeEach(() => { - component = setupCompoent(CheckboxesComponent, (comp) => { + component = setupComponent(CheckboxesComponent, (comp) => { comp.controlValue = true; comp.layoutNode.options = {titleMap: [ {value: 'check1', name: 'Test1'}, @@ -182,7 +217,7 @@ describe('widgets', () => { expect(component.layoutOrientation).toEqual('horizontal'); }); - it('should initialize valeus in titleMap list', () => { + it('should initialize values in titleMap list', () => { component.boundControl = true; fixture.detectChanges(); expect(component.checkboxList).toEqual([{ @@ -225,4 +260,124 @@ describe('widgets', () => { expect(mockFormService.updateArrayCheckboxList).toHaveBeenCalledWith(component, component.checkboxList); }); }); + + // File + // Hidden + // Input + // Message - verify message set + // None + // Number - verify allowDecimal set + // OneOf + + describe('RadiosComponent', () => { + let component: RadiosComponent; + + beforeEach(() => { + component = setupComponent(RadiosComponent, (comp) => { + comp.layoutNode.options = {titleMap: [ + {value: 'radio1', name: 'Test1'}, + {value: 'radio2', name: 'Test2'} + ], required: true}; + + return true; + }); + }); + + it('should set orianentation to horizontal', () => { + component.layoutNode.type = 'radios-inline'; + fixture.detectChanges(); + expect(component.layoutOrientation).toEqual('horizontal'); + }); + + it('should initialize values in titleMap list', () => { + fixture.detectChanges(); + expect(component.radiosList).toEqual([{ + name: 'Test1', + value: 'radio1' + }, { + name: 'Test2', + value: 'radio2' + }]); + }); + }); + + describe('RootComponent', () => {}); + + describe('SectionComponent', () => {}); + + describe('SelectFrameworkComponent', () => { + let component: SelectFrameworkComponent; + + beforeEach(() => { + component = setupComponent(SelectFrameworkComponent, (comp) => { + comp['jsf'].framework = TestComponent; + }); + }); + + it('should instantiate framework', () => { + expect(component.newComponent.componentType).toEqual(TestComponent); + }); + }); + + describe('SelectWidgetComponent', () => { + let component: SelectWidgetComponent; + + beforeEach(() => { + component = setupComponent(SelectWidgetComponent, (comp) => { + comp.layoutNode.widget = MessageComponent; + }); + }); + + it('should instantiate widget', () => { + expect(component.newComponent.componentType).toEqual(MessageComponent); + }); + }); + + describe('SelectComponent', () => { + let component: SelectComponent; + + beforeEach(() => { + component = setupComponent(SelectComponent, (comp) => { + comp.layoutNode.options = {titleMap: [ + {value: 'option1', name: 'Test1'}, + {value: 'option2', name: 'Test2'} + ], required: true}; + }); + }); + + it('should initialize values in titleMap list', () => { + expect(component.selectList).toEqual([{ + name: 'Test1', + value: 'option1' + }, { + name: 'Test2', + value: 'option2' + }]); + }); + }); + + describe('SubmitComponent', () => {}); + + // Tab + + describe('TabsComponent', () => {}); + + describe('TemplateComponent', () => { + let component: TemplateComponent; + + beforeEach(() => { + component = setupComponent(TemplateComponent, (comp) => { + comp.layoutNode.options = {template: TestComponent}; + }); + }); + + it('should instantiate template and set properties', () => { + expect(component.newComponent.componentType).toEqual(TestComponent); + expect(component.newComponent.instance.layoutNode).toEqual(component.layoutNode); + expect(component.newComponent.instance.layoutIndex).toEqual(component.layoutIndex); + expect(component.newComponent.instance.dataIndex).toEqual(component.dataIndex); + }); + }); + + // TextArea }); From 85f80f35adb262e0a40de40850e2ccbb9bec634e Mon Sep 17 00:00:00 2001 From: James Scharett Date: Fri, 1 Jun 2018 04:26:17 -0400 Subject: [PATCH 09/18] Renamed AbstractWidget to just Widget --- .../widget-library/add-reference.component.ts | 4 +-- .../src/widget-library/button.component.ts | 4 +-- .../src/widget-library/checkbox.component.ts | 4 +-- .../widget-library/checkboxes.component.ts | 4 +-- src/lib/src/widget-library/file.component.ts | 4 +-- .../src/widget-library/hidden.component.ts | 4 +-- src/lib/src/widget-library/index.ts | 4 +-- src/lib/src/widget-library/input.component.ts | 4 +-- .../src/widget-library/message.component.ts | 4 +-- src/lib/src/widget-library/none.component.ts | 4 +-- .../src/widget-library/number.component.ts | 4 +-- .../src/widget-library/one-of.component.ts | 4 +-- .../src/widget-library/radios.component.ts | 4 +-- src/lib/src/widget-library/root.component.ts | 4 +-- .../src/widget-library/section.component.ts | 4 +-- .../src/widget-library/select.component.ts | 4 +-- .../src/widget-library/submit.component.ts | 4 +-- src/lib/src/widget-library/tab.component.ts | 4 +-- src/lib/src/widget-library/tabs.component.ts | 4 +-- .../src/widget-library/template.component.ts | 4 +-- .../src/widget-library/textarea.component.ts | 4 +-- .../{abstract-widget.ts => widget.ts} | 2 +- src/lib/src/widget-library/widgets.spec.ts | 33 ++++++++++++++++--- 23 files changed, 72 insertions(+), 47 deletions(-) rename src/lib/src/widget-library/{abstract-widget.ts => widget.ts} (92%) diff --git a/src/lib/src/widget-library/add-reference.component.ts b/src/lib/src/widget-library/add-reference.component.ts index e62a6c0d..79eff256 100755 --- a/src/lib/src/widget-library/add-reference.component.ts +++ b/src/lib/src/widget-library/add-reference.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'add-reference-widget', @@ -14,7 +14,7 @@ import { AbstractWidget } from './abstract-widget'; ` }) -export class AddReferenceComponent extends AbstractWidget { +export class AddReferenceComponent extends Widget { itemCount: number; previousLayoutIndex: number[]; previousDataIndex: number[]; diff --git a/src/lib/src/widget-library/button.component.ts b/src/lib/src/widget-library/button.component.ts index c5fac65c..34be5a4f 100755 --- a/src/lib/src/widget-library/button.component.ts +++ b/src/lib/src/widget-library/button.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'button-widget', @@ -23,7 +23,7 @@ import { AbstractWidget } from './abstract-widget'; `, }) -export class ButtonComponent extends AbstractWidget { +export class ButtonComponent extends Widget { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/checkbox.component.ts b/src/lib/src/widget-library/checkbox.component.ts index 960659a4..1c7e46e7 100755 --- a/src/lib/src/widget-library/checkbox.component.ts +++ b/src/lib/src/widget-library/checkbox.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'checkbox-widget', @@ -37,7 +37,7 @@ import { AbstractWidget } from './abstract-widget'; [innerHTML]="options?.title"> `, }) -export class CheckboxComponent extends AbstractWidget implements OnInit { +export class CheckboxComponent extends Widget implements OnInit { trueValue: any = true; falseValue: any = false; diff --git a/src/lib/src/widget-library/checkboxes.component.ts b/src/lib/src/widget-library/checkboxes.component.ts index b73a8172..520381d9 100755 --- a/src/lib/src/widget-library/checkboxes.component.ts +++ b/src/lib/src/widget-library/checkboxes.component.ts @@ -3,7 +3,7 @@ import { FormArray, AbstractControl } from '@angular/forms'; import { JsonSchemaFormService, TitleMapItem } from '../json-schema-form.service'; import { buildTitleMap } from '../shared'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'checkboxes-widget', @@ -57,7 +57,7 @@ import { AbstractWidget } from './abstract-widget'; `, }) -export class CheckboxesComponent extends AbstractWidget implements OnInit { +export class CheckboxesComponent extends Widget implements OnInit { layoutOrientation: string; formArray: AbstractControl; checkboxList: TitleMapItem[] = []; diff --git a/src/lib/src/widget-library/file.component.ts b/src/lib/src/widget-library/file.component.ts index c4b283e4..0ae35bc1 100755 --- a/src/lib/src/widget-library/file.component.ts +++ b/src/lib/src/widget-library/file.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; // TODO: Add this control @@ -10,7 +10,7 @@ import { AbstractWidget } from './abstract-widget'; selector: 'file-widget', template: ``, }) -export class FileComponent extends AbstractWidget { +export class FileComponent extends Widget { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/hidden.component.ts b/src/lib/src/widget-library/hidden.component.ts index 5ff11e1b..6afe1fbd 100755 --- a/src/lib/src/widget-library/hidden.component.ts +++ b/src/lib/src/widget-library/hidden.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'hidden-widget', @@ -18,7 +18,7 @@ import { AbstractWidget } from './abstract-widget'; type="hidden" [value]="controlValue">`, }) -export class HiddenComponent extends AbstractWidget { +export class HiddenComponent extends Widget { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/index.ts b/src/lib/src/widget-library/index.ts index f13bfe62..8447bc38 100755 --- a/src/lib/src/widget-library/index.ts +++ b/src/lib/src/widget-library/index.ts @@ -1,4 +1,4 @@ -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; import { AddReferenceComponent } from './add-reference.component'; import { OneOfComponent } from './one-of.component'; import { ButtonComponent } from './button.component'; @@ -31,7 +31,7 @@ export const BASIC_WIDGETS = [ TemplateComponent, TextareaComponent ]; -export { AbstractWidget } from './abstract-widget'; +export { Widget } from './widget'; export { AddReferenceComponent } from './add-reference.component'; export { OneOfComponent } from './one-of.component'; export { ButtonComponent } from './button.component'; diff --git a/src/lib/src/widget-library/input.component.ts b/src/lib/src/widget-library/input.component.ts index ae04b300..3d55d33b 100755 --- a/src/lib/src/widget-library/input.component.ts +++ b/src/lib/src/widget-library/input.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'input-widget', @@ -48,7 +48,7 @@ import { AbstractWidget } from './abstract-widget'; `, }) -export class InputComponent extends AbstractWidget { +export class InputComponent extends Widget { autoCompleteList: string[] = []; constructor(jsf: JsonSchemaFormService) { diff --git a/src/lib/src/widget-library/message.component.ts b/src/lib/src/widget-library/message.component.ts index 8ad239e7..4e8f631a 100755 --- a/src/lib/src/widget-library/message.component.ts +++ b/src/lib/src/widget-library/message.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'message-widget', @@ -10,7 +10,7 @@ import { AbstractWidget } from './abstract-widget'; [class]="options?.labelHtmlClass || ''" [innerHTML]="message">`, }) -export class MessageComponent extends AbstractWidget implements OnInit { +export class MessageComponent extends Widget implements OnInit { message: string = null; constructor(jsf: JsonSchemaFormService) { diff --git a/src/lib/src/widget-library/none.component.ts b/src/lib/src/widget-library/none.component.ts index dffc3b3e..3d1944c0 100755 --- a/src/lib/src/widget-library/none.component.ts +++ b/src/lib/src/widget-library/none.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'none-widget', template: ``, }) -export class NoneComponent extends AbstractWidget { +export class NoneComponent extends Widget { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/number.component.ts b/src/lib/src/widget-library/number.component.ts index f7628b91..3f2e65d6 100755 --- a/src/lib/src/widget-library/number.component.ts +++ b/src/lib/src/widget-library/number.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'number-widget', @@ -47,7 +47,7 @@ import { AbstractWidget } from './abstract-widget'; `, }) -export class NumberComponent extends AbstractWidget implements OnInit { +export class NumberComponent extends Widget implements OnInit { allowNegative = true; allowDecimal = true; allowExponents = false; diff --git a/src/lib/src/widget-library/one-of.component.ts b/src/lib/src/widget-library/one-of.component.ts index 86c370c1..01a109e4 100644 --- a/src/lib/src/widget-library/one-of.component.ts +++ b/src/lib/src/widget-library/one-of.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; // TODO: Add this control @@ -9,7 +9,7 @@ import { AbstractWidget } from './abstract-widget'; selector: 'one-of-widget', template: ``, }) -export class OneOfComponent extends AbstractWidget { +export class OneOfComponent extends Widget { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/radios.component.ts b/src/lib/src/widget-library/radios.component.ts index 494f2cb8..5150b8de 100755 --- a/src/lib/src/widget-library/radios.component.ts +++ b/src/lib/src/widget-library/radios.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap } from '../shared'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'radios-widget', @@ -63,7 +63,7 @@ import { AbstractWidget } from './abstract-widget'; `, }) -export class RadiosComponent extends AbstractWidget implements OnInit { +export class RadiosComponent extends Widget implements OnInit { layoutOrientation = 'vertical'; radiosList: any[] = []; diff --git a/src/lib/src/widget-library/root.component.ts b/src/lib/src/widget-library/root.component.ts index e818502f..94662e45 100755 --- a/src/lib/src/widget-library/root.component.ts +++ b/src/lib/src/widget-library/root.component.ts @@ -2,7 +2,7 @@ import { Component, Input, Host, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { hasValue, JsonPointer } from '../shared'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'root-widget', @@ -48,7 +48,7 @@ import { AbstractWidget } from './abstract-widget'; } `], }) -export class RootComponent extends AbstractWidget implements OnInit { +export class RootComponent extends Widget implements OnInit { @Input() isOrderable: boolean; @Input() isFlexItem = false; diff --git a/src/lib/src/widget-library/section.component.ts b/src/lib/src/widget-library/section.component.ts index b82c66f6..8c04643a 100755 --- a/src/lib/src/widget-library/section.component.ts +++ b/src/lib/src/widget-library/section.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { toTitleCase } from '../shared'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'section-widget', @@ -74,7 +74,7 @@ import { AbstractWidget } from './abstract-widget'; .expanded > legend:before, .expanded > label:before { content: '▼'; padding-right: .2em; } `], }) -export class SectionComponent extends AbstractWidget implements OnInit { +export class SectionComponent extends Widget implements OnInit { expanded = true; containerType: string; diff --git a/src/lib/src/widget-library/select.component.ts b/src/lib/src/widget-library/select.component.ts index ac41fdc8..65cad2e0 100755 --- a/src/lib/src/widget-library/select.component.ts +++ b/src/lib/src/widget-library/select.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { buildTitleMap, isArray } from '../shared'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'select-widget', @@ -63,7 +63,7 @@ import { AbstractWidget } from './abstract-widget'; `, }) -export class SelectComponent extends AbstractWidget implements OnInit { +export class SelectComponent extends Widget implements OnInit { selectList: any[] = []; isArray = isArray; diff --git a/src/lib/src/widget-library/submit.component.ts b/src/lib/src/widget-library/submit.component.ts index 104f48fd..f6fae95b 100755 --- a/src/lib/src/widget-library/submit.component.ts +++ b/src/lib/src/widget-library/submit.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { hasOwn } from '../shared/utility.functions'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'submit-widget', @@ -22,7 +22,7 @@ import { AbstractWidget } from './abstract-widget'; (click)="updateValue($event)"> `, }) -export class SubmitComponent extends AbstractWidget implements OnInit { +export class SubmitComponent extends Widget implements OnInit { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/tab.component.ts b/src/lib/src/widget-library/tab.component.ts index 13c3c1c9..14acbf03 100755 --- a/src/lib/src/widget-library/tab.component.ts +++ b/src/lib/src/widget-library/tab.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'tab-widget', @@ -13,7 +13,7 @@ import { AbstractWidget } from './abstract-widget'; [layout]="layoutNode.items"> `, }) -export class TabComponent extends AbstractWidget implements OnInit { +export class TabComponent extends Widget implements OnInit { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/tabs.component.ts b/src/lib/src/widget-library/tabs.component.ts index 03b7d12a..bfd4ce81 100755 --- a/src/lib/src/widget-library/tabs.component.ts +++ b/src/lib/src/widget-library/tabs.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'tabs-widget', @@ -36,7 +36,7 @@ import { AbstractWidget } from './abstract-widget'; `, styles: [` a { cursor: pointer; } `], }) -export class TabsComponent extends AbstractWidget implements OnInit { +export class TabsComponent extends Widget implements OnInit { itemCount: number; selectedItem = 0; showAddTab = true; diff --git a/src/lib/src/widget-library/template.component.ts b/src/lib/src/widget-library/template.component.ts index 7fa16238..da029b73 100755 --- a/src/lib/src/widget-library/template.component.ts +++ b/src/lib/src/widget-library/template.component.ts @@ -4,13 +4,13 @@ import { } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'template-widget', template: `
`, }) -export class TemplateComponent extends AbstractWidget implements OnInit, OnChanges { +export class TemplateComponent extends Widget implements OnInit, OnChanges { newComponent: ComponentRef = null; @ViewChild('widgetContainer', { read: ViewContainerRef }) widgetContainer: ViewContainerRef; diff --git a/src/lib/src/widget-library/textarea.component.ts b/src/lib/src/widget-library/textarea.component.ts index 7d3c6dcf..07ea278f 100755 --- a/src/lib/src/widget-library/textarea.component.ts +++ b/src/lib/src/widget-library/textarea.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; @Component({ selector: 'textarea-widget', @@ -41,7 +41,7 @@ import { AbstractWidget } from './abstract-widget'; (input)="updateValue($event)">{{controlValue}} `, }) -export class TextareaComponent extends AbstractWidget { +export class TextareaComponent extends Widget { constructor(jsf: JsonSchemaFormService) { super(jsf); diff --git a/src/lib/src/widget-library/abstract-widget.ts b/src/lib/src/widget-library/widget.ts similarity index 92% rename from src/lib/src/widget-library/abstract-widget.ts rename to src/lib/src/widget-library/widget.ts index 6db94b66..1a588b00 100644 --- a/src/lib/src/widget-library/abstract-widget.ts +++ b/src/lib/src/widget-library/widget.ts @@ -3,7 +3,7 @@ import { AbstractControl } from '@angular/forms'; import { JsonSchemaFormService } from '../json-schema-form.service'; -export abstract class AbstractWidget implements OnInit { +export abstract class Widget implements OnInit { boundControl = false; controlDisabled = false; controlName: string; diff --git a/src/lib/src/widget-library/widgets.spec.ts b/src/lib/src/widget-library/widgets.spec.ts index 1dcd7ebe..ad7471c9 100644 --- a/src/lib/src/widget-library/widgets.spec.ts +++ b/src/lib/src/widget-library/widgets.spec.ts @@ -3,7 +3,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { JsonSchemaFormService, Framework } from '../..'; -import { AbstractWidget } from './abstract-widget'; +import { Widget } from './widget'; import { AddReferenceComponent } from './add-reference.component'; import { ButtonComponent } from './button.component'; import { CheckboxComponent } from './checkbox.component'; @@ -13,6 +13,8 @@ import { RadiosComponent } from './radios.component'; import { SelectFrameworkComponent } from './select-framework.component'; import { SelectWidgetComponent } from './select-widget.component'; import { SelectComponent } from './select.component'; +import { SubmitComponent } from './submit.component'; +import { TabsComponent } from './tabs.component'; import { TemplateComponent } from './template.component'; import { CommonModule } from '@angular/common'; @@ -42,13 +44,14 @@ describe('widgets', () => { let fixture: ComponentFixture; let mockFormService: JsonSchemaFormService; - function setupComponent
(clazz: new (...args: any[]) => A, onBeforeInit: Function = (comp: A) => {}): A { + function setupComponent(clazz: new (...args: any[]) => A, onBeforeInit: Function = (comp: A) => {}): A { fixture = TestBed.createComponent(clazz); const component = fixture.componentInstance; component.layoutNode = {}; component.layoutIndex = [0]; component.dataIndex = []; + component.jsf.formOptions = {}; if (!onBeforeInit(component)) { fixture.detectChanges(); @@ -83,6 +86,8 @@ describe('widgets', () => { SelectFrameworkComponent, SelectWidgetComponent, SelectComponent, + SubmitComponent, + TabsComponent, TemplateComponent ], providers: [{ @@ -356,11 +361,31 @@ describe('widgets', () => { }); }); - describe('SubmitComponent', () => {}); + describe('SubmitComponent', () => { + let component: SubmitComponent; + + beforeEach(() => { + component = setupComponent(SubmitComponent, (comp) => { + comp.layoutNode.type = 'submit'; + }); + }); + + it('should fail', fail); + }); // Tab - describe('TabsComponent', () => {}); + describe('TabsComponent', () => { + let component: TabsComponent; + + beforeEach(() => { + component = setupComponent(TabsComponent, (comp) => { + comp.layoutNode.items = [{}]; + }); + }); + + it('should fail', fail); + }); describe('TemplateComponent', () => { let component: TemplateComponent; From 91dad3eaedf2202d6d79c5eca578702fc12ff497 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Fri, 1 Jun 2018 09:54:07 -0400 Subject: [PATCH 10/18] Tests Added tests for remaingin widgets, with 4 widgets needing full test cases --- .../src/widget-library/number.component.ts | 11 +- .../src/widget-library/submit.component.ts | 12 +- src/lib/src/widget-library/tab.component.ts | 1 - .../src/widget-library/textarea.component.ts | 2 - src/lib/src/widget-library/widgets.spec.ts | 240 +++++++++++++++--- 5 files changed, 206 insertions(+), 60 deletions(-) diff --git a/src/lib/src/widget-library/number.component.ts b/src/lib/src/widget-library/number.component.ts index 3f2e65d6..75f0dbf3 100755 --- a/src/lib/src/widget-library/number.component.ts +++ b/src/lib/src/widget-library/number.component.ts @@ -48,10 +48,10 @@ import { Widget } from './widget'; `, }) export class NumberComponent extends Widget implements OnInit { - allowNegative = true; - allowDecimal = true; - allowExponents = false; - lastValidNumber = ''; + allowDecimal = true; // Not implemented + allowExponents = false; // Not implemented + allowNegative = true; // Not implemented + lastValidNumber = ''; // Not implemented constructor(jsf: JsonSchemaFormService) { super(jsf); @@ -59,7 +59,8 @@ export class NumberComponent extends Widget implements OnInit { ngOnInit() { super.ngOnInit(); - if (this.layoutNode.dataType === 'integer') { this.allowDecimal = false; } + // TODO + // if (this.layoutNode.dataType === 'integer') { this.allowDecimal = false; } } } diff --git a/src/lib/src/widget-library/submit.component.ts b/src/lib/src/widget-library/submit.component.ts index f6fae95b..3881004f 100755 --- a/src/lib/src/widget-library/submit.component.ts +++ b/src/lib/src/widget-library/submit.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { hasOwn } from '../shared/utility.functions'; -import { Widget } from './widget'; +import { ButtonComponent } from './button.component'; @Component({ selector: 'submit-widget', @@ -22,7 +22,7 @@ import { Widget } from './widget'; (click)="updateValue($event)"> `, }) -export class SubmitComponent extends Widget implements OnInit { +export class SubmitComponent extends ButtonComponent implements OnInit { constructor(jsf: JsonSchemaFormService) { super(jsf); @@ -40,12 +40,4 @@ export class SubmitComponent extends Widget implements OnInit { this.controlValue = this.options.title; } } - - updateValue(event) { - if (typeof this.options.onClick === 'function') { - this.options.onClick(event); - } else { - this.jsf.updateValue(this, event.target.value); - } - } } diff --git a/src/lib/src/widget-library/tab.component.ts b/src/lib/src/widget-library/tab.component.ts index 14acbf03..80ca8e77 100755 --- a/src/lib/src/widget-library/tab.component.ts +++ b/src/lib/src/widget-library/tab.component.ts @@ -14,7 +14,6 @@ import { Widget } from './widget'; `, }) export class TabComponent extends Widget implements OnInit { - constructor(jsf: JsonSchemaFormService) { super(jsf); } diff --git a/src/lib/src/widget-library/textarea.component.ts b/src/lib/src/widget-library/textarea.component.ts index 07ea278f..1eebe4dd 100755 --- a/src/lib/src/widget-library/textarea.component.ts +++ b/src/lib/src/widget-library/textarea.component.ts @@ -42,9 +42,7 @@ import { Widget } from './widget'; `, }) export class TextareaComponent extends Widget { - constructor(jsf: JsonSchemaFormService) { super(jsf); } - } diff --git a/src/lib/src/widget-library/widgets.spec.ts b/src/lib/src/widget-library/widgets.spec.ts index ad7471c9..2c9ac3d5 100644 --- a/src/lib/src/widget-library/widgets.spec.ts +++ b/src/lib/src/widget-library/widgets.spec.ts @@ -1,22 +1,19 @@ +import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA, Component, NgModule, Injectable } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Subject } from 'rxjs/Subject'; + import { JsonSchemaFormService, Framework } from '../..'; -import { Widget } from './widget'; -import { AddReferenceComponent } from './add-reference.component'; -import { ButtonComponent } from './button.component'; -import { CheckboxComponent } from './checkbox.component'; -import { CheckboxesComponent } from './checkboxes.component'; -import { MessageComponent } from './message.component'; -import { RadiosComponent } from './radios.component'; -import { SelectFrameworkComponent } from './select-framework.component'; -import { SelectWidgetComponent } from './select-widget.component'; -import { SelectComponent } from './select.component'; -import { SubmitComponent } from './submit.component'; -import { TabsComponent } from './tabs.component'; -import { TemplateComponent } from './template.component'; -import { CommonModule } from '@angular/common'; +import { + AddReferenceComponent, ButtonComponent, CheckboxComponent, CheckboxesComponent, + FileComponent, HiddenComponent, InputComponent, MessageComponent, NoneComponent, NumberComponent, + OneOfComponent, RadiosComponent, RootComponent, SectionComponent, + SelectFrameworkComponent, SelectWidgetComponent, SelectComponent, SubmitComponent, + TabComponent, TabsComponent, TemplateComponent, TextareaComponent, + BASIC_WIDGETS, Widget +} from '.'; @Component({ selector: 'test-component', @@ -32,8 +29,8 @@ class TestFramework extends Framework { @NgModule({ imports: [ CommonModule ], - declarations: [ TestComponent, MessageComponent ], - entryComponents: [ TestComponent, MessageComponent ], + declarations: [ TestComponent ], + entryComponents: [ TestComponent ], providers: [ { provide: Framework, useClass: TestFramework, multi: true } ] @@ -68,6 +65,7 @@ describe('widgets', () => { getParentNode: {}, initializeControl: undefined, setArrayItemTitle: '', + setItemTitle: '', updateArrayCheckboxList: undefined, updateValue: undefined }); @@ -78,17 +76,7 @@ describe('widgets', () => { TestBed.configureTestingModule({ imports: [ TestModule ], declarations: [ - AddReferenceComponent, - ButtonComponent, - CheckboxComponent, - CheckboxesComponent, - RadiosComponent, - SelectFrameworkComponent, - SelectWidgetComponent, - SelectComponent, - SubmitComponent, - TabsComponent, - TemplateComponent + BASIC_WIDGETS ], providers: [{ provide: JsonSchemaFormService, @@ -266,13 +254,117 @@ describe('widgets', () => { }); }); - // File - // Hidden - // Input - // Message - verify message set - // None - // Number - verify allowDecimal set - // OneOf + describe('FileComponent', () => { + let component: FileComponent; + + beforeEach(() => { + component = setupComponent(FileComponent); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + }); + }); + + describe('HiddenComponent', () => { + let component: HiddenComponent; + + beforeEach(() => { + component = setupComponent(HiddenComponent); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + }); + }); + + describe('InputComponent', () => { + let component: InputComponent; + + beforeEach(() => { + component = setupComponent(InputComponent); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + }); + }); + + describe('MessageComponent', () => { + let component: MessageComponent; + + beforeEach(() => { + component = setupComponent(MessageComponent, (comp) => { + comp.layoutNode.options = { + help: 'Help', + helpvalue: 'HelpValue', + msg: 'Msg', + message: 'Message' + }; + + return true; + }); + }); + + it('should set message to options.help', () => { + fixture.detectChanges(); + expect(component.message).toEqual(component.options.help); + }); + + it('should set message to options.helpvalue', () => { + component.layoutNode.options.help = null; + fixture.detectChanges(); + expect(component.message).toEqual(component.options.helpvalue); + }); + + it('should set message to options.msg', () => { + component.layoutNode.options.help = component.layoutNode.options.helpvalue = null; + fixture.detectChanges(); + expect(component.message).toEqual(component.options.msg); + }); + + it('should set message to options.message', () => { + component.layoutNode.options.help = component.layoutNode.options.helpvalue = component.layoutNode.options.msg = null; + fixture.detectChanges(); + expect(component.message).toEqual(component.options.message); + }); + }); + + describe('NoneComponent', () => { + let component: NoneComponent; + + beforeEach(() => { + component = setupComponent(NoneComponent); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + }); + }); + + describe('NumberComponent', () => { + let component: NumberComponent; + + beforeEach(() => { + component = setupComponent(NumberComponent); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + }); + }); + + describe('OneOfComponent', () => { + let component: OneOfComponent; + + beforeEach(() => { + component = setupComponent(OneOfComponent); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + }); + }); describe('RadiosComponent', () => { let component: RadiosComponent; @@ -288,7 +380,7 @@ describe('widgets', () => { }); }); - it('should set orianentation to horizontal', () => { + it('should set orientation to horizontal', () => { component.layoutNode.type = 'radios-inline'; fixture.detectChanges(); expect(component.layoutOrientation).toEqual('horizontal'); @@ -306,9 +398,25 @@ describe('widgets', () => { }); }); - describe('RootComponent', () => {}); + describe('RootComponent', () => { + let component: RootComponent; - describe('SectionComponent', () => {}); + beforeEach(() => { + component = setupComponent(RootComponent); + }); + + it('should fail', fail); + }); + + describe('SectionComponent', () => { + let component: SectionComponent; + + beforeEach(() => { + component = setupComponent(SectionComponent); + }); + + it('should fail', fail); + }); describe('SelectFrameworkComponent', () => { let component: SelectFrameworkComponent; @@ -329,12 +437,12 @@ describe('widgets', () => { beforeEach(() => { component = setupComponent(SelectWidgetComponent, (comp) => { - comp.layoutNode.widget = MessageComponent; + comp.layoutNode.widget = TestComponent; }); }); it('should instantiate widget', () => { - expect(component.newComponent.componentType).toEqual(MessageComponent); + expect(component.newComponent.componentType).toEqual(TestComponent); }); }); @@ -367,13 +475,49 @@ describe('widgets', () => { beforeEach(() => { component = setupComponent(SubmitComponent, (comp) => { comp.layoutNode.type = 'submit'; + comp['jsf'].isValidChanges = new Subject(); + + return true; }); }); - it('should fail', fail); + it('should set controlDisabled to options.disabled', () => { + component.layoutNode.options = {disabled: true}; + fixture.detectChanges(); + expect(component.controlDisabled).toBeTruthy(); + }); + + it('should set controlDisabled to form valid state', () => { + component['jsf'].formOptions.disableInvalidSubmit = true; + component['jsf'].isValid = false; + fixture.detectChanges(); + expect(component.controlDisabled).toBeTruthy(); + component['jsf'].isValidChanges.next(true); + expect(component.controlDisabled).toBeFalsy(); + }); + + it('should set controlValue to options.title', () => { + component.controlValue = null; + component.layoutNode.options = {title: 'Submit'}; + fixture.detectChanges(); + expect(component.controlValue).toEqual('Submit'); + }); }); - // Tab + describe('TabComponent', () => { + let component: TabComponent; + + beforeEach(() => { + component = setupComponent(TabComponent, (comp) => { + comp.layoutNode.options = {items: []}; + }); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + expect(component.options).toEqual({items: []}); + }); + }); describe('TabsComponent', () => { let component: TabsComponent; @@ -402,7 +546,19 @@ describe('widgets', () => { expect(component.newComponent.instance.layoutIndex).toEqual(component.layoutIndex); expect(component.newComponent.instance.dataIndex).toEqual(component.dataIndex); }); + + it('should fail', fail); }); - // TextArea + describe('TextareaComponent', () => { + let component: TextareaComponent; + + beforeEach(() => { + component = setupComponent(TextareaComponent); + }); + + it('should instantiate', () => { + expect(component).toBeDefined(); + }); + }); }); From 7b2f172b003a1574c58de64a89a463b7c28a0e70 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Tue, 5 Jun 2018 13:35:01 -0400 Subject: [PATCH 11/18] Implemented tests for Root and Tabs components --- package.json | 6 +- src/lib/src/widget-library/root.component.ts | 2 +- src/lib/src/widget-library/tabs.component.ts | 6 +- src/lib/src/widget-library/widgets.spec.ts | 162 ++++++++++++++++++- 4 files changed, 162 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 05765a49..3c52cab6 100755 --- a/package.json +++ b/package.json @@ -40,9 +40,9 @@ "ng": "ng", "serve": "ng serve", "start": "ng serve", - "test": "ng test --app lib --sr && ng test --app demo --sr", - "test:lib": "ng test --app lib", - "test:demo": "ng test --app demo", + "test": "ng test --cc --app lib --sr && ng test --cc --app demo --sr", + "test:lib": "ng test --cc --app lib", + "test:demo": "ng test --cc --app demo", "lint": "ng lint", "docs": "typedoc src/lib/src/", "clean": "rimraf out-ngc dist/*", diff --git a/src/lib/src/widget-library/root.component.ts b/src/lib/src/widget-library/root.component.ts index 94662e45..705f7182 100755 --- a/src/lib/src/widget-library/root.component.ts +++ b/src/lib/src/widget-library/root.component.ts @@ -65,7 +65,7 @@ export class RootComponent extends Widget implements OnInit { // Set attributes for flexbox child // (container attributes are set in section.component) - getFlexAttribute(node: any, attribute: string) { + getFlexAttribute(node: any, attribute: string): string { const index = ['flex-grow', 'flex-shrink', 'flex-basis'].indexOf(attribute); return ((node.options || {}).flex || '').split(/\s+/)[index] || (node.options || {})[attribute] || ['1', '1', 'auto'][index]; diff --git a/src/lib/src/widget-library/tabs.component.ts b/src/lib/src/widget-library/tabs.component.ts index bfd4ce81..8b32d122 100755 --- a/src/lib/src/widget-library/tabs.component.ts +++ b/src/lib/src/widget-library/tabs.component.ts @@ -66,11 +66,7 @@ export class TabsComponent extends Widget implements OnInit { updateControl() { const lastItem = this.layoutNode.items[this.layoutNode.items.length - 1]; - if (lastItem.type === '$ref' && - this.itemCount >= (lastItem.options.maxItems || 1000) - ) { - this.showAddTab = false; - } + this.showAddTab = lastItem.type !== '$ref' || this.itemCount < (lastItem.options.maxItems || 1000); } setTabTitle(item: any, index: number): string { diff --git a/src/lib/src/widget-library/widgets.spec.ts b/src/lib/src/widget-library/widgets.spec.ts index 2c9ac3d5..c980a071 100644 --- a/src/lib/src/widget-library/widgets.spec.ts +++ b/src/lib/src/widget-library/widgets.spec.ts @@ -60,6 +60,7 @@ describe('widgets', () => { beforeEach(async(() => { mockFormService = jasmine.createSpyObj('JsonSchemaFormService', { addItem: undefined, + evaluateCondition: true, getFormControl: null, getFormControlValue: null, getParentNode: {}, @@ -161,26 +162,40 @@ describe('widgets', () => { beforeEach(() => { component = setupComponent(CheckboxComponent, (comp) => { comp.controlValue = true; + + return true; }); }); it('should return true for checked', () => { + fixture.detectChanges(); (mockFormService.getFormControlValue).and.returnValue(true); expect(component.isChecked).toBeTruthy(); }); it('should return false for checked', () => { + fixture.detectChanges(); (mockFormService.getFormControlValue).and.returnValue(false); expect(component.isChecked).toBeFalsy(); }); it('should call jsf to update value', () => { + fixture.detectChanges(); component.updateValue({target: {checked: true}, preventDefault: jasmine.createSpy('0')}); expect(mockFormService.updateValue).toHaveBeenCalledWith(component, true); component.updateValue({target: {}, preventDefault: jasmine.createSpy('1')}); expect(mockFormService.updateValue).toHaveBeenCalledWith(component, false); }); + + it('should set controlValue via options', () => { + component.layoutNode.options = { + title: 'test' + }; + component.controlValue = null; + fixture.detectChanges(); + expect(component.controlValue).toEqual('test'); + }); }); describe('CheckboxesComponent', () => { @@ -403,9 +418,78 @@ describe('widgets', () => { beforeEach(() => { component = setupComponent(RootComponent); + component.dataIndex = [2]; + }); + + it('should be draggable', () => { + component.isOrderable = true; + + expect(component.isDraggable({ + arrayItem: true, + type: 'number', + arrayItemType: 'list' + })).toBeTruthy(); + + component.isOrderable = undefined; + + expect(component.isDraggable({ + arrayItem: true, + type: 'number', + arrayItemType: 'list' + })).toBeTruthy(); + }); + + it('should NOT be draggable', () => { + component.isOrderable = false; + + expect(component.isDraggable({ + arrayItem: true, + type: 'number', + arrayItemType: 'list' + })).toBeFalsy(); + + component.isOrderable = true; + + expect(component.isDraggable({ + arrayItem: false, + type: 'number', + arrayItemType: 'list' + })).toBeFalsy(); + expect(component.isDraggable({ + arrayItem: true, + type: '$ref', + arrayItemType: 'list' + })).toBeFalsy(); + expect(component.isDraggable({ + arrayItem: true, + type: 'number', + arrayItemType: 'array' + })).toBeFalsy(); + }); + + it('should get flex attribute from defaults', () => { + expect(component.getFlexAttribute({}, 'flex-grow')).toEqual('1'); + }); + + it('should get flex attribute from base options', () => { + expect(component.getFlexAttribute({options: {'flex-shrink': '0'}}, 'flex-shrink')).toEqual('0'); + }); + + it('should get flex attribute from options.flex', () => { + expect(component.getFlexAttribute({options: {flex: '1 1 200px'}}, 'flex-basis')).toEqual('200px'); }); - it('should fail', fail); + it('should show widget', () => { + (mockFormService.evaluateCondition).and.returnValue(true); + expect(component.showWidget({})).toBeTruthy(); + expect(mockFormService.evaluateCondition).toHaveBeenCalledWith({}, component.dataIndex); + }); + + it('should hide widget', () => { + (mockFormService.evaluateCondition).and.returnValue(false); + expect(component.showWidget({})).toBeFalsy(); + expect(mockFormService.evaluateCondition).toHaveBeenCalledWith({}, component.dataIndex); + }); }); describe('SectionComponent', () => { @@ -415,7 +499,26 @@ describe('widgets', () => { component = setupComponent(SectionComponent); }); - it('should fail', fail); + it('should NOT toggle the expanded property by default', () => { + component.toggleExpanded(); + expect(component.expanded).toBeTruthy(); + }); + + it('should toggle the expanded property', () => { + component.options.expandable = true; + component.toggleExpanded(); + expect(component.expanded).toBeFalsy(); + }); + + it('should return null for title', () => { + component.options.notitle = true; + expect(component.sectionTitle).toBeNull(); + }); + + it('should call service for title', () => { + (mockFormService.setItemTitle).and.returnValue('Hi'); + expect(component.sectionTitle).toEqual('Hi'); + }); }); describe('SelectFrameworkComponent', () => { @@ -524,11 +627,56 @@ describe('widgets', () => { beforeEach(() => { component = setupComponent(TabsComponent, (comp) => { - comp.layoutNode.items = [{}]; + comp.layoutNode.items = [{options: {}}]; + }); + }); + + it('should call service to setTitle', () => { + (mockFormService.setArrayItemTitle).and.returnValue('Hello'); + expect(component.setTabTitle({x: 0}, 2)).toEqual('Hello'); + expect(mockFormService.setArrayItemTitle).toHaveBeenCalledWith(component, {x: 0}, 2); + }); + + it('should show tab', () => { + component.showAddTab = false; + component.layoutNode.items[0].type = 'number'; + component.updateControl(); + expect(component.showAddTab).toBeTruthy(); + }); + + it('should show tab', () => { + component.showAddTab = false; + component.layoutNode.items[0].type = '$ref'; + component.updateControl(); + expect(component.showAddTab).toBeTruthy(); + }); + + it('should NOT show tab', () => { + component.showAddTab = true; + component.layoutNode.items[0].type = '$ref'; + component.layoutNode.items[0].options.maxItems = 1; + component.itemCount = 1; + component.updateControl(); + expect(component.showAddTab).toBeFalsy(); + }); + + it('should call service to select tab', () => { + component.layoutNode.items[0].type = '$ref'; + component.select(0); + expect(component.selectedItem).toEqual(0); + expect(mockFormService.addItem).toHaveBeenCalledWith({ + layoutNode: component.layoutNode.items[0], + layoutIndex: [0, 0], + dataIndex: [0] }); + expect(component.itemCount).toEqual(1); }); - it('should fail', fail); + it('should NOT call service to show existing tab', () => { + component.select(0); + expect(component.selectedItem).toEqual(0); + expect(mockFormService.addItem).not.toHaveBeenCalled(); + }); }); describe('TemplateComponent', () => { @@ -547,7 +695,11 @@ describe('widgets', () => { expect(component.newComponent.instance.dataIndex).toEqual(component.dataIndex); }); - it('should fail', fail); + it('should update component when input changes', () => { + component.dataIndex = [3]; + component.ngOnChanges(); + expect(component.newComponent.instance.dataIndex).toEqual(component.dataIndex); + }); }); describe('TextareaComponent', () => { From dfecc62a9581873c6a7d7e235b170e819a9760fa Mon Sep 17 00:00:00 2001 From: James Scharett Date: Tue, 5 Jun 2018 15:50:14 -0400 Subject: [PATCH 12/18] Tests for Section widget --- .../src/widget-library/section.component.ts | 2 +- src/lib/src/widget-library/widgets.spec.ts | 100 ++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/lib/src/widget-library/section.component.ts b/src/lib/src/widget-library/section.component.ts index 8c04643a..330a9ecf 100755 --- a/src/lib/src/widget-library/section.component.ts +++ b/src/lib/src/widget-library/section.component.ts @@ -112,7 +112,7 @@ export class SectionComponent extends Widget implements OnInit { this.layoutNode.type === 'flex' || !!this.options.displayFlex || this.options.display === 'flex'; - if (attribute !== 'flex' && !flexActive) { return null; } + if (!flexActive && attribute !== 'flex' && attribute !== 'display') { return null; } switch (attribute) { case 'is-flex': return flexActive; diff --git a/src/lib/src/widget-library/widgets.spec.ts b/src/lib/src/widget-library/widgets.spec.ts index c980a071..9b657153 100644 --- a/src/lib/src/widget-library/widgets.spec.ts +++ b/src/lib/src/widget-library/widgets.spec.ts @@ -499,6 +499,31 @@ describe('widgets', () => { component = setupComponent(SectionComponent); }); + it('should default to div', () => { + expect(component.containerType).toEqual('div'); + }); + + it('should set container type to fieldset', () => { + ['fieldset', 'array', 'tab', 'advancedfieldset', + 'authfieldset', 'optionfieldset', 'selectfieldset'].forEach((type) => { + component.containerType = 'div'; + component.layoutNode.type = type; + component.ngOnInit(); + expect(component.containerType).toEqual('fieldset'); + }); + }); + + it('should set default expanded to false', () => { + component.layoutNode.options = {expanded: false}; + component.ngOnInit(); + expect(component.expanded).toBeFalsy(); + + component.layoutNode.options.expanded = undefined; + component.layoutNode.options.expandable = true; + component.ngOnInit(); + expect(component.expanded).toBeFalsy(); + }); + it('should NOT toggle the expanded property by default', () => { component.toggleExpanded(); expect(component.expanded).toBeTruthy(); @@ -519,6 +544,81 @@ describe('widgets', () => { (mockFormService.setItemTitle).and.returnValue('Hi'); expect(component.sectionTitle).toEqual('Hi'); }); + + describe('getFlexAttribute', () => { + it('should return null', () => { + expect(component.getFlexAttribute('is-flex')).toBeNull(); + }); + + it('should return undefined', () => { + expect(component.getFlexAttribute('flex')).toBeUndefined(); + }); + + it('should return is-flex as true', () => { + component.layoutNode.type = 'flex'; + expect(component.getFlexAttribute('is-flex')).toBeTruthy(); + + component.layoutNode = {}; + component.options.displayFlex = true; + + expect(component.getFlexAttribute('is-flex')).toBeTruthy(); + + component.options.displayFlex = undefined; + component.options.display = 'flex'; + + expect(component.getFlexAttribute('is-flex')).toBeTruthy(); + }); + + it('should return is-flex as false', () => { + expect(component.getFlexAttribute('is-flex')).toBeFalsy(); + }); + + it('should resolve display as flex', () => { + component.layoutNode.type = 'flex'; + expect(component.getFlexAttribute('display')).toEqual('flex'); + }); + + it('should resolve display as initial', () => { + expect(component.getFlexAttribute('display')).toEqual('initial'); + }); + + it('should resolve flex-direction and flex-wrap with defaults', () => { + component.layoutNode.type = 'flex'; + expect(component.getFlexAttribute('flex-direction')).toEqual('column'); + expect(component.getFlexAttribute('flex-wrap')).toEqual('nowrap'); + }); + + it('should resolve flex-direction and flex-wrap with options', () => { + component.layoutNode.type = 'flex'; + component.options = { + 'flex-direction': 'row', + 'flex-wrap': 'wrap' + }; + expect(component.getFlexAttribute('flex-direction')).toEqual('row'); + expect(component.getFlexAttribute('flex-wrap')).toEqual('wrap'); + }); + + it('should resolve flex-direction and flex-wrap with flex-flow', () => { + component.layoutNode.type = 'flex'; + component.options = { + 'flex-flow': 'row wrap' + }; + expect(component.getFlexAttribute('flex-direction')).toEqual('row'); + expect(component.getFlexAttribute('flex-wrap')).toEqual('wrap'); + }); + + it('should resolve justify-content, align-items, align-content', () => { + component.layoutNode.type = 'flex'; + component.options = { + 'justify-content': 'flex-start', + 'align-items': 'flex-end', + 'align-content': 'center' + }; + expect(component.getFlexAttribute('justify-content')).toEqual('flex-start'); + expect(component.getFlexAttribute('align-items')).toEqual('flex-end'); + expect(component.getFlexAttribute('align-content')).toEqual('center'); + }); + }); }); describe('SelectFrameworkComponent', () => { From 4012b68b5bb65d7378421bb9c2c4be2109645a44 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Tue, 5 Jun 2018 16:04:37 -0400 Subject: [PATCH 13/18] Restored layout prop to root component --- src/lib/src/widget-library/root.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/src/widget-library/root.component.ts b/src/lib/src/widget-library/root.component.ts index 705f7182..9b05a3f7 100755 --- a/src/lib/src/widget-library/root.component.ts +++ b/src/lib/src/widget-library/root.component.ts @@ -51,6 +51,7 @@ import { Widget } from './widget'; export class RootComponent extends Widget implements OnInit { @Input() isOrderable: boolean; @Input() isFlexItem = false; + @Input() layout: any[]; constructor(jsf: JsonSchemaFormService) { super(jsf); From 5ae4e63d802dcddff476eb36f2ff8431f61e1e50 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Wed, 6 Jun 2018 20:40:26 -0400 Subject: [PATCH 14/18] Tests for minand max Items --- src/lib/src/shared/json.validators.spec.ts | 106 +++++++++++++++++++++ src/lib/src/shared/json.validators.ts | 2 +- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/lib/src/shared/json.validators.spec.ts diff --git a/src/lib/src/shared/json.validators.spec.ts b/src/lib/src/shared/json.validators.spec.ts new file mode 100644 index 00000000..b6f75045 --- /dev/null +++ b/src/lib/src/shared/json.validators.spec.ts @@ -0,0 +1,106 @@ +import { JsonValidators } from '.'; +import { AbstractControl } from '@angular/forms'; + +describe('JsonValidators', () => { + let control: AbstractControl; + let controlValue: any; + + beforeEach(() => { + controlValue = null; + control = { + get value() { + return controlValue; + } + }; + }); + +describe('required', () => {}); + describe('type', () => {}); + describe('enum', () => {}); + describe('const', () => {}); +describe('minLength', () => {}); +describe('maxLength', () => {}); +describe('pattern', () => {}); + describe('format', () => {}); + describe('minimum', () => {}); + describe('exclusiveMinimum', () => {}); + describe('maximum', () => {}); + describe('exclusiveMaximum', () => {}); + describe('multipleOf', () => {}); + describe('minProperties', () => {}); + describe('maxProperties', () => {}); + describe('dependencies', () => {}); + + describe('minItems', () => { + describe('valid', () => { + it('should be valid when minItems = null', () => { + expect(JsonValidators.minItems(null)(control)).toBeNull(); + }); + it('should be valid when value = minItems', () => { + controlValue = [1, 2, 3]; + expect(JsonValidators.minItems(3)(control)).toBeNull(); + }); + it('should be valid when value > minItems', () => { + controlValue = [1, 2, 3, 4]; + expect(JsonValidators.minItems(3)(control)).toBeNull(); + }); + }); + describe('invalid', () => { + it('should be invalid when value < minItems', () => { + controlValue = [1, 2]; + expect(JsonValidators.minItems(3)(control)).toEqual({ + minItems: { + minimumItems: 3, + currentItems: 2 + } + }); + }); + it('should be invalid when no items', () => { + controlValue = []; + expect(JsonValidators.minItems(3)(control)).toEqual({ + minItems: { + minimumItems: 3, + currentItems: 0 + } + }); + }); + }); + }); + + describe('maxItems', () => { + describe('valid', () => { + it('should be valid when maxItems = null', () => { + expect(JsonValidators.maxItems(null)(control)).toBeNull(); + }); + it('should be valid when value < maxItems', () => { + controlValue = [1, 2]; + expect(JsonValidators.maxItems(3)(control)).toBeNull(); + }); + it('should be valid when value = maxItems', () => { + controlValue = [1, 2, 3]; + expect(JsonValidators.maxItems(3)(control)).toBeNull(); + }); + }); + describe('invalid', () => { + it('should be invalid when value > maxItems', () => { + controlValue = [1, 2, 3, 4]; + expect(JsonValidators.maxItems(3)(control)).toEqual({ + maxItems: { + maximumItems: 3, + currentItems: 4 + } + }); + }); + }); + }); + + describe('uniqueItems', () => {}); + describe('contains', () => {}); +describe('nullValidator', () => {}); + describe('composeAnyOf', () => {}); + describe('composeOneOf', () => {}); + describe('composeAllOf', () => {}); + describe('composeNot', () => {}); +describe('compose', () => {}); +describe('composeAsync', () => {}); +}); diff --git a/src/lib/src/shared/json.validators.ts b/src/lib/src/shared/json.validators.ts index 34ebb8e0..7f5817e7 100755 --- a/src/lib/src/shared/json.validators.ts +++ b/src/lib/src/shared/json.validators.ts @@ -586,7 +586,7 @@ export class JsonValidators { static minItems(minimumItems: number): IValidatorFn { if (!hasValue(minimumItems)) { return JsonValidators.nullValidator; } return (control: AbstractControl, invert = false): ValidationErrors|null => { - if (isEmpty(control.value)) { return null; } + if (!isDefined(control.value)) { return null; } let currentItems = isArray(control.value) ? control.value.length : 0; let isValid = currentItems >= minimumItems; return xor(isValid, invert) ? From 98edae9a7a607c0902f67cb9c5f94f1302043988 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Fri, 8 Jun 2018 09:55:10 -0400 Subject: [PATCH 15/18] Fixed uniqueItems Added tests for inverted validators --- src/lib/src/shared/json.validators.spec.ts | 65 +++++++++++++++++++++- src/lib/src/shared/json.validators.ts | 2 +- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/lib/src/shared/json.validators.spec.ts b/src/lib/src/shared/json.validators.spec.ts index b6f75045..4c025262 100644 --- a/src/lib/src/shared/json.validators.spec.ts +++ b/src/lib/src/shared/json.validators.spec.ts @@ -44,6 +44,10 @@ describe('pattern', () => {}); controlValue = [1, 2, 3, 4]; expect(JsonValidators.minItems(3)(control)).toBeNull(); }); + it('should be valid when value < minItems and inverted', () => { + controlValue = [1, 2]; + expect(JsonValidators.minItems(3)(control, true)).toBeNull(); + }); }); describe('invalid', () => { it('should be invalid when value < minItems', () => { @@ -64,6 +68,15 @@ describe('pattern', () => {}); } }); }); + it('should be invalid when value > minItems and inverted', () => { + controlValue = [1, 2, 3, 4]; + expect(JsonValidators.minItems(3)(control, true)).toEqual({ + minItems: { + minimumItems: 3, + currentItems: 4 + } + }); + }); }); }); @@ -80,6 +93,10 @@ describe('pattern', () => {}); controlValue = [1, 2, 3]; expect(JsonValidators.maxItems(3)(control)).toBeNull(); }); + it('should be valid when value > maxItems and inverted', () => { + controlValue = [1, 2, 3, 4]; + expect(JsonValidators.maxItems(3)(control, true)).toBeNull(); + }); }); describe('invalid', () => { it('should be invalid when value > maxItems', () => { @@ -91,10 +108,56 @@ describe('pattern', () => {}); } }); }); + it('should be invalid when value <= maxItems and inverted', () => { + controlValue = [1, 2]; + expect(JsonValidators.maxItems(3)(control, true)).toEqual({ + maxItems: { + maximumItems: 3, + currentItems: 2 + } + }); + }); + }); + }); + + describe('uniqueItems', () => { + describe('valid', () => { + it('should be valid when all items unique', () => { + controlValue = [1, 2, 3, 4]; + expect(JsonValidators.uniqueItems()(control)).toBeNull(); + }); + it('should be valid when no items', () => { + controlValue = []; + expect(JsonValidators.uniqueItems()(control)).toBeNull(); + }); + it('should be valid when no value', () => { + expect(JsonValidators.uniqueItems()(control)).toBeNull(); + }); + it('should be valid when duplicates and inverted', () => { + controlValue = [1, 3, 5, 2, 3, 4, 5]; + expect(JsonValidators.uniqueItems()(control, true)).toBeNull(); + }); + }); + describe('invalid', () => { + it('should be invalid when there are duplicates', () => { + controlValue = [1, 3, 5, 2, 3, 4, 5]; + expect(JsonValidators.uniqueItems()(control)).toEqual({ + uniqueItems: { + duplicateItems: [3, 5] + } + }); + }); + it('should be invalid when unique and inverted', () => { + controlValue = [1, 3, 5]; + expect(JsonValidators.uniqueItems()(control, true)).toEqual({ + uniqueItems: { + duplicateItems: [] + } + }); + }); }); }); - describe('uniqueItems', () => {}); describe('contains', () => {}); describe('nullValidator', () => {}); describe('composeAnyOf', () => {}); diff --git a/src/lib/src/shared/json.validators.ts b/src/lib/src/shared/json.validators.ts index 7f5817e7..a1e074b5 100755 --- a/src/lib/src/shared/json.validators.ts +++ b/src/lib/src/shared/json.validators.ts @@ -627,7 +627,7 @@ export class JsonValidators { let sorted: any[] = control.value.slice().sort(); let duplicateItems = []; for (let i = 1; i < sorted.length; i++) { - if (sorted[i - 1] === sorted[i] && duplicateItems.includes(sorted[i])) { + if (sorted[i - 1] === sorted[i] && !duplicateItems.includes(sorted[i])) { duplicateItems.push(sorted[i]); } } From f68d84c351fcc94b4223bd99d6c6540e91054cde Mon Sep 17 00:00:00 2001 From: James Scharett Date: Thu, 14 Jun 2018 15:49:22 -0400 Subject: [PATCH 16/18] Test multipleOf --- src/lib/src/shared/json.validators.spec.ts | 44 ++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/lib/src/shared/json.validators.spec.ts b/src/lib/src/shared/json.validators.spec.ts index 4c025262..17ad67e4 100644 --- a/src/lib/src/shared/json.validators.spec.ts +++ b/src/lib/src/shared/json.validators.spec.ts @@ -22,11 +22,49 @@ describe('minLength', () => {}); describe('maxLength', () => {}); describe('pattern', () => {}); describe('format', () => {}); - describe('minimum', () => {}); + describe('minimum', () => {}); describe('exclusiveMinimum', () => {}); - describe('maximum', () => {}); + describe('maximum', () => {}); describe('exclusiveMaximum', () => {}); - describe('multipleOf', () => {}); + + describe('multipleOf', () => { + describe('valid', () => { + it('should be vaild when multiple', () => { + controlValue = 12; + expect(JsonValidators.multipleOf(1)(control)).toBeNull(); + expect(JsonValidators.multipleOf(2)(control)).toBeNull(); + expect(JsonValidators.multipleOf(3)(control)).toBeNull(); + expect(JsonValidators.multipleOf(4)(control)).toBeNull(); + expect(JsonValidators.multipleOf(6)(control)).toBeNull(); + expect(JsonValidators.multipleOf(12)(control)).toBeNull(); + }); + it('should be valid when invalid and inverted', () => { + controlValue = 12; + expect(JsonValidators.multipleOf(5)(control, true)).toBeNull(); + }); + }); + describe('invalid', () => { + it('should be invalid when not multiple ', () => { + controlValue = 12; + expect(JsonValidators.multipleOf(5)(control)).toEqual({ + multipleOf: { + multipleOfValue: 5, + currentValue: 12 + } + }); + }); + it('should be invalid when valid and inverted', () => { + controlValue = 12; + expect(JsonValidators.multipleOf(3)(control, true)).toEqual({ + multipleOf: { + multipleOfValue: 3, + currentValue: 12 + } + }); + }); + }); + }); + describe('minProperties', () => {}); describe('maxProperties', () => {}); describe('dependencies', () => {}); From d7ff57dcec074171aa1894ed47491220240b5b62 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Wed, 25 Jul 2018 10:08:20 -0400 Subject: [PATCH 17/18] Added tests for required validator --- src/lib/src/shared/json.validators.spec.ts | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/lib/src/shared/json.validators.spec.ts b/src/lib/src/shared/json.validators.spec.ts index 17ad67e4..2365a963 100644 --- a/src/lib/src/shared/json.validators.spec.ts +++ b/src/lib/src/shared/json.validators.spec.ts @@ -15,7 +15,49 @@ describe('JsonValidators', () => { }); describe('required', () => {}); - describe('type', () => {}); + + describe('type', () => { + describe('valid', () => { + it('should be valid when matches type', () => { + controlValue = 12; + expect(JsonValidators.type('number')(control)).toBeNull(); + expect(JsonValidators.type('integer')(control)).toBeNull(); + }); + it('should be valid when null', () => { + expect(JsonValidators.type('number')(control)).toBeNull(); + }); + }); + describe('invalid', () => { + it('should be invalid when not of type', () => { + controlValue = 12; + expect(JsonValidators.type('string')(control)).toEqual({ + type: { + requiredType: 'string', + currentValue: 12 + } + }); + }); + it('should be invalid when not of 1 or more are not or type', () => { + controlValue = 1.2; + expect(JsonValidators.type(['string', 'boolean', 'integer'])(control)).toEqual({ + type: { + requiredType: ['string', 'boolean', 'integer'], + currentValue: 1.2 + } + }); + }); + it('should be invalid when valid and inverted', () => { + controlValue = 12; + expect(JsonValidators.type('number')(control, true)).toEqual({ + type: { + requiredType: 'number', + currentValue: 12 + } + }); + }); + }); + }); + describe('enum', () => {}); describe('const', () => {}); describe('minLength', () => {}); From b31ba6ffd2bbba0602e0a8d9ccb4944714c63085 Mon Sep 17 00:00:00 2001 From: James Scharett Date: Fri, 27 Jul 2018 13:02:05 -0400 Subject: [PATCH 18/18] Added missing export --- src/lib/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/index.ts b/src/lib/index.ts index 718e59e3..a4a8f744 100755 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -37,6 +37,7 @@ export { JsonSchemaFormModule } from './src/json-schema-form.module'; export { WidgetLibraryService } from './src/widget-library/widget-library.service'; export { WidgetLibraryModule } from './src/widget-library/widget-library.module'; +export { Widget } from './src/widget-library/widget'; export { AddReferenceComponent } from './src/widget-library/add-reference.component'; export { OneOfComponent } from './src/widget-library/one-of.component'; export { ButtonComponent } from './src/widget-library/button.component';