From b3bdd7046fde12c2d06d53d43d8a7c9268cf9cc5 Mon Sep 17 00:00:00 2001 From: underfin <2218301630@qq.com> Date: Fri, 26 Jun 2020 02:04:23 +0800 Subject: [PATCH] test(Transition): more complete transition e2e tests (#1151) --- packages/vue/__tests__/Transition.spec.ts | 1636 +++++++++++++++++ .../vue/{examples => }/__tests__/e2eUtils.ts | 2 +- .../index.html => __tests__/transition.html} | 17 +- .../vue/examples/__tests__/commits.spec.ts | 2 +- packages/vue/examples/__tests__/grid.spec.ts | 2 +- .../vue/examples/__tests__/markdown.spec.ts | 2 +- packages/vue/examples/__tests__/svg.spec.ts | 2 +- .../vue/examples/__tests__/todomvc.spec.ts | 2 +- .../__tests__/transition/Transition.spec.ts | 85 - packages/vue/examples/__tests__/tree.spec.ts | 2 +- 10 files changed, 1645 insertions(+), 107 deletions(-) create mode 100644 packages/vue/__tests__/Transition.spec.ts rename packages/vue/{examples => }/__tests__/e2eUtils.ts (98%) rename packages/vue/{examples/transition/index.html => __tests__/transition.html} (73%) delete mode 100644 packages/vue/examples/__tests__/transition/Transition.spec.ts diff --git a/packages/vue/__tests__/Transition.spec.ts b/packages/vue/__tests__/Transition.spec.ts new file mode 100644 index 00000000..135343ef --- /dev/null +++ b/packages/vue/__tests__/Transition.spec.ts @@ -0,0 +1,1636 @@ +import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils' +import path from 'path' +import { mockWarn } from '@vue/shared' +import { h, createApp, Transition } from 'vue' + +describe('e2e: Transition', () => { + mockWarn() + const { page, html, classList, isVisible } = setupPuppeteer() + const baseUrl = `file://${path.resolve(__dirname, './transition.html')}` + + const duration = 50 + const buffer = 5 + + const classWhenTransitionStart = () => + page().evaluate(() => { + (document.querySelector('#toggleBtn') as any)!.click() + return Promise.resolve().then(() => { + return document.querySelector('#container div')!.className.split(/\s+/g) + }) + }) + + const transitionFinish = (time = duration) => + new Promise(r => { + setTimeout(r, time + buffer) + }) + + const nextFrame = () => { + return page().evaluate(() => { + return new Promise(resolve => { + requestAnimationFrame(() => { + requestAnimationFrame(resolve) + }) + }) + }) + } + + beforeEach(async () => { + await page().goto(baseUrl) + await page().waitFor('#app') + }) + + describe('transition with v-if', () => { + test( + 'basic transition', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'v-leave-active', + 'v-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'v-leave-active', + 'v-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'v-enter-active', + 'v-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'v-enter-active', + 'v-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'named transition', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'custom transition classes', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'bye-active', + 'bye-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'bye-active', + 'bye-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'hello-active', + 'hello-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'hello-active', + 'hello-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'transition with dynamic name', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + + `, + setup: () => { + const name = ref('test') + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + const changeName = () => (name.value = 'changed') + return { toggle, click, name, changeName } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + await page().evaluate(() => { + ;(document.querySelector('#changeNameBtn') as any).click() + }) + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'changed-enter-active', + 'changed-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'changed-enter-active', + 'changed-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'transition events without appear', + async () => { + const beforeLeaveSpy = jest.fn() + const onLeaveSpy = jest.fn() + const afterLeaveSpy = jest.fn() + const beforeEnterSpy = jest.fn() + const onEnterSpy = jest.fn() + const afterEnterSpy = jest.fn() + + await page().exposeFunction('onLeaveSpy', onLeaveSpy) + await page().exposeFunction('onEnterSpy', onEnterSpy) + await page().exposeFunction('beforeLeaveSpy', beforeLeaveSpy) + await page().exposeFunction('beforeEnterSpy', beforeEnterSpy) + await page().exposeFunction('afterLeaveSpy', afterLeaveSpy) + await page().exposeFunction('afterEnterSpy', afterEnterSpy) + + await page().evaluate(() => { + const { + beforeEnterSpy, + onEnterSpy, + afterEnterSpy, + beforeLeaveSpy, + onLeaveSpy, + afterLeaveSpy + } = window as any + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { + toggle, + click, + beforeEnterSpy, + onEnterSpy, + afterEnterSpy, + beforeLeaveSpy, + onLeaveSpy, + afterLeaveSpy + } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + // todo test event with arguments. Note: not get dom, get object. '{}' + expect(beforeLeaveSpy).toBeCalled() + expect(onLeaveSpy).not.toBeCalled() + expect(afterLeaveSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + expect(beforeLeaveSpy).toBeCalled() + expect(afterLeaveSpy).not.toBeCalled() + await transitionFinish() + expect(await html('#container')).toBe('') + expect(afterLeaveSpy).toBeCalled() + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + expect(beforeEnterSpy).toBeCalled() + expect(onEnterSpy).not.toBeCalled() + expect(afterEnterSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + expect(onEnterSpy).toBeCalled() + expect(afterEnterSpy).not.toBeCalled() + await transitionFinish() + expect(await html('#container')).toBe('
content
') + expect(afterEnterSpy).toBeCalled() + }, + E2E_TIMEOUT + ) + + test('onEnterCancelled', async () => { + const enterCancelledSpy = jest.fn() + + await page().exposeFunction('enterCancelledSpy', enterCancelledSpy) + + await page().evaluate(() => { + const { enterCancelledSpy } = window as any + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(false) + const click = () => (toggle.value = !toggle.value) + return { + toggle, + click, + enterCancelledSpy + } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + + // cancel (leave) + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + // fixme + expect(enterCancelledSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + }) + + test( + 'transition on appear', + async () => { + await page().evaluate(async () => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + // appear + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-appear-active', + 'test-appear-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-appear-active', + 'test-appear-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'transition events with appear', + async () => { + const onLeaveSpy = jest.fn() + const onEnterSpy = jest.fn() + const onAppearSpy = jest.fn() + const beforeLeaveSpy = jest.fn() + const beforeEnterSpy = jest.fn() + const beforeAppearSpy = jest.fn() + const afterLeaveSpy = jest.fn() + const afterEnterSpy = jest.fn() + const afterAppearSpy = jest.fn() + + await page().exposeFunction('onLeaveSpy', onLeaveSpy) + await page().exposeFunction('onEnterSpy', onEnterSpy) + await page().exposeFunction('onAppearSpy', onAppearSpy) + await page().exposeFunction('beforeLeaveSpy', beforeLeaveSpy) + await page().exposeFunction('beforeEnterSpy', beforeEnterSpy) + await page().exposeFunction('beforeAppearSpy', beforeAppearSpy) + await page().exposeFunction('afterLeaveSpy', afterLeaveSpy) + await page().exposeFunction('afterEnterSpy', afterEnterSpy) + await page().exposeFunction('afterAppearSpy', afterAppearSpy) + + const appearClass = await page().evaluate(async () => { + const { + beforeAppearSpy, + onAppearSpy, + afterAppearSpy, + beforeEnterSpy, + onEnterSpy, + afterEnterSpy, + beforeLeaveSpy, + onLeaveSpy, + afterLeaveSpy + } = window as any + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { + toggle, + click, + beforeAppearSpy, + onAppearSpy, + afterAppearSpy, + beforeEnterSpy, + onEnterSpy, + afterEnterSpy, + beforeLeaveSpy, + onLeaveSpy, + afterLeaveSpy + } + } + }).mount('#app') + return Promise.resolve().then(() => { + return document.querySelector('.test')!.className.split(/\s+/g) + }) + }) + // appear fixme spy called + expect(appearClass).toStrictEqual([ + 'test', + 'test-appear-active', + 'test-appear-from' + ]) + expect(beforeAppearSpy).not.toBeCalled() + expect(onAppearSpy).not.toBeCalled() + expect(afterAppearSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-appear-active', + 'test-appear-to' + ]) + expect(onAppearSpy).not.toBeCalled() + expect(afterAppearSpy).not.toBeCalled() + await transitionFinish() + expect(await html('#container')).toBe('
content
') + expect(afterAppearSpy).not.toBeCalled() + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + expect(beforeLeaveSpy).toBeCalled() + expect(onLeaveSpy).not.toBeCalled() + expect(afterLeaveSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + expect(onLeaveSpy).toBeCalled() + expect(afterLeaveSpy).not.toBeCalled() + await transitionFinish() + expect(await html('#container')).toBe('') + expect(afterLeaveSpy).toBeCalled() + + // enter fixme spy called + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + expect(beforeEnterSpy).toBeCalled() + expect(onEnterSpy).toBeCalled() + expect(afterEnterSpy).toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + expect(onEnterSpy).toBeCalled() + expect(afterEnterSpy).toBeCalled() + await transitionFinish() + expect(await html('#container')).toBe('
content
') + expect(afterEnterSpy).toBeCalled() + }, + E2E_TIMEOUT + ) + + // fixme + test( + 'css: false', + async () => { + const onLeaveSpy = jest.fn() + const onEnterSpy = jest.fn() + + await page().exposeFunction('onLeaveSpy', onLeaveSpy) + await page().exposeFunction('onEnterSpy', onEnterSpy) + + await page().evaluate(() => { + const { onLeaveSpy, onEnterSpy } = window as any + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click, onLeaveSpy, onEnterSpy } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + await classWhenTransitionStart() + expect(onLeaveSpy).toBeCalled() + expect(await html('#container')).toBe( + '
content
' + ) + // enter + await classWhenTransitionStart() + expect(onEnterSpy).toBeCalled() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'no transition detected', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'noop-leave-active', + 'noop-leave-from' + ]) + await nextFrame() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'noop-enter-active', + 'noop-enter-from' + ]) + await nextFrame() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'animations', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test-anim-leave-active', + 'test-anim-leave-from' + ]) + await nextFrame() + expect(await classList('#container div')).toStrictEqual([ + 'test-anim-leave-active', + 'test-anim-leave-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test-anim-enter-active', + 'test-anim-enter-from' + ]) + await nextFrame() + expect(await classList('#container div')).toStrictEqual([ + 'test-anim-enter-active', + 'test-anim-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'explicit transition type', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
content
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test-anim-long-leave-active', + 'test-anim-long-leave-from' + ]) + await nextFrame() + expect(await classList('#container div')).toStrictEqual([ + 'test-anim-long-leave-active', + 'test-anim-long-leave-to' + ]) + await new Promise(r => { + setTimeout(r, duration + 5) + }) + expect(await classList('#container div')).toStrictEqual([ + 'test-anim-long-leave-active', + 'test-anim-long-leave-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test-anim-long-enter-active', + 'test-anim-long-enter-from' + ]) + await nextFrame() + expect(await classList('#container div')).toStrictEqual([ + 'test-anim-long-enter-active', + 'test-anim-long-enter-to' + ]) + await new Promise(r => { + setTimeout(r, duration + 5) + }) + expect(await classList('#container div')).toStrictEqual([ + 'test-anim-long-enter-active', + 'test-anim-long-enter-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'transition on SVG elements', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` + + + + + + + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe( + '' + ) + + const svgTransitionStart = () => + page().evaluate(() => { + document.querySelector('button')!.click() + return Promise.resolve().then(() => { + return document + .querySelector('.test')! + .getAttribute('class')! + .split(/\s+/g) + }) + }) + + // leave + expect(await svgTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await svgTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe( + '' + ) + }, + E2E_TIMEOUT + ) + + test( + 'custom transition higher-order component', + async () => { + await page().evaluate(() => { + const { createApp, ref, h, Transition } = (window as any).Vue + createApp({ + template: ` +
content
+ + `, + components: { + 'my-transition': (props: any, { slots }: any) => { + return h(Transition, { name: 'test' }, slots) + } + }, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'transition on child components with empty root node', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ + + +
+ + + `, + components: { + one: { + template: '
one
' + }, + two: { + template: '
two
' + } + }, + setup: () => { + const toggle = ref(true) + const view = ref('one') + const click = () => (toggle.value = !toggle.value) + const change = () => + (view.value = view.value === 'one' ? 'two' : 'one') + return { toggle, click, change, view } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('') + + // change view -> 'two' + await page().evaluate(() => { + (document.querySelector('#changeViewBtn') as any)!.click() + }) + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
two
') + + // change view -> 'one' + await page().evaluate(() => { + (document.querySelector('#changeViewBtn') as any)!.click() + }) + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + }, + E2E_TIMEOUT + ) + }) + + describe('transition with v-show', () => { + test( + 'named transition with v-show', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + expect(await isVisible('.test')).toBe(true) + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await isVisible('.test')).toBe(false) + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe( + '
content
' + ) + }, + E2E_TIMEOUT + ) + + test( + 'transition events with v-show', + async () => { + const beforeLeaveSpy = jest.fn() + const onLeaveSpy = jest.fn() + const afterLeaveSpy = jest.fn() + const beforeEnterSpy = jest.fn() + const onEnterSpy = jest.fn() + const afterEnterSpy = jest.fn() + + await page().exposeFunction('onLeaveSpy', onLeaveSpy) + await page().exposeFunction('onEnterSpy', onEnterSpy) + await page().exposeFunction('beforeLeaveSpy', beforeLeaveSpy) + await page().exposeFunction('beforeEnterSpy', beforeEnterSpy) + await page().exposeFunction('afterLeaveSpy', afterLeaveSpy) + await page().exposeFunction('afterEnterSpy', afterEnterSpy) + + await page().evaluate(() => { + const { + beforeEnterSpy, + onEnterSpy, + afterEnterSpy, + beforeLeaveSpy, + onLeaveSpy, + afterLeaveSpy + } = window as any + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { + toggle, + click, + beforeEnterSpy, + onEnterSpy, + afterEnterSpy, + beforeLeaveSpy, + onLeaveSpy, + afterLeaveSpy + } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + expect(beforeLeaveSpy).toBeCalled() + expect(onLeaveSpy).not.toBeCalled() + expect(afterLeaveSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + expect(beforeLeaveSpy).toBeCalled() + expect(afterLeaveSpy).not.toBeCalled() + await transitionFinish() + expect(await isVisible('.test')).toBe(false) + expect(afterLeaveSpy).toBeCalled() + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + expect(beforeEnterSpy).toBeCalled() + expect(onEnterSpy).not.toBeCalled() + expect(afterEnterSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + expect(onEnterSpy).toBeCalled() + expect(afterEnterSpy).not.toBeCalled() + await transitionFinish() + expect(await html('#container')).toBe( + '
content
' + ) + expect(afterEnterSpy).toBeCalled() + }, + E2E_TIMEOUT + ) + + test( + 'onLeaveCancelled (v-show only)', + async () => { + const onLeaveCancelledSpy = jest.fn() + + await page().exposeFunction('onLeaveCancelledSpy', onLeaveCancelledSpy) + await page().evaluate(() => { + const { onLeaveCancelledSpy } = window as any + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click, onLeaveCancelledSpy } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + expect(await isVisible('.test')).toBe(true) + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + + // cancel (enter) + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + // fixme + expect(onLeaveCancelledSpy).not.toBeCalled() + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe( + '
content
' + ) + }, + E2E_TIMEOUT + ) + + test( + 'transition on appear with v-show', + async () => { + const appearClass = await page().evaluate(async () => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + return Promise.resolve().then(() => { + return document.querySelector('.test')!.className.split(/\s+/g) + }) + }) + // appear + expect(appearClass).toStrictEqual([ + 'test', + 'test-appear-active', + 'test-appear-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-appear-active', + 'test-appear-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await isVisible('.test')).toBe(false) + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe( + '
content
' + ) + }, + E2E_TIMEOUT + ) + }) + + test( + 'warn when used on multiple elements', + async () => { + createApp({ + render() { + return h(Transition, null, { + default: () => [h('div'), h('div')] + }) + } + }).mount(document.createElement('div')) + expect( + ' can only be used on a single element or component' + ).toHaveBeenWarned() + }, + E2E_TIMEOUT + ) + + describe('explicit durations', () => { + test( + 'single value', + async () => { + await page().evaluate(duration => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }, duration) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'enter with explicit durations', + async () => { + await page().evaluate(duration => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }, duration) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'leave with explicit durations', + async () => { + await page().evaluate(duration => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }, duration) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + test( + 'separate enter and leave', + async () => { + await page().evaluate(duration => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ +
content
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }, duration) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to' + ]) + await transitionFinish(duration * 2) + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to' + ]) + await transitionFinish(200) + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + // fixme + test.todo('warn invalid durations') + }) +}) diff --git a/packages/vue/examples/__tests__/e2eUtils.ts b/packages/vue/__tests__/e2eUtils.ts similarity index 98% rename from packages/vue/examples/__tests__/e2eUtils.ts rename to packages/vue/__tests__/e2eUtils.ts index f014623d..7d5a0a0e 100644 --- a/packages/vue/examples/__tests__/e2eUtils.ts +++ b/packages/vue/__tests__/e2eUtils.ts @@ -79,7 +79,7 @@ export function setupPuppeteer() { await page.$eval( selector, (node, value) => { - (node as HTMLInputElement).value = value + ;(node as HTMLInputElement).value = value node.dispatchEvent(new Event('input')) }, value diff --git a/packages/vue/examples/transition/index.html b/packages/vue/__tests__/transition.html similarity index 73% rename from packages/vue/examples/transition/index.html rename to packages/vue/__tests__/transition.html index af66e19d..51553064 100644 --- a/packages/vue/examples/transition/index.html +++ b/packages/vue/__tests__/transition.html @@ -1,19 +1,6 @@ - -
- + +