]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: port tests and fix bugs
authordaiwei <daiwei521@126.com>
Wed, 12 Mar 2025 14:36:38 +0000 (22:36 +0800)
committerdaiwei <daiwei521@126.com>
Wed, 12 Mar 2025 14:56:20 +0000 (22:56 +0800)
packages-private/vapor-e2e-test/__tests__/transition.spec.ts
packages-private/vapor-e2e-test/transition/App.vue
packages/runtime-core/src/components/BaseTransition.ts
packages/runtime-vapor/src/components/Transition.ts

index ebc9567b0c15316f71a2c8eaa33d32ca45bb168b..509751fad88dd1d8d4e49e9666148405fd456f0f 100644 (file)
@@ -16,6 +16,7 @@ const {
   html,
   transitionStart,
   waitForElement,
+  click,
 } = setupPuppeteer()
 
 const duration = process.env.CI ? 200 : 50
@@ -42,6 +43,234 @@ describe('vapor transition', () => {
     await page().waitForSelector('#app')
   })
 
+  describe('transition with v-if', () => {
+    test(
+      'basic transition',
+      async () => {
+        const btnSelector = '.if-basic > button'
+        const containerSelector = '.if-basic > div'
+        const childSelector = `${containerSelector} > div`
+
+        expect(await html(containerSelector)).toBe(
+          `<div class="test">content</div>`,
+        )
+
+        // leave
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'v-leave-from', 'v-leave-active'])
+
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'v-leave-active',
+          'v-leave-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe('')
+
+        // enter
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'v-enter-from', 'v-enter-active'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'v-enter-active',
+          'v-enter-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe(
+          '<div class="test">content</div>',
+        )
+      },
+      E2E_TIMEOUT,
+    )
+
+    test(
+      'named transition',
+      async () => {
+        const btnSelector = '.if-named > button'
+        const containerSelector = '.if-named > div'
+        const childSelector = `${containerSelector} > div`
+
+        expect(await html(containerSelector)).toBe(
+          '<div class="test">content</div>',
+        )
+
+        // leave
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'test-leave-active',
+          'test-leave-to',
+        ])
+
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe('')
+
+        // enter
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'test-enter-active',
+          'test-enter-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe(
+          '<div class="test">content</div>',
+        )
+      },
+      E2E_TIMEOUT,
+    )
+
+    test(
+      'custom transition classes',
+      async () => {
+        const btnSelector = '.if-custom-classes > button'
+        const containerSelector = '.if-custom-classes > div'
+        const childSelector = `${containerSelector} > div`
+
+        expect(await html(containerSelector)).toBe(
+          '<div class="test">content</div>',
+        )
+        // leave
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'bye-from', 'bye-active'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'bye-active',
+          'bye-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe('')
+
+        // enter
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'hello-from', 'hello-active'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'hello-active',
+          'hello-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe(
+          '<div class="test">content</div>',
+        )
+      },
+      E2E_TIMEOUT,
+    )
+
+    test(
+      'transition with dynamic name',
+      async () => {
+        const btnSelector = '.if-dynamic-name > button.toggle'
+        const btnChangeNameSelector = '.if-dynamic-name > button.change'
+        const containerSelector = '.if-dynamic-name > div'
+        const childSelector = `${containerSelector} > div`
+
+        expect(await html(containerSelector)).toBe(
+          '<div class="test">content</div>',
+        )
+
+        // leave
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'test-leave-active',
+          'test-leave-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe('')
+
+        // enter
+        await click(btnChangeNameSelector)
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'changed-enter-from', 'changed-enter-active'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'changed-enter-active',
+          'changed-enter-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe(
+          '<div class="test">content</div>',
+        )
+      },
+      E2E_TIMEOUT,
+    )
+    test.todo('transition events without appear', async () => {}, E2E_TIMEOUT)
+    test.todo('events with arguments', async () => {}, E2E_TIMEOUT)
+    test.todo('onEnterCancelled', async () => {}, E2E_TIMEOUT)
+    test.todo('transition on appear', async () => {}, E2E_TIMEOUT)
+    test.todo('transition events with appear', async () => {}, E2E_TIMEOUT)
+    test.todo('no transition detected', async () => {}, E2E_TIMEOUT)
+    test.todo('animations', async () => {}, E2E_TIMEOUT)
+    test.todo('explicit transition type', async () => {}, E2E_TIMEOUT)
+    test.todo('transition on SVG elements', async () => {}, E2E_TIMEOUT)
+    test.todo(
+      'custom transition higher-order component',
+      async () => {},
+      E2E_TIMEOUT,
+    )
+    test.todo(
+      'transition on child components with empty root node',
+      async () => {},
+      E2E_TIMEOUT,
+    )
+    test.todo(
+      'transition with v-if at component root-level',
+      async () => {},
+      E2E_TIMEOUT,
+    )
+    test.todo(
+      'wrapping transition + fallthrough attrs',
+      async () => {},
+      E2E_TIMEOUT,
+    )
+    test.todo(
+      'transition + fallthrough attrs (in-out mode)',
+      async () => {},
+      E2E_TIMEOUT,
+    )
+  })
+
+  describe('transition with v-show', () => {
+    test.todo('named transition with v-show', async () => {}, E2E_TIMEOUT)
+    test.todo('transition events with v-show', async () => {}, E2E_TIMEOUT)
+    test.todo('onLeaveCancelled (v-show only)', async () => {}, E2E_TIMEOUT)
+    test.todo('transition on appear with v-show', async () => {}, E2E_TIMEOUT)
+    test.todo(
+      'transition events should not call onEnter with v-show false',
+      async () => {},
+      E2E_TIMEOUT,
+    )
+    test.todo('transition on appear with v-show', async () => {}, E2E_TIMEOUT)
+  })
+
+  describe('explicit durations', () => {
+    test.todo('single value', async () => {}, E2E_TIMEOUT)
+    test.todo('enter with explicit durations', async () => {}, E2E_TIMEOUT)
+    test.todo('leave with explicit durations', async () => {}, E2E_TIMEOUT)
+    test.todo('separate enter and leave', async () => {}, E2E_TIMEOUT)
+    test.todo('warn invalid durations', async () => {}, E2E_TIMEOUT)
+  })
+
   test(
     'should work with v-show',
     async () => {
index b8470c10749da007eb6705e369f9b6eb138d247a..b5f2e77ab3350d15e1355b619612b4d55b0608c4 100644 (file)
@@ -23,10 +23,53 @@ function toggleInteropComponent() {
   interopComponent.value =
     interopComponent.value === VaporCompA ? VDomComp : VaporCompA
 }
+
+const name = ref('test')
 </script>
 
 <template>
   <div class="transition-container">
+    <div class="if-basic">
+      <div>
+        <transition>
+          <div v-if="toggle" class="test">content</div>
+        </transition>
+      </div>
+      <button @click="toggle = !toggle">basic toggle</button>
+    </div>
+    <div class="if-named">
+      <div>
+        <transition name="test">
+          <div v-if="toggle" class="test">content</div>
+        </transition>
+      </div>
+      <button @click="toggle = !toggle">button</button>
+    </div>
+    <div class="if-custom-classes">
+      <div>
+        <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 @click="toggle = !toggle">button</button>
+    </div>
+    <div class="if-dynamic-name">
+      <div>
+        <transition :name="name">
+          <div v-if="toggle" class="test">content</div>
+        </transition>
+      </div>
+      <button class="toggle" @click="toggle = !toggle">button</button>
+      <button class="change" @click="name = 'changed'">{{ name }}</button>
+    </div>
+
     <div class="vshow">
       <button @click="show = !show">Show</button>
       <Transition>
index 5c51fde1f496de3fb12d5178528baeb7238fc6e5..44b4678927b86ab9b94abf8d0e40099ae46f22d5 100644 (file)
@@ -168,7 +168,7 @@ const BaseTransitionImpl: ComponentOptions = {
       const rawProps = toRaw(props)
       const { mode } = rawProps
       // check mode
-      __DEV__ && checkTransitionMode(mode)
+      checkTransitionMode(mode)
 
       if (state.isLeaving) {
         return emptyPlaceholder(child)
@@ -619,7 +619,13 @@ export function getTransitionRawChildren(
  * dev-only
  */
 export function checkTransitionMode(mode: string | undefined): void {
-  if (mode && mode !== 'in-out' && mode !== 'out-in' && mode !== 'default') {
+  if (
+    __DEV__ &&
+    mode &&
+    mode !== 'in-out' &&
+    mode !== 'out-in' &&
+    mode !== 'default'
+  ) {
     warn(`invalid <transition> mode: ${mode}`)
   }
 }
index 384bac42273349507b6836978e827f744275b535..f5f0a98785b087b9e5fa150f7e77659f6567e884 100644 (file)
@@ -23,6 +23,7 @@ import {
 } from '../block'
 import { type VaporComponentInstance, isVaporComponent } from '../component'
 import { isArray } from '@vue/shared'
+import { renderEffect } from '../renderEffect'
 
 const decorate = (t: typeof VaporTransition) => {
   t.displayName = 'VaporTransition'
@@ -37,12 +38,21 @@ export const VaporTransition: FunctionalComponent<TransitionProps> =
     if (!children) return
 
     const { mode } = props
-    __DEV__ && checkTransitionMode(mode)
+    checkTransitionMode(mode)
 
-    applyTransitionEnterHooks(children, {
+    let resolvedProps
+    renderEffect(() => {
+      resolvedProps = resolveTransitionProps(props)
+      if (isFragment(children) && children.$transition) {
+        children.$transition.props = resolvedProps
+      }
+    })
+
+    const hooks = {
       state: useTransitionState(),
-      props: resolveTransitionProps(props),
-    } as VaporTransitionHooks)
+      props: resolvedProps!,
+    } as VaporTransitionHooks
+    applyTransitionEnterHooks(children, hooks)
 
     return children
   })