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
- 2
- 3
',
)
})
})