UNPKG

aurelia-templating

Version:

An extensible HTML templating engine supporting databinding, custom elements, attached behaviors and more.

296 lines (237 loc) 8.39 kB
import './setup'; import {metadata} from 'aurelia-metadata'; import { Logger } from 'aurelia-logging'; import {bindingMode, valueConverter, bindingBehavior, ValueConverterResource, BindingBehaviorResource} from 'aurelia-binding'; import {Container} from 'aurelia-dependency-injection'; import { customElement, customAttribute, bindable } from '../src/decorators'; import {ViewResources} from '../src/view-resources'; import { HtmlBehaviorResource } from '../src/html-behavior'; import { viewEngineHooks } from '../src/view-engine-hooks-resource'; describe('ViewResources', () => { /**@type {Container} */ let container; /**@type {ViewResources} */ let resources; beforeEach(() => { container = new Container(); resources = new ViewResources(); }); describe('convention', () => { it('recognizes convention', () => { class El { static $resource() { return 'el1'; } } let meta = ViewResources.convention(El); expect(meta.elementName).toBe('el1'); class A { static $resource = { type: 'attribute', } } meta = ViewResources.convention(A); expect(meta.attributeName).toBe('a'); class ElOrA { static $resource = { type: 'element', bindables: ['b', 'c', { name: 'd', defaultBindingMode: 'twoWay' }] } } meta = ViewResources.convention(ElOrA); expect(meta.properties.length).toBe(3); expect(meta.attributes.d.defaultBindingMode).toBe(bindingMode.twoWay); class Vc { static $resource = { type: 'valueConverter' } } meta = ViewResources.convention(Vc); expect(meta instanceof ValueConverterResource).toBe(true); expect(meta.name).toBe('vc'); class Bb { static $resource = { type: 'bindingBehavior' } } meta = ViewResources.convention(Bb); expect(meta instanceof BindingBehaviorResource).toBe(true); expect(meta.name).toBe('bb'); }); it('warns when using uppercase letters in custom element / attribute name', () => { let spy = spyOn(Logger.prototype, 'warn').and.callThrough(); class ElEl { static $resource() { return 'ElEl'; } } let meta = ViewResources.convention(ElEl); expect(meta.elementName).toBe('el-el'); expect(spy).toHaveBeenCalledWith(`'ElEl' is not a valid custom element name and has been converted to 'el-el'. Upper-case letters are not allowed because the DOM is not case-sensitive.`); }); it('invokes static method with correct context', () => { class Base { static get elName() { return 'base'; } static $resource() { return this.elName; } } class El extends Base { } let meta = ViewResources.convention(El); expect(meta.elementName).toBe('base'); class El1 extends Base { static get elName() { return 'el'; } } meta = ViewResources.convention(El1); expect(meta.elementName).toBe('el'); }); it('does not reapply convention', () => { class El { static $resource = { bindables: ['value'] } } let meta = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, El); ViewResources.convention(El, meta); expect(meta.elementName).toBe('el'); expect(meta.properties.length).toBe(1); expect(meta.__au_resource__).toBe(true); El.$resource.bindables.push('name', 'label', 'type'); ViewResources.convention(El, meta); expect(meta.properties.length).toBe(1); }); }); it('auto register', () => { let resourceMetaType; class El {} let eMeta = resources.autoRegister(container, El); resourceMetaType = metadata.get(metadata.resource, El); expect(eMeta).toBe(resourceMetaType); expect(resourceMetaType.target).toBe(El); expect(resourceMetaType instanceof HtmlBehaviorResource).toBe(true); class ElCustomElement {} expect(() => resources.autoRegister(container, ElCustomElement)).toThrow(); @customElement('el') class Ell {} expect(() => resources.autoRegister(container, Ell)).toThrow(); // ========= class ACustomAttribute {} let aMeta = resources.autoRegister(container, ACustomAttribute); resourceMetaType = metadata.get(metadata.resource, ACustomAttribute); expect(aMeta).toBe(resourceMetaType); expect(aMeta.target).toBe(ACustomAttribute); expect(aMeta instanceof HtmlBehaviorResource).toBe(true); @customAttribute('a') class AA {} expect(() => resources.autoRegister(container, AA)).toThrow(); // ========= class VValueConverter {} let vMeta = resources.autoRegister(container, VValueConverter); resourceMetaType = metadata.get(metadata.resource, VValueConverter); expect(vMeta).toBe(resourceMetaType); @valueConverter('v') class V {} expect(() => resources.autoRegister(container, V)).toThrow(); // ========= class BBindingBehavior {} let bMeta = resources.autoRegister(container, BBindingBehavior); resourceMetaType = metadata.get(metadata.resource, BBindingBehavior); expect(bMeta).toBe(resourceMetaType); @bindingBehavior('b') class B {} expect(() => resources.autoRegister(container, B)).toThrow(); // ======== class HViewEngineHooks { beforeCompile() {} } let hMeta = resources.autoRegister(container, HViewEngineHooks); resourceMetaType = metadata.get(metadata.resource, HViewEngineHooks); expect(hMeta).toBe(resourceMetaType); expect(resources.beforeCompile).toBe(true); @viewEngineHooks() class H { beforeCompile() {} afterCompile() {} } resources.autoRegister(container, H); expect(resources.afterCompile).toBe(true); expect(resources.beforeCompile1).toBeDefined(); expect(resources.beforeCompile2).toBeDefined(); }); it('auto register with static `resource` convention ', () => { class El3 { static $resource = 'el3' } resources.autoRegister(container, El3); expect(resources.getElement('el3').target).toBe(El3); }); describe('interop', () => { it('uses existing HtmlBehaviorResource metadata for naming', () => { @customElement('a') class El { static $resource = 'b' } resources.autoRegister(container, El); expect(resources.getElement('a').target).toBe(El); @customAttribute('b') class At { static $resource = { type: 'attribute', name: 'c' } } resources.autoRegister(container, At); expect(resources.getAttribute('b').target).toBe(At) }); // it('adds bindables', () => { // class El { // static $resource() { // return { // bindables: ['name', 'value'] // } // } // @bindable() name // @bindable() value // } // resources.autoRegister(container, El); // expect(resources.getElement('el').properties.length).toBe(4); // }); describe('with inheritance', () => { it('works with base class using static config and derived class using decorator', () => { class Base { static $resource = { bindables: ['name', 'value'] } } class Field extends Base { @bindable() label; } resources.autoRegister(container, Field); expect(resources.getElement('field').properties.length).toBe(3); }); it('works with base class using decorators and derivde class using static config', () => { class Base { @bindable() name @bindable() value; } class Field extends Base { static $resource = { bindables: ['label'] } } const meta = resources.autoRegister(container, Field); expect(resources.getElement('field').properties.length).toBe(3); // Just a little check to ensure metadata are expect(resources.getElement('base')).toBeFalsy(); expect(meta).toBe(resources.getElement('field')); expect(metadata.getOwn(metadata.resource, Base)).not.toBe(meta); }); }); }); });