UNPKG

ohayolibs

Version:

Ohayo is a set of essential modules for ohayojp.

512 lines (499 loc) 15.3 kB
import { DebugElement } from '@angular/core'; import { ComponentFixture, discardPeriodicTasks, fakeAsync } from '@angular/core/testing'; import { createTestContext } from '@ohayo/testing'; import { deepCopy } from '@ohayo/util'; import { ObjectProperty } from '../src/model/object.property'; import { SFSchema } from '../src/schema/index'; import { SFUISchema, SFUISchemaItem } from '../src/schema/ui'; import { configureSFTestSuite, SFPage, TestFormComponent } from './base.spec'; describe('form: schema', () => { let fixture: ComponentFixture<TestFormComponent>; let dl: DebugElement; let context: TestFormComponent; let page: SFPage; configureSFTestSuite(); beforeEach(() => { ({ fixture, dl, context } = createTestContext(TestFormComponent)); fixture.detectChanges(); page = new SFPage(context.comp); page.prop(dl, context, fixture); }); describe('[cover schema]', () => { beforeEach(() => spyOn(console, 'warn')); it('should be using select widget when not ui and enum exists', () => { page .newSchema({ properties: { name: { type: 'string', enum: ['a'] }, }, }) .checkUI('/name', 'widget', 'select'); }); it('should be using autocomplete widget when format equal email', () => { page .newSchema({ properties: { name: { type: 'string', format: 'email' }, }, }) .checkUI('/name', 'widget', 'autocomplete'); }); it('support ui property is a string', () => { page .newSchema({ properties: { name: { type: 'string', ui: 'textarea' }, }, }) .checkUI('/name', 'widget', 'textarea'); }); it('should be inherit all properties with * for ui schema', () => { const schema: SFSchema = { properties: { name1: { type: 'string' }, name2: { type: 'array', items: { type: 'object', properties: { a: { type: 'string', ui: { grid: { span: 12 }, }, }, b: { type: 'string' }, }, ui: { spanLabelFixed: 10 }, }, }, }, }; const label = 10; const ui: SFUISchema = { '*': { spanLabel: label }, $name2: { $items: { $a: { spanLabel: 9 }, }, }, }; page .newSchema(schema, ui) .checkUI('/name1', 'spanLabel', label) .add() .checkUI('/name2/0/a', 'spanLabel', null) // 当指定标签为固定宽度时无须指定 `spanLabel`,`spanControl` 会强制清理 .checkUI('/name2/0/b', 'spanLabelFixed', 10); }); it('should be fixed label width', () => { const schema: SFSchema = { properties: { name: { type: 'string' }, protocol: { type: 'boolean', title: '同意本协议', description: '《用户协议》', ui: { widget: 'checkbox', }, default: true, }, }, ui: { spanLabelFixed: 10, debug: true }, }; page.newSchema(schema).checkUI('/name', 'spanLabelFixed', 10).checkUI('/protocol', 'spanLabelFixed', 10); }); it('support invalid format value', () => { page .newSchema({ properties: { name: { type: 'string', format: 'email1' }, }, }) .checkUI('/name', 'widget', 'string'); }); it('should be null spanLabel when not horizontal layout', () => { context.layout = 'inline'; fixture.detectChanges(); page.checkUI('/name', 'spanLabel', null); }); it('should call refreshSchema changed schema', fakeAsync(() => { context.comp.refreshSchema( { properties: { user: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'number' }, }, }, }, }, { '*': { spanLabelFixed: 100, spanControl: 10, offsetControl: 11 } }, ); page.checkUI('/user/name', 'spanLabelFixed', 100); page.checkUI('/user/name', 'spanControl', null); // 当指定标签为固定宽度时无须指定 `spanLabel`,`spanControl` 会强制清理 page.checkUI('/user/name', 'offsetControl', 11); discardPeriodicTasks(); })); it('support ui is null', () => { expect(() => { context.ui = null; fixture.detectChanges(); }).not.toThrow(); }); describe('#array', () => { const arrUI: SFUISchemaItem = { spanLabel: 10, grid: { arraySpan: 12 } }; const arrSchema: SFSchema = { properties: { name: { type: 'array', items: { type: 'object', properties: { a: { type: 'string' }, }, }, }, }, }; describe('[#via in json schema]', () => { it('should be has $items when is array', () => { const schema = deepCopy(arrSchema) as SFSchema; schema.properties!.name.ui = deepCopy(arrUI); page.newSchema(schema).checkUI('/name', 'grid.arraySpan', arrUI.grid!.arraySpan); }); }); describe('[#via ui property]', () => { it('should be has $items when is array', () => { const schema = deepCopy(arrSchema); const uiSchema: SFUISchema = { $name: { $items: {}, ...deepCopy(arrUI), }, }; page.newSchema(schema, uiSchema).checkUI('/name', 'grid.arraySpan', arrUI.grid!.arraySpan); }); }); }); describe('#optionalHelp', () => { it('should working when value is string', fakeAsync(() => { context.comp.refreshSchema({ properties: { name: { type: 'string', ui: { optionalHelp: 'a' } }, }, }); page.checkCount('.sf__optional [nz-tooltip]', 1); discardPeriodicTasks(); })); it('should working when value is object', fakeAsync(() => { context.comp.refreshSchema({ properties: { name: { type: 'string', ui: { optionalHelp: { text: 'b', placement: 'bottomRight' } } }, }, }); page.checkCount('.sf__optional [nz-tooltip]', 1); discardPeriodicTasks(); })); it('should be hide when not text value in object', fakeAsync(() => { context.comp.refreshSchema({ properties: { name: { type: 'string', ui: { optionalHelp: { text: '', placement: 'bottomRight' } } }, }, }); page.checkCount('.sf__optional [nz-tooltip]', 0); discardPeriodicTasks(); })); it('should be inherit the root config', fakeAsync(() => { context.comp.refreshSchema( { properties: { name: { type: 'string', ui: { optionalHelp: { text: 'a' } } }, }, }, { '*': { optionalHelp: { text: '', placement: 'bottomRight' } } }, ); const prop = page.getProperty('/name'); expect((prop!.ui!.optionalHelp as any).placement!).toBe(`bottomRight`); discardPeriodicTasks(); })); }); }); describe('[definitions]', () => { it('should be ref definitions', () => { page .newSchema({ definitions: { large: { type: 'string', maxLength: 10, }, }, properties: { name: { $ref: '#/definitions/large' }, }, }) .checkSchema('/name', 'maxLength', 10); }); it('should be throw error when not fond defind', () => { expect(() => { page.newSchema({ definitions: {}, properties: { name: { $ref: '#/definitions/large' }, }, }); }).toThrow(); }); it('should be throw error when is invalid $ref', () => { expect(() => { page.newSchema({ definitions: {}, properties: { name: { $ref: 'definitions/large' }, }, }); }).toThrow(); }); }); describe('[if]', () => { it('should be changed login type via if', () => { page .newSchema({ properties: { login_type: { type: 'string', title: '登录方式', enum: [ { label: '手机', value: 'mobile' }, { label: '账密', value: 'account' }, ], default: 'mobile', ui: { widget: 'radio', class: 'j-login_type', }, }, mobile: { type: 'string', ui: { class: 'j-mobile' } }, code: { type: 'number', ui: { class: 'j-code' } }, name: { type: 'string', ui: { class: 'j-name' } }, pwd: { type: 'string', ui: { type: 'password', class: 'j-pwd', }, }, }, required: ['login_type'], if: { properties: { login_type: { enum: ['mobile'] } }, }, then: { required: ['mobile', 'code'], }, else: { required: ['name', 'pwd'], }, }) .checkCount('.j-mobile', 1) .checkCount('.j-name', 0); const labels = page.getEl('.j-login_type nz-radio-group').querySelectorAll('label'); expect(labels.length).toBe(2); labels[1].click(); page.checkCount('.j-mobile', 0).checkCount('.j-name', 1); }); it('should be not else', () => { page .newSchema({ properties: { login_type: { type: 'string', title: '登录方式', enum: [ { label: '手机', value: 'mobile' }, { label: '账密', value: 'account' }, ], default: 'mobile', ui: { widget: 'radio', class: 'j-login_type', }, }, mobile: { type: 'string', ui: { class: 'j-mobile' } }, code: { type: 'number', ui: { class: 'j-code' } }, name: { type: 'string', ui: { class: 'j-name' } }, pwd: { type: 'string', ui: { type: 'password', class: 'j-pwd', }, }, }, required: ['login_type'], if: { properties: { login_type: { enum: ['mobile'] } }, }, then: { required: ['mobile', 'code'], }, }) .checkCount('.j-mobile', 1) .checkCount('.j-name', 1); const labels = page.getEl('.j-login_type nz-radio-group').querySelectorAll('label'); expect(labels.length).toBe(2); labels[1].click(); page.checkCount('.j-mobile', 0).checkCount('.j-name', 1); }); it(`should be throw error when is not 'properties' for if`, () => { expect(() => { page.newSchema({ properties: { name: { type: 'string' } }, if: {}, then: {}, }); }).toThrowError(`if: does not contain 'properties'`); }); it(`should be throw error when invalid key for 'properties' in if`, () => { expect(() => { page.newSchema({ properties: { login_type: { type: 'string', title: '登录方式', enum: [ { label: '手机', value: 'mobile' }, { label: '账密', value: 'account' }, ], default: 'mobile', ui: { widget: 'radio', class: 'j-login_type', }, }, mobile: { type: 'string', ui: { class: 'j-mobile' } }, code: { type: 'number', ui: { class: 'j-code' } }, name: { type: 'string', ui: { class: 'j-name' } }, pwd: { type: 'string', ui: { type: 'password', class: 'j-pwd', }, }, }, required: ['login_type'], if: { properties: { login_type1: { enum: ['mobile'] } }, }, then: { required: ['mobile', 'code'], }, }); }).toThrow(); }); }); describe('[order]', () => { function genKeys(): string { return JSON.stringify(Object.keys((context.comp.rootProperty as ObjectProperty).properties!)); } function checkOrderKeys(arr: string[]): void { expect(genKeys()).toBe(JSON.stringify(arr)); } it('should be adjust the order', () => { const order = ['pwd', 'name']; page.newSchema({ properties: { name: { type: 'string' }, pwd: { type: 'string' }, }, ui: { order, }, }); checkOrderKeys(order); }); it('should be used *', () => { page.newSchema({ properties: { a: { type: 'string' }, b: { type: 'string' }, c: { type: 'string' }, }, ui: { order: ['b', '*'], }, }); checkOrderKeys(['b', 'a', 'c']); }); describe('should be throw error', () => { beforeEach(() => spyOn(console, 'error')); it('when has extraneous key', () => { expect(() => { page.newSchema({ properties: { a: { type: 'string' }, b: { type: 'string' }, }, ui: { order: ['c', 'a'], }, }); }).toThrow(); }); it('when does not contain all keys', () => { expect(() => { page.newSchema({ properties: { a: { type: 'string' }, b: { type: 'string' }, }, ui: { order: ['a'], }, }); }).toThrow(); }); it('when contains more than one wildcard item', () => { expect(() => { page.newSchema({ properties: { a: { type: 'string' }, b: { type: 'string' }, }, ui: { order: ['a', '*', '*', '*', '*'], }, }); }).toThrow(); }); }); }); describe('[$ref]', () => { it('should be required valid', () => { page .newSchema({ definitions: { nameRef: { type: 'string', title: 'nameRef', }, }, properties: { name: { type: 'string', title: 'Name', }, nameTwo: { $ref: '#/definitions/nameRef', }, }, required: ['name', 'nameTwo'], }) .checkUI('/nameTwo', '_required', true); }); }); });