]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: port tests and fix bugs
authordaiwei <daiwei521@126.com>
Thu, 13 Mar 2025 06:51:52 +0000 (14:51 +0800)
committerdaiwei <daiwei521@126.com>
Thu, 13 Mar 2025 06:51:52 +0000 (14:51 +0800)
packages-private/vapor-e2e-test/__tests__/transition.spec.ts
packages-private/vapor-e2e-test/transition/App.vue
packages/runtime-vapor/src/components/Transition.ts

index e7590ef4cd591f0c1128802b608ca4341ba92244..52b3bb95049da861203355403e44ab1366480642 100644 (file)
@@ -349,8 +349,55 @@ describe('vapor transition', () => {
       E2E_TIMEOUT,
     )
 
-    test.todo('onEnterCancelled', async () => {}, E2E_TIMEOUT)
-    test.todo('transition on appear', async () => {}, E2E_TIMEOUT)
+    test(
+      'onEnterCancelled',
+      async () => {
+        const btnSelector = '.if-enter-cancelled > button'
+        const containerSelector = '.if-enter-cancelled > div'
+        const childSelector = `${containerSelector} > div`
+
+        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',
+        ])
+
+        // cancel (leave)
+        expect(
+          (await transitionStart(btnSelector, childSelector)).classNames,
+        ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+        let calls = await page().evaluate(() => {
+          return (window as any).getCalls('enterCancel')
+        })
+        expect(calls).toStrictEqual(['enterCancelled'])
+        await nextFrame()
+        expect(await classList(childSelector)).toStrictEqual([
+          'test',
+          'test-leave-active',
+          'test-leave-to',
+        ])
+        await transitionFinish()
+        expect(await html(containerSelector)).toBe('')
+      },
+      E2E_TIMEOUT,
+    )
+
+    test.todo(
+      'transition on appear',
+      async () => {
+        const btnSelector = '.if-appear > button'
+        const containerSelector = '.if-appear > div'
+        const childSelector = `${containerSelector} > div`
+      },
+      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)
index 19b2c97a21a1ee5fc7f9266f15ea81fddd798bd4..1ccc6a452b6e65d00861a5f095f2c67aef48c3c7 100644 (file)
@@ -4,13 +4,16 @@ const show = ref(true)
 const toggle = ref(true)
 const count = ref(0)
 
+const timeout = (fn, time) => setTimeout(fn, time)
+
 let calls = {
   basic: [],
   withOutAppear: [],
-  withArgs: []
+  withArgs: [],
+  enterCancel: [],
 }
-window.getCalls = (key) => calls[key]
-window.resetCalls = (key) => calls[key] = []
+window.getCalls = key => calls[key]
+window.resetCalls = key => (calls[key] = [])
 
 import VaporCompA from './components/VaporCompA.vue'
 import VaporCompB from './components/VaporCompB.vue'
@@ -52,8 +55,14 @@ const name = ref('test')
     </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">
+        <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>
@@ -70,10 +79,15 @@ const name = ref('test')
     </div>
     <div class="if-events-without-appear">
       <div>
-        <transition name="test" @before-enter="() => calls.withOutAppear.push('beforeEnter')"
-          @enter="() => calls.withOutAppear.push('onEnter')" @after-enter="() => calls.withOutAppear.push('afterEnter')"
+        <transition
+          name="test"
+          @before-enter="() => calls.withOutAppear.push('beforeEnter')"
+          @enter="() => calls.withOutAppear.push('onEnter')"
+          @after-enter="() => calls.withOutAppear.push('afterEnter')"
           @beforeLeave="() => calls.withOutAppear.push('beforeLeave')"
-          @leave="() => calls.withOutAppear.push('onLeave')" @afterLeave="() => calls.withOutAppear.push('afterLeave')">
+          @leave="() => calls.withOutAppear.push('onLeave')"
+          @afterLeave="() => calls.withOutAppear.push('afterLeave')"
+        >
           <div v-if="toggle" class="test">content</div>
         </transition>
       </div>
@@ -81,31 +95,81 @@ const name = ref('test')
     </div>
     <div class="if-events-with-args">
       <div id="container">
-        <transition :css="false" name="test" @before-enter="(el) => {
-          calls.withArgs.push('beforeEnter');
-          el.classList.add('before-enter')
-        }" @enter="(el, done) => {
-          calls.withArgs.push('onEnter');
-          el.classList.add('enter')
-          setTimeout(done, 200)
-        }" @after-enter="(el) => {
-          calls.withArgs.push('afterEnter');
-          el.classList.add('after-enter')
-        }" @before-leave="(el) => {
-          calls.withArgs.push('beforeLeave');
-          el.classList.add('before-leave')
-        }" @leave="(el, done) => {
-          calls.withArgs.push('onLeave');
-          el.classList.add('leave')
-          setTimeout(done, 200)
-        }" @after-leave="() => {
-          calls.withArgs.push('afterLeave');
-        }">
+        <transition
+          :css="false"
+          name="test"
+          @before-enter="
+            el => {
+              calls.withArgs.push('beforeEnter')
+              el.classList.add('before-enter')
+            }
+          "
+          @enter="
+            (el, done) => {
+              calls.withArgs.push('onEnter')
+              el.classList.add('enter')
+              timeout(done, 200)
+            }
+          "
+          @after-enter="
+            el => {
+              calls.withArgs.push('afterEnter')
+              el.classList.add('after-enter')
+            }
+          "
+          @before-leave="
+            el => {
+              calls.withArgs.push('beforeLeave')
+              el.classList.add('before-leave')
+            }
+          "
+          @leave="
+            (el, done) => {
+              calls.withArgs.push('onLeave')
+              el.classList.add('leave')
+              timeout(done, 200)
+            }
+          "
+          @after-leave="
+            () => {
+              calls.withArgs.push('afterLeave')
+            }
+          "
+        >
           <div v-if="toggle" class="test">content</div>
         </transition>
       </div>
       <button id="toggleBtn" @click="toggle = !toggle">button</button>
     </div>
+    <div class="if-enter-cancelled">
+      <div>
+        <transition
+          name="test"
+          @enter-cancelled="
+            () => {
+              calls.enterCancel.push('enterCancelled')
+            }
+          "
+        >
+          <div v-if="!toggle" class="test">content</div>
+        </transition>
+      </div>
+      <button @click="toggle = !toggle">cancelled</button>
+    </div>
+    <div class="if-appear">
+      <div>
+        <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 @click="toggle = !toggle">button</button>
+    </div>
 
     <div class="vshow">
       <button @click="show = !show">Show</button>
@@ -115,11 +179,18 @@ const name = ref('test')
     </div>
     <div class="vif">
       <button @click="toggle = !toggle">Toggle</button>
-      <Transition appear @beforeEnter="() => calls.basic.push('beforeEnter')" @enter="() => calls.basic.push('onEnter')"
-        @afterEnter="() => calls.basic.push('afterEnter')" @beforeLeave="() => calls.basic.push('beforeLeave')"
-        @leave="() => calls.basic.push('onLeave')" @afterLeave="() => calls.basic.push('afterLeave')"
-        @beforeAppear="() => calls.basic.push('beforeAppear')" @appear="() => calls.basic.push('onAppear')"
-        @afterAppear="() => calls.basic.push('afterAppear')">
+      <Transition
+        appear
+        @beforeEnter="() => calls.basic.push('beforeEnter')"
+        @enter="() => calls.basic.push('onEnter')"
+        @afterEnter="() => calls.basic.push('afterEnter')"
+        @beforeLeave="() => calls.basic.push('beforeLeave')"
+        @leave="() => calls.basic.push('onLeave')"
+        @afterLeave="() => calls.basic.push('afterLeave')"
+        @beforeAppear="() => calls.basic.push('beforeAppear')"
+        @appear="() => calls.basic.push('onAppear')"
+        @afterAppear="() => calls.basic.push('afterAppear')"
+      >
         <h1 v-if="toggle">vIf</h1>
       </Transition>
     </div>
@@ -182,7 +253,7 @@ const name = ref('test')
 }
 </style>
 <style>
-.transition-container>div {
+.transition-container > div {
   padding: 15px;
   border: 1px solid #f7f7f7;
   margin-top: 15px;
index e2a467d8a575fcd4e1c988e185998001afe57487..ced53428cc3665aeb3daa393bb6351839e245f46 100644 (file)
@@ -41,18 +41,23 @@ export const VaporTransition: FunctionalComponent<TransitionProps> =
     checkTransitionMode(mode)
 
     let resolvedProps
+    let isMounted = false
     renderEffect(() => {
       resolvedProps = resolveTransitionProps(props)
-      // only update props for Fragment block, for later reusing
-      if (isFragment(children) && children.$transition) {
-        children.$transition.props = resolvedProps
-      } else {
-        // replace existing transition hooks
-        const child = findTransitionBlock(children)
-        if (child && child.$transition) {
-          child.$transition.props = resolvedProps
-          applyTransitionHooks(child, child.$transition)
+      if (isMounted) {
+        // only update props for Fragment block, for later reusing
+        if (isFragment(children)) {
+          if (children.$transition) children.$transition.props = resolvedProps
+        } else {
+          // replace existing transition hooks
+          const child = findTransitionBlock(children)
+          if (child && child.$transition) {
+            child.$transition.props = resolvedProps
+            applyTransitionHooks(child, child.$transition)
+          }
         }
+      } else {
+        isMounted = true
       }
     })
 
@@ -133,8 +138,13 @@ export function applyTransitionHooks(
   block: Block,
   hooks: VaporTransitionHooks,
 ): VaporTransitionHooks {
-  const child = findTransitionBlock(block)
-  if (!child) return hooks
+  const inFragment = isFragment(block)
+  const child = findTransitionBlock(block, inFragment)
+  if (!child) {
+    // set transition hooks on fragment for reusing during it's updating
+    if (inFragment) setTransitionHooksToFragment(block, hooks)
+    return hooks
+  }
 
   const { props, state, delayedLeave } = hooks
   let resolvedHooks = resolveTransitionHooks(
@@ -146,10 +156,7 @@ export function applyTransitionHooks(
   )
   resolvedHooks.delayedLeave = delayedLeave
   setTransitionHooks(child, resolvedHooks)
-  if (isFragment(block)) {
-    // also set transition hooks on fragment for reusing during it's updating
-    setTransitionHooksToFragment(block, resolvedHooks)
-  }
+  if (inFragment) setTransitionHooksToFragment(block, resolvedHooks)
   return resolvedHooks
 }
 
@@ -203,7 +210,10 @@ export function applyTransitionLeaveHooks(
 }
 
 const transitionBlockCache = new WeakMap<Block, TransitionBlock>()
-export function findTransitionBlock(block: Block): TransitionBlock | undefined {
+export function findTransitionBlock(
+  block: Block,
+  inFragment: boolean = false,
+): TransitionBlock | undefined {
   if (transitionBlockCache.has(block)) {
     return transitionBlockCache.get(block)
   }
@@ -238,11 +248,11 @@ export function findTransitionBlock(block: Block): TransitionBlock | undefined {
     if (block.insert) {
       child = block
     } else {
-      child = findTransitionBlock(block.nodes)
+      child = findTransitionBlock(block.nodes, true)
     }
   }
 
-  if (__DEV__ && !child) {
+  if (__DEV__ && !child && !inFragment) {
     warn('Transition component has no valid child element')
   }