--- /dev/null
+import { h, render, Component, nextTick } from '@vue/renderer-dom'
+
+describe('attribute fallthrough', () => {
+ it('should not fallthrough on components with no declared props', async () => {
+ const nativeClick = jest.fn()
+ const childUpdated = jest.fn()
+
+ class Hello extends Component {
+ data() {
+ return {
+ count: 0
+ }
+ }
+ inc() {
+ this.count++
+ nativeClick()
+ }
+ render() {
+ return h(Child, {
+ foo: 1,
+ id: 'test',
+ class: 'c' + this.count,
+ style: { color: this.count ? 'red' : 'green' },
+ nativeOnClick: this.inc
+ })
+ }
+ }
+
+ class Child extends Component {
+ updated() {
+ childUpdated()
+ }
+ render(props: any) {
+ 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
+
+ // attrs do not fallthrough because no props are declared
+ expect(node.hasAttribute('id')).toBe(false)
+ expect(node.hasAttribute('foo')).toBe(false)
+
+ // class, style and nativeOn* always fallthrough
+ 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(nativeClick).toHaveBeenCalled()
+
+ await nextTick()
+ expect(childUpdated).toHaveBeenCalled()
+ expect(node.hasAttribute('id')).toBe(false)
+ expect(node.hasAttribute('foo')).toBe(false)
+ expect(node.getAttribute('class')).toBe('c2 c1')
+ expect(node.style.color).toBe('red')
+ expect(node.style.fontWeight).toBe('bold')
+ })
+
+ it('should fallthrough on components with declared props', async () => {
+ const nativeClick = jest.fn()
+ const childUpdated = jest.fn()
+
+ class Hello extends Component {
+ data() {
+ return {
+ count: 0
+ }
+ }
+ inc() {
+ this.count++
+ nativeClick()
+ }
+ render() {
+ return h(Child, {
+ foo: 1,
+ id: 'test',
+ class: 'c' + this.count,
+ style: { color: this.count ? 'red' : 'green' },
+ nativeOnClick: this.inc
+ })
+ }
+ }
+
+ class Child extends Component {
+ static options = {
+ props: {
+ foo: Number
+ }
+ }
+ updated() {
+ childUpdated()
+ }
+ render(props: any) {
+ 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
+
+ // with declared props, any parent attr that isn't a prop falls through
+ expect(node.getAttribute('id')).toBe('test')
+ // ...while declared ones remain props
+ expect(node.hasAttribute('foo')).toBe(false)
+
+ // class, style and nativeOn* always fallthrough
+ 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(nativeClick).toHaveBeenCalled()
+
+ await nextTick()
+ expect(childUpdated).toHaveBeenCalled()
+ expect(node.getAttribute('id')).toBe('test')
+ expect(node.hasAttribute('foo')).toBe(false)
+ expect(node.getAttribute('class')).toBe('c2 c1')
+ expect(node.style.color).toBe('red')
+ expect(node.style.fontWeight).toBe('bold')
+ })
+})