diff --git a/packages-private/vapor-e2e-test/__tests__/teleport.spec.ts b/packages-private/vapor-e2e-test/__tests__/teleport.spec.ts
new file mode 100644
index 000000000..ce383dadf
--- /dev/null
+++ b/packages-private/vapor-e2e-test/__tests__/teleport.spec.ts
@@ -0,0 +1,62 @@
+import path from 'node:path'
+import {
+ E2E_TIMEOUT,
+ setupPuppeteer,
+} from '../../../packages/vue/__tests__/e2e/e2eUtils'
+import connect from 'connect'
+import sirv from 'sirv'
+import { nextTick } from 'vue'
+import { ports } from '../utils'
+const { page, click, html } = setupPuppeteer()
+
+describe('vapor teleport', () => {
+ let server: any
+ const port = ports.teleport
+ beforeAll(() => {
+ server = connect()
+ .use(sirv(path.resolve(import.meta.dirname, '../dist')))
+ .listen(port)
+ process.on('SIGTERM', () => server && server.close())
+ })
+
+ afterAll(() => {
+ server.close()
+ })
+
+ beforeEach(async () => {
+ const baseUrl = `http://localhost:${port}/teleport/`
+ await page().goto(baseUrl)
+ await page().waitForSelector('#app')
+ })
+
+ test(
+ 'render vdom component',
+ async () => {
+ const targetSelector = '.target'
+ const testSelector = '.interop-render-vdom-comp'
+ const containerSelector = `${testSelector} > div`
+ const btnSelector = `${testSelector} > button`
+
+ const tt = await html('#app')
+ console.log(tt)
+
+ // teleport is disabled
+ expect(await html(containerSelector)).toBe('
vdom comp
')
+ expect(await html(targetSelector)).toBe('')
+
+ // enable teleport
+ await click(btnSelector)
+ await nextTick()
+
+ expect(await html(containerSelector)).toBe('')
+ expect(await html(targetSelector)).toBe('vdom comp
')
+
+ // disable teleport
+ await click(btnSelector)
+ await nextTick()
+ expect(await html(containerSelector)).toBe('vdom comp
')
+ expect(await html(targetSelector)).toBe('')
+ },
+ E2E_TIMEOUT,
+ )
+})
diff --git a/packages-private/vapor-e2e-test/__tests__/todomvc.spec.ts b/packages-private/vapor-e2e-test/__tests__/todomvc.spec.ts
index 3de8392e5..035691fd6 100644
--- a/packages-private/vapor-e2e-test/__tests__/todomvc.spec.ts
+++ b/packages-private/vapor-e2e-test/__tests__/todomvc.spec.ts
@@ -5,6 +5,7 @@ import {
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
import connect from 'connect'
import sirv from 'sirv'
+import { ports } from '../utils'
describe('e2e: todomvc', () => {
const {
@@ -23,7 +24,7 @@ describe('e2e: todomvc', () => {
} = setupPuppeteer()
let server: any
- const port = '8194'
+ const port = ports.todomvc
beforeAll(() => {
server = connect()
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
diff --git a/packages-private/vapor-e2e-test/__tests__/transition-group.spec.ts b/packages-private/vapor-e2e-test/__tests__/transition-group.spec.ts
new file mode 100644
index 000000000..13e1f1df3
--- /dev/null
+++ b/packages-private/vapor-e2e-test/__tests__/transition-group.spec.ts
@@ -0,0 +1,407 @@
+import path from 'node:path'
+import {
+ E2E_TIMEOUT,
+ setupPuppeteer,
+} from '../../../packages/vue/__tests__/e2e/e2eUtils'
+import connect from 'connect'
+import sirv from 'sirv'
+import { expect } from 'vitest'
+const { page, nextFrame, timeout, html, transitionStart } = setupPuppeteer()
+import { ports } from '../utils'
+
+const duration = process.env.CI ? 200 : 50
+const buffer = process.env.CI ? 50 : 20
+const transitionFinish = (time = duration) => timeout(time + buffer)
+
+describe('vapor transition-group', () => {
+ let server: any
+ const port = ports.transitionGroup
+ beforeAll(() => {
+ server = connect()
+ .use(sirv(path.resolve(import.meta.dirname, '../dist')))
+ .listen(port)
+ process.on('SIGTERM', () => server && server.close())
+ })
+
+ afterAll(() => {
+ server.close()
+ })
+
+ beforeEach(async () => {
+ const baseUrl = `http://localhost:${port}/transition-group/`
+ await page().goto(baseUrl)
+ await page().waitForSelector('#app')
+ })
+
+ test(
+ 'enter',
+ async () => {
+ const btnSelector = '.enter > button'
+ const containerSelector = '.enter > div'
+
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
` +
+ `e
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
` +
+ `e
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
` +
+ `e
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'leave',
+ async () => {
+ const btnSelector = '.leave > button'
+ const containerSelector = '.leave > div'
+
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(`b
`)
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'enter + leave',
+ async () => {
+ const btnSelector = '.enter-leave > button'
+ const containerSelector = '.enter-leave > div'
+
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
`,
+ )
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `b
` +
+ `c
` +
+ `d
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'appear',
+ async () => {
+ const btnSelector = '.appear > button'
+ const containerSelector = '.appear > div'
+
+ expect(await html('.appear')).toBe(``)
+
+ await page().evaluate(() => {
+ return (window as any).setAppear()
+ })
+
+ // appear
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
` +
+ `e
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
` +
+ `e
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
` +
+ `e
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'move',
+ async () => {
+ const btnSelector = '.move > button'
+ const containerSelector = '.move > div'
+
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `d
` +
+ `b
` +
+ `a
` +
+ `c
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `d
` +
+ `b
` +
+ `a
` +
+ `c
`,
+ )
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe(
+ `d
` +
+ `b
` +
+ `a
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test('dynamic name', async () => {
+ const btnSelector = '.dynamic-name button.toggleBtn'
+ const btnChangeName = '.dynamic-name button.changeNameBtn'
+ const containerSelector = '.dynamic-name > div'
+
+ expect(await html(containerSelector)).toBe(
+ `a
` + `b
` + `c
`,
+ )
+
+ // invalid name
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(`b
` + `c
` + `a
`)
+
+ // change name
+ expect(
+ (await transitionStart(btnChangeName, containerSelector)).innerHTML,
+ ).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+ })
+
+ test('events', async () => {
+ const btnSelector = '.events > button'
+ const containerSelector = '.events > div'
+
+ expect(await html('.events')).toBe(``)
+
+ await page().evaluate(() => {
+ return (window as any).setAppear()
+ })
+
+ // appear
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toContain('beforeAppear')
+ expect(calls).toContain('onAppear')
+ expect(calls).not.toContain('afterAppear')
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
`,
+ )
+
+ expect(
+ await page().evaluate(() => {
+ return (window as any).getCalls()
+ }),
+ ).toContain('afterAppear')
+
+ // enter + leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
`,
+ )
+
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toContain('beforeLeave')
+ expect(calls).toContain('onLeave')
+ expect(calls).not.toContain('afterLeave')
+ expect(calls).toContain('beforeEnter')
+ expect(calls).toContain('onEnter')
+ expect(calls).not.toContain('afterEnter')
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `a
` +
+ `b
` +
+ `c
` +
+ `d
`,
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).not.toContain('afterLeave')
+ expect(calls).not.toContain('afterEnter')
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `b
` +
+ `c
` +
+ `d
`,
+ )
+
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toContain('afterLeave')
+ expect(calls).toContain('afterEnter')
+ })
+
+ test('interop: render vdom component', async () => {
+ const btnSelector = '.interop > button'
+ const containerSelector = '.interop > div'
+
+ expect(await html(containerSelector)).toBe(
+ `` +
+ `` +
+ ``,
+ )
+
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `` +
+ `` +
+ `` +
+ ``,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `` +
+ `` +
+ `` +
+ ``,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `` +
+ `` +
+ ``,
+ )
+ })
+})
diff --git a/packages-private/vapor-e2e-test/__tests__/transition.spec.ts b/packages-private/vapor-e2e-test/__tests__/transition.spec.ts
new file mode 100644
index 000000000..ccb0475f3
--- /dev/null
+++ b/packages-private/vapor-e2e-test/__tests__/transition.spec.ts
@@ -0,0 +1,1661 @@
+import path from 'node:path'
+import {
+ E2E_TIMEOUT,
+ setupPuppeteer,
+} from '../../../packages/vue/__tests__/e2e/e2eUtils'
+import connect from 'connect'
+import sirv from 'sirv'
+import { nextTick } from 'vue'
+const {
+ page,
+ classList,
+ text,
+ nextFrame,
+ timeout,
+ isVisible,
+ count,
+ html,
+ transitionStart,
+ waitForElement,
+ click,
+} = setupPuppeteer()
+import { ports } from '../utils'
+
+const duration = process.env.CI ? 200 : 50
+const buffer = process.env.CI ? 50 : 20
+const transitionFinish = (time = duration) => timeout(time + buffer)
+
+describe('vapor transition', () => {
+ let server: any
+ const port = ports.transition
+ beforeAll(() => {
+ server = connect()
+ .use(sirv(path.resolve(import.meta.dirname, '../dist')))
+ .listen(port)
+ process.on('SIGTERM', () => server && server.close())
+ })
+
+ afterAll(() => {
+ server.close()
+ })
+
+ beforeEach(async () => {
+ const baseUrl = `http://localhost:${port}/transition/`
+ await page().goto(baseUrl)
+ 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(
+ `content
`,
+ )
+
+ // 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(
+ 'content
',
+ )
+ },
+ 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(
+ 'content
',
+ )
+
+ // 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(
+ 'content
',
+ )
+ },
+ 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(
+ 'content
',
+ )
+ // 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(
+ 'content
',
+ )
+ },
+ 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(
+ 'content
',
+ )
+
+ // 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(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition events without appear',
+ async () => {
+ const btnSelector = '.if-events-without-appear > button'
+ const containerSelector = '.if-events-without-appear > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ // 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('withoutAppear')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-leave-active',
+ 'test-leave-to',
+ ])
+
+ expect(
+ await page().evaluate(() => {
+ return (window as any).getCalls('withoutAppear')
+ }),
+ ).not.contain('afterLeave')
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe('')
+ expect(
+ await page().evaluate(() => {
+ return (window as any).getCalls('withoutAppear')
+ }),
+ ).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('withoutAppear')
+ })
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
+
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withoutAppear')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-enter-active',
+ 'test-enter-to',
+ ])
+ expect(
+ await page().evaluate(() => {
+ return (window as any).getCalls('withoutAppear')
+ }),
+ ).not.contain('afterEnter')
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ expect(
+ await page().evaluate(() => {
+ return (window as any).getCalls('withoutAppear')
+ }),
+ ).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'events with arguments',
+ async () => {
+ const btnSelector = '.if-events-with-args > button'
+ const containerSelector = '.if-events-with-args > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // leave
+ await click(btnSelector)
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('withArgs')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'before-leave',
+ 'leave',
+ ])
+
+ await timeout(200 + buffer)
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withArgs')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
+ expect(await html(containerSelector)).toBe('')
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('withArgs')
+ })
+
+ // enter
+ await click(btnSelector)
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withArgs')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'before-enter',
+ 'enter',
+ ])
+
+ await timeout(200 + buffer)
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withArgs')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ 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(
+ 'transition on appear',
+ async () => {
+ const btnSelector = '.if-appear > button'
+ const containerSelector = '.if-appear > div'
+ const childSelector = `${containerSelector} > div`
+
+ // appear
+ expect(await classList(childSelector)).contains('test-appear-active')
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition events with appear',
+ async () => {
+ const btnSelector = '.if-events-with-appear > button'
+ const containerSelector = '.if-events-with-appear > div'
+ const childSelector = `${containerSelector} > div`
+ // appear
+ expect(await classList(childSelector)).contains('test-appear-active')
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeAppear', 'onAppear'])
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeAppear', 'onAppear', 'afterAppear'])
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('withAppear')
+ })
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
+
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-leave-active',
+ 'test-leave-to',
+ ])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).not.contain('afterLeave')
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe('')
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('withAppear')
+ })
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-enter-active',
+ 'test-enter-to',
+ ])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).not.contain('afterEnter')
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ },
+ E2E_TIMEOUT,
+ )
+ test(
+ 'css: false',
+ async () => {
+ const btnSelector = '.if-css-false > button'
+ const containerSelector = '.if-css-false > div'
+ const childSelector = `${containerSelector} > div`
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // leave
+ await click(btnSelector)
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('cssFalse')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
+ expect(await html(containerSelector)).toBe('')
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('cssFalse')
+ })
+
+ // enter
+ await transitionStart(btnSelector, childSelector)
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('cssFalse')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'no transition detected',
+ async () => {
+ const btnSelector = '.if-no-trans > button'
+ const containerSelector = '.if-no-trans > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('content
')
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['noop-leave-from', 'noop-leave-active'])
+ await nextFrame()
+ expect(await html(containerSelector)).toBe('')
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['noop-enter-from', 'noop-enter-active'])
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'animations',
+ async () => {
+ const btnSelector = '.if-ani > button'
+ const containerSelector = '.if-ani > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('content
')
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test-anim-leave-from', 'test-anim-leave-active'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-leave-active',
+ 'test-anim-leave-to',
+ ])
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe('')
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test-anim-enter-from', 'test-anim-enter-active'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-enter-active',
+ 'test-anim-enter-to',
+ ])
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'explicit transition type',
+ async () => {
+ const btnSelector = '.if-ani-explicit-type > button'
+ const containerSelector = '.if-ani-explicit-type > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('content
')
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual([
+ 'test-anim-long-leave-from',
+ 'test-anim-long-leave-active',
+ ])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-leave-active',
+ 'test-anim-long-leave-to',
+ ])
+
+ if (!process.env.CI) {
+ await new Promise(r => {
+ setTimeout(r, duration - buffer)
+ })
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-leave-active',
+ 'test-anim-long-leave-to',
+ ])
+ }
+
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe('')
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual([
+ 'test-anim-long-enter-from',
+ 'test-anim-long-enter-active',
+ ])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-enter-active',
+ 'test-anim-long-enter-to',
+ ])
+
+ if (!process.env.CI) {
+ await new Promise(r => {
+ setTimeout(r, duration - buffer)
+ })
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-enter-active',
+ 'test-anim-long-enter-to',
+ ])
+ }
+
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test.todo('transition on SVG elements', async () => {}, E2E_TIMEOUT)
+
+ test(
+ 'custom transition higher-order component',
+ async () => {
+ const btnSelector = '.if-high-order > button'
+ const containerSelector = '.if-high-order > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition on child components with empty root node',
+ async () => {
+ const btnSelector = '.if-empty-root > button.toggle'
+ const btnChangeSelector = '.if-empty-root > button.change'
+ const containerSelector = '.if-empty-root > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('')
+
+ // change view -> 'two'
+ await click(btnChangeSelector)
+
+ // 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(
+ 'two
',
+ )
+
+ // change view -> 'one'
+ await click(btnChangeSelector)
+
+ // 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('')
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition with v-if at component root-level',
+ async () => {
+ const btnSelector = '.if-at-component-root-level > button.toggle'
+ const btnChangeSelector = '.if-at-component-root-level > button.change'
+ const containerSelector = '.if-at-component-root-level > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('')
+
+ // change view -> 'two'
+ await click(btnChangeSelector)
+ // 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(
+ 'two
',
+ )
+
+ // change view -> 'one'
+ await click(btnChangeSelector)
+ // 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('')
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'wrapping transition + fallthrough attrs',
+ async () => {
+ const btnSelector = '.if-fallthrough-attr > button'
+ const containerSelector = '.if-fallthrough-attr > div'
+
+ expect(await html(containerSelector)).toBe('content
')
+
+ await click(btnSelector)
+ // toggle again before leave finishes
+ await nextTick()
+ await click(btnSelector)
+
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition + fallthrough attrs (in-out mode)',
+ async () => {
+ const btnSelector = '.if-fallthrough-attr-in-out > button'
+ const containerSelector = '.if-fallthrough-attr-in-out > div'
+
+ expect(await html(containerSelector)).toBe('one
')
+
+ // toggle
+ await click(btnSelector)
+ await nextTick()
+ await transitionFinish(duration * 3)
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('ifInOut')
+ })
+ expect(calls).toStrictEqual([
+ 'beforeEnter',
+ 'onEnter',
+ 'afterEnter',
+ 'beforeLeave',
+ 'onLeave',
+ 'afterLeave',
+ ])
+
+ expect(await html(containerSelector)).toBe(
+ 'two
',
+ )
+
+ // clear calls
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('ifInOut')
+ })
+
+ // toggle back
+ await click(btnSelector)
+ await nextTick()
+ await transitionFinish(duration * 3)
+
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('ifInOut')
+ })
+ expect(calls).toStrictEqual([
+ 'beforeEnter',
+ 'onEnter',
+ 'afterEnter',
+ 'beforeLeave',
+ 'onLeave',
+ 'afterLeave',
+ ])
+
+ expect(await html(containerSelector)).toBe(
+ 'one
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+ })
+
+ describe.todo('transition with KeepAlive', () => {})
+ describe.todo('transition with Suspense', () => {})
+ describe.todo('transition with Teleport', () => {})
+
+ describe('transition with v-show', () => {
+ test(
+ 'named transition with v-show',
+ async () => {
+ const btnSelector = '.show-named > button'
+ const containerSelector = '.show-named > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ expect(await isVisible(childSelector)).toBe(true)
+
+ // 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 isVisible(childSelector)).toBe(false)
+
+ // 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(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition events with v-show',
+ async () => {
+ const btnSelector = '.show-events > button'
+ const containerSelector = '.show-events > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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('show')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-leave-active',
+ 'test-leave-to',
+ ])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('show')
+ })
+ expect(calls).not.contain('afterLeave')
+ await transitionFinish()
+ expect(await isVisible(childSelector)).toBe(false)
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('show')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
+
+ // clear calls
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('show')
+ })
+
+ // 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',
+ ])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('show')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('show')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'onLeaveCancelled (v-show only)',
+ async () => {
+ const btnSelector = '.show-leave-cancelled > button'
+ const containerSelector = '.show-leave-cancelled > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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',
+ ])
+
+ // cancel (enter)
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('showLeaveCancel')
+ })
+ expect(calls).toStrictEqual(['leaveCancelled'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-enter-active',
+ 'test-enter-to',
+ ])
+ await transitionFinish()
+ expect(await isVisible(childSelector)).toBe(true)
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition on appear with v-show',
+ async () => {
+ const btnSelector = '.show-appear > button'
+ const containerSelector = '.show-appear > div'
+ const childSelector = `${containerSelector} > div`
+
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('showAppear')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
+
+ // appear
+ expect(await classList(childSelector)).contains('test-appear-active')
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('showAppear')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+
+ // 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 isVisible(childSelector)).toBe(false)
+
+ // 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(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'transition events should not call onEnter with v-show false',
+ async () => {
+ const btnSelector = '.show-appear-not-enter > button'
+ const containerSelector = '.show-appear-not-enter > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await isVisible(childSelector)).toBe(false)
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('notEnter')
+ })
+ expect(calls).toStrictEqual([])
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('notEnter')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-enter-active',
+ 'test-enter-to',
+ ])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('notEnter')
+ })
+ expect(calls).not.contain('afterEnter')
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('notEnter')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ },
+ E2E_TIMEOUT,
+ )
+ })
+
+ describe('explicit durations', () => {
+ test(
+ 'single value',
+ async () => {
+ const btnSelector = '.duration-single-value > button'
+ const containerSelector = '.duration-single-value > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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(duration * 2)
+ 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(duration * 2)
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'enter with explicit durations',
+ async () => {
+ const btnSelector = '.duration-enter > button'
+ const containerSelector = '.duration-enter > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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(duration * 2)
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'leave with explicit durations',
+ async () => {
+ const btnSelector = '.duration-leave > button'
+ const containerSelector = '.duration-leave > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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(duration * 2)
+ 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(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'separate enter and leave',
+ async () => {
+ const btnSelector = '.duration-enter-leave > button'
+ const containerSelector = '.duration-enter-leave > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+
+ // 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(duration * 2)
+ 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(duration * 4)
+ expect(await html(containerSelector)).toBe(
+ 'content
',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+ })
+
+ test(
+ 'should work with keyed element',
+ async () => {
+ const btnSelector = '.keyed > button'
+ const containerSelector = '.keyed > h1'
+
+ expect(await text(containerSelector)).toContain('0')
+
+ // change key
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).classNames,
+ ).toStrictEqual(['v-leave-from', 'v-leave-active'])
+
+ await nextFrame()
+ expect(await classList(containerSelector)).toStrictEqual([
+ 'v-leave-active',
+ 'v-leave-to',
+ ])
+
+ await transitionFinish()
+ await nextFrame()
+ expect(await text(containerSelector)).toContain('1')
+
+ // change key again
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).classNames,
+ ).toStrictEqual(['v-leave-from', 'v-leave-active'])
+
+ await nextFrame()
+ expect(await classList(containerSelector)).toStrictEqual([
+ 'v-leave-active',
+ 'v-leave-to',
+ ])
+
+ await transitionFinish()
+ await nextFrame()
+ expect(await text(containerSelector)).toContain('2')
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'should work with out-in mode',
+ async () => {
+ const btnSelector = '.out-in > button'
+ const containerSelector = '.out-in > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(`vapor compB
`)
+
+ // compB -> compA
+ // compB leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(`vapor compB
`)
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compB
`,
+ )
+
+ // compA enter
+ await waitForElement(childSelector, 'vapor compA', [
+ 'fade-enter-from',
+ 'fade-enter-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ await transitionFinish()
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ // compA -> compB
+ // compA leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(`vapor compA
`)
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ // compB enter
+ await waitForElement(childSelector, 'vapor compB', [
+ 'fade-enter-from',
+ 'fade-enter-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compB
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vapor compB
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'should work with in-out mode',
+ async () => {
+ const btnSelector = '.in-out > button'
+ const containerSelector = '.in-out > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(`vapor compB
`)
+
+ // compA enter
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `vapor compB
vapor compA
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compB
vapor compA
`,
+ )
+
+ // compB leave
+ await waitForElement(childSelector, 'vapor compB', [
+ 'fade-leave-from',
+ 'fade-leave-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compB
vapor compA
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ // tests for using vdom component in createVaporApp + vaporInteropPlugin
+ describe('interop', () => {
+ test(
+ 'render vdom component',
+ async () => {
+ const btnSelector = '.vdom > button'
+ const containerSelector = '.vdom > div'
+
+ expect(await html(containerSelector)).toBe(`vdom comp
`)
+
+ // comp leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(`vdom comp
`)
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(``)
+
+ // comp enter
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(`vdom comp
`)
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'switch between vdom/vapor component (out-in mode)',
+ async () => {
+ const btnSelector = '.vdom-vapor-out-in > button'
+ const containerSelector = '.vdom-vapor-out-in > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(`vdom comp
`)
+
+ // switch to vapor comp
+ // vdom comp leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(`vdom comp
`)
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+
+ // vapor comp enter
+ await waitForElement(childSelector, 'vapor compA', [
+ 'fade-enter-from',
+ 'fade-enter-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ // switch to vdom comp
+ // vapor comp leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `vapor compA
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ // vdom comp enter
+ await waitForElement(childSelector, 'vdom comp', [
+ 'fade-enter-from',
+ 'fade-enter-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'switch between vdom/vapor component (in-out mode)',
+ async () => {
+ const btnSelector = '.vdom-vapor-in-out > button'
+ const containerSelector = '.vdom-vapor-in-out > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(`vapor compA
`)
+
+ // switch to vdom comp
+ // vdom comp enter
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `vapor compA
vdom comp
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
vdom comp
`,
+ )
+
+ // vapor comp leave
+ await waitForElement(childSelector, 'vapor compA', [
+ 'fade-leave-from',
+ 'fade-leave-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
vdom comp
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+
+ // switch to vapor comp
+ // vapor comp enter
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `vdom comp
vapor compA
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
vapor compA
`,
+ )
+
+ // vdom comp leave
+ await waitForElement(childSelector, 'vdom comp', [
+ 'fade-leave-from',
+ 'fade-leave-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
vapor compA
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+ })
+})
diff --git a/packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts b/packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts
index 360f48085..33d7502b3 100644
--- a/packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts
+++ b/packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts
@@ -5,12 +5,28 @@ import {
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
import connect from 'connect'
import sirv from 'sirv'
+const {
+ page,
+ click,
+ text,
+ enterValue,
+ html,
+ transitionStart,
+ waitForElement,
+ nextFrame,
+ timeout,
+} = setupPuppeteer()
+
+const duration = process.env.CI ? 200 : 50
+const buffer = process.env.CI ? 50 : 20
+const transitionFinish = (time = duration) => timeout(time + buffer)
+
+import { ports } from '../utils'
+import { nextTick } from 'vue'
describe('vdom / vapor interop', () => {
- const { page, click, text, enterValue } = setupPuppeteer()
-
let server: any
- const port = '8193'
+ const port = ports.vdomInterop
beforeAll(() => {
server = connect()
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
@@ -18,16 +34,25 @@ describe('vdom / vapor interop', () => {
process.on('SIGTERM', () => server && server.close())
})
+ beforeEach(async () => {
+ const baseUrl = `http://localhost:${port}/interop/`
+ await page().goto(baseUrl)
+ await page().waitForSelector('#app')
+ })
+
afterAll(() => {
server.close()
})
+ beforeEach(async () => {
+ const baseUrl = `http://localhost:${port}/interop/`
+ await page().goto(baseUrl)
+ await page().waitForSelector('#app')
+ })
+
test(
'should work',
async () => {
- const baseUrl = `http://localhost:${port}/interop/`
- await page().goto(baseUrl)
-
expect(await text('.vapor > h2')).toContain('Vapor component in VDOM')
expect(await text('.vapor-prop')).toContain('hello')
@@ -81,4 +106,205 @@ describe('vdom / vapor interop', () => {
},
E2E_TIMEOUT,
)
+
+ describe('vdom transition', () => {
+ test(
+ 'render vapor component',
+ async () => {
+ const btnSelector = '.trans-vapor > button'
+ const containerSelector = '.trans-vapor > div'
+
+ expect(await html(containerSelector)).toBe(`vapor compA
`)
+
+ // comp leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `vapor compA
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(``)
+
+ // comp enter
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(`vapor compA
`)
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'switch between vdom/vapor component (out-in mode)',
+ async () => {
+ const btnSelector = '.trans-vdom-vapor-out-in > button'
+ const containerSelector = '.trans-vdom-vapor-out-in > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(`vdom comp
`)
+
+ // switch to vapor comp
+ // vdom comp leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `vdom comp
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+
+ // vapor comp enter
+ await waitForElement(childSelector, 'vapor compA', [
+ 'fade-enter-from',
+ 'fade-enter-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ // switch to vdom comp
+ // vapor comp leave
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `vapor compA
`,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vapor compA
`,
+ )
+
+ // vdom comp enter
+ await waitForElement(childSelector, 'vdom comp', [
+ 'fade-enter-from',
+ 'fade-enter-active',
+ ])
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `vdom comp
`,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+ })
+
+ describe('vdom transition-group', () => {
+ test(
+ 'render vapor component',
+ async () => {
+ const btnSelector = '.trans-group-vapor > button'
+ const containerSelector = '.trans-group-vapor > div'
+
+ expect(await html(containerSelector)).toBe(
+ `` +
+ `` +
+ ``,
+ )
+
+ // insert
+ expect(
+ (await transitionStart(btnSelector, containerSelector)).innerHTML,
+ ).toBe(
+ `` +
+ `` +
+ `` +
+ `` +
+ ``,
+ )
+
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ `` +
+ `` +
+ `` +
+ `` +
+ ``,
+ )
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ `` +
+ `` +
+ `` +
+ `` +
+ ``,
+ )
+ },
+ E2E_TIMEOUT,
+ )
+ describe('teleport', () => {
+ const testSelector = '.teleport'
+ test('render vapor component', async () => {
+ const targetSelector = `${testSelector} .teleport-target`
+ const containerSelector = `${testSelector} .render-vapor-comp`
+ const buttonSelector = `${containerSelector} button`
+
+ // teleport is disabled by default
+ expect(await html(containerSelector)).toBe(
+ `vapor comp
`,
+ )
+ expect(await html(targetSelector)).toBe('')
+
+ // disabled -> enabled
+ await click(buttonSelector)
+ await nextTick()
+ expect(await html(containerSelector)).toBe(``)
+ expect(await html(targetSelector)).toBe('vapor comp
')
+
+ // enabled -> disabled
+ await click(buttonSelector)
+ await nextTick()
+ expect(await html(containerSelector)).toBe(
+ `vapor comp
`,
+ )
+ expect(await html(targetSelector)).toBe('')
+ })
+ })
+ describe('async component', () => {
+ const container = '.async-component-interop'
+ test(
+ 'with-vdom-inner-component',
+ async () => {
+ const testContainer = `${container} .with-vdom-component`
+ expect(await html(testContainer)).toBe('loading...')
+
+ await timeout(duration)
+ expect(await html(testContainer)).toBe('foo
')
+ },
+ E2E_TIMEOUT,
+ )
+ })
+ })
})
diff --git a/packages-private/vapor-e2e-test/index.html b/packages-private/vapor-e2e-test/index.html
index 7dc205e5a..85a18d79e 100644
--- a/packages-private/vapor-e2e-test/index.html
+++ b/packages-private/vapor-e2e-test/index.html
@@ -1,2 +1,12 @@
VDOM / Vapor interop
Vapor TodoMVC
+Vapor Transition
+Vapor TransitionGroup
+Vapor Teleport
+
+
diff --git a/packages-private/vapor-e2e-test/interop/App.vue b/packages-private/vapor-e2e-test/interop/App.vue
index 772a6989d..e50c86d2d 100644
--- a/packages-private/vapor-e2e-test/interop/App.vue
+++ b/packages-private/vapor-e2e-test/interop/App.vue
@@ -1,9 +1,39 @@
@@ -19,4 +49,59 @@ const passSlot = ref(true)
A test slot
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages-private/vapor-e2e-test/interop/components/SimpleVaporComp.vue b/packages-private/vapor-e2e-test/interop/components/SimpleVaporComp.vue
new file mode 100644
index 000000000..65661740c
--- /dev/null
+++ b/packages-private/vapor-e2e-test/interop/components/SimpleVaporComp.vue
@@ -0,0 +1,6 @@
+
+
+ {{ msg }}
+
diff --git a/packages-private/vapor-e2e-test/interop/VaporComp.vue b/packages-private/vapor-e2e-test/interop/components/VaporComp.vue
similarity index 93%
rename from packages-private/vapor-e2e-test/interop/VaporComp.vue
rename to packages-private/vapor-e2e-test/interop/components/VaporComp.vue
index 88a60c782..f01565449 100644
--- a/packages-private/vapor-e2e-test/interop/VaporComp.vue
+++ b/packages-private/vapor-e2e-test/interop/components/VaporComp.vue
@@ -27,7 +27,8 @@ const slotProp = ref('slot prop')
change slot prop
- #default:
+ #default:
+
#test:
fallback content
@@ -40,7 +41,7 @@ const slotProp = ref('slot prop')
>
Toggle default slot to vdom
-
+
slot prop: {{ foo }}
component prop: {{ msg }}
diff --git a/packages-private/vapor-e2e-test/interop/VdomComp.vue b/packages-private/vapor-e2e-test/interop/components/VdomComp.vue
similarity index 100%
rename from packages-private/vapor-e2e-test/interop/VdomComp.vue
rename to packages-private/vapor-e2e-test/interop/components/VdomComp.vue
diff --git a/packages-private/vapor-e2e-test/interop/components/VdomFoo.vue b/packages-private/vapor-e2e-test/interop/components/VdomFoo.vue
new file mode 100644
index 000000000..ee13cfbb1
--- /dev/null
+++ b/packages-private/vapor-e2e-test/interop/components/VdomFoo.vue
@@ -0,0 +1,5 @@
+
+
+
+ foo
+
diff --git a/packages-private/vapor-e2e-test/interop/main.ts b/packages-private/vapor-e2e-test/interop/main.ts
index d5d6d7dcf..41155dc5c 100644
--- a/packages-private/vapor-e2e-test/interop/main.ts
+++ b/packages-private/vapor-e2e-test/interop/main.ts
@@ -1,4 +1,5 @@
import { createApp, vaporInteropPlugin } from 'vue'
import App from './App.vue'
+import '../transition/style.css'
createApp(App).use(vaporInteropPlugin).mount('#app')
diff --git a/packages-private/vapor-e2e-test/teleport/App.vue b/packages-private/vapor-e2e-test/teleport/App.vue
new file mode 100644
index 000000000..d2aeba8e1
--- /dev/null
+++ b/packages-private/vapor-e2e-test/teleport/App.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/packages-private/vapor-e2e-test/teleport/components/VdomComp.vue b/packages-private/vapor-e2e-test/teleport/components/VdomComp.vue
new file mode 100644
index 000000000..2c7a626f2
--- /dev/null
+++ b/packages-private/vapor-e2e-test/teleport/components/VdomComp.vue
@@ -0,0 +1,7 @@
+
+
+
+ {{ msg }}
+
diff --git a/packages-private/vapor-e2e-test/teleport/index.html b/packages-private/vapor-e2e-test/teleport/index.html
new file mode 100644
index 000000000..79052a023
--- /dev/null
+++ b/packages-private/vapor-e2e-test/teleport/index.html
@@ -0,0 +1,2 @@
+
+
diff --git a/packages-private/vapor-e2e-test/teleport/main.ts b/packages-private/vapor-e2e-test/teleport/main.ts
new file mode 100644
index 000000000..2e962efe7
--- /dev/null
+++ b/packages-private/vapor-e2e-test/teleport/main.ts
@@ -0,0 +1,5 @@
+import { createVaporApp, vaporInteropPlugin } from 'vue'
+import App from './App.vue'
+import 'todomvc-app-css/index.css'
+
+createVaporApp(App).use(vaporInteropPlugin).mount('#app')
diff --git a/packages-private/vapor-e2e-test/transition-group/App.vue b/packages-private/vapor-e2e-test/transition-group/App.vue
new file mode 100644
index 000000000..55775743c
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition-group/App.vue
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
calls.push('beforeEnter')"
+ @enter="() => calls.push('onEnter')"
+ @afterEnter="() => calls.push('afterEnter')"
+ @beforeLeave="() => calls.push('beforeLeave')"
+ @leave="() => calls.push('onLeave')"
+ @afterLeave="() => calls.push('afterLeave')"
+ @beforeAppear="() => calls.push('beforeAppear')"
+ @appear="() => calls.push('onAppear')"
+ @afterAppear="() => calls.push('afterAppear')"
+ >
+ {{ item }}
+
+
+
+
+
+
+
diff --git a/packages-private/vapor-e2e-test/transition-group/components/VaporComp.vue b/packages-private/vapor-e2e-test/transition-group/components/VaporComp.vue
new file mode 100644
index 000000000..906795d22
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition-group/components/VaporComp.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/packages-private/vapor-e2e-test/transition-group/components/VdomComp.vue b/packages-private/vapor-e2e-test/transition-group/components/VdomComp.vue
new file mode 100644
index 000000000..afd7d55f2
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition-group/components/VdomComp.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/packages-private/vapor-e2e-test/transition-group/index.html b/packages-private/vapor-e2e-test/transition-group/index.html
new file mode 100644
index 000000000..79052a023
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition-group/index.html
@@ -0,0 +1,2 @@
+
+
diff --git a/packages-private/vapor-e2e-test/transition-group/main.ts b/packages-private/vapor-e2e-test/transition-group/main.ts
new file mode 100644
index 000000000..efa06a296
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition-group/main.ts
@@ -0,0 +1,5 @@
+import { createVaporApp, vaporInteropPlugin } from 'vue'
+import App from './App.vue'
+import '../../../packages/vue/__tests__/e2e/style.css'
+
+createVaporApp(App).use(vaporInteropPlugin).mount('#app')
diff --git a/packages-private/vapor-e2e-test/transition/App.vue b/packages-private/vapor-e2e-test/transition/App.vue
new file mode 100644
index 000000000..485509824
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/App.vue
@@ -0,0 +1,528 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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')"
+ >
+ content
+
+
+
+
+
+
+
{
+ 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')
+ }
+ "
+ >
+ content
+
+
+
+
+
+
+
{
+ calls.enterCancel.push('enterCancelled')
+ }
+ "
+ >
+ content
+
+
+
+
+
+
+
+
calls.withAppear.push('beforeEnter')"
+ @enter="() => calls.withAppear.push('onEnter')"
+ @afterEnter="() => calls.withAppear.push('afterEnter')"
+ @beforeLeave="() => calls.withAppear.push('beforeLeave')"
+ @leave="() => calls.withAppear.push('onLeave')"
+ @afterLeave="() => calls.withAppear.push('afterLeave')"
+ @beforeAppear="() => calls.withAppear.push('beforeAppear')"
+ @appear="() => calls.withAppear.push('onAppear')"
+ @afterAppear="() => calls.withAppear.push('afterAppear')"
+ >
+ content
+
+
+
+
+
+
+
calls.cssFalse.push('beforeEnter')"
+ @enter="() => calls.cssFalse.push('onEnter')"
+ @afterEnter="() => calls.cssFalse.push('afterEnter')"
+ @beforeLeave="() => calls.cssFalse.push('beforeLeave')"
+ @leave="() => calls.cssFalse.push('onLeave')"
+ @afterLeave="() => calls.cssFalse.push('afterLeave')"
+ >
+ content
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ calls.ifInOut.push('beforeEnter')"
+ @enter="() => calls.ifInOut.push('onEnter')"
+ @afterEnter="() => calls.ifInOut.push('afterEnter')"
+ @beforeLeave="() => calls.ifInOut.push('beforeLeave')"
+ @leave="() => calls.ifInOut.push('onLeave')"
+ @afterLeave="() => calls.ifInOut.push('afterLeave')"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
calls.show.push('beforeEnter')"
+ @enter="() => calls.show.push('onEnter')"
+ @afterEnter="() => calls.show.push('afterEnter')"
+ @beforeLeave="() => calls.show.push('beforeLeave')"
+ @leave="() => calls.show.push('onLeave')"
+ @afterLeave="() => calls.show.push('afterLeave')"
+ >
+ content
+
+
+
+
+
+
+
calls.showLeaveCancel.push('leaveCancelled')"
+ >
+ content
+
+
+
+
+
+
+
calls.showAppear.push('beforeEnter')"
+ @enter="() => calls.showAppear.push('onEnter')"
+ @afterEnter="() => calls.showAppear.push('afterEnter')"
+ >
+ content
+
+
+
+
+
+
+
calls.notEnter.push('beforeEnter')"
+ @enter="() => calls.notEnter.push('onEnter')"
+ @afterEnter="() => calls.notEnter.push('afterEnter')"
+ >
+ content
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ count }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages-private/vapor-e2e-test/transition/components/VaporCompA.vue b/packages-private/vapor-e2e-test/transition/components/VaporCompA.vue
new file mode 100644
index 000000000..f6902d8cf
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/components/VaporCompA.vue
@@ -0,0 +1,6 @@
+
+
+ {{ msg }}
+
diff --git a/packages-private/vapor-e2e-test/transition/components/VaporCompB.vue b/packages-private/vapor-e2e-test/transition/components/VaporCompB.vue
new file mode 100644
index 000000000..db90f993f
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/components/VaporCompB.vue
@@ -0,0 +1,6 @@
+
+
+ {{ msg }}
+
diff --git a/packages-private/vapor-e2e-test/transition/components/VaporSlot.vue b/packages-private/vapor-e2e-test/transition/components/VaporSlot.vue
new file mode 100644
index 000000000..f5eff0100
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/components/VaporSlot.vue
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/packages-private/vapor-e2e-test/transition/components/VdomComp.vue b/packages-private/vapor-e2e-test/transition/components/VdomComp.vue
new file mode 100644
index 000000000..cb6ec7cca
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/components/VdomComp.vue
@@ -0,0 +1,6 @@
+
+
+ {{ msg }}
+
diff --git a/packages-private/vapor-e2e-test/transition/index.html b/packages-private/vapor-e2e-test/transition/index.html
new file mode 100644
index 000000000..79052a023
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/index.html
@@ -0,0 +1,2 @@
+
+
diff --git a/packages-private/vapor-e2e-test/transition/main.ts b/packages-private/vapor-e2e-test/transition/main.ts
new file mode 100644
index 000000000..e77d51d1c
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/main.ts
@@ -0,0 +1,6 @@
+import { createVaporApp, vaporInteropPlugin } from 'vue'
+import App from './App.vue'
+import '../../../packages/vue/__tests__/e2e/style.css'
+import './style.css'
+
+createVaporApp(App).use(vaporInteropPlugin).mount('#app')
diff --git a/packages-private/vapor-e2e-test/transition/style.css b/packages-private/vapor-e2e-test/transition/style.css
new file mode 100644
index 000000000..e6faf6cea
--- /dev/null
+++ b/packages-private/vapor-e2e-test/transition/style.css
@@ -0,0 +1,35 @@
+.v-enter-active,
+.v-leave-active {
+ transition: opacity 50ms ease;
+}
+
+.v-enter-from,
+.v-leave-to {
+ opacity: 0;
+}
+
+.fade-enter-active,
+.fade-leave-active {
+ transition: opacity 50ms ease;
+}
+
+.fade-enter-from,
+.fade-leave-to {
+ opacity: 0;
+}
+
+.test-move,
+.test-enter-active,
+.test-leave-active {
+ transition: all 50ms cubic-bezier(0.55, 0, 0.1, 1);
+}
+
+.test-enter-from,
+.test-leave-to {
+ opacity: 0;
+ transform: scaleY(0.01) translate(30px, 0);
+}
+
+.test-leave-active {
+ position: absolute;
+}
diff --git a/packages-private/vapor-e2e-test/utils.ts b/packages-private/vapor-e2e-test/utils.ts
new file mode 100644
index 000000000..88461f8db
--- /dev/null
+++ b/packages-private/vapor-e2e-test/utils.ts
@@ -0,0 +1,8 @@
+// make sure these ports are unique
+export const ports = {
+ vdomInterop: 8193,
+ todomvc: 8194,
+ transition: 8195,
+ transitionGroup: 8196,
+ teleport: 8197,
+}
diff --git a/packages-private/vapor-e2e-test/vite.config.ts b/packages-private/vapor-e2e-test/vite.config.ts
index 1e29a4dbd..2cfb660db 100644
--- a/packages-private/vapor-e2e-test/vite.config.ts
+++ b/packages-private/vapor-e2e-test/vite.config.ts
@@ -14,6 +14,12 @@ export default defineConfig({
input: {
interop: resolve(import.meta.dirname, 'interop/index.html'),
todomvc: resolve(import.meta.dirname, 'todomvc/index.html'),
+ teleport: resolve(import.meta.dirname, 'teleport/index.html'),
+ transition: resolve(import.meta.dirname, 'transition/index.html'),
+ transitionGroup: resolve(
+ import.meta.dirname,
+ 'transition-group/index.html',
+ ),
},
},
},
diff --git a/packages/compiler-dom/src/index.ts b/packages/compiler-dom/src/index.ts
index 950901e7b..446a917ad 100644
--- a/packages/compiler-dom/src/index.ts
+++ b/packages/compiler-dom/src/index.ts
@@ -76,4 +76,5 @@ export {
} from './errors'
export { resolveModifiers } from './transforms/vOn'
export { isValidHTMLNesting } from './htmlNesting'
+export { postTransformTransition } from './transforms/Transition'
export * from '@vue/compiler-core'
diff --git a/packages/compiler-dom/src/transforms/Transition.ts b/packages/compiler-dom/src/transforms/Transition.ts
index f6cf968e3..30ea083d8 100644
--- a/packages/compiler-dom/src/transforms/Transition.ts
+++ b/packages/compiler-dom/src/transforms/Transition.ts
@@ -1,4 +1,5 @@
import {
+ type CompilerError,
type ComponentNode,
ElementTypes,
type IfBranchNode,
@@ -15,47 +16,55 @@ export const transformTransition: NodeTransform = (node, context) => {
) {
const component = context.isBuiltInComponent(node.tag)
if (component === TRANSITION) {
- return () => {
- if (!node.children.length) {
- return
- }
+ return postTransformTransition(node, context.onError)
+ }
+ }
+}
- // warn multiple transition children
- if (hasMultipleChildren(node)) {
- context.onError(
- createDOMCompilerError(
- DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN,
- {
- start: node.children[0].loc.start,
- end: node.children[node.children.length - 1].loc.end,
- source: '',
- },
- ),
- )
- }
+export function postTransformTransition(
+ node: ComponentNode,
+ onError: (error: CompilerError) => void,
+ hasMultipleChildren: (
+ node: ComponentNode,
+ ) => boolean = defaultHasMultipleChildren,
+): () => void {
+ return () => {
+ if (!node.children.length) {
+ return
+ }
- // check if it's s single child w/ v-show
- // if yes, inject "persisted: true" to the transition props
- const child = node.children[0]
- if (child.type === NodeTypes.ELEMENT) {
- for (const p of child.props) {
- if (p.type === NodeTypes.DIRECTIVE && p.name === 'show') {
- node.props.push({
- type: NodeTypes.ATTRIBUTE,
- name: 'persisted',
- nameLoc: node.loc,
- value: undefined,
- loc: node.loc,
- })
- }
- }
+ if (hasMultipleChildren(node)) {
+ onError(
+ createDOMCompilerError(DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN, {
+ start: node.children[0].loc.start,
+ end: node.children[node.children.length - 1].loc.end,
+ source: '',
+ }),
+ )
+ }
+
+ // check if it's s single child w/ v-show
+ // if yes, inject "persisted: true" to the transition props
+ const child = node.children[0]
+ if (child.type === NodeTypes.ELEMENT) {
+ for (const p of child.props) {
+ if (p.type === NodeTypes.DIRECTIVE && p.name === 'show') {
+ node.props.push({
+ type: NodeTypes.ATTRIBUTE,
+ name: 'persisted',
+ nameLoc: node.loc,
+ value: undefined,
+ loc: node.loc,
+ })
}
}
}
}
}
-function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
+function defaultHasMultipleChildren(
+ node: ComponentNode | IfBranchNode,
+): boolean {
// #1352 filter out potential comment nodes.
const children = (node.children = node.children.filter(
c =>
@@ -66,6 +75,7 @@ function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
return (
children.length !== 1 ||
child.type === NodeTypes.FOR ||
- (child.type === NodeTypes.IF && child.branches.some(hasMultipleChildren))
+ (child.type === NodeTypes.IF &&
+ child.branches.some(defaultHasMultipleChildren))
)
}
diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts
index 5825aa032..eb3b2d119 100644
--- a/packages/compiler-sfc/src/compileScript.ts
+++ b/packages/compiler-sfc/src/compileScript.ts
@@ -984,7 +984,7 @@ export function compileScript(
ctx.s.prependLeft(
startOffset,
`\n${genDefaultAs} /*@__PURE__*/${ctx.helper(
- vapor ? `defineVaporComponent` : `defineComponent`,
+ vapor && !ssr ? `defineVaporComponent` : `defineComponent`,
)}({${def}${runtimeOptions}\n ${
hasAwait ? `async ` : ``
}setup(${args}) {\n${exposeCall}`,
diff --git a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
index 2fde4560e..fb2fff865 100644
--- a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
@@ -39,6 +39,7 @@ describe('ssr: components', () => {
return function ssrRender(_ctx, _push, _parent, _attrs) {
_ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("foo"), _mergeProps({ prop: "b" }, _attrs), null), _parent)
+ _push(\`\`)
}"
`)
@@ -49,6 +50,7 @@ describe('ssr: components', () => {
return function ssrRender(_ctx, _push, _parent, _attrs) {
_ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.foo), _mergeProps({ prop: "b" }, _attrs), null), _parent)
+ _push(\`\`)
}"
`)
})
@@ -244,7 +246,8 @@ describe('ssr: components', () => {
_ssrRenderList(list, (i) => {
_push(\`\`)
})
- _push(\` \`)
+ _push(\`\`)
+ _push(\`\`)
} else {
_push(\`\`)
}
@@ -267,7 +270,8 @@ describe('ssr: components', () => {
_ssrRenderList(_ctx.list, (i) => {
_push(\`\`)
})
- _push(\`\`)
+ _push(\`\`)
+ _push(\`\`)
} else {
_push(\`\`)
}
@@ -361,6 +365,7 @@ describe('ssr: components', () => {
_push(\`\`)
if (false) {
_push(\`\`)
+ _push(\`\`)
} else {
_push(\`\`)
}
diff --git a/packages/compiler-ssr/__tests__/ssrElement.spec.ts b/packages/compiler-ssr/__tests__/ssrElement.spec.ts
index f1d509acf..d344405f3 100644
--- a/packages/compiler-ssr/__tests__/ssrElement.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrElement.spec.ts
@@ -396,4 +396,50 @@ describe('ssr: element', () => {
`)
})
})
+
+ describe('dynamic anchor', () => {
+ test('two consecutive components', () => {
+ expect(
+ getCompiledString(`
+
+ `),
+ ).toMatchInlineSnapshot(`
+ "\`\`)
+ _push(_ssrRenderComponent(_component_Comp1, null, null, _parent))
+ _push(\`\`)
+ _push(_ssrRenderComponent(_component_Comp2, null, null, _parent))
+ _push(\`
\`"
+ `)
+ })
+
+ test('multiple consecutive components', () => {
+ expect(
+ getCompiledString(`
+
+ `),
+ ).toMatchInlineSnapshot(`
+ "\`\`)
+ _push(_ssrRenderComponent(_component_Comp1, null, null, _parent))
+ _push(\`\`)
+ _push(_ssrRenderComponent(_component_Comp2, null, null, _parent))
+ _push(\`\`)
+ _push(_ssrRenderComponent(_component_Comp3, null, null, _parent))
+ _push(\`\`)
+ _push(_ssrRenderComponent(_component_Comp4, null, null, _parent))
+ _push(\`
\`"
+ `)
+ })
+ })
})
diff --git a/packages/compiler-ssr/__tests__/ssrFallthroughAttrs.spec.ts b/packages/compiler-ssr/__tests__/ssrFallthroughAttrs.spec.ts
index 7b3d1962c..712c09d09 100644
--- a/packages/compiler-ssr/__tests__/ssrFallthroughAttrs.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrFallthroughAttrs.spec.ts
@@ -29,6 +29,7 @@ describe('ssr: attrs fallthrough', () => {
_push(\`\`)
if (true) {
_push(\`\`)
+ _push(\`\`)
} else {
_push(\`\`)
}
diff --git a/packages/compiler-ssr/__tests__/ssrInjectCssVars.spec.ts b/packages/compiler-ssr/__tests__/ssrInjectCssVars.spec.ts
index 9e70dac0b..0666e8949 100644
--- a/packages/compiler-ssr/__tests__/ssrInjectCssVars.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrInjectCssVars.spec.ts
@@ -70,6 +70,7 @@ describe('ssr: inject
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a8c6e9bb4..52d16261e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -55,7 +55,7 @@ importers:
version: 5.0.4(rollup@4.44.0)
'@swc/core':
specifier: ^1.11.24
- version: 1.12.3
+ version: 1.12.4
'@types/hash-sum':
specifier: ^1.0.2
version: 1.0.2
@@ -1288,68 +1288,68 @@ packages:
cpu: [x64]
os: [win32]
- '@swc/core-darwin-arm64@1.12.3':
- resolution: {integrity: sha512-QCV9vQ/s27AMxm8j8MTDL/nDoiEMrANiENRrWnb0Fxvz/O39CajPVShp/W7HlOkzt1GYtUXPdQJpSKylugfrWw==}
+ '@swc/core-darwin-arm64@1.12.4':
+ resolution: {integrity: sha512-HihKfeitjZU2ab94Zf893sxzFryLKX0TweGsNXXOLNtkSMLw50auuYfpRM0BOL9/uXXtuCWgRIF6P030SAX5xQ==}
engines: {node: '>=10'}
cpu: [arm64]
os: [darwin]
- '@swc/core-darwin-x64@1.12.3':
- resolution: {integrity: sha512-LylCMfzGhdvl5tyKaTT9ePetHUX7wSsST7hxWiHzS+cUMj7FnhcfdEr6kcNVT7y1RJn3fCvuv7T98ZB+T2q3HA==}
+ '@swc/core-darwin-x64@1.12.4':
+ resolution: {integrity: sha512-meYCXHyYb6RDdu2N5PNAf0EelyxPBFhRcVo4kBFLuvuNb0m6EUg///VWy8MUMXq9/s9uzGS9kJVXXdRdr/d6FA==}
engines: {node: '>=10'}
cpu: [x64]
os: [darwin]
- '@swc/core-linux-arm-gnueabihf@1.12.3':
- resolution: {integrity: sha512-DQODb7S+q+pwQY41Azcavwb2rb4rGxP70niScRDxB9X68hHOM9D0w9fxzC+Nr3AHcPSmVJUYUIiq5h38O5hVgQ==}
+ '@swc/core-linux-arm-gnueabihf@1.12.4':
+ resolution: {integrity: sha512-szfDbf7mE8V64of0q/LSqbk+em+T+TD3uqnH40Z7Qu/aL8vi5CHgyLjWG2SLkLLpyjgkAUF6AKrupgnBYcC2NA==}
engines: {node: '>=10'}
cpu: [arm]
os: [linux]
- '@swc/core-linux-arm64-gnu@1.12.3':
- resolution: {integrity: sha512-nTxtJSq78AjeaQBueYImoFBs5j7qXbgOxtirpyt8jE29NQBd0VFzDzRBhkr6I9jq0hNiChgMkqBN4eUkEQjytg==}
+ '@swc/core-linux-arm64-gnu@1.12.4':
+ resolution: {integrity: sha512-n0IY76w+Scx8m3HIVRvLkoResuwsQgjDfAk9bxn99dq4leQO+mE0fkPl0Yw/1BIsPh+kxGfopIJH9zsZ1Z2YrA==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
- '@swc/core-linux-arm64-musl@1.12.3':
- resolution: {integrity: sha512-lBGvC5UgPSxqLr/y1NZxQhyRQ7nXy3/Ec1Z47YNXtqtpKiG1EcOGPyS0UZgwiYQkXqq8NBFMHnyHmpKnXTvRDA==}
+ '@swc/core-linux-arm64-musl@1.12.4':
+ resolution: {integrity: sha512-wE5jmFi5cEQyLy8WmCWmNwfKETrnzy2D8YNi/xpYWpLPWqPhcelpa6tswkfYlbsMmmOh7hQNoTba1QdGu0jvHQ==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
- '@swc/core-linux-x64-gnu@1.12.3':
- resolution: {integrity: sha512-61wZ8hwxNYzBY9MCWB50v90ICzdIhOuPk1O1qXswz9AXw5O6iQStEBHQ1rozPkfQ/rmhepk0pOf/6LCwssJOwg==}
+ '@swc/core-linux-x64-gnu@1.12.4':
+ resolution: {integrity: sha512-6S50Xd/7ePjEwrXyHMxpKTZ+KBrgUwMA8hQPbArUOwH4S5vHBr51heL0iXbUkppn1bkSr0J0IbOove5hzn+iqQ==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
- '@swc/core-linux-x64-musl@1.12.3':
- resolution: {integrity: sha512-NNeBiTpCgWt80vumTKVoaj6Fa/ZjUcaNQNM7np3PIgB8EbuXfyztboV7vUxpkmD/lUgsk8GlEFYViHvo6VMefQ==}
+ '@swc/core-linux-x64-musl@1.12.4':
+ resolution: {integrity: sha512-hbYRyaHhC13vYKuGG5BrAG5fjjWEQFfQetuFp/4QKEoXDzdnabJoixxWTQACDL3m0JW32nJ+gUzsYIPtFYkwXg==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
- '@swc/core-win32-arm64-msvc@1.12.3':
- resolution: {integrity: sha512-fxraM7exaPb1/W0CoHW45EFNOQUQh0nonBEcNFm2iv095mziBwttyxZyQBoDkQocpkd5NtsZw3xW5FTBPnn+Vw==}
+ '@swc/core-win32-arm64-msvc@1.12.4':
+ resolution: {integrity: sha512-e6EbfjPL8GA/bb1lc9Omtxjlz+1ThTsAuBsy4Q3Kpbuh6B3jclg8KzxU/6t91v23wG593mieTyR5f3Pr7X3AWw==}
engines: {node: '>=10'}
cpu: [arm64]
os: [win32]
- '@swc/core-win32-ia32-msvc@1.12.3':
- resolution: {integrity: sha512-FFIhMPXIDjRcewomwbYGPvem7Fj76AsuzbRahnAyp+OzJwrrtxVmra/kyUCfj4kix7vdGByY0WvVfiVCf5b7Mg==}
+ '@swc/core-win32-ia32-msvc@1.12.4':
+ resolution: {integrity: sha512-RG2FzmllBTUf4EksANlIvLckcBrLZEA0t13LIa6L213UZKQfEuDNHezqESgoVhJMg2S/tWauitATOCFgZNSmjg==}
engines: {node: '>=10'}
cpu: [ia32]
os: [win32]
- '@swc/core-win32-x64-msvc@1.12.3':
- resolution: {integrity: sha512-Sf4iSg+IYT5AzFSDDmii08DfeKcvtkVxIuo+uS8BJMbiLjFNjgMkkVlBthknGyJcSK15ncg9248XjnM4jU8DZA==}
+ '@swc/core-win32-x64-msvc@1.12.4':
+ resolution: {integrity: sha512-oRHKnZlR83zaMeVUCmHENa4j5uNRAWbmEpjYbzRcfC45LPFNWKGWGAGERLx0u87XMUtTGqnVYxnBTHN/rzDHOw==}
engines: {node: '>=10'}
cpu: [x64]
os: [win32]
- '@swc/core@1.12.3':
- resolution: {integrity: sha512-c4NeXW8P3gPqcFwtm+4aH+F2Cj5KJLMiLaKhSj3mpv19glq+jmekomdktAw/VHyjsXlsmouOeNWrk8rVlkCRsg==}
+ '@swc/core@1.12.4':
+ resolution: {integrity: sha512-hn30ebV4njAn0NAUM+3a0qCF+MJgqTNSrfA/hUAbC6TVjOQy2OYGQwkUvCu/V7S2+rZxrUsTpKOnZ7qqECZV9Q==}
engines: {node: '>=10'}
peerDependencies:
'@swc/helpers': '>=0.5.17'
@@ -4482,51 +4482,51 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.44.0':
optional: true
- '@swc/core-darwin-arm64@1.12.3':
+ '@swc/core-darwin-arm64@1.12.4':
optional: true
- '@swc/core-darwin-x64@1.12.3':
+ '@swc/core-darwin-x64@1.12.4':
optional: true
- '@swc/core-linux-arm-gnueabihf@1.12.3':
+ '@swc/core-linux-arm-gnueabihf@1.12.4':
optional: true
- '@swc/core-linux-arm64-gnu@1.12.3':
+ '@swc/core-linux-arm64-gnu@1.12.4':
optional: true
- '@swc/core-linux-arm64-musl@1.12.3':
+ '@swc/core-linux-arm64-musl@1.12.4':
optional: true
- '@swc/core-linux-x64-gnu@1.12.3':
+ '@swc/core-linux-x64-gnu@1.12.4':
optional: true
- '@swc/core-linux-x64-musl@1.12.3':
+ '@swc/core-linux-x64-musl@1.12.4':
optional: true
- '@swc/core-win32-arm64-msvc@1.12.3':
+ '@swc/core-win32-arm64-msvc@1.12.4':
optional: true
- '@swc/core-win32-ia32-msvc@1.12.3':
+ '@swc/core-win32-ia32-msvc@1.12.4':
optional: true
- '@swc/core-win32-x64-msvc@1.12.3':
+ '@swc/core-win32-x64-msvc@1.12.4':
optional: true
- '@swc/core@1.12.3':
+ '@swc/core@1.12.4':
dependencies:
'@swc/counter': 0.1.3
'@swc/types': 0.1.23
optionalDependencies:
- '@swc/core-darwin-arm64': 1.12.3
- '@swc/core-darwin-x64': 1.12.3
- '@swc/core-linux-arm-gnueabihf': 1.12.3
- '@swc/core-linux-arm64-gnu': 1.12.3
- '@swc/core-linux-arm64-musl': 1.12.3
- '@swc/core-linux-x64-gnu': 1.12.3
- '@swc/core-linux-x64-musl': 1.12.3
- '@swc/core-win32-arm64-msvc': 1.12.3
- '@swc/core-win32-ia32-msvc': 1.12.3
- '@swc/core-win32-x64-msvc': 1.12.3
+ '@swc/core-darwin-arm64': 1.12.4
+ '@swc/core-darwin-x64': 1.12.4
+ '@swc/core-linux-arm-gnueabihf': 1.12.4
+ '@swc/core-linux-arm64-gnu': 1.12.4
+ '@swc/core-linux-arm64-musl': 1.12.4
+ '@swc/core-linux-x64-gnu': 1.12.4
+ '@swc/core-linux-x64-musl': 1.12.4
+ '@swc/core-win32-arm64-msvc': 1.12.4
+ '@swc/core-win32-ia32-msvc': 1.12.4
+ '@swc/core-win32-x64-msvc': 1.12.4
'@swc/counter@0.1.3': {}