| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- // using DOM renderer because this case is mostly DOM-specific
- import {
- h,
- render,
- nextTick,
- mergeProps,
- ref,
- onUpdated,
- createComponent
- } from '@vue/runtime-dom'
- describe('attribute fallthrough', () => {
- it('everything should be in props when component has no declared props', async () => {
- const click = jest.fn()
- const childUpdated = jest.fn()
- const Hello = {
- setup() {
- const count = ref(0)
- function inc() {
- count.value++
- click()
- }
- return () =>
- h(Child, {
- foo: 1,
- id: 'test',
- class: 'c' + count.value,
- style: { color: count.value ? 'red' : 'green' },
- onClick: inc
- })
- }
- }
- const Child = {
- setup(props: any) {
- onUpdated(childUpdated)
- return () =>
- h(
- 'div',
- mergeProps(
- {
- class: 'c2',
- style: { fontWeight: 'bold' }
- },
- props
- ),
- 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('1')
- 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')
- expect(node.getAttribute('foo')).toBe('1')
- expect(node.getAttribute('class')).toBe('c2 c1')
- expect(node.style.color).toBe('red')
- expect(node.style.fontWeight).toBe('bold')
- })
- it('should separate in attrs when component has declared props', async () => {
- const click = jest.fn()
- const childUpdated = jest.fn()
- const Hello = {
- setup() {
- const count = ref(0)
- function inc() {
- count.value++
- click()
- }
- return () =>
- h(Child, {
- foo: 1,
- id: 'test',
- class: 'c' + count.value,
- style: { color: count.value ? 'red' : 'green' },
- onClick: inc
- })
- }
- }
- const Child = createComponent({
- props: {
- foo: Number
- },
- setup(props, { attrs }) {
- onUpdated(childUpdated)
- return () =>
- h(
- 'div',
- mergeProps(
- {
- class: 'c2',
- style: { fontWeight: 'bold' }
- },
- attrs
- ),
- props.foo
- )
- }
- })
- const root = document.createElement('div')
- document.body.appendChild(root)
- render(h(Hello), root)
- const node = root.children[0] as HTMLElement
- // with declared props, any parent attr that isn't a prop falls through
- expect(node.getAttribute('id')).toBe('test')
- 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()
- // ...while declared ones remain props
- expect(node.hasAttribute('foo')).toBe(false)
- await nextTick()
- expect(childUpdated).toHaveBeenCalled()
- expect(node.getAttribute('id')).toBe('test')
- expect(node.getAttribute('class')).toBe('c2 c1')
- expect(node.style.color).toBe('red')
- expect(node.style.fontWeight).toBe('bold')
- expect(node.hasAttribute('foo')).toBe(false)
- })
- it('should fallthrough on multi-nested components', async () => {
- const click = jest.fn()
- const childUpdated = jest.fn()
- const grandChildUpdated = jest.fn()
- const Hello = {
- setup() {
- const count = ref(0)
- function inc() {
- count.value++
- click()
- }
- return () =>
- h(Child, {
- foo: 1,
- id: 'test',
- class: 'c' + count.value,
- style: { color: count.value ? 'red' : 'green' },
- onClick: inc
- })
- }
- }
- const Child = {
- setup(props: any) {
- onUpdated(childUpdated)
- return () => h(GrandChild, props)
- }
- }
- const GrandChild = createComponent({
- props: {
- foo: Number
- },
- setup(props, { attrs }) {
- onUpdated(grandChildUpdated)
- return () =>
- h(
- 'div',
- mergeProps(
- {
- class: 'c2',
- style: { fontWeight: 'bold' }
- },
- attrs
- ),
- props.foo
- )
- }
- })
- const root = document.createElement('div')
- document.body.appendChild(root)
- render(h(Hello), root)
- const node = root.children[0] as HTMLElement
- // with declared props, any parent attr that isn't a prop falls through
- expect(node.getAttribute('id')).toBe('test')
- 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()
- // ...while declared ones remain props
- expect(node.hasAttribute('foo')).toBe(false)
- await nextTick()
- expect(childUpdated).toHaveBeenCalled()
- expect(grandChildUpdated).toHaveBeenCalled()
- expect(node.getAttribute('id')).toBe('test')
- expect(node.getAttribute('class')).toBe('c2 c1')
- expect(node.style.color).toBe('red')
- expect(node.style.fontWeight).toBe('bold')
- expect(node.hasAttribute('foo')).toBe(false)
- })
- })
|