From: Evan You Date: Mon, 1 Oct 2018 22:21:44 +0000 (-0400) Subject: test: fragment specs X-Git-Tag: v3.0.0-alpha.0~1167 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=612167f4703ca9a8b524f002961f162612bc7423;p=thirdparty%2Fvuejs%2Fcore.git test: fragment specs --- diff --git a/packages/core/__tests__/attrsFallthrough.spec.ts b/packages/core/__tests__/attrsFallthrough.spec.ts index a962db53cf..dae88be147 100644 --- a/packages/core/__tests__/attrsFallthrough.spec.ts +++ b/packages/core/__tests__/attrsFallthrough.spec.ts @@ -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 index 0000000000..388c124afa --- /dev/null +++ b/packages/core/__tests__/fragment.spec.ts @@ -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(`
one
two
`) + 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(`
one
two
`) + }) + + 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(`
one
two
`) + + state.ok = false + await nextTick() + expect(serialize(root)).toBe(`
foo
barbaz
`) + }) + + 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(`
one
two
`) + + state.ok = false + await nextTick() + expect(serialize(root)).toBe(`
foo
barbaz
`) + }) + + 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(`
one
two
`) + + resetOps() + state.ok = false + await nextTick() + expect(serialize(root)).toBe(`
two
one
`) + 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( + `
outer
one
two
` + ) + + resetOps() + state.ok = false + await nextTick() + expect(serialize(parent)).toBe( + `
two
one
outer
` + ) + 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( + `
outer
one
two
` + ) + + resetOps() + state.ok = false + await nextTick() + expect(serialize(root)).toBe( + `
two
one
outer
` + ) + const ops = dumpOps() + // should be moving nodes instead of re-creating them + expect(ops.some(op => op.type === NodeOpTypes.CREATE)).toBe(false) + }) +})