From a848466f07efd26060747d61dc9bda0d1754ad4f Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 24 Sep 2018 21:13:06 -0400 Subject: [PATCH] test: test for attrs fallthrough --- jest.config.js | 3 +- .../core/__tests__/attrsFallthrough.spec.ts | 143 ++++++++++++++++++ packages/global.d.ts | 1 + packages/renderer-dom/src/modules/events.ts | 2 +- rollup.config.js | 4 +- 5 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 packages/core/__tests__/attrsFallthrough.spec.ts diff --git a/jest.config.js b/jest.config.js index 4eb301058..d92d38864 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,7 +2,8 @@ module.exports = { preset: 'ts-jest', globals: { __DEV__: true, - __COMPAT__: false + __COMPAT__: false, + __JSDOM__: true }, coverageDirectory: 'coverage', coverageReporters: ['html', 'lcov', 'text'], diff --git a/packages/core/__tests__/attrsFallthrough.spec.ts b/packages/core/__tests__/attrsFallthrough.spec.ts new file mode 100644 index 000000000..a962db53c --- /dev/null +++ b/packages/core/__tests__/attrsFallthrough.spec.ts @@ -0,0 +1,143 @@ +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') + }) +}) diff --git a/packages/global.d.ts b/packages/global.d.ts index 11614e940..f82292626 100644 --- a/packages/global.d.ts +++ b/packages/global.d.ts @@ -1,3 +1,4 @@ // Global compile-time constants declare var __DEV__: boolean declare var __COMPAT__: boolean +declare var __JSDOM__: boolean diff --git a/packages/renderer-dom/src/modules/events.ts b/packages/renderer-dom/src/modules/events.ts index 452ff0014..fda02d46d 100644 --- a/packages/renderer-dom/src/modules/events.ts +++ b/packages/renderer-dom/src/modules/events.ts @@ -9,7 +9,7 @@ export function patchEvent( prevValue: EventValue | null, nextValue: EventValue | null ) { - if (delegateRE.test(name)) { + if (delegateRE.test(name) && !__JSDOM__) { handleDelegatedEvent(el, name, nextValue) } else { handleNormalEvent(el, name, prevValue, nextValue) diff --git a/rollup.config.js b/rollup.config.js index 6e4690543..a7dd1924b 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -124,7 +124,9 @@ function createReplacePlugin(isProduction, isBunlderESMBuild, isCompat) { : // hard coded dev/prod builds !isProduction, // compatibility builds - __COMPAT__: !!packageOptions.compat + __COMPAT__: !!packageOptions.compat, + // this is only used during tests + __JSDOM__: false }) }