test: basic tests for hooks

This commit is contained in:
Evan You 2018-10-28 17:45:53 -04:00
parent 665cd8e3d9
commit a6a571f973
2 changed files with 69 additions and 9 deletions

View File

@ -0,0 +1,60 @@
import { withHooks, useState, h, nextTick, useEffect } from '../src'
import { renderIntsance, serialize, triggerEvent } from '@vue/runtime-test'
describe('hooks', () => {
it('useState', async () => {
const Counter = withHooks(() => {
const [count, setCount] = useState(0)
return h(
'div',
{
onClick: () => {
setCount(count + 1)
}
},
count
)
})
const counter = renderIntsance(Counter)
expect(serialize(counter.$el)).toBe(`<div>0</div>`)
triggerEvent(counter.$el, 'click')
await nextTick()
expect(serialize(counter.$el)).toBe(`<div>1</div>`)
})
it('useEffect', async () => {
let effect = -1
const Counter = withHooks(() => {
const [count, setCount] = useState(0)
useEffect(() => {
effect = count
})
return h(
'div',
{
onClick: () => {
setCount(count + 1)
}
},
count
)
})
const counter = renderIntsance(Counter)
expect(effect).toBe(0)
triggerEvent(counter.$el, 'click')
await nextTick()
expect(effect).toBe(1)
})
it('useEffect with empty keys', async () => {
// TODO
})
it('useEffect with keys', async () => {
// TODO
})
})

View File

@ -1,4 +1,4 @@
import { ComponentInstance, FunctionalComponent } from '../component' import { ComponentInstance, FunctionalComponent, Component } from '../component'
import { mergeLifecycleHooks, Data } from '../componentOptions' import { mergeLifecycleHooks, Data } from '../componentOptions'
import { VNode, Slots } from '../vdom' import { VNode, Slots } from '../vdom'
import { observable } from '@vue/observer' import { observable } from '@vue/observer'
@ -36,7 +36,7 @@ export function unsetCurrentInstance() {
currentInstance = null currentInstance = null
} }
export function useState(initial: any) { export function useState<T>(initial: T): [T, (newValue: T) => void] {
if (!currentInstance) { if (!currentInstance) {
throw new Error( throw new Error(
`useState must be called in a function passed to withHooks.` `useState must be called in a function passed to withHooks.`
@ -107,20 +107,20 @@ function injectEffect(
: effect : effect
} }
export function withHooks<T extends FunctionalComponent>(render: T): T { export function withHooks(render: FunctionalComponent): new () => Component {
return { return class ComponentWithHooks extends Component {
displayName: render.name, static displayName = render.name
created() { created() {
hooksState.set(this._self, { hooksState.set((this as any)._self, {
state: observable({}), state: observable({}),
effects: [] effects: []
}) })
}, }
render(props: Data, slots: Slots, attrs: Data, parentVNode: VNode) { render(props: Data, slots: Slots, attrs: Data, parentVNode: VNode) {
setCurrentInstance(this._self) setCurrentInstance((this as any)._self)
const ret = render(props, slots, attrs, parentVNode) const ret = render(props, slots, attrs, parentVNode)
unsetCurrentInstance() unsetCurrentInstance()
return ret return ret
} }
} as any }
} }