refactor(runtime-core): adjust attr fallthrough behavior
BREAKING CHANGE: attribute fallthrough behavior has been adjusted according to https://github.com/vuejs/rfcs/pull/154
This commit is contained in:
@@ -54,7 +54,8 @@ describe('api: setup context', () => {
|
||||
}
|
||||
|
||||
const Child = defineComponent({
|
||||
setup(props: { count: number }) {
|
||||
props: { count: Number },
|
||||
setup(props) {
|
||||
watchEffect(() => {
|
||||
dummy = props.count
|
||||
})
|
||||
|
||||
@@ -222,7 +222,8 @@ describe('Suspense', () => {
|
||||
|
||||
test('content update before suspense resolve', async () => {
|
||||
const Async = defineAsyncComponent({
|
||||
setup(props: { msg: string }) {
|
||||
props: { msg: String },
|
||||
setup(props: any) {
|
||||
return () => h('div', props.msg)
|
||||
}
|
||||
})
|
||||
@@ -569,7 +570,8 @@ describe('Suspense', () => {
|
||||
const calls: number[] = []
|
||||
|
||||
const AsyncChildWithSuspense = defineAsyncComponent({
|
||||
setup(props: { msg: string }) {
|
||||
props: { msg: String },
|
||||
setup(props: any) {
|
||||
onMounted(() => {
|
||||
calls.push(0)
|
||||
})
|
||||
@@ -583,7 +585,8 @@ describe('Suspense', () => {
|
||||
|
||||
const AsyncInsideNestedSuspense = defineAsyncComponent(
|
||||
{
|
||||
setup(props: { msg: string }) {
|
||||
props: { msg: String },
|
||||
setup(props: any) {
|
||||
onMounted(() => {
|
||||
calls.push(2)
|
||||
})
|
||||
@@ -594,7 +597,8 @@ describe('Suspense', () => {
|
||||
)
|
||||
|
||||
const AsyncChildParent = defineAsyncComponent({
|
||||
setup(props: { msg: string }) {
|
||||
props: { msg: String },
|
||||
setup(props: any) {
|
||||
onMounted(() => {
|
||||
calls.push(1)
|
||||
})
|
||||
@@ -604,7 +608,8 @@ describe('Suspense', () => {
|
||||
|
||||
const NestedAsyncChild = defineAsyncComponent(
|
||||
{
|
||||
setup(props: { msg: string }) {
|
||||
props: { msg: String },
|
||||
setup(props: any) {
|
||||
onMounted(() => {
|
||||
calls.push(3)
|
||||
})
|
||||
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
createStaticVNode,
|
||||
Suspense,
|
||||
onMounted,
|
||||
defineAsyncComponent
|
||||
defineAsyncComponent,
|
||||
defineComponent
|
||||
} from '@vue/runtime-dom'
|
||||
import { renderToString } from '@vue/server-renderer'
|
||||
import { mockWarn } from '@vue/shared'
|
||||
@@ -448,8 +449,9 @@ describe('SSR hydration', () => {
|
||||
const mountedCalls: number[] = []
|
||||
const asyncDeps: Promise<any>[] = []
|
||||
|
||||
const AsyncChild = {
|
||||
async setup(props: { n: number }) {
|
||||
const AsyncChild = defineComponent({
|
||||
props: ['n'],
|
||||
async setup(props) {
|
||||
const count = ref(props.n)
|
||||
onMounted(() => {
|
||||
mountedCalls.push(props.n)
|
||||
@@ -468,7 +470,7 @@ describe('SSR hydration', () => {
|
||||
count.value
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const done = jest.fn()
|
||||
const App = {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { mockWarn } from '@vue/shared'
|
||||
describe('attribute fallthrough', () => {
|
||||
mockWarn()
|
||||
|
||||
it('should allow whitelisted attrs to fallthrough', async () => {
|
||||
it('should allow attrs to fallthrough', async () => {
|
||||
const click = jest.fn()
|
||||
const childUpdated = jest.fn()
|
||||
|
||||
@@ -30,12 +30,12 @@ describe('attribute fallthrough', () => {
|
||||
|
||||
return () =>
|
||||
h(Child, {
|
||||
foo: 1,
|
||||
foo: count.value + 1,
|
||||
id: 'test',
|
||||
class: 'c' + count.value,
|
||||
style: { color: count.value ? 'red' : 'green' },
|
||||
onClick: inc,
|
||||
'data-id': 1
|
||||
'data-id': count.value + 1
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,6 @@ describe('attribute fallthrough', () => {
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
id: props.id, // id is not whitelisted
|
||||
class: 'c2',
|
||||
style: { fontWeight: 'bold' }
|
||||
},
|
||||
@@ -62,8 +61,8 @@ describe('attribute fallthrough', () => {
|
||||
|
||||
const node = root.children[0] as HTMLElement
|
||||
|
||||
expect(node.getAttribute('id')).toBe('test') // id is not whitelisted, but explicitly bound
|
||||
expect(node.getAttribute('foo')).toBe(null) // foo is not whitelisted
|
||||
expect(node.getAttribute('id')).toBe('test')
|
||||
expect(node.getAttribute('foo')).toBe('1')
|
||||
expect(node.getAttribute('class')).toBe('c2 c0')
|
||||
expect(node.style.color).toBe('green')
|
||||
expect(node.style.fontWeight).toBe('bold')
|
||||
@@ -71,6 +70,121 @@ describe('attribute fallthrough', () => {
|
||||
node.dispatchEvent(new CustomEvent('click'))
|
||||
expect(click).toHaveBeenCalled()
|
||||
|
||||
await nextTick()
|
||||
expect(childUpdated).toHaveBeenCalled()
|
||||
expect(node.getAttribute('id')).toBe('test')
|
||||
expect(node.getAttribute('foo')).toBe('2')
|
||||
expect(node.getAttribute('class')).toBe('c2 c1')
|
||||
expect(node.style.color).toBe('red')
|
||||
expect(node.style.fontWeight).toBe('bold')
|
||||
expect(node.dataset.id).toBe('2')
|
||||
})
|
||||
|
||||
it('should only allow whitelisted fallthrough on functional component with optional props', async () => {
|
||||
const click = jest.fn()
|
||||
const childUpdated = jest.fn()
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
function inc() {
|
||||
count.value++
|
||||
click()
|
||||
}
|
||||
|
||||
const Hello = () =>
|
||||
h(Child, {
|
||||
foo: count.value + 1,
|
||||
id: 'test',
|
||||
class: 'c' + count.value,
|
||||
style: { color: count.value ? 'red' : 'green' },
|
||||
onClick: inc
|
||||
})
|
||||
|
||||
const Child = (props: any) => {
|
||||
childUpdated()
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
class: 'c2',
|
||||
style: { fontWeight: 'bold' }
|
||||
},
|
||||
props.foo
|
||||
)
|
||||
}
|
||||
|
||||
const root = document.createElement('div')
|
||||
document.body.appendChild(root)
|
||||
render(h(Hello), root)
|
||||
|
||||
const node = root.children[0] as HTMLElement
|
||||
|
||||
// not whitelisted
|
||||
expect(node.getAttribute('id')).toBe(null)
|
||||
expect(node.getAttribute('foo')).toBe(null)
|
||||
|
||||
// whitelisted: style, class, event listeners
|
||||
expect(node.getAttribute('class')).toBe('c2 c0')
|
||||
expect(node.style.color).toBe('green')
|
||||
expect(node.style.fontWeight).toBe('bold')
|
||||
node.dispatchEvent(new CustomEvent('click'))
|
||||
expect(click).toHaveBeenCalled()
|
||||
|
||||
await nextTick()
|
||||
expect(childUpdated).toHaveBeenCalled()
|
||||
expect(node.getAttribute('id')).toBe(null)
|
||||
expect(node.getAttribute('foo')).toBe(null)
|
||||
expect(node.getAttribute('class')).toBe('c2 c1')
|
||||
expect(node.style.color).toBe('red')
|
||||
expect(node.style.fontWeight).toBe('bold')
|
||||
})
|
||||
|
||||
it('should allow all attrs on functional component with declared props', async () => {
|
||||
const click = jest.fn()
|
||||
const childUpdated = jest.fn()
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
function inc() {
|
||||
count.value++
|
||||
click()
|
||||
}
|
||||
|
||||
const Hello = () =>
|
||||
h(Child, {
|
||||
foo: count.value + 1,
|
||||
id: 'test',
|
||||
class: 'c' + count.value,
|
||||
style: { color: count.value ? 'red' : 'green' },
|
||||
onClick: inc
|
||||
})
|
||||
|
||||
const Child = (props: { foo: number }) => {
|
||||
childUpdated()
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
class: 'c2',
|
||||
style: { fontWeight: 'bold' }
|
||||
},
|
||||
props.foo
|
||||
)
|
||||
}
|
||||
Child.props = ['foo']
|
||||
|
||||
const root = document.createElement('div')
|
||||
document.body.appendChild(root)
|
||||
render(h(Hello), root)
|
||||
|
||||
const node = root.children[0] as HTMLElement
|
||||
|
||||
expect(node.getAttribute('id')).toBe('test')
|
||||
expect(node.getAttribute('foo')).toBe(null) // declared as prop
|
||||
expect(node.getAttribute('class')).toBe('c2 c0')
|
||||
expect(node.style.color).toBe('green')
|
||||
expect(node.style.fontWeight).toBe('bold')
|
||||
node.dispatchEvent(new CustomEvent('click'))
|
||||
expect(click).toHaveBeenCalled()
|
||||
|
||||
await nextTick()
|
||||
expect(childUpdated).toHaveBeenCalled()
|
||||
expect(node.getAttribute('id')).toBe('test')
|
||||
|
||||
Reference in New Issue
Block a user