import * as glassEasel from 'glass-easel' import { tmpl } from './base/env' import { MiniProgramEnv } from '../src' import { StyleIsolation } from '../src/types' const domHtml = (elem: glassEasel.Element): string => { const domElem = elem.getBackendElement() as unknown as Element return domElem.innerHTML } describe('trait behavior', () => { test('implement trait behavior', () => { const env = new MiniProgramEnv() const codeSpace = env.createCodeSpace('', true) codeSpace.addComponentStaticConfig('path/to/comp', {}) codeSpace.addCompiledTemplate( 'path/to/comp', tmpl(`
{{r}}
`), ) codeSpace.componentEnv('path/to/comp', ({ Component, Behavior }) => { const trait = Behavior.trait< { add(a: number, b: number): number }, { minus(a: number, b: number): number } >(({ add }) => ({ minus(a, b) { return add(a, -b) }, })) Component() .data(() => ({ r: 0, })) .init(({ self, setData, lifetime, implement }) => { implement(trait, { add: (a, b) => a + b }) lifetime('attached', () => { const r = self.traitBehavior(trait)!.minus(5, 3) setData({ r }) }) expect(self.hasBehavior(trait)).toBe(true) }) .register() }) const ab = env.associateBackend() const root = ab.createRoot('body', codeSpace, 'path/to/comp') glassEasel.Element.pretendAttached(root.getComponent()) expect(domHtml(root.getComponent())).toBe('
2
') }) test('trait behavior in relations', () => { const env = new MiniProgramEnv() const codeSpace = env.createCodeSpace('', true) const childTrait = codeSpace.traitBehavior<{ setA(a: number): void }>() const parentTrait = codeSpace.traitBehavior() codeSpace.addComponentStaticConfig('child/list', { component: true, styleIsolation: StyleIsolation.Shared, }) codeSpace.addCompiledTemplate( 'child/list', tmpl(`
{{count}}
`), ) // eslint-disable-next-line arrow-body-style codeSpace.componentEnv('child/list', ({ Component }) => { return Component() .data(() => ({ count: 0, })) .implement(parentTrait, {}) .init(({ relation, setData }) => { const childRel = relation({ type: 'child', target: childTrait, linked(child) { // eslint-disable-next-line no-use-before-define expect(child.asInstanceOf(itemDef)).not.toBe(null) setData({ count: this.data.count + 1 }) childRel.listAsTrait().forEach((c, index) => { c.setA(index + 2) }) }, }) }) .register() }) codeSpace.addComponentStaticConfig('child/item', { component: true, styleIsolation: StyleIsolation.Shared, }) codeSpace.addCompiledTemplate('child/item', tmpl('{{a}}')) // eslint-disable-next-line arrow-body-style const itemDef = codeSpace.componentEnv('child/item', ({ Component }) => { return Component() .data(() => ({ a: 0, })) .init(({ implement, relation, setData }) => { implement(childTrait, { setA(a: number) { setData({ a }) }, }) relation({ type: 'parent', target: parentTrait, }) }) .register() }) codeSpace.addComponentStaticConfig('path/to/comp', { usingComponents: { list: '/child/list', item: '/child/item', }, }) codeSpace.addCompiledTemplate( 'path/to/comp', tmpl(` `), ) codeSpace.componentEnv('path/to/comp', ({ Component }) => { Component().register() }) const ab = env.associateBackend() const root = ab.createRoot('body', codeSpace, 'path/to/comp') glassEasel.Element.pretendAttached(root.getComponent()) expect(domHtml(root.getComponent())).toBe( '
2
23
', ) }) })