]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: simplify runtime-dom class tests
authorEvan You <yyx990803@gmail.com>
Fri, 10 Apr 2020 19:23:01 +0000 (15:23 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 10 Apr 2020 19:23:01 +0000 (15:23 -0400)
packages/runtime-dom/__tests__/modules/attrs.spec.ts
packages/runtime-dom/__tests__/modules/class.spec.ts
packages/runtime-dom/__tests__/modules/events.spec.ts
packages/runtime-dom/__tests__/modules/style.spec.ts
packages/runtime-dom/src/modules/class.ts
packages/runtime-dom/src/nodeOps.ts

index 9df8d14bbe6a34cd3a6a51aeb261f4fbb87d47c7..2a3bad0d37f073e49efba1d167e6f3c8e8ea58df 100644 (file)
@@ -1,7 +1,7 @@
 import { patchProp } from '../../src/patchProp'
 import { xlinkNS } from '../../src/modules/attrs'
 
-describe('attrs', () => {
+describe('runtime-dom: attrs patching', () => {
   test('xlink attributes', () => {
     const el = document.createElementNS('http://www.w3.org/2000/svg', 'use')
     patchProp(el, 'xlink:href', null, 'a', true)
index 2cb40951f10063f7c70d56018e775d54afcb8faf..d6bfdeca7b54ba75a6c3a6260d9de4ecd8d40177 100644 (file)
-// https://github.com/vuejs/vue/blob/dev/test/unit/features/directives/class.spec.js
-
-import { h, render, defineComponent } from '../../src'
-
-type ClassItem = {
-  value: string | object | string[]
-}
-
-function assertClass(assertions: Array<Array<any>>) {
-  const root = document.createElement('div')
-  const dynamic = { value: '' }
-  const wrapper = () => h('div', { class: ['foo', dynamic.value] })
-
-  for (const [input, expected] of assertions) {
-    if (typeof input === 'function') {
-      input(dynamic.value)
-    } else {
-      dynamic.value = input
-    }
-
-    render(wrapper(), root)
-    expect(root.children[0].className).toBe(expected)
-  }
-}
-
-describe('class', () => {
-  test('plain string', () => {
-    assertClass([
-      ['bar', 'foo bar'],
-      ['baz qux', 'foo baz qux'],
-      ['qux', 'foo qux'],
-      [undefined, 'foo']
-    ])
-  })
-
-  test('object value', () => {
-    assertClass([
-      [{ bar: true, baz: false }, 'foo bar'],
-      [{ baz: true }, 'foo baz'],
-      [null, 'foo'],
-      [{ 'bar baz': true, qux: false }, 'foo bar baz'],
-      [{ qux: true }, 'foo qux']
-    ])
-  })
-
-  test('array value', () => {
-    assertClass([
-      [['bar', 'baz'], 'foo bar baz'],
-      [['qux', 'baz'], 'foo qux baz'],
-      [['w', 'x y z'], 'foo w x y z'],
-      [undefined, 'foo'],
-      [['bar'], 'foo bar'],
-      [(val: Array<any>) => val.push('baz'), 'foo bar baz']
-    ])
-  })
-
-  test('array of mixed values', () => {
-    assertClass([
-      [['x', { y: true, z: true }], 'foo x y z'],
-      [['x', { y: true, z: false }], 'foo x y'],
-      [['f', { z: true }], 'foo f z'],
-      [['l', 'f', { n: true, z: true }], 'foo l f n z'],
-      [['x', {}], 'foo x'],
-      [undefined, 'foo']
-    ])
-  })
-
-  test('class merge between parent and child', () => {
-    const root = document.createElement('div')
-
-    const childClass: ClassItem = { value: 'd' }
-    const child = {
-      render: () => h('div', { class: ['c', childClass.value] })
-    }
-
-    const parentClass: ClassItem = { value: 'b' }
-    const parent = {
-      render: () => h(child, { class: ['a', parentClass.value] })
-    }
-
-    render(h(parent), root)
-    expect(root.children[0].className).toBe('c d a b')
-
-    parentClass.value = 'e'
-    // the `foo` here is just for forcing parent to be updated
-    // (otherwise it's skipped since its props never change)
-    render(h(parent, { foo: 1 }), root)
-    expect(root.children[0].className).toBe('c d a e')
-
-    parentClass.value = 'f'
-    render(h(parent, { foo: 2 }), root)
-    expect(root.children[0].className).toBe('c d a f')
-
-    parentClass.value = { foo: true }
-    childClass.value = ['bar', 'baz']
-    render(h(parent, { foo: 3 }), root)
-    expect(root.children[0].className).toBe('c bar baz a foo')
-  })
-
-  test('class merge between multiple nested components sharing same element', () => {
-    const component1 = defineComponent({
-      render() {
-        return this.$slots.default!()[0]
-      }
-    })
-
-    const component2 = defineComponent({
-      render() {
-        return this.$slots.default!()[0]
-      }
-    })
-
-    const component3 = defineComponent({
-      render() {
-        return h(
-          'div',
-          {
-            class: 'staticClass'
-          },
-          [this.$slots.default!()]
-        )
-      }
-    })
-
-    const root = document.createElement('div')
-    const componentClass1 = { value: 'componentClass1' }
-    const componentClass2 = { value: 'componentClass2' }
-    const componentClass3 = { value: 'componentClass3' }
-
-    const wrapper = () =>
-      h(component1, { class: componentClass1.value }, () => [
-        h(component2, { class: componentClass2.value }, () => [
-          h(component3, { class: componentClass3.value }, () => ['some text'])
-        ])
-      ])
-
-    render(wrapper(), root)
-    expect(root.children[0].className).toBe(
-      'staticClass componentClass3 componentClass2 componentClass1'
-    )
-
-    componentClass1.value = 'c1'
-    render(wrapper(), root)
-    expect(root.children[0].className).toBe(
-      'staticClass componentClass3 componentClass2 c1'
-    )
-
-    componentClass2.value = 'c2'
-    render(wrapper(), root)
-    expect(root.children[0].className).toBe('staticClass componentClass3 c2 c1')
-
-    componentClass3.value = 'c3'
-    render(wrapper(), root)
-    expect(root.children[0].className).toBe('staticClass c3 c2 c1')
-  })
-
-  test('deep update', () => {
-    const root = document.createElement('div')
-    const test = {
-      a: true,
-      b: false
-    }
-
-    const wrapper = () => h('div', { class: test })
-    render(wrapper(), root)
-    expect(root.children[0].className).toBe('a')
-
-    test.b = true
-    render(wrapper(), root)
-    expect(root.children[0].className).toBe('a b')
-  })
-
-  // a vdom patch edge case where the user has several un-keyed elements of the
-  // same tag next to each other, and toggling them.
-  test('properly remove staticClass for toggling un-keyed children', () => {
-    const root = document.createElement('div')
-    const ok = { value: true }
-    const wrapper = () =>
-      h('div', [ok.value ? h('div', { class: 'a' }) : h('div')])
-
-    render(wrapper(), root)
-    expect(root.children[0].children[0].className).toBe('a')
-
-    ok.value = false
-    render(wrapper(), root)
-    expect(root.children[0].children[0].className).toBe('')
+import { patchProp } from '../../src/patchProp'
+import { ElementWithTransition } from '../../src/components/Transition'
+import { svgNS } from '../../src/nodeOps'
+
+describe('runtime-dom: class patching', () => {
+  test('basics', () => {
+    const el = document.createElement('div')
+    patchProp(el, 'class', null, 'foo')
+    expect(el.className).toBe('foo')
+    patchProp(el, 'class', null, null)
+    expect(el.className).toBe('')
+  })
+
+  test('transition class', () => {
+    const el = document.createElement('div') as ElementWithTransition
+    el._vtc = new Set(['bar', 'baz'])
+    patchProp(el, 'class', null, 'foo')
+    expect(el.className).toBe('foo bar baz')
+    patchProp(el, 'class', null, null)
+    expect(el.className).toBe('bar baz')
+    delete el._vtc
+    patchProp(el, 'class', null, 'foo')
+    expect(el.className).toBe('foo')
+  })
+
+  test('svg', () => {
+    const el = document.createElementNS(svgNS, 'svg')
+    patchProp(el, 'class', null, 'foo', true)
+    expect(el.getAttribute('class')).toBe('foo')
   })
 })
index 2aced378fc4f0614f4fd0278a9ea7d46762c7df5..3b365e1ca3ae6c89e629302686e5a251705bc5cd 100644 (file)
@@ -2,7 +2,7 @@ import { patchProp } from '../../src/patchProp'
 
 const timeout = () => new Promise(r => setTimeout(r))
 
-describe(`events`, () => {
+describe(`runtime-dom: events patching`, () => {
   it('should assign event handler', async () => {
     const el = document.createElement('div')
     const event = new Event('click')
index a3174fca8af69faae39e45a17955c53092e09633..90fd60f0db0e574a1e272ca0ecaa95994fdc2949 100644 (file)
@@ -1,6 +1,6 @@
 import { patchProp } from '../../src/patchProp'
 
-describe(`module style`, () => {
+describe(`runtime-dom: style patching`, () => {
   it('string', () => {
     const el = document.createElement('div')
     patchProp(el, 'style', {}, 'color:red')
index e81d7fe74b6844d90f7c47b3183d1162c44b5d0b..d26867d9a068d5f5c3d17a8e5fc5f1d8410a29a0 100644 (file)
@@ -6,15 +6,18 @@ export function patchClass(el: Element, value: string | null, isSVG: boolean) {
   if (value == null) {
     value = ''
   }
-  // directly setting className should be faster than setAttribute in theory
   if (isSVG) {
     el.setAttribute('class', value)
   } else {
+    // directly setting className should be faster than setAttribute in theory
     // if this is an element during a transition, take the temporary transition
     // classes into account.
     const transitionClasses = (el as ElementWithTransition)._vtc
     if (transitionClasses) {
-      value = [value, ...transitionClasses].join(' ')
+      value = (value
+        ? [value, ...transitionClasses]
+        : [...transitionClasses]
+      ).join(' ')
     }
     el.className = value
   }
index 38b494ebbc50250414d9f485effe9a8a1047f05a..b147da308f5a21f06f4a5045291c3c76ad87dbd5 100644 (file)
@@ -1,7 +1,8 @@
 import { RendererOptions } from '@vue/runtime-core'
 
+export const svgNS = 'http://www.w3.org/2000/svg'
+
 const doc = (typeof document !== 'undefined' ? document : null) as Document
-const svgNS = 'http://www.w3.org/2000/svg'
 
 let tempContainer: HTMLElement
 let tempSVGContainer: SVGElement