]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: fragment specs
authorEvan You <yyx990803@gmail.com>
Mon, 1 Oct 2018 22:21:44 +0000 (18:21 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 1 Oct 2018 22:21:44 +0000 (18:21 -0400)
packages/core/__tests__/attrsFallthrough.spec.ts
packages/core/__tests__/fragment.spec.ts [new file with mode: 0644]

index a962db53cf6b9504cf3c397e3e7175ec3f453886..dae88be147f1acc16acac0d7258ea6f658504551 100644 (file)
@@ -1,3 +1,4 @@
+// using DOM renderer because this case is mostly DOM-specific
 import { h, render, Component, nextTick } from '@vue/renderer-dom'
 
 describe('attribute fallthrough', () => {
diff --git a/packages/core/__tests__/fragment.spec.ts b/packages/core/__tests__/fragment.spec.ts
new file mode 100644 (file)
index 0000000..388c124
--- /dev/null
@@ -0,0 +1,198 @@
+import {
+  h,
+  Component,
+  render,
+  nodeOps,
+  NodeTypes,
+  TestElement,
+  Fragment,
+  observable,
+  serialize,
+  ChildrenFlags,
+  nextTick,
+  resetOps,
+  dumpOps,
+  NodeOpTypes
+} from '@vue/renderer-test'
+
+describe('Fragments', () => {
+  it('should allow returning multiple component root nodes', () => {
+    class App extends Component {
+      render() {
+        return [h('div', 'one'), 'two']
+      }
+    }
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+    expect(serialize(root)).toBe(`<div><div>one</div>two</div>`)
+    expect(root.children.length).toBe(2)
+    expect(root.children[0]).toMatchObject({
+      type: NodeTypes.ELEMENT,
+      tag: 'div'
+    })
+    expect((root.children[0] as TestElement).children[0]).toMatchObject({
+      type: NodeTypes.TEXT,
+      text: 'one'
+    })
+    expect(root.children[1]).toMatchObject({
+      type: NodeTypes.TEXT,
+      text: 'two'
+    })
+  })
+
+  it('should be able to explicitly create fragments', () => {
+    class App extends Component {
+      render() {
+        return h('div', [h(Fragment, [h('div', 'one'), 'two'])])
+      }
+    }
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+    const parent = root.children[0] as TestElement
+    expect(serialize(parent)).toBe(`<div><div>one</div>two</div>`)
+  })
+
+  it('should be able to patch fragment children (unkeyed)', async () => {
+    const state = observable({ ok: true })
+    class App extends Component {
+      render() {
+        return state.ok
+          ? h.f([h('div', 'one'), h.t('two')], ChildrenFlags.NONE_KEYED_VNODES)
+          : h.f(
+              [h('div', 'foo'), h.t('bar'), h.t('baz')],
+              ChildrenFlags.NONE_KEYED_VNODES
+            )
+      }
+    }
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+
+    expect(serialize(root)).toBe(`<div><div>one</div>two</div>`)
+
+    state.ok = false
+    await nextTick()
+    expect(serialize(root)).toBe(`<div><div>foo</div>barbaz</div>`)
+  })
+
+  it('should be able to patch fragment children (implicitly keyed)', async () => {
+    const state = observable({ ok: true })
+    class App extends Component {
+      render() {
+        return state.ok
+          ? [h('div', 'one'), 'two']
+          : [h('div', 'foo'), 'bar', 'baz']
+      }
+    }
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+
+    expect(serialize(root)).toBe(`<div><div>one</div>two</div>`)
+
+    state.ok = false
+    await nextTick()
+    expect(serialize(root)).toBe(`<div><div>foo</div>barbaz</div>`)
+  })
+
+  it('should be able to patch fragment children (explcitly keyed)', async () => {
+    const state = observable({ ok: true })
+    class App extends Component {
+      render() {
+        return state.ok
+          ? [h('div', { key: 1 }, 'one'), h('div', { key: 2 }, 'two')]
+          : [h('div', { key: 2 }, 'two'), h('div', { key: 1 }, 'one')]
+      }
+    }
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+
+    expect(serialize(root)).toBe(`<div><div>one</div><div>two</div></div>`)
+
+    resetOps()
+    state.ok = false
+    await nextTick()
+    expect(serialize(root)).toBe(`<div><div>two</div><div>one</div></div>`)
+    const ops = dumpOps()
+    // should be moving nodes instead of re-creating them
+    expect(ops.some(op => op.type === NodeOpTypes.CREATE)).toBe(false)
+  })
+
+  it('should be able to move fragment', async () => {
+    const state = observable({ ok: true })
+    class App extends Component {
+      render() {
+        return state.ok
+          ? h('div', [
+              h('div', { key: 1 }, 'outer'),
+              h(Fragment, { key: 2 }, [
+                h('div', { key: 1 }, 'one'),
+                h('div', { key: 2 }, 'two')
+              ])
+            ])
+          : h('div', [
+              h(Fragment, { key: 2 }, [
+                h('div', { key: 2 }, 'two'),
+                h('div', { key: 1 }, 'one')
+              ]),
+              h('div', { key: 1 }, 'outer')
+            ])
+      }
+    }
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+    const parent = root.children[0] as TestElement
+
+    expect(serialize(parent)).toBe(
+      `<div><div>outer</div><div>one</div><div>two</div></div>`
+    )
+
+    resetOps()
+    state.ok = false
+    await nextTick()
+    expect(serialize(parent)).toBe(
+      `<div><div>two</div><div>one</div><div>outer</div></div>`
+    )
+    const ops = dumpOps()
+    // should be moving nodes instead of re-creating them
+    expect(ops.some(op => op.type === NodeOpTypes.CREATE)).toBe(false)
+  })
+
+  it('should be able to handle nested fragments', async () => {
+    const state = observable({ ok: true })
+    class App extends Component {
+      render() {
+        return state.ok
+          ? [
+              h('div', { key: 1 }, 'outer'),
+              h(Fragment, { key: 2 }, [
+                h('div', { key: 1 }, 'one'),
+                h('div', { key: 2 }, 'two')
+              ])
+            ]
+          : [
+              h(Fragment, { key: 2 }, [
+                h('div', { key: 2 }, 'two'),
+                h('div', { key: 1 }, 'one')
+              ]),
+              h('div', { key: 1 }, 'outer')
+            ]
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+
+    expect(serialize(root)).toBe(
+      `<div><div>outer</div><div>one</div><div>two</div></div>`
+    )
+
+    resetOps()
+    state.ok = false
+    await nextTick()
+    expect(serialize(root)).toBe(
+      `<div><div>two</div><div>one</div><div>outer</div></div>`
+    )
+    const ops = dumpOps()
+    // should be moving nodes instead of re-creating them
+    expect(ops.some(op => op.type === NodeOpTypes.CREATE)).toBe(false)
+  })
+})