expect(host.innerHTML).toBe(`foobar!barbaz!`)
})
- test.todo('directive', () => {
+ test('directive', () => {
const spy1 = vi.fn()
const spy2 = vi.fn()
},
}).create()
- const FooBar = { mounted: spy1 }
+ const FooBar = spy1
app.directive('FooBar', FooBar)
expect(app.directive('FooBar')).toBe(FooBar)
- app.directive('BarBaz', { mounted: spy2 })
- app.directive('BarBaz', { mounted: spy2 })
+ app.directive('BarBaz', spy2)
+ app.directive('BarBaz', spy2)
expect(
'Directive "BarBaz" has already been registered in target app.',
).toHaveBeenWarnedTimes(1)
const Wrapper = defineComponent({
setup(_) {
const n0 = createSlot('default')
- setInheritAttrs(false, true)
+ setInheritAttrs(true)
return n0
},
})
+++ /dev/null
-import {
- type DirectiveBinding,
- type DirectiveHook,
- createComponent,
- defineComponent,
- nextTick,
- ref,
- renderEffect,
- setText,
- template,
- withDirectives,
-} from '../src'
-import {
- type Component,
- type ComponentInternalInstance,
- currentInstance,
-} from '../src/component'
-import { makeRender } from './_utils'
-
-const define = makeRender()
-
-describe.todo('directives', () => {
- it('should work', async () => {
- const count = ref(0)
-
- function assertBindings(binding: DirectiveBinding) {
- expect(binding.value).toBe(count.value)
- expect(binding.arg).toBe('foo')
- expect(binding.instance).toBe(_instance)
- expect(binding.modifiers && binding.modifiers.ok).toBe(true)
- }
-
- const beforeMount = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should not be inserted yet
- expect(el.parentNode).toBe(null)
- expect(host.children.length).toBe(0)
-
- assertBindings(binding)
-
- expect(el).toBe(_node)
- }) as DirectiveHook)
-
- const mounted = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should be inserted now
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const beforeUpdate = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- // node should not have been updated yet
- expect(el.childNodes[0].textContent).toBe(`${count.value - 1}`)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const updated = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- // node should have been updated
- expect(el.childNodes[0].textContent).toBe(`${count.value}`)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const beforeUnmount = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should be removed now
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const unmounted = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should have been removed
- expect(el.parentNode).toBe(null)
- expect(host.children.length).toBe(0)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const dir = {
- beforeMount,
- mounted,
- beforeUpdate,
- updated,
- beforeUnmount,
- unmounted,
- }
-
- let _instance: ComponentInternalInstance | null = null
- let _node: Node | null = null
-
- const { host, render } = define({
- setup() {
- _instance = currentInstance
- },
- render() {
- _node = template('<div>')()
- renderEffect(() => {
- setText(_node!, count.value)
- })
- withDirectives(_node, [
- [
- dir,
- // value
- () => count.value,
- // argument
- 'foo',
- // modifiers
- { ok: true },
- ],
- ])
- return _node
- },
- })
- const { app } = render()
-
- expect(beforeMount).toHaveBeenCalledTimes(1)
- expect(mounted).toHaveBeenCalledTimes(1)
-
- count.value++
- await nextTick()
- expect(beforeUpdate).toHaveBeenCalledTimes(1)
- expect(updated).toHaveBeenCalledTimes(1)
-
- app.unmount()
- expect(beforeUnmount).toHaveBeenCalledTimes(1)
- expect(unmounted).toHaveBeenCalledTimes(1)
- })
-
- it('should work with a function directive', async () => {
- const count = ref(0)
-
- function assertBindings(binding: DirectiveBinding) {
- expect(binding.value).toBe(count.value)
- expect(binding.arg).toBe('foo')
- expect(binding.instance).toBe(_instance)
- expect(binding.modifiers && binding.modifiers.ok).toBe(true)
- }
-
- const fn = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(host)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- let _instance: ComponentInternalInstance | null = null
- let _node: Node | null = null
- const Comp = {
- setup() {
- _instance = currentInstance
- },
- render() {
- _node = template('<div>')()
- renderEffect(() => {
- setText(_node!, count.value)
- })
- withDirectives(_node, [
- [
- fn,
- // value
- () => count.value,
- // argument
- 'foo',
- // modifiers
- { ok: true },
- ],
- ])
- return _node
- },
- }
-
- const { host, render } = define(Comp)
- render()
-
- expect(fn).toHaveBeenCalledTimes(1)
-
- count.value++
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(2)
- })
-
- it('should work on components', async () => {
- const count = ref(0)
-
- function assertBindings(binding: DirectiveBinding) {
- expect(binding.value).toBe(count.value)
- expect(binding.arg).toBe('foo')
- expect(binding.instance).toBe(_instance)
- expect(binding.modifiers && binding.modifiers.ok).toBe(true)
- }
-
- const beforeMount = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should not be inserted yet
- expect(el.parentNode).toBe(null)
- expect(host.children.length).toBe(0)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const mounted = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should be inserted now
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const beforeUpdate = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- // node should not have been updated yet
- expect(el.childNodes[0].textContent).toBe(`${count.value - 1}`)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const updated = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- // node should have been updated
- expect(el.childNodes[0].textContent).toBe(`${count.value}`)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const beforeUnmount = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should be removed now
- expect(el.parentNode).toBe(host)
- expect(host.children[0]).toBe(el)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const unmounted = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should have been removed
- expect(el.parentNode).toBe(null)
- expect(host.children.length).toBe(0)
-
- assertBindings(binding)
- }) as DirectiveHook)
-
- const dir = {
- beforeMount,
- mounted,
- beforeUpdate,
- updated,
- beforeUnmount,
- unmounted,
- }
-
- let _instance: ComponentInternalInstance | null = null
- let _node: Node | null = null
-
- const Child = (props: { count: number }) => {
- _node = template('<div>')()
- renderEffect(() => {
- setText(_node!, props.count)
- })
- return _node
- }
-
- const Comp = {
- setup() {
- _instance = currentInstance
- },
- render() {
- _node = template('<div>')()
- return withDirectives(
- createComponent(Child, { count: () => count.value }),
- [
- [
- dir,
- // value
- () => count.value,
- // argument
- 'foo',
- // modifiers
- { ok: true },
- ],
- ],
- )
- },
- }
-
- const { host, render } = define(Comp)
- render()
-
- expect(beforeMount).toHaveBeenCalledTimes(1)
- expect(mounted).toHaveBeenCalledTimes(1)
-
- count.value++
- await nextTick()
- expect(beforeUpdate).toHaveBeenCalledTimes(1)
- expect(updated).toHaveBeenCalledTimes(1)
-
- render(null, host)
- expect(beforeUnmount).toHaveBeenCalledTimes(1)
- expect(unmounted).toHaveBeenCalledTimes(1)
- })
-
- // #2298
- it('directive merging on component root', () => {
- const d1 = {
- mounted: vi.fn(),
- }
- const d2 = {
- mounted: vi.fn(),
- }
- const Comp: Component = {
- render() {
- return withDirectives(template('<div>')(), [[d2]])
- },
- }
-
- const App = {
- name: 'App',
- render() {
- return withDirectives(createComponent(Comp), [[d1]])
- },
- }
-
- define(App).render()
- expect(d1.mounted).toHaveBeenCalled()
- expect(d2.mounted).toHaveBeenCalled()
- })
-
- test('should disable tracking inside directive lifecycle hooks', async () => {
- const count = ref(0)
- const text = ref('')
- const beforeUpdate = vi.fn(() => count.value++)
-
- const App = {
- render() {
- const node = template('<p>')()
- renderEffect(() => {
- setText(node, text.value)
- })
- return withDirectives(node, [
- [
- {
- beforeUpdate,
- },
- ],
- ])
- },
- }
-
- define(App).render()
- expect(beforeUpdate).toHaveBeenCalledTimes(0)
- expect(count.value).toBe(0)
-
- text.value = 'foo'
- await nextTick()
- expect(beforeUpdate).toHaveBeenCalledTimes(1)
- expect(count.value).toBe(1)
- })
-
- test('should receive exposeProxy for closed instances', async () => {
- let res: string
- const App = defineComponent({
- setup(_, { expose }) {
- expose({
- msg: 'Test',
- })
-
- return withDirectives(template('<p>')(), [
- [
- {
- mounted(el, { instance }) {
- res = instance.exposed!.msg
- },
- },
- ],
- ])
- },
- })
- define(App).render()
- expect(res!).toBe('Test')
- })
-
- test('should not throw with unknown directive', async () => {
- const d1 = {
- mounted: vi.fn(),
- }
- const App = {
- name: 'App',
- render() {
- // simulates the code generated on an unknown directive
- return withDirectives(template('<div>')(), [[undefined], [d1]])
- },
- }
-
- define(App).render()
- expect(d1.mounted).toHaveBeenCalled()
- })
-})
+++ /dev/null
-import { ref } from '@vue/reactivity'
-import {
- type ComponentInternalInstance,
- type DirectiveBinding,
- type DirectiveHook,
- createComponent,
- getCurrentInstance,
- nextTick,
- renderEffect,
- setText,
- template,
- withDirectives,
-} from '@vue/runtime-vapor'
-import { makeRender } from '../_utils'
-
-const define = makeRender()
-
-describe.todo('directives', () => {
- it('should work', async () => {
- const count = ref(0)
-
- function assertBindings(binding: DirectiveBinding) {
- expect(binding.value).toBe(count.value)
- expect(binding.arg).toBe('foo')
- expect(binding.instance).toBe(_instance)
- expect(binding.modifiers && binding.modifiers.ok).toBe(true)
- }
-
- const beforeMount = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should not be inserted yet
- expect(el.parentNode).toBe(null)
- expect(root.children.length).toBe(0)
-
- assertBindings(binding)
-
- // expect(vnode).toBe(_vnode)
- // expect(prevVNode).toBe(null)
- }) as DirectiveHook<Element>)
-
- const mounted = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should be inserted now
- expect(el.parentNode).toBe(root)
- expect(root.children[0]).toBe(el)
-
- assertBindings(binding)
- }) as DirectiveHook<Element>)
-
- const beforeUpdate = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(root)
- expect(root.children[0]).toBe(el)
-
- // node should not have been updated yet
- expect(el.firstChild?.textContent).toBe(`${count.value - 1}`)
-
- assertBindings(binding)
- }) as DirectiveHook<Element>)
-
- const updated = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(root)
- expect(root.children[0]).toBe(el)
-
- // node should have been updated
- expect(el.firstChild?.textContent).toBe(`${count.value}`)
-
- assertBindings(binding)
- }) as DirectiveHook<Element>)
-
- const beforeUnmount = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should be removed now
- expect(el.parentNode).toBe(root)
- expect(root.children[0]).toBe(el)
-
- assertBindings(binding)
- }) as DirectiveHook<Element>)
-
- const unmounted = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- // should have been removed
- expect(el.parentNode).toBe(null)
- expect(root.children.length).toBe(0)
-
- assertBindings(binding)
- }) as DirectiveHook<Element>)
-
- const dir = {
- beforeMount,
- mounted,
- beforeUpdate,
- updated,
- beforeUnmount,
- unmounted,
- }
-
- let _instance: ComponentInternalInstance | null = null
- const { render } = define({
- setup() {
- _instance = getCurrentInstance()
- },
- render() {
- const n0 = template('<div></div>')()
- renderEffect(() => setText(n0, count.value))
- withDirectives(n0, [
- [
- dir,
- // value
- () => count.value,
- // argument
- 'foo',
- // modifiers
- { ok: true },
- ],
- ])
- return n0
- },
- })
-
- const root = document.createElement('div')
-
- render(null, root)
- expect(beforeMount).toHaveBeenCalledTimes(1)
- expect(mounted).toHaveBeenCalledTimes(1)
-
- count.value++
- await nextTick()
- expect(beforeUpdate).toHaveBeenCalledTimes(1)
- expect(updated).toHaveBeenCalledTimes(1)
-
- render(null, root)
- expect(beforeUnmount).toHaveBeenCalledTimes(1)
- expect(unmounted).toHaveBeenCalledTimes(1)
- })
-
- it('should work with a function directive', async () => {
- const count = ref(0)
-
- function assertBindings(binding: DirectiveBinding) {
- expect(binding.value).toBe(count.value)
- expect(binding.arg).toBe('foo')
- expect(binding.instance).toBe(_instance)
- expect(binding.modifiers && binding.modifiers.ok).toBe(true)
- }
-
- const fn = vi.fn(((el, binding) => {
- expect(el.tagName).toBe('DIV')
- expect(el.parentNode).toBe(root)
-
- assertBindings(binding)
- }) as DirectiveHook<Element>)
-
- let _instance: ComponentInternalInstance | null = null
- const { render } = define({
- setup() {
- _instance = getCurrentInstance()
- },
- render() {
- const n0 = template('<div></div>')()
- renderEffect(() => setText(n0, count.value))
- withDirectives(n0, [
- [
- fn,
- // value
- () => count.value,
- // argument
- 'foo',
- // modifiers
- { ok: true },
- ],
- ])
- return n0
- },
- })
-
- const root = document.createElement('div')
- render(null, root)
-
- expect(fn).toHaveBeenCalledTimes(1)
-
- count.value++
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(2)
- })
-
- // #2298
- it('directive merging on component root', () => {
- const d1 = {
- mounted: vi.fn(),
- }
- const d2 = {
- mounted: vi.fn(),
- }
- const Comp = {
- render() {
- const n0 = template('<div></div>')()
- withDirectives(n0, [[d2]])
- return n0
- },
- }
-
- const { render } = define({
- name: 'App',
- render() {
- const n0 = createComponent(Comp)
- withDirectives(n0, [[d1]])
- return n0
- },
- })
-
- const root = document.createElement('div')
- render(null, root)
- expect(d1.mounted).toHaveBeenCalled()
- expect(d2.mounted).toHaveBeenCalled()
- })
-
- test('should disable tracking inside directive lifecycle hooks', async () => {
- const count = ref(0)
- const text = ref('')
- const beforeUpdate = vi.fn(() => count.value++)
-
- const { render } = define({
- render() {
- const n0 = template('<p></p>')()
- renderEffect(() => setText(n0, text.value))
- withDirectives(n0, [
- [
- {
- beforeUpdate,
- },
- ],
- ])
- return n0
- },
- })
-
- const root = document.createElement('div')
- render(null, root)
- expect(beforeUpdate).toHaveBeenCalledTimes(0)
- expect(count.value).toBe(0)
-
- text.value = 'foo'
- await nextTick()
- expect(beforeUpdate).toHaveBeenCalledTimes(1)
- expect(count.value).toBe(1)
- })
-
- test('should receive exposeProxy for closed instances', async () => {
- let res: string
- const { render } = define({
- setup(_, { expose }) {
- expose({
- msg: 'Test',
- })
- },
- render() {
- const n0 = template('<p>Lore Ipsum</p>')()
- withDirectives(n0, [
- [
- {
- mounted(el, { instance }) {
- res = (instance.exposed as any).msg as string
- },
- },
- ],
- ])
- return n0
- },
- })
- const root = document.createElement('div')
- render(null, root)
- expect(res!).toBe('Test')
- })
-
- test('should not throw with unknown directive', async () => {
- const d1 = {
- mounted: vi.fn(),
- }
- const { render } = define({
- name: 'App',
- render() {
- const n0 = template('<div></div>')()
- // simulates the code generated on an unknown directive
- withDirectives(n0, [[undefined], [d1]])
- return n0
- },
- })
-
- const root = document.createElement('div')
- render(null, root)
- expect(d1.mounted).toHaveBeenCalled()
- })
-})
on(n1 as HTMLElement, 'click', () => handleClick)
return n0
})
-describe.todo('directive: v-show', () => {
+
+describe('directive: v-show', () => {
test('basic', async () => {
const { host } = createDemo(true).render()
const btn = host.querySelector('button')
},
})
- const { instance, host } = define({
+ const { host } = define({
render() {
const n1 = t1()
const n2 = createComponent(Child, [], null, true)
}).render()
expect(host.innerHTML).toBe('<button>toggle</button><div>child</div>')
- expect(instance?.scope.dirs!.get(n0)![0].dir).toBe(vShow)
const btn = host.querySelector('button')
btn?.click()
-import { insert, normalizeBlock, prepend, remove } from '../../src/dom/element'
-import { fragmentKey } from '../../src/apiRender'
+import { fragmentKey, normalizeBlock } from '../../src/block'
+import { insert, prepend, remove } from '../../src/dom/element'
const node1 = document.createTextNode('node1')
const node2 = document.createTextNode('node2')
import {
- type Directive,
- children,
createFor,
nextTick,
ref,
renderEffect,
shallowRef,
- template,
triggerRef,
- withDirectives,
} from '../src'
import { makeRender } from './_utils'
-import { unmountComponent } from '../src/apiRender'
const define = makeRender()
expect(host.innerHTML).toBe('<!--for-->')
})
- test.fails('should work with directive hooks', async () => {
- const calls: string[] = []
- const list = ref([0])
- const update = ref(0)
- const add = () => list.value.push(list.value.length)
- const spySrcFn = vi.fn(() => list.value)
-
- const vDirective: Directive = {
- created: (el, { value }) => calls.push(`${value} created`),
- beforeMount: (el, { value }) => calls.push(`${value} beforeMount`),
- mounted: (el, { value }) => calls.push(`${value} mounted`),
- beforeUpdate: (el, { value }) => calls.push(`${value} beforeUpdate`),
- updated: (el, { value }) => calls.push(`${value} updated`),
- beforeUnmount: (el, { value }) => calls.push(`${value} beforeUnmount`),
- unmounted: (el, { value }) => calls.push(`${value} unmounted`),
- }
-
- const t0 = template('<p></p>')
- const { instance } = define(() => {
- const n1 = createFor(spySrcFn, ctx0 => {
- const n2 = t0()
- const n3 = children(n2, 0)
- withDirectives(n3, [[vDirective, () => ctx0[0]]])
- renderEffect(() => {
- calls.push(`${ctx0[0]} effecting`)
- })
- return n2
- })
- renderEffect(() => update.value)
- return [n1]
- }).render()
-
- await nextTick()
- // `${item index} ${hook name}`
- expect(calls).toEqual([
- '0 created',
- '0 effecting',
- '0 beforeMount',
- '0 mounted',
- ])
- calls.length = 0
- expect(spySrcFn).toHaveBeenCalledTimes(1)
-
- add()
- await nextTick()
- expect(calls).toEqual([
- '0 beforeUpdate',
- '1 created',
- '1 effecting',
- '1 beforeMount',
- '0 updated',
- '1 mounted',
- ])
- calls.length = 0
- expect(spySrcFn).toHaveBeenCalledTimes(2)
-
- list.value.reverse()
- await nextTick()
- expect(calls).toEqual([
- '1 beforeUpdate',
- '0 beforeUpdate',
- '1 effecting',
- '0 effecting',
- '1 updated',
- '0 updated',
- ])
- expect(spySrcFn).toHaveBeenCalledTimes(3)
- list.value.reverse()
- await nextTick()
- calls.length = 0
- expect(spySrcFn).toHaveBeenCalledTimes(4)
-
- update.value++
- await nextTick()
- expect(calls).toEqual([
- '0 beforeUpdate',
- '1 beforeUpdate',
- '0 updated',
- '1 updated',
- ])
- calls.length = 0
- expect(spySrcFn).toHaveBeenCalledTimes(4)
-
- // change item
- list.value[1] = 2
- await nextTick()
- expect(calls).toEqual([
- '0 beforeUpdate',
- '2 beforeUpdate',
- '2 effecting',
- '0 updated',
- '2 updated',
- ])
- expect(spySrcFn).toHaveBeenCalledTimes(5)
- list.value[1] = 1
- await nextTick()
- calls.length = 0
- expect(spySrcFn).toHaveBeenCalledTimes(6)
-
- // remove the last item
- list.value.pop()
- await nextTick()
- expect(calls).toEqual([
- '0 beforeUpdate',
- '1 beforeUnmount',
- '0 updated',
- '1 unmounted',
- ])
- calls.length = 0
- expect(spySrcFn).toHaveBeenCalledTimes(7)
-
- unmountComponent(instance!)
- expect(calls).toEqual(['0 beforeUnmount', '0 unmounted'])
- expect(spySrcFn).toHaveBeenCalledTimes(7)
- })
-
test('de-structured value', async () => {
const list = ref([{ name: '1' }, { name: '2' }, { name: '3' }])
function reverse() {
const define = makeRender()
describe('resolveAssets', () => {
- test('todo', () => {
- expect(true).toBeTruthy()
- })
test('should work', () => {
const FooBar = () => []
- const BarBaz = { mounted: () => null }
+ const BarBaz = () => undefined
let component1: Component | string
let component2: Component | string
let component3: Component | string
validateComponentName,
} from './component'
import { warn } from './warning'
-import { type Directive, version } from '.'
+import { version } from '.'
import {
normalizeContainer,
render,
} from './apiRender'
import type { InjectionKey } from './apiInject'
import type { RawProps } from './componentProps'
-import { validateDirectiveName } from './directives'
+import { type Directive, validateDirectiveName } from './directives'
import { devtoolsInitApp, setDevtoolsHook } from './devtools'
let uid = 0
import { camelize, capitalize, isString } from '@vue/shared'
-import { type Directive, warn } from '..'
+import { warn } from '../warning'
+import type { Directive } from '../directives'
import { type Component, currentInstance } from '../component'
import { getComponentName } from '../component'
-export const COMPONENTS = 'components'
-export const DIRECTIVES = 'directives'
+const COMPONENTS = 'components'
+const DIRECTIVES = 'directives'
export type AssetTypes = typeof COMPONENTS | typeof DIRECTIVES