]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test(Transition): more complete transition e2e tests (#1151)
authorunderfin <2218301630@qq.com>
Thu, 25 Jun 2020 18:04:23 +0000 (02:04 +0800)
committerGitHub <noreply@github.com>
Thu, 25 Jun 2020 18:04:23 +0000 (14:04 -0400)
packages/vue/__tests__/Transition.spec.ts [new file with mode: 0644]
packages/vue/__tests__/e2eUtils.ts [moved from packages/vue/examples/__tests__/e2eUtils.ts with 98% similarity]
packages/vue/__tests__/transition.html [moved from packages/vue/examples/transition/index.html with 73% similarity]
packages/vue/examples/__tests__/commits.spec.ts
packages/vue/examples/__tests__/grid.spec.ts
packages/vue/examples/__tests__/markdown.spec.ts
packages/vue/examples/__tests__/svg.spec.ts
packages/vue/examples/__tests__/todomvc.spec.ts
packages/vue/examples/__tests__/transition/Transition.spec.ts [deleted file]
packages/vue/examples/__tests__/tree.spec.ts

diff --git a/packages/vue/__tests__/Transition.spec.ts b/packages/vue/__tests__/Transition.spec.ts
new file mode 100644 (file)
index 0000000..135343e
--- /dev/null
@@ -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: `
+            <div id="container">
+              <transition>
+                <div v-if="toggle" class="test">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'named transition',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container">
+                <transition name="test">
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'custom transition classes',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+          <div id="container">
+            <transition enter-from-class="hello-from"
+              enter-active-class="hello-active"
+              enter-to-class="hello-to"
+              leave-from-class="bye-from"
+              leave-active-class="bye-active"
+              leave-to-class="bye-to">
+              <div v-if="toggle" class="test">content</div>
+            </transition>
+          </div>
+          <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'transition with dynamic name',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+          <div id="container">
+            <transition :name="name">
+              <div v-if="toggle" class="test">content</div>
+            </transition>
+          </div>
+          <button id="toggleBtn" @click="click">button</button>
+          <button id="changeNameBtn" @click="changeName">button</button>
+          `,
+            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('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      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: `
+            <div id="container">
+              <transition
+                name="test"
+                @before-enter="beforeEnterSpy"
+                @enter="onEnterSpy"
+                @after-enter="afterEnterSpy"
+                @before-leave="beforeLeaveSpy"
+                @leave="onLeaveSpy"
+                @after-leave="afterLeaveSpy">
+                <div v-if="toggle" class="test">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            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('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+        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('<div class="test">content</div>')
+        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: `
+            <div id="container">
+              <transition
+                name="test"
+                @enter-cancelled="enterCancelledSpy">
+                <div v-if="toggle" class="test">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+          setup: () => {
+            const toggle = ref(false)
+            const click = () => (toggle.value = !toggle.value)
+            return {
+              toggle,
+              click,
+              enterCancelledSpy
+            }
+          }
+        }).mount('#app')
+      })
+      expect(await html('#container')).toBe('<!--v-if-->')
+
+      // 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('<!--v-if-->')
+    })
+
+    test(
+      'transition on appear',
+      async () => {
+        await page().evaluate(async () => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container">
+                <transition name="test"
+                            appear
+                            appear-from-class="test-appear-from"
+                            appear-to-class="test-appear-to"
+                            appear-active-class="test-appear-active">
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            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('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      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: `
+              <div id="container">
+                <transition
+                  name="test"
+                  appear
+                  appear-from-class="test-appear-from"
+                  appear-to-class="test-appear-to"
+                  appear-active-class="test-appear-active"
+                  @before-enter="beforeEnterSpy"
+                  @enter="onEnterSpy"
+                  @after-enter="afterEnterSpy"
+                  @before-leave="beforeLeaveSpy"
+                  @leave="onLeaveSpy"
+                  @after-leave="afterLeaveSpy"
+                  @before-appear="beforeAppearSpy"
+                  @appear="onAppearSpy"
+                  @after-appear="afterAppearSpy">
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            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('<div class="test">content</div>')
+        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('<!--v-if-->')
+        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('<div class="test">content</div>')
+        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: `
+            <div id="container">
+              <transition
+                :css="false"
+                name="test"
+                @enter="onEnterSpy"
+                @leave="onLeaveSpy">
+                <div v-if="toggle" class="test">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click"></button>
+          `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click, onLeaveSpy, onEnterSpy }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // leave
+        await classWhenTransitionStart()
+        expect(onLeaveSpy).toBeCalled()
+        expect(await html('#container')).toBe(
+          '<div class="test">content</div><!--v-if-->'
+        )
+        // enter
+        await classWhenTransitionStart()
+        expect(onEnterSpy).toBeCalled()
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'no transition detected',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+            <div id="container">
+              <transition name="noop">
+                <div v-if="toggle">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div>content</div>')
+
+        // leave
+        expect(await classWhenTransitionStart()).toStrictEqual([
+          'noop-leave-active',
+          'noop-leave-from'
+        ])
+        await nextFrame()
+        expect(await html('#container')).toBe('<!--v-if-->')
+
+        // enter
+        expect(await classWhenTransitionStart()).toStrictEqual([
+          'noop-enter-active',
+          'noop-enter-from'
+        ])
+        await nextFrame()
+        expect(await html('#container')).toBe('<div class="">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'animations',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container">
+                <transition name="test-anim">
+                  <div v-if="toggle">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div>content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'explicit transition type',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container"><transition name="test-anim-long" type="animation"><div v-if="toggle">content</div></transition></div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div>content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'transition on SVG elements',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <svg id="container">
+                <transition name="test">
+                  <circle v-if="toggle" cx="0" cy="0" r="10" class="test"></circle>
+                </transition>
+              </svg>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe(
+          '<circle cx="0" cy="0" r="10" class="test"></circle>'
+        )
+
+        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('<!--v-if-->')
+
+        // 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(
+          '<circle cx="0" cy="0" r="10" class="test"></circle>'
+        )
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'custom transition higher-order component',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref, h, Transition } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container"><my-transition><div v-if="toggle" class="test">content</div></my-transition></div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            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('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'transition on child components with empty root node',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container">
+                <transition name="test">
+                  <component class="test" :is="view"></component>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+              <button id="changeViewBtn" @click="change">button</button>
+            `,
+            components: {
+              one: {
+                template: '<div v-if="false">one</div>'
+              },
+              two: {
+                template: '<div>two</div>'
+              }
+            },
+            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('<!--v-if-->')
+
+        // 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('<div class="test">two</div>')
+
+        // 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('<!--v-if-->')
+      },
+      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: `
+            <div id="container">
+              <transition name="test">
+                <div v-show="toggle" class="test">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+        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(
+          '<div class="test" style="">content</div>'
+        )
+      },
+      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: `
+            <div id="container">
+              <transition
+                name="test"
+                @before-enter="beforeEnterSpy"
+                @enter="onEnterSpy"
+                @after-enter="afterEnterSpy"
+                @before-leave="beforeLeaveSpy"
+                @leave="onLeaveSpy"
+                @after-leave="afterLeaveSpy">
+                <div v-show="toggle" class="test">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            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('<div class="test">content</div>')
+
+        // 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(
+          '<div class="test" style="">content</div>'
+        )
+        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: `
+            <div id="container">
+              <transition name="test">
+                <div v-show="toggle" class="test" @leave-cancelled="onLeaveCancelledSpy">content</div>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click, onLeaveCancelledSpy }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+        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(
+          '<div class="test" style="">content</div>'
+        )
+      },
+      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: `
+              <div id="container">
+                <transition name="test"
+                            appear
+                            appear-from-class="test-appear-from"
+                            appear-to-class="test-appear-to"
+                            appear-active-class="test-appear-active">
+                  <div v-show="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            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('<div class="test">content</div>')
+
+        // 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(
+          '<div class="test" style="">content</div>'
+        )
+      },
+      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(
+        '<transition> 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: `
+              <div id="container">
+                <transition name="test" duration="${duration * 2}">
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        }, duration)
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'enter with explicit durations',
+      async () => {
+        await page().evaluate(duration => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container">
+                <transition name="test" :duration="{ enter: ${duration * 2} }">
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        }, duration)
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'leave with explicit durations',
+      async () => {
+        await page().evaluate(duration => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container">
+                <transition name="test" :duration="{ leave: ${duration * 2} }">
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        }, duration)
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    test(
+      'separate enter and leave',
+      async () => {
+        await page().evaluate(duration => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+              <div id="container">
+                <transition name="test" :duration="{
+                  enter: ${duration * 4},
+                  leave: ${duration * 2}
+                }">
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </div>
+              <button id="toggleBtn" @click="click">button</button>
+            `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        }, duration)
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    // fixme
+    test.todo('warn invalid durations')
+  })
+})
similarity index 98%
rename from packages/vue/examples/__tests__/e2eUtils.ts
rename to packages/vue/__tests__/e2eUtils.ts
index f014623d8fec71ceff094c480b2ed344e197fc48..7d5a0a0e069d688b764c1f87343990e11935c9c8 100644 (file)
@@ -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
similarity index 73%
rename from packages/vue/examples/transition/index.html
rename to packages/vue/__tests__/transition.html
index af66e19df855b863933be91baf78ff96b7dc68f1..51553064554f78dd8ac25a85ae6e89fe95bab1f6 100644 (file)
@@ -1,19 +1,6 @@
-<script src="../../dist/vue.global.js"></script>
-<div id="app"></div>
-<script>
-  Vue.createApp({
-    template: `
-      <div id="test"><transition><div v-if="toggle" class="test">content</div></transition></div>
-      <button @click="click">button</button>
-    `,
-    setup:() => {
-      const toggle = Vue.ref(true)
-      const click = () => toggle.value = !toggle.value
-      return { toggle, click }
-    }
-  }).mount('#app')
-</script>
+<script src="../dist/vue.global.js"></script>
 
+<div id="app"></div>
 <style>
   .test {
     -webkit-transition: opacity 50ms ease;
index d48a1957487dcafbef9b87cdcd1f7aa922fe26f7..380a8083e346ee63d4dd81831f959e54abb7a692 100644 (file)
@@ -1,5 +1,5 @@
 import path from 'path'
-import { setupPuppeteer, E2E_TIMEOUT } from './e2eUtils'
+import { setupPuppeteer, E2E_TIMEOUT } from '../../__tests__/e2eUtils'
 import mocks from './commits.mock'
 
 describe('e2e: commits', () => {
index 6fde334fd49e2f045249bd441e49cfc5d934d0bd..c82e7eedef29238fca8d2fabbb78660053ee892f 100644 (file)
@@ -1,5 +1,5 @@
 import path from 'path'
-import { setupPuppeteer, E2E_TIMEOUT } from './e2eUtils'
+import { setupPuppeteer, E2E_TIMEOUT } from '../../__tests__/e2eUtils'
 
 interface TableData {
   name: string
index 77409fa74130d7d0cba71f560cc78de9a49b5253..f5496f8aa6ba13eb9902e19ba68ca63b61cb30fa 100644 (file)
@@ -1,5 +1,5 @@
 import path from 'path'
-import { setupPuppeteer, E2E_TIMEOUT } from './e2eUtils'
+import { setupPuppeteer, E2E_TIMEOUT } from '../../__tests__/e2eUtils'
 
 describe('e2e: markdown', () => {
   const { page, isVisible, value, html } = setupPuppeteer()
index fce05ac0bd1410610bf33abc3f67677c96e0518d..b41708fa3bbd0f923dce9f28868a993e941c9397 100644 (file)
@@ -1,5 +1,5 @@
 import path from 'path'
-import { setupPuppeteer, E2E_TIMEOUT } from './e2eUtils'
+import { setupPuppeteer, E2E_TIMEOUT } from '../../__tests__/e2eUtils'
 
 declare const globalStats: {
   label: string
index de55102362e59242a8dac00f884169d75990b22d..f6f1b05e576b41485f52831e0edbf0e943caab27 100644 (file)
@@ -1,5 +1,5 @@
 import path from 'path'
-import { setupPuppeteer, E2E_TIMEOUT } from './e2eUtils'
+import { setupPuppeteer, E2E_TIMEOUT } from '../../__tests__/e2eUtils'
 
 describe('e2e: todomvc', () => {
   const {
diff --git a/packages/vue/examples/__tests__/transition/Transition.spec.ts b/packages/vue/examples/__tests__/transition/Transition.spec.ts
deleted file mode 100644 (file)
index 650919d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-import { E2E_TIMEOUT, setupPuppeteer } from '../e2eUtils'
-import path from 'path'
-
-describe('e2e: Transition', () => {
-  const { page, html, classList } = setupPuppeteer()
-  const baseUrl = `file://${path.resolve(
-    __dirname,
-    '../../transition/index.html'
-  )}`
-
-  const container = '#test'
-
-  const duration = 50
-  const buffer = 10
-  const transitionFinish = () =>
-    new Promise(r => {
-      setTimeout(r, duration + buffer)
-    })
-
-  const nextFrame = () => {
-    return page().evaluate(() => {
-      return new Promise(resolve => {
-        requestAnimationFrame(() => {
-          requestAnimationFrame(resolve)
-        })
-      })
-    })
-  }
-
-  test(
-    'basic transition',
-    async () => {
-      await page().goto(baseUrl)
-      await page().waitFor('#app')
-      expect(await html(container)).toBe('<div class="test">content</div>')
-
-      const leaveStartClasses = await page().evaluate(() => {
-        document.querySelector('button')!.click()
-        return Promise.resolve().then(() => {
-          return document.querySelector('#test div')!.className.split(/\s+/g)
-        })
-      })
-
-      expect(leaveStartClasses).toStrictEqual([
-        'test',
-        'v-leave-active',
-        'v-leave-from'
-      ])
-
-      await nextFrame()
-      expect(await classList('#test div')).toStrictEqual([
-        'test',
-        'v-leave-active',
-        'v-leave-to'
-      ])
-
-      await transitionFinish()
-      expect(await html('#test')).toBe('<!--v-if-->')
-
-      const enterStartClasses = await page().evaluate(() => {
-        document.querySelector('button')!.click()
-        return Promise.resolve().then(() => {
-          return document.querySelector('#test div')!.className.split(/\s+/g)
-        })
-      })
-
-      expect(enterStartClasses).toStrictEqual([
-        'test',
-        'v-enter-active',
-        'v-enter-from'
-      ])
-
-      await nextFrame()
-      expect(await classList('#test div')).toStrictEqual([
-        'test',
-        'v-enter-active',
-        'v-enter-to'
-      ])
-
-      await transitionFinish()
-      expect(await html('#test')).toBe('<div class="test">content</div>')
-    },
-    E2E_TIMEOUT
-  )
-})
index c8095b0aa29dbb6bb2bbce929342bf7400bc475e..e1d14090f3069f96857ddaed20ac6de4a8f3641e 100644 (file)
@@ -1,5 +1,5 @@
 import path from 'path'
-import { setupPuppeteer, E2E_TIMEOUT } from './e2eUtils'
+import { setupPuppeteer, E2E_TIMEOUT } from '../../__tests__/e2eUtils'
 
 describe('e2e: tree', () => {
   const { page, click, count, text, children, isVisible } = setupPuppeteer()