mirror of https://github.com/vuejs/core.git
test(vapor): block tests
This commit is contained in:
parent
ec23ab9e3a
commit
b7aec139cb
|
@ -1,12 +1,11 @@
|
||||||
import { fragmentKey, normalizeBlock } from '../../src/block'
|
import { Fragment, insert, normalizeBlock, prepend, remove } from '../src/block'
|
||||||
import { insert, prepend, remove } from '../../src/dom/node'
|
|
||||||
|
|
||||||
const node1 = document.createTextNode('node1')
|
const node1 = document.createTextNode('node1')
|
||||||
const node2 = document.createTextNode('node2')
|
const node2 = document.createTextNode('node2')
|
||||||
const node3 = document.createTextNode('node3')
|
const node3 = document.createTextNode('node3')
|
||||||
const anchor = document.createTextNode('anchor')
|
const anchor = document.createTextNode('anchor')
|
||||||
|
|
||||||
describe('element', () => {
|
describe('node ops', () => {
|
||||||
test('normalizeBlock', () => {
|
test('normalizeBlock', () => {
|
||||||
expect(normalizeBlock([node1, node2, node3])).toEqual([node1, node2, node3])
|
expect(normalizeBlock([node1, node2, node3])).toEqual([node1, node2, node3])
|
||||||
expect(normalizeBlock([node1, [node2, [node3]]])).toEqual([
|
expect(normalizeBlock([node1, [node2, [node3]]])).toEqual([
|
||||||
|
@ -14,13 +13,14 @@ describe('element', () => {
|
||||||
node2,
|
node2,
|
||||||
node3,
|
node3,
|
||||||
])
|
])
|
||||||
expect(
|
const frag = new Fragment(node2)
|
||||||
normalizeBlock([
|
frag.anchor = anchor
|
||||||
node1,
|
expect(normalizeBlock([node1, frag, [node3]])).toEqual([
|
||||||
{ nodes: node2, anchor, [fragmentKey]: true },
|
node1,
|
||||||
[node3],
|
node2,
|
||||||
]),
|
anchor,
|
||||||
).toEqual([node1, node2, anchor, node3])
|
node3,
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('insert', () => {
|
test('insert', () => {
|
||||||
|
@ -39,15 +39,16 @@ describe('element', () => {
|
||||||
test('prepend', () => {
|
test('prepend', () => {
|
||||||
const container = document.createElement('div')
|
const container = document.createElement('div')
|
||||||
prepend(container, [node1], node2)
|
prepend(container, [node1], node2)
|
||||||
prepend(container, { nodes: node3, [fragmentKey]: true })
|
prepend(container, new Fragment(node3))
|
||||||
expect(Array.from(container.childNodes)).toEqual([node3, node1, node2])
|
expect(Array.from(container.childNodes)).toEqual([node3, node1, node2])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('remove', () => {
|
test('remove', () => {
|
||||||
const container = document.createElement('div')
|
const container = document.createElement('div')
|
||||||
container.append(node1, node2, node3)
|
container.append(node1, node2, node3)
|
||||||
|
const frag = new Fragment(node3)
|
||||||
remove([node1], container)
|
remove([node1], container)
|
||||||
remove({ nodes: node3, [fragmentKey]: true }, container)
|
remove(frag, container)
|
||||||
expect(Array.from(container.childNodes)).toEqual([node2])
|
expect(Array.from(container.childNodes)).toEqual([node2])
|
||||||
|
|
||||||
expect(() => remove(anchor, container)).toThrowError(
|
expect(() => remove(anchor, container)).toThrowError(
|
|
@ -1,4 +1,4 @@
|
||||||
import type { NodeRef } from 'packages/runtime-vapor/src/dom/templateRef'
|
import type { NodeRef } from '../../src/dom/templateRef'
|
||||||
import {
|
import {
|
||||||
createFor,
|
createFor,
|
||||||
createIf,
|
createIf,
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
import {
|
|
||||||
type Component,
|
|
||||||
type Directive,
|
|
||||||
createVaporApp,
|
|
||||||
resolveComponent,
|
|
||||||
resolveDirective,
|
|
||||||
} from 'packages/runtime-vapor/src/_old'
|
|
||||||
import { makeRender } from '../_utils'
|
|
||||||
|
|
||||||
const define = makeRender()
|
|
||||||
|
|
||||||
describe('resolveAssets', () => {
|
|
||||||
test('should work', () => {
|
|
||||||
const FooBar = () => []
|
|
||||||
const BarBaz = () => undefined
|
|
||||||
let component1: Component | string
|
|
||||||
let component2: Component | string
|
|
||||||
let component3: Component | string
|
|
||||||
let component4: Component | string
|
|
||||||
let directive1: Directive
|
|
||||||
let directive2: Directive
|
|
||||||
let directive3: Directive
|
|
||||||
let directive4: Directive
|
|
||||||
const Root = define({
|
|
||||||
render() {
|
|
||||||
component1 = resolveComponent('FooBar')!
|
|
||||||
directive1 = resolveDirective('BarBaz')!
|
|
||||||
// camelize
|
|
||||||
component2 = resolveComponent('Foo-bar')!
|
|
||||||
directive2 = resolveDirective('Bar-baz')!
|
|
||||||
// capitalize
|
|
||||||
component3 = resolveComponent('fooBar')!
|
|
||||||
directive3 = resolveDirective('barBaz')!
|
|
||||||
// camelize and capitalize
|
|
||||||
component4 = resolveComponent('foo-bar')!
|
|
||||||
directive4 = resolveDirective('bar-baz')!
|
|
||||||
return []
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const app = createVaporApp(Root.component)
|
|
||||||
app.component('FooBar', FooBar)
|
|
||||||
app.directive('BarBaz', BarBaz)
|
|
||||||
const root = document.createElement('div')
|
|
||||||
app.mount(root)
|
|
||||||
expect(component1!).toBe(FooBar)
|
|
||||||
expect(component2!).toBe(FooBar)
|
|
||||||
expect(component3!).toBe(FooBar)
|
|
||||||
expect(component4!).toBe(FooBar)
|
|
||||||
expect(directive1!).toBe(BarBaz)
|
|
||||||
expect(directive2!).toBe(BarBaz)
|
|
||||||
expect(directive3!).toBe(BarBaz)
|
|
||||||
expect(directive4!).toBe(BarBaz)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('warning', () => {
|
|
||||||
test('used outside render() or setup()', () => {
|
|
||||||
resolveComponent('foo')
|
|
||||||
expect(
|
|
||||||
'[Vue warn]: resolveComponent can only be used in render() or setup().',
|
|
||||||
).toHaveBeenWarned()
|
|
||||||
resolveDirective('foo')
|
|
||||||
expect(
|
|
||||||
'[Vue warn]: resolveDirective can only be used in render() or setup().',
|
|
||||||
).toHaveBeenWarned()
|
|
||||||
})
|
|
||||||
test('not exist', () => {
|
|
||||||
const Root = define({
|
|
||||||
setup() {
|
|
||||||
resolveComponent('foo')
|
|
||||||
resolveDirective('bar')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const app = createVaporApp(Root.component)
|
|
||||||
const root = document.createElement('div')
|
|
||||||
app.mount(root)
|
|
||||||
expect('Failed to resolve component: foo').toHaveBeenWarned()
|
|
||||||
expect('Failed to resolve directive: bar').toHaveBeenWarned()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,6 +1,11 @@
|
||||||
import { isArray } from '@vue/shared'
|
import { isArray } from '@vue/shared'
|
||||||
import { type VaporComponentInstance, isVaporComponent } from './component'
|
import {
|
||||||
import { createComment, insert, remove } from './dom/node'
|
type VaporComponentInstance,
|
||||||
|
isVaporComponent,
|
||||||
|
mountComponent,
|
||||||
|
unmountComponent,
|
||||||
|
} from './component'
|
||||||
|
import { createComment } from './dom/node'
|
||||||
import { EffectScope } from '@vue/reactivity'
|
import { EffectScope } from '@vue/reactivity'
|
||||||
|
|
||||||
export type Block = Node | Fragment | VaporComponentInstance | Block[]
|
export type Block = Node | Fragment | VaporComponentInstance | Block[]
|
||||||
|
@ -84,28 +89,50 @@ export function normalizeBlock(block: Block): Node[] {
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findFirstRootElement(
|
|
||||||
instance: VaporComponentInstance,
|
|
||||||
): Element | undefined {
|
|
||||||
const element = getFirstNode(instance.block)
|
|
||||||
return element instanceof Element ? element : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFirstNode(block: Block | null): Node | undefined {
|
|
||||||
if (!block || isVaporComponent(block)) return
|
|
||||||
if (block instanceof Node) return block
|
|
||||||
if (isArray(block)) {
|
|
||||||
if (block.length === 1) {
|
|
||||||
return getFirstNode(block[0])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return getFirstNode(block.nodes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO optimize
|
// TODO optimize
|
||||||
export function isValidBlock(block: Block): boolean {
|
export function isValidBlock(block: Block): boolean {
|
||||||
return (
|
return (
|
||||||
normalizeBlock(block).filter(node => !(node instanceof Comment)).length > 0
|
normalizeBlock(block).filter(node => !(node instanceof Comment)).length > 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function insert(
|
||||||
|
block: Block,
|
||||||
|
parent: ParentNode,
|
||||||
|
anchor: Node | null | 0 = null,
|
||||||
|
): void {
|
||||||
|
if (block instanceof Node) {
|
||||||
|
parent.insertBefore(block, anchor === 0 ? parent.firstChild : anchor)
|
||||||
|
} else if (isVaporComponent(block)) {
|
||||||
|
mountComponent(block, parent, anchor)
|
||||||
|
} else if (isArray(block)) {
|
||||||
|
for (let i = 0; i < block.length; i++) {
|
||||||
|
insert(block[i], parent, anchor)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// fragment
|
||||||
|
insert(block.nodes, parent, anchor)
|
||||||
|
if (block.anchor) insert(block.anchor, parent, anchor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function prepend(parent: ParentNode, ...blocks: Block[]): void {
|
||||||
|
let i = blocks.length
|
||||||
|
while (i--) insert(blocks[i], parent, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function remove(block: Block, parent: ParentNode): void {
|
||||||
|
if (block instanceof Node) {
|
||||||
|
parent.removeChild(block)
|
||||||
|
} else if (isVaporComponent(block)) {
|
||||||
|
unmountComponent(block, parent)
|
||||||
|
} else if (isArray(block)) {
|
||||||
|
for (let i = 0; i < block.length; i++) {
|
||||||
|
remove(block[i], parent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// fragment
|
||||||
|
remove(block.nodes, parent)
|
||||||
|
if (block.anchor) remove(block.anchor, parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
unregisterHMR,
|
unregisterHMR,
|
||||||
warn,
|
warn,
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
import { type Block, isBlock } from './block'
|
import { type Block, insert, isBlock, remove } from './block'
|
||||||
import { pauseTracking, proxyRefs, resetTracking } from '@vue/reactivity'
|
import { pauseTracking, proxyRefs, resetTracking } from '@vue/reactivity'
|
||||||
import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared'
|
import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
|
@ -41,7 +41,6 @@ import {
|
||||||
dynamicSlotsProxyHandlers,
|
dynamicSlotsProxyHandlers,
|
||||||
getSlot,
|
getSlot,
|
||||||
} from './componentSlots'
|
} from './componentSlots'
|
||||||
import { insert, remove } from './dom/node'
|
|
||||||
import { hmrReload, hmrRerender } from './hmr'
|
import { hmrReload, hmrRerender } from './hmr'
|
||||||
|
|
||||||
export { currentInstance } from '@vue/runtime-dom'
|
export { currentInstance } from '@vue/runtime-dom'
|
||||||
|
|
|
@ -1,53 +1,6 @@
|
||||||
import { isArray } from '@vue/shared'
|
import { isArray } from '@vue/shared'
|
||||||
import { renderEffect } from '../renderEffect'
|
import { renderEffect } from '../renderEffect'
|
||||||
import { setText } from './prop'
|
import { setText } from './prop'
|
||||||
import type { Block } from '../block'
|
|
||||||
import {
|
|
||||||
isVaporComponent,
|
|
||||||
mountComponent,
|
|
||||||
unmountComponent,
|
|
||||||
} from '../component'
|
|
||||||
|
|
||||||
export function insert(
|
|
||||||
block: Block,
|
|
||||||
parent: ParentNode,
|
|
||||||
anchor: Node | null | 0 = null,
|
|
||||||
): void {
|
|
||||||
if (block instanceof Node) {
|
|
||||||
parent.insertBefore(block, anchor === 0 ? parent.firstChild : anchor)
|
|
||||||
} else if (isVaporComponent(block)) {
|
|
||||||
mountComponent(block, parent, anchor)
|
|
||||||
} else if (isArray(block)) {
|
|
||||||
for (let i = 0; i < block.length; i++) {
|
|
||||||
insert(block[i], parent, anchor)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// fragment
|
|
||||||
insert(block.nodes, parent, anchor)
|
|
||||||
if (block.anchor) insert(block.anchor, parent, anchor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function prepend(parent: ParentNode, ...blocks: Block[]): void {
|
|
||||||
for (const b of blocks) insert(b, parent, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO invoke unmount recursive
|
|
||||||
export function remove(block: Block, parent: ParentNode): void {
|
|
||||||
if (block instanceof Node) {
|
|
||||||
parent.removeChild(block)
|
|
||||||
} else if (isVaporComponent(block)) {
|
|
||||||
unmountComponent(block, parent)
|
|
||||||
} else if (isArray(block)) {
|
|
||||||
for (let i = 0; i < block.length; i++) {
|
|
||||||
remove(block[i], parent)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// fragment
|
|
||||||
remove(block.nodes, parent)
|
|
||||||
if (block.anchor) remove(block.anchor, parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createTextNode(values?: any[] | (() => any[])): Text {
|
export function createTextNode(values?: any[] | (() => any[])): Text {
|
||||||
// eslint-disable-next-line no-restricted-globals
|
// eslint-disable-next-line no-restricted-globals
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
pushWarningContext,
|
pushWarningContext,
|
||||||
simpleSetCurrentInstance,
|
simpleSetCurrentInstance,
|
||||||
} from '@vue/runtime-core'
|
} from '@vue/runtime-core'
|
||||||
import { normalizeBlock } from './block'
|
import { insert, normalizeBlock, remove } from './block'
|
||||||
import {
|
import {
|
||||||
type VaporComponent,
|
type VaporComponent,
|
||||||
type VaporComponentInstance,
|
type VaporComponentInstance,
|
||||||
|
@ -13,7 +13,6 @@ import {
|
||||||
mountComponent,
|
mountComponent,
|
||||||
unmountComponent,
|
unmountComponent,
|
||||||
} from './component'
|
} from './component'
|
||||||
import { insert, remove } from './dom/node'
|
|
||||||
|
|
||||||
export function hmrRerender(instance: VaporComponentInstance): void {
|
export function hmrRerender(instance: VaporComponentInstance): void {
|
||||||
const normalized = normalizeBlock(instance.block)
|
const normalized = normalizeBlock(instance.block)
|
||||||
|
|
|
@ -3,11 +3,12 @@ export { createVaporApp } from './apiCreateApp'
|
||||||
export { defineVaporComponent } from './apiDefineComponent'
|
export { defineVaporComponent } from './apiDefineComponent'
|
||||||
|
|
||||||
// compiler-use only
|
// compiler-use only
|
||||||
|
export { insert, prepend, remove } from './block'
|
||||||
export { createComponent, createComponentWithFallback } from './component'
|
export { createComponent, createComponentWithFallback } from './component'
|
||||||
export { renderEffect } from './renderEffect'
|
export { renderEffect } from './renderEffect'
|
||||||
export { createSlot } from './componentSlots'
|
export { createSlot } from './componentSlots'
|
||||||
export { template, children, next } from './dom/template'
|
export { template, children, next } from './dom/template'
|
||||||
export { insert, prepend, remove, createTextNode } from './dom/node'
|
export { createTextNode } from './dom/node'
|
||||||
export { setStyle } from './dom/style'
|
export { setStyle } from './dom/style'
|
||||||
export {
|
export {
|
||||||
setText,
|
setText,
|
||||||
|
|
Loading…
Reference in New Issue