transition.spec.ts 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660
  1. import path from 'node:path'
  2. import {
  3. E2E_TIMEOUT,
  4. setupPuppeteer,
  5. } from '../../../packages/vue/__tests__/e2e/e2eUtils'
  6. import connect from 'connect'
  7. import sirv from 'sirv'
  8. import { nextTick } from 'vue'
  9. const {
  10. page,
  11. classList,
  12. text,
  13. nextFrame,
  14. timeout,
  15. isVisible,
  16. count,
  17. html,
  18. transitionStart,
  19. waitForElement,
  20. click,
  21. } = setupPuppeteer()
  22. const duration = process.env.CI ? 200 : 50
  23. const buffer = process.env.CI ? 50 : 20
  24. const transitionFinish = (time = duration) => timeout(time + buffer)
  25. describe('vapor transition', () => {
  26. let server: any
  27. const port = '8195'
  28. beforeAll(() => {
  29. server = connect()
  30. .use(sirv(path.resolve(import.meta.dirname, '../dist')))
  31. .listen(port)
  32. process.on('SIGTERM', () => server && server.close())
  33. })
  34. afterAll(() => {
  35. server.close()
  36. })
  37. beforeEach(async () => {
  38. const baseUrl = `http://localhost:${port}/transition/`
  39. await page().goto(baseUrl)
  40. await page().waitForSelector('#app')
  41. })
  42. describe('transition with v-if', () => {
  43. test(
  44. 'basic transition',
  45. async () => {
  46. const btnSelector = '.if-basic > button'
  47. const containerSelector = '.if-basic > div'
  48. const childSelector = `${containerSelector} > div`
  49. expect(await html(containerSelector)).toBe(
  50. `<div class="test">content</div>`,
  51. )
  52. // leave
  53. expect(
  54. (await transitionStart(btnSelector, childSelector)).classNames,
  55. ).toStrictEqual(['test', 'v-leave-from', 'v-leave-active'])
  56. await nextFrame()
  57. expect(await classList(childSelector)).toStrictEqual([
  58. 'test',
  59. 'v-leave-active',
  60. 'v-leave-to',
  61. ])
  62. await transitionFinish()
  63. expect(await html(containerSelector)).toBe('')
  64. // enter
  65. expect(
  66. (await transitionStart(btnSelector, childSelector)).classNames,
  67. ).toStrictEqual(['test', 'v-enter-from', 'v-enter-active'])
  68. await nextFrame()
  69. expect(await classList(childSelector)).toStrictEqual([
  70. 'test',
  71. 'v-enter-active',
  72. 'v-enter-to',
  73. ])
  74. await transitionFinish()
  75. expect(await html(containerSelector)).toBe(
  76. '<div class="test">content</div>',
  77. )
  78. },
  79. E2E_TIMEOUT,
  80. )
  81. test(
  82. 'named transition',
  83. async () => {
  84. const btnSelector = '.if-named > button'
  85. const containerSelector = '.if-named > div'
  86. const childSelector = `${containerSelector} > div`
  87. expect(await html(containerSelector)).toBe(
  88. '<div class="test">content</div>',
  89. )
  90. // leave
  91. expect(
  92. (await transitionStart(btnSelector, childSelector)).classNames,
  93. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  94. await nextFrame()
  95. expect(await classList(childSelector)).toStrictEqual([
  96. 'test',
  97. 'test-leave-active',
  98. 'test-leave-to',
  99. ])
  100. await transitionFinish()
  101. expect(await html(containerSelector)).toBe('')
  102. // enter
  103. expect(
  104. (await transitionStart(btnSelector, childSelector)).classNames,
  105. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  106. await nextFrame()
  107. expect(await classList(childSelector)).toStrictEqual([
  108. 'test',
  109. 'test-enter-active',
  110. 'test-enter-to',
  111. ])
  112. await transitionFinish()
  113. expect(await html(containerSelector)).toBe(
  114. '<div class="test">content</div>',
  115. )
  116. },
  117. E2E_TIMEOUT,
  118. )
  119. test(
  120. 'custom transition classes',
  121. async () => {
  122. const btnSelector = '.if-custom-classes > button'
  123. const containerSelector = '.if-custom-classes > div'
  124. const childSelector = `${containerSelector} > div`
  125. expect(await html(containerSelector)).toBe(
  126. '<div class="test">content</div>',
  127. )
  128. // leave
  129. expect(
  130. (await transitionStart(btnSelector, childSelector)).classNames,
  131. ).toStrictEqual(['test', 'bye-from', 'bye-active'])
  132. await nextFrame()
  133. expect(await classList(childSelector)).toStrictEqual([
  134. 'test',
  135. 'bye-active',
  136. 'bye-to',
  137. ])
  138. await transitionFinish()
  139. expect(await html(containerSelector)).toBe('')
  140. // enter
  141. expect(
  142. (await transitionStart(btnSelector, childSelector)).classNames,
  143. ).toStrictEqual(['test', 'hello-from', 'hello-active'])
  144. await nextFrame()
  145. expect(await classList(childSelector)).toStrictEqual([
  146. 'test',
  147. 'hello-active',
  148. 'hello-to',
  149. ])
  150. await transitionFinish()
  151. expect(await html(containerSelector)).toBe(
  152. '<div class="test">content</div>',
  153. )
  154. },
  155. E2E_TIMEOUT,
  156. )
  157. test(
  158. 'transition with dynamic name',
  159. async () => {
  160. const btnSelector = '.if-dynamic-name > button.toggle'
  161. const btnChangeNameSelector = '.if-dynamic-name > button.change'
  162. const containerSelector = '.if-dynamic-name > div'
  163. const childSelector = `${containerSelector} > div`
  164. expect(await html(containerSelector)).toBe(
  165. '<div class="test">content</div>',
  166. )
  167. // leave
  168. expect(
  169. (await transitionStart(btnSelector, childSelector)).classNames,
  170. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  171. await nextFrame()
  172. expect(await classList(childSelector)).toStrictEqual([
  173. 'test',
  174. 'test-leave-active',
  175. 'test-leave-to',
  176. ])
  177. await transitionFinish()
  178. expect(await html(containerSelector)).toBe('')
  179. // enter
  180. await click(btnChangeNameSelector)
  181. expect(
  182. (await transitionStart(btnSelector, childSelector)).classNames,
  183. ).toStrictEqual(['test', 'changed-enter-from', 'changed-enter-active'])
  184. await nextFrame()
  185. expect(await classList(childSelector)).toStrictEqual([
  186. 'test',
  187. 'changed-enter-active',
  188. 'changed-enter-to',
  189. ])
  190. await transitionFinish()
  191. expect(await html(containerSelector)).toBe(
  192. '<div class="test">content</div>',
  193. )
  194. },
  195. E2E_TIMEOUT,
  196. )
  197. test(
  198. 'transition events without appear',
  199. async () => {
  200. const btnSelector = '.if-events-without-appear > button'
  201. const containerSelector = '.if-events-without-appear > div'
  202. const childSelector = `${containerSelector} > div`
  203. expect(await html(containerSelector)).toBe(
  204. '<div class="test">content</div>',
  205. )
  206. // leave
  207. expect(
  208. (await transitionStart(btnSelector, childSelector)).classNames,
  209. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  210. let calls = await page().evaluate(() => {
  211. return (window as any).getCalls('withoutAppear')
  212. })
  213. expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
  214. await nextFrame()
  215. expect(await classList(childSelector)).toStrictEqual([
  216. 'test',
  217. 'test-leave-active',
  218. 'test-leave-to',
  219. ])
  220. expect(
  221. await page().evaluate(() => {
  222. return (window as any).getCalls('withoutAppear')
  223. }),
  224. ).not.contain('afterLeave')
  225. await transitionFinish()
  226. expect(await html(containerSelector)).toBe('')
  227. expect(
  228. await page().evaluate(() => {
  229. return (window as any).getCalls('withoutAppear')
  230. }),
  231. ).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
  232. await page().evaluate(() => {
  233. ;(window as any).resetCalls('withoutAppear')
  234. })
  235. // enter
  236. expect(
  237. (await transitionStart(btnSelector, childSelector)).classNames,
  238. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  239. calls = await page().evaluate(() => {
  240. return (window as any).getCalls('withoutAppear')
  241. })
  242. expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
  243. await nextFrame()
  244. expect(await classList(childSelector)).toStrictEqual([
  245. 'test',
  246. 'test-enter-active',
  247. 'test-enter-to',
  248. ])
  249. expect(
  250. await page().evaluate(() => {
  251. return (window as any).getCalls('withoutAppear')
  252. }),
  253. ).not.contain('afterEnter')
  254. await transitionFinish()
  255. expect(await html(containerSelector)).toBe(
  256. '<div class="test">content</div>',
  257. )
  258. expect(
  259. await page().evaluate(() => {
  260. return (window as any).getCalls('withoutAppear')
  261. }),
  262. ).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
  263. },
  264. E2E_TIMEOUT,
  265. )
  266. test(
  267. 'events with arguments',
  268. async () => {
  269. const btnSelector = '.if-events-with-args > button'
  270. const containerSelector = '.if-events-with-args > div'
  271. const childSelector = `${containerSelector} > div`
  272. expect(await html(containerSelector)).toBe(
  273. '<div class="test">content</div>',
  274. )
  275. // leave
  276. await click(btnSelector)
  277. let calls = await page().evaluate(() => {
  278. return (window as any).getCalls('withArgs')
  279. })
  280. expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
  281. expect(await classList(childSelector)).toStrictEqual([
  282. 'test',
  283. 'before-leave',
  284. 'leave',
  285. ])
  286. await timeout(200 + buffer)
  287. calls = await page().evaluate(() => {
  288. return (window as any).getCalls('withArgs')
  289. })
  290. expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
  291. expect(await html(containerSelector)).toBe('')
  292. await page().evaluate(() => {
  293. ;(window as any).resetCalls('withArgs')
  294. })
  295. // enter
  296. await click(btnSelector)
  297. calls = await page().evaluate(() => {
  298. return (window as any).getCalls('withArgs')
  299. })
  300. expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
  301. expect(await classList(childSelector)).toStrictEqual([
  302. 'test',
  303. 'before-enter',
  304. 'enter',
  305. ])
  306. await timeout(200 + buffer)
  307. calls = await page().evaluate(() => {
  308. return (window as any).getCalls('withArgs')
  309. })
  310. expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
  311. expect(await html(containerSelector)).toBe(
  312. '<div class="test before-enter enter after-enter">content</div>',
  313. )
  314. },
  315. E2E_TIMEOUT,
  316. )
  317. test(
  318. 'onEnterCancelled',
  319. async () => {
  320. const btnSelector = '.if-enter-cancelled > button'
  321. const containerSelector = '.if-enter-cancelled > div'
  322. const childSelector = `${containerSelector} > div`
  323. expect(await html(containerSelector)).toBe('')
  324. // enter
  325. expect(
  326. (await transitionStart(btnSelector, childSelector)).classNames,
  327. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  328. await nextFrame()
  329. expect(await classList(childSelector)).toStrictEqual([
  330. 'test',
  331. 'test-enter-active',
  332. 'test-enter-to',
  333. ])
  334. // cancel (leave)
  335. expect(
  336. (await transitionStart(btnSelector, childSelector)).classNames,
  337. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  338. let calls = await page().evaluate(() => {
  339. return (window as any).getCalls('enterCancel')
  340. })
  341. expect(calls).toStrictEqual(['enterCancelled'])
  342. await nextFrame()
  343. expect(await classList(childSelector)).toStrictEqual([
  344. 'test',
  345. 'test-leave-active',
  346. 'test-leave-to',
  347. ])
  348. await transitionFinish()
  349. expect(await html(containerSelector)).toBe('')
  350. },
  351. E2E_TIMEOUT,
  352. )
  353. test(
  354. 'transition on appear',
  355. async () => {
  356. const btnSelector = '.if-appear > button'
  357. const containerSelector = '.if-appear > div'
  358. const childSelector = `${containerSelector} > div`
  359. // appear
  360. expect(await classList(childSelector)).contains('test-appear-active')
  361. await transitionFinish()
  362. expect(await html(containerSelector)).toBe(
  363. '<div class="test">content</div>',
  364. )
  365. // leave
  366. expect(
  367. (await transitionStart(btnSelector, childSelector)).classNames,
  368. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  369. await nextFrame()
  370. expect(await classList(childSelector)).toStrictEqual([
  371. 'test',
  372. 'test-leave-active',
  373. 'test-leave-to',
  374. ])
  375. await transitionFinish()
  376. expect(await html(containerSelector)).toBe('')
  377. // enter
  378. expect(
  379. (await transitionStart(btnSelector, childSelector)).classNames,
  380. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  381. await nextFrame()
  382. expect(await classList(childSelector)).toStrictEqual([
  383. 'test',
  384. 'test-enter-active',
  385. 'test-enter-to',
  386. ])
  387. await transitionFinish()
  388. expect(await html(containerSelector)).toBe(
  389. '<div class="test">content</div>',
  390. )
  391. },
  392. E2E_TIMEOUT,
  393. )
  394. test(
  395. 'transition events with appear',
  396. async () => {
  397. const btnSelector = '.if-events-with-appear > button'
  398. const containerSelector = '.if-events-with-appear > div'
  399. const childSelector = `${containerSelector} > div`
  400. // appear
  401. expect(await classList(childSelector)).contains('test-appear-active')
  402. let calls = await page().evaluate(() => {
  403. return (window as any).getCalls('withAppear')
  404. })
  405. expect(calls).toStrictEqual(['beforeAppear', 'onAppear'])
  406. await transitionFinish()
  407. expect(await html(containerSelector)).toBe(
  408. '<div class="test">content</div>',
  409. )
  410. calls = await page().evaluate(() => {
  411. return (window as any).getCalls('withAppear')
  412. })
  413. expect(calls).toStrictEqual(['beforeAppear', 'onAppear', 'afterAppear'])
  414. await page().evaluate(() => {
  415. ;(window as any).resetCalls('withAppear')
  416. })
  417. // leave
  418. expect(
  419. (await transitionStart(btnSelector, childSelector)).classNames,
  420. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  421. calls = await page().evaluate(() => {
  422. return (window as any).getCalls('withAppear')
  423. })
  424. expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
  425. await nextFrame()
  426. expect(await classList(childSelector)).toStrictEqual([
  427. 'test',
  428. 'test-leave-active',
  429. 'test-leave-to',
  430. ])
  431. calls = await page().evaluate(() => {
  432. return (window as any).getCalls('withAppear')
  433. })
  434. expect(calls).not.contain('afterLeave')
  435. await transitionFinish()
  436. expect(await html(containerSelector)).toBe('')
  437. calls = await page().evaluate(() => {
  438. return (window as any).getCalls('withAppear')
  439. })
  440. expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
  441. await page().evaluate(() => {
  442. ;(window as any).resetCalls('withAppear')
  443. })
  444. // enter
  445. expect(
  446. (await transitionStart(btnSelector, childSelector)).classNames,
  447. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  448. calls = await page().evaluate(() => {
  449. return (window as any).getCalls('withAppear')
  450. })
  451. expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
  452. await nextFrame()
  453. expect(await classList(childSelector)).toStrictEqual([
  454. 'test',
  455. 'test-enter-active',
  456. 'test-enter-to',
  457. ])
  458. calls = await page().evaluate(() => {
  459. return (window as any).getCalls('withAppear')
  460. })
  461. expect(calls).not.contain('afterEnter')
  462. await transitionFinish()
  463. expect(await html(containerSelector)).toBe(
  464. '<div class="test">content</div>',
  465. )
  466. calls = await page().evaluate(() => {
  467. return (window as any).getCalls('withAppear')
  468. })
  469. expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
  470. },
  471. E2E_TIMEOUT,
  472. )
  473. test(
  474. 'css: false',
  475. async () => {
  476. const btnSelector = '.if-css-false > button'
  477. const containerSelector = '.if-css-false > div'
  478. const childSelector = `${containerSelector} > div`
  479. expect(await html(containerSelector)).toBe(
  480. '<div class="test">content</div>',
  481. )
  482. // leave
  483. await click(btnSelector)
  484. let calls = await page().evaluate(() => {
  485. return (window as any).getCalls('cssFalse')
  486. })
  487. expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
  488. expect(await html(containerSelector)).toBe('')
  489. await page().evaluate(() => {
  490. ;(window as any).resetCalls('cssFalse')
  491. })
  492. // enter
  493. await transitionStart(btnSelector, childSelector)
  494. calls = await page().evaluate(() => {
  495. return (window as any).getCalls('cssFalse')
  496. })
  497. expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
  498. expect(await html(containerSelector)).toBe(
  499. '<div class="test">content</div>',
  500. )
  501. },
  502. E2E_TIMEOUT,
  503. )
  504. test(
  505. 'no transition detected',
  506. async () => {
  507. const btnSelector = '.if-no-trans > button'
  508. const containerSelector = '.if-no-trans > div'
  509. const childSelector = `${containerSelector} > div`
  510. expect(await html(containerSelector)).toBe('<div>content</div>')
  511. // leave
  512. expect(
  513. (await transitionStart(btnSelector, childSelector)).classNames,
  514. ).toStrictEqual(['noop-leave-from', 'noop-leave-active'])
  515. await nextFrame()
  516. expect(await html(containerSelector)).toBe('')
  517. // enter
  518. expect(
  519. (await transitionStart(btnSelector, childSelector)).classNames,
  520. ).toStrictEqual(['noop-enter-from', 'noop-enter-active'])
  521. await nextFrame()
  522. expect(await html(containerSelector)).toBe(
  523. '<div class="">content</div>',
  524. )
  525. },
  526. E2E_TIMEOUT,
  527. )
  528. test(
  529. 'animations',
  530. async () => {
  531. const btnSelector = '.if-ani > button'
  532. const containerSelector = '.if-ani > div'
  533. const childSelector = `${containerSelector} > div`
  534. expect(await html(containerSelector)).toBe('<div>content</div>')
  535. // leave
  536. expect(
  537. (await transitionStart(btnSelector, childSelector)).classNames,
  538. ).toStrictEqual(['test-anim-leave-from', 'test-anim-leave-active'])
  539. await nextFrame()
  540. expect(await classList(childSelector)).toStrictEqual([
  541. 'test-anim-leave-active',
  542. 'test-anim-leave-to',
  543. ])
  544. await transitionFinish(duration * 2)
  545. expect(await html(containerSelector)).toBe('')
  546. // enter
  547. expect(
  548. (await transitionStart(btnSelector, childSelector)).classNames,
  549. ).toStrictEqual(['test-anim-enter-from', 'test-anim-enter-active'])
  550. await nextFrame()
  551. expect(await classList(childSelector)).toStrictEqual([
  552. 'test-anim-enter-active',
  553. 'test-anim-enter-to',
  554. ])
  555. await transitionFinish()
  556. expect(await html(containerSelector)).toBe(
  557. '<div class="">content</div>',
  558. )
  559. },
  560. E2E_TIMEOUT,
  561. )
  562. test(
  563. 'explicit transition type',
  564. async () => {
  565. const btnSelector = '.if-ani-explicit-type > button'
  566. const containerSelector = '.if-ani-explicit-type > div'
  567. const childSelector = `${containerSelector} > div`
  568. expect(await html(containerSelector)).toBe('<div>content</div>')
  569. // leave
  570. expect(
  571. (await transitionStart(btnSelector, childSelector)).classNames,
  572. ).toStrictEqual([
  573. 'test-anim-long-leave-from',
  574. 'test-anim-long-leave-active',
  575. ])
  576. await nextFrame()
  577. expect(await classList(childSelector)).toStrictEqual([
  578. 'test-anim-long-leave-active',
  579. 'test-anim-long-leave-to',
  580. ])
  581. if (!process.env.CI) {
  582. await new Promise(r => {
  583. setTimeout(r, duration - buffer)
  584. })
  585. expect(await classList(childSelector)).toStrictEqual([
  586. 'test-anim-long-leave-active',
  587. 'test-anim-long-leave-to',
  588. ])
  589. }
  590. await transitionFinish(duration * 2)
  591. expect(await html(containerSelector)).toBe('')
  592. // enter
  593. expect(
  594. (await transitionStart(btnSelector, childSelector)).classNames,
  595. ).toStrictEqual([
  596. 'test-anim-long-enter-from',
  597. 'test-anim-long-enter-active',
  598. ])
  599. await nextFrame()
  600. expect(await classList(childSelector)).toStrictEqual([
  601. 'test-anim-long-enter-active',
  602. 'test-anim-long-enter-to',
  603. ])
  604. if (!process.env.CI) {
  605. await new Promise(r => {
  606. setTimeout(r, duration - buffer)
  607. })
  608. expect(await classList(childSelector)).toStrictEqual([
  609. 'test-anim-long-enter-active',
  610. 'test-anim-long-enter-to',
  611. ])
  612. }
  613. await transitionFinish(duration * 2)
  614. expect(await html(containerSelector)).toBe(
  615. '<div class="">content</div>',
  616. )
  617. },
  618. E2E_TIMEOUT,
  619. )
  620. test.todo('transition on SVG elements', async () => {}, E2E_TIMEOUT)
  621. test(
  622. 'custom transition higher-order component',
  623. async () => {
  624. const btnSelector = '.if-high-order > button'
  625. const containerSelector = '.if-high-order > div'
  626. const childSelector = `${containerSelector} > div`
  627. expect(await html(containerSelector)).toBe(
  628. '<div class="test">content</div>',
  629. )
  630. // leave
  631. expect(
  632. (await transitionStart(btnSelector, childSelector)).classNames,
  633. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  634. await nextFrame()
  635. expect(await classList(childSelector)).toStrictEqual([
  636. 'test',
  637. 'test-leave-active',
  638. 'test-leave-to',
  639. ])
  640. await transitionFinish()
  641. expect(await html(containerSelector)).toBe('')
  642. // enter
  643. expect(
  644. (await transitionStart(btnSelector, childSelector)).classNames,
  645. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  646. await nextFrame()
  647. expect(await classList(childSelector)).toStrictEqual([
  648. 'test',
  649. 'test-enter-active',
  650. 'test-enter-to',
  651. ])
  652. await transitionFinish()
  653. expect(await html(containerSelector)).toBe(
  654. '<div class="test">content</div>',
  655. )
  656. },
  657. E2E_TIMEOUT,
  658. )
  659. test(
  660. 'transition on child components with empty root node',
  661. async () => {
  662. const btnSelector = '.if-empty-root > button.toggle'
  663. const btnChangeSelector = '.if-empty-root > button.change'
  664. const containerSelector = '.if-empty-root > div'
  665. const childSelector = `${containerSelector} > div`
  666. expect(await html(containerSelector)).toBe('')
  667. // change view -> 'two'
  668. await click(btnChangeSelector)
  669. // enter
  670. expect(
  671. (await transitionStart(btnSelector, childSelector)).classNames,
  672. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  673. await nextFrame()
  674. expect(await classList(childSelector)).toStrictEqual([
  675. 'test',
  676. 'test-enter-active',
  677. 'test-enter-to',
  678. ])
  679. await transitionFinish()
  680. expect(await html(containerSelector)).toBe(
  681. '<div class="test">two</div>',
  682. )
  683. // change view -> 'one'
  684. await click(btnChangeSelector)
  685. // leave
  686. expect(
  687. (await transitionStart(btnSelector, childSelector)).classNames,
  688. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  689. await nextFrame()
  690. expect(await classList(childSelector)).toStrictEqual([
  691. 'test',
  692. 'test-leave-active',
  693. 'test-leave-to',
  694. ])
  695. await transitionFinish()
  696. expect(await html(containerSelector)).toBe('')
  697. },
  698. E2E_TIMEOUT,
  699. )
  700. test(
  701. 'transition with v-if at component root-level',
  702. async () => {
  703. const btnSelector = '.if-at-component-root-level > button.toggle'
  704. const btnChangeSelector = '.if-at-component-root-level > button.change'
  705. const containerSelector = '.if-at-component-root-level > div'
  706. const childSelector = `${containerSelector} > div`
  707. expect(await html(containerSelector)).toBe('')
  708. // change view -> 'two'
  709. await click(btnChangeSelector)
  710. // enter
  711. expect(
  712. (await transitionStart(btnSelector, childSelector)).classNames,
  713. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  714. await nextFrame()
  715. expect(await classList(childSelector)).toStrictEqual([
  716. 'test',
  717. 'test-enter-active',
  718. 'test-enter-to',
  719. ])
  720. await transitionFinish()
  721. expect(await html(containerSelector)).toBe(
  722. '<div class="test">two</div>',
  723. )
  724. // change view -> 'one'
  725. await click(btnChangeSelector)
  726. // leave
  727. expect(
  728. (await transitionStart(btnSelector, childSelector)).classNames,
  729. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  730. await nextFrame()
  731. expect(await classList(childSelector)).toStrictEqual([
  732. 'test',
  733. 'test-leave-active',
  734. 'test-leave-to',
  735. ])
  736. await transitionFinish()
  737. expect(await html(containerSelector)).toBe('')
  738. },
  739. E2E_TIMEOUT,
  740. )
  741. test(
  742. 'wrapping transition + fallthrough attrs',
  743. async () => {
  744. const btnSelector = '.if-fallthrough-attr > button'
  745. const containerSelector = '.if-fallthrough-attr > div'
  746. expect(await html(containerSelector)).toBe('<div foo="1">content</div>')
  747. await click(btnSelector)
  748. // toggle again before leave finishes
  749. await nextTick()
  750. await click(btnSelector)
  751. await transitionFinish(duration * 2)
  752. expect(await html(containerSelector)).toBe(
  753. '<div foo="1" class="">content</div>',
  754. )
  755. },
  756. E2E_TIMEOUT,
  757. )
  758. test(
  759. 'transition + fallthrough attrs (in-out mode)',
  760. async () => {
  761. const btnSelector = '.if-fallthrough-attr-in-out > button'
  762. const containerSelector = '.if-fallthrough-attr-in-out > div'
  763. expect(await html(containerSelector)).toBe('<div foo="1">one</div>')
  764. // toggle
  765. await click(btnSelector)
  766. await nextTick()
  767. await transitionFinish(duration * 3)
  768. let calls = await page().evaluate(() => {
  769. return (window as any).getCalls('ifInOut')
  770. })
  771. expect(calls).toStrictEqual([
  772. 'beforeEnter',
  773. 'onEnter',
  774. 'afterEnter',
  775. 'beforeLeave',
  776. 'onLeave',
  777. 'afterLeave',
  778. ])
  779. expect(await html(containerSelector)).toBe(
  780. '<div foo="1" class="">two</div>',
  781. )
  782. // clear calls
  783. await page().evaluate(() => {
  784. ;(window as any).resetCalls('ifInOut')
  785. })
  786. // toggle back
  787. await click(btnSelector)
  788. await nextTick()
  789. await transitionFinish(duration * 3)
  790. calls = await page().evaluate(() => {
  791. return (window as any).getCalls('ifInOut')
  792. })
  793. expect(calls).toStrictEqual([
  794. 'beforeEnter',
  795. 'onEnter',
  796. 'afterEnter',
  797. 'beforeLeave',
  798. 'onLeave',
  799. 'afterLeave',
  800. ])
  801. expect(await html(containerSelector)).toBe(
  802. '<div foo="1" class="">one</div>',
  803. )
  804. },
  805. E2E_TIMEOUT,
  806. )
  807. })
  808. describe.todo('transition with KeepAlive', () => {})
  809. describe.todo('transition with Suspense', () => {})
  810. describe.todo('transition with Teleport', () => {})
  811. describe('transition with v-show', () => {
  812. test(
  813. 'named transition with v-show',
  814. async () => {
  815. const btnSelector = '.show-named > button'
  816. const containerSelector = '.show-named > div'
  817. const childSelector = `${containerSelector} > div`
  818. expect(await html(containerSelector)).toBe(
  819. '<div class="test">content</div>',
  820. )
  821. expect(await isVisible(childSelector)).toBe(true)
  822. // leave
  823. expect(
  824. (await transitionStart(btnSelector, childSelector)).classNames,
  825. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  826. await nextFrame()
  827. expect(await classList(childSelector)).toStrictEqual([
  828. 'test',
  829. 'test-leave-active',
  830. 'test-leave-to',
  831. ])
  832. await transitionFinish()
  833. expect(await isVisible(childSelector)).toBe(false)
  834. // enter
  835. expect(
  836. (await transitionStart(btnSelector, childSelector)).classNames,
  837. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  838. await nextFrame()
  839. expect(await classList(childSelector)).toStrictEqual([
  840. 'test',
  841. 'test-enter-active',
  842. 'test-enter-to',
  843. ])
  844. await transitionFinish()
  845. expect(await html(containerSelector)).toBe(
  846. '<div class="test" style="">content</div>',
  847. )
  848. },
  849. E2E_TIMEOUT,
  850. )
  851. test(
  852. 'transition events with v-show',
  853. async () => {
  854. const btnSelector = '.show-events > button'
  855. const containerSelector = '.show-events > div'
  856. const childSelector = `${containerSelector} > div`
  857. expect(await html(containerSelector)).toBe(
  858. '<div class="test">content</div>',
  859. )
  860. // leave
  861. expect(
  862. (await transitionStart(btnSelector, childSelector)).classNames,
  863. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  864. let calls = await page().evaluate(() => {
  865. return (window as any).getCalls('show')
  866. })
  867. expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
  868. await nextFrame()
  869. expect(await classList(childSelector)).toStrictEqual([
  870. 'test',
  871. 'test-leave-active',
  872. 'test-leave-to',
  873. ])
  874. calls = await page().evaluate(() => {
  875. return (window as any).getCalls('show')
  876. })
  877. expect(calls).not.contain('afterLeave')
  878. await transitionFinish()
  879. expect(await isVisible(childSelector)).toBe(false)
  880. calls = await page().evaluate(() => {
  881. return (window as any).getCalls('show')
  882. })
  883. expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
  884. // clear calls
  885. await page().evaluate(() => {
  886. ;(window as any).resetCalls('show')
  887. })
  888. // enter
  889. expect(
  890. (await transitionStart(btnSelector, childSelector)).classNames,
  891. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  892. await nextFrame()
  893. expect(await classList(childSelector)).toStrictEqual([
  894. 'test',
  895. 'test-enter-active',
  896. 'test-enter-to',
  897. ])
  898. calls = await page().evaluate(() => {
  899. return (window as any).getCalls('show')
  900. })
  901. expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
  902. await transitionFinish()
  903. expect(await html(containerSelector)).toBe(
  904. '<div class="test" style="">content</div>',
  905. )
  906. calls = await page().evaluate(() => {
  907. return (window as any).getCalls('show')
  908. })
  909. expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
  910. },
  911. E2E_TIMEOUT,
  912. )
  913. test(
  914. 'onLeaveCancelled (v-show only)',
  915. async () => {
  916. const btnSelector = '.show-leave-cancelled > button'
  917. const containerSelector = '.show-leave-cancelled > div'
  918. const childSelector = `${containerSelector} > div`
  919. expect(await html(containerSelector)).toBe(
  920. '<div class="test">content</div>',
  921. )
  922. // leave
  923. expect(
  924. (await transitionStart(btnSelector, childSelector)).classNames,
  925. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  926. await nextFrame()
  927. expect(await classList(childSelector)).toStrictEqual([
  928. 'test',
  929. 'test-leave-active',
  930. 'test-leave-to',
  931. ])
  932. // cancel (enter)
  933. expect(
  934. (await transitionStart(btnSelector, childSelector)).classNames,
  935. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  936. let calls = await page().evaluate(() => {
  937. return (window as any).getCalls('showLeaveCancel')
  938. })
  939. expect(calls).toStrictEqual(['leaveCancelled'])
  940. await nextFrame()
  941. expect(await classList(childSelector)).toStrictEqual([
  942. 'test',
  943. 'test-enter-active',
  944. 'test-enter-to',
  945. ])
  946. await transitionFinish()
  947. expect(await isVisible(childSelector)).toBe(true)
  948. },
  949. E2E_TIMEOUT,
  950. )
  951. test(
  952. 'transition on appear with v-show',
  953. async () => {
  954. const btnSelector = '.show-appear > button'
  955. const containerSelector = '.show-appear > div'
  956. const childSelector = `${containerSelector} > div`
  957. let calls = await page().evaluate(() => {
  958. return (window as any).getCalls('showAppear')
  959. })
  960. expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
  961. // appear
  962. expect(await classList(childSelector)).contains('test-appear-active')
  963. await transitionFinish()
  964. expect(await html(containerSelector)).toBe(
  965. '<div class="test">content</div>',
  966. )
  967. calls = await page().evaluate(() => {
  968. return (window as any).getCalls('showAppear')
  969. })
  970. expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
  971. // leave
  972. expect(
  973. (await transitionStart(btnSelector, childSelector)).classNames,
  974. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  975. await nextFrame()
  976. expect(await classList(childSelector)).toStrictEqual([
  977. 'test',
  978. 'test-leave-active',
  979. 'test-leave-to',
  980. ])
  981. await transitionFinish()
  982. expect(await isVisible(childSelector)).toBe(false)
  983. // enter
  984. expect(
  985. (await transitionStart(btnSelector, childSelector)).classNames,
  986. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  987. await nextFrame()
  988. expect(await classList(childSelector)).toStrictEqual([
  989. 'test',
  990. 'test-enter-active',
  991. 'test-enter-to',
  992. ])
  993. await transitionFinish()
  994. expect(await html(containerSelector)).toBe(
  995. '<div class="test" style="">content</div>',
  996. )
  997. },
  998. E2E_TIMEOUT,
  999. )
  1000. test(
  1001. 'transition events should not call onEnter with v-show false',
  1002. async () => {
  1003. const btnSelector = '.show-appear-not-enter > button'
  1004. const containerSelector = '.show-appear-not-enter > div'
  1005. const childSelector = `${containerSelector} > div`
  1006. expect(await isVisible(childSelector)).toBe(false)
  1007. let calls = await page().evaluate(() => {
  1008. return (window as any).getCalls('notEnter')
  1009. })
  1010. expect(calls).toStrictEqual([])
  1011. // enter
  1012. expect(
  1013. (await transitionStart(btnSelector, childSelector)).classNames,
  1014. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  1015. calls = await page().evaluate(() => {
  1016. return (window as any).getCalls('notEnter')
  1017. })
  1018. expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
  1019. await nextFrame()
  1020. expect(await classList(childSelector)).toStrictEqual([
  1021. 'test',
  1022. 'test-enter-active',
  1023. 'test-enter-to',
  1024. ])
  1025. calls = await page().evaluate(() => {
  1026. return (window as any).getCalls('notEnter')
  1027. })
  1028. expect(calls).not.contain('afterEnter')
  1029. await transitionFinish()
  1030. expect(await html(containerSelector)).toBe(
  1031. '<div class="test" style="">content</div>',
  1032. )
  1033. calls = await page().evaluate(() => {
  1034. return (window as any).getCalls('notEnter')
  1035. })
  1036. expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
  1037. },
  1038. E2E_TIMEOUT,
  1039. )
  1040. })
  1041. describe('explicit durations', () => {
  1042. test(
  1043. 'single value',
  1044. async () => {
  1045. const btnSelector = '.duration-single-value > button'
  1046. const containerSelector = '.duration-single-value > div'
  1047. const childSelector = `${containerSelector} > div`
  1048. expect(await html(containerSelector)).toBe(
  1049. '<div class="test">content</div>',
  1050. )
  1051. // leave
  1052. expect(
  1053. (await transitionStart(btnSelector, childSelector)).classNames,
  1054. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  1055. await nextFrame()
  1056. expect(await classList(childSelector)).toStrictEqual([
  1057. 'test',
  1058. 'test-leave-active',
  1059. 'test-leave-to',
  1060. ])
  1061. await transitionFinish(duration * 2)
  1062. expect(await html(containerSelector)).toBe('')
  1063. // enter
  1064. expect(
  1065. (await transitionStart(btnSelector, childSelector)).classNames,
  1066. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  1067. await nextFrame()
  1068. expect(await classList(childSelector)).toStrictEqual([
  1069. 'test',
  1070. 'test-enter-active',
  1071. 'test-enter-to',
  1072. ])
  1073. await transitionFinish(duration * 2)
  1074. expect(await html(containerSelector)).toBe(
  1075. '<div class="test">content</div>',
  1076. )
  1077. },
  1078. E2E_TIMEOUT,
  1079. )
  1080. test(
  1081. 'enter with explicit durations',
  1082. async () => {
  1083. const btnSelector = '.duration-enter > button'
  1084. const containerSelector = '.duration-enter > div'
  1085. const childSelector = `${containerSelector} > div`
  1086. expect(await html(containerSelector)).toBe(
  1087. '<div class="test">content</div>',
  1088. )
  1089. // leave
  1090. expect(
  1091. (await transitionStart(btnSelector, childSelector)).classNames,
  1092. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  1093. await nextFrame()
  1094. expect(await classList(childSelector)).toStrictEqual([
  1095. 'test',
  1096. 'test-leave-active',
  1097. 'test-leave-to',
  1098. ])
  1099. await transitionFinish()
  1100. expect(await html(containerSelector)).toBe('')
  1101. // enter
  1102. expect(
  1103. (await transitionStart(btnSelector, childSelector)).classNames,
  1104. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  1105. await nextFrame()
  1106. expect(await classList(childSelector)).toStrictEqual([
  1107. 'test',
  1108. 'test-enter-active',
  1109. 'test-enter-to',
  1110. ])
  1111. await transitionFinish(duration * 2)
  1112. expect(await html(containerSelector)).toBe(
  1113. '<div class="test">content</div>',
  1114. )
  1115. },
  1116. E2E_TIMEOUT,
  1117. )
  1118. test(
  1119. 'leave with explicit durations',
  1120. async () => {
  1121. const btnSelector = '.duration-leave > button'
  1122. const containerSelector = '.duration-leave > div'
  1123. const childSelector = `${containerSelector} > div`
  1124. expect(await html(containerSelector)).toBe(
  1125. '<div class="test">content</div>',
  1126. )
  1127. // leave
  1128. expect(
  1129. (await transitionStart(btnSelector, childSelector)).classNames,
  1130. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  1131. await nextFrame()
  1132. expect(await classList(childSelector)).toStrictEqual([
  1133. 'test',
  1134. 'test-leave-active',
  1135. 'test-leave-to',
  1136. ])
  1137. await transitionFinish(duration * 2)
  1138. expect(await html(containerSelector)).toBe('')
  1139. // enter
  1140. expect(
  1141. (await transitionStart(btnSelector, childSelector)).classNames,
  1142. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  1143. await nextFrame()
  1144. expect(await classList(childSelector)).toStrictEqual([
  1145. 'test',
  1146. 'test-enter-active',
  1147. 'test-enter-to',
  1148. ])
  1149. await transitionFinish()
  1150. expect(await html(containerSelector)).toBe(
  1151. '<div class="test">content</div>',
  1152. )
  1153. },
  1154. E2E_TIMEOUT,
  1155. )
  1156. test(
  1157. 'separate enter and leave',
  1158. async () => {
  1159. const btnSelector = '.duration-enter-leave > button'
  1160. const containerSelector = '.duration-enter-leave > div'
  1161. const childSelector = `${containerSelector} > div`
  1162. expect(await html(containerSelector)).toBe(
  1163. '<div class="test">content</div>',
  1164. )
  1165. // leave
  1166. expect(
  1167. (await transitionStart(btnSelector, childSelector)).classNames,
  1168. ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
  1169. await nextFrame()
  1170. expect(await classList(childSelector)).toStrictEqual([
  1171. 'test',
  1172. 'test-leave-active',
  1173. 'test-leave-to',
  1174. ])
  1175. await transitionFinish(duration * 2)
  1176. expect(await html(containerSelector)).toBe('')
  1177. // enter
  1178. expect(
  1179. (await transitionStart(btnSelector, childSelector)).classNames,
  1180. ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
  1181. await nextFrame()
  1182. expect(await classList(childSelector)).toStrictEqual([
  1183. 'test',
  1184. 'test-enter-active',
  1185. 'test-enter-to',
  1186. ])
  1187. await transitionFinish(duration * 4)
  1188. expect(await html(containerSelector)).toBe(
  1189. '<div class="test">content</div>',
  1190. )
  1191. },
  1192. E2E_TIMEOUT,
  1193. )
  1194. })
  1195. test(
  1196. 'should work with keyed element',
  1197. async () => {
  1198. const btnSelector = '.keyed > button'
  1199. const containerSelector = '.keyed > h1'
  1200. expect(await text(containerSelector)).toContain('0')
  1201. // change key
  1202. expect(
  1203. (await transitionStart(btnSelector, containerSelector)).classNames,
  1204. ).toStrictEqual(['v-leave-from', 'v-leave-active'])
  1205. await nextFrame()
  1206. expect(await classList(containerSelector)).toStrictEqual([
  1207. 'v-leave-active',
  1208. 'v-leave-to',
  1209. ])
  1210. await transitionFinish()
  1211. await nextFrame()
  1212. expect(await text(containerSelector)).toContain('1')
  1213. // change key again
  1214. expect(
  1215. (await transitionStart(btnSelector, containerSelector)).classNames,
  1216. ).toStrictEqual(['v-leave-from', 'v-leave-active'])
  1217. await nextFrame()
  1218. expect(await classList(containerSelector)).toStrictEqual([
  1219. 'v-leave-active',
  1220. 'v-leave-to',
  1221. ])
  1222. await transitionFinish()
  1223. await nextFrame()
  1224. expect(await text(containerSelector)).toContain('2')
  1225. },
  1226. E2E_TIMEOUT,
  1227. )
  1228. test(
  1229. 'should work with out-in mode',
  1230. async () => {
  1231. const btnSelector = '.out-in > button'
  1232. const containerSelector = '.out-in > div'
  1233. const childSelector = `${containerSelector} > div`
  1234. expect(await html(containerSelector)).toBe(`<div>vapor compB</div>`)
  1235. // compB -> compA
  1236. // compB leave
  1237. expect(
  1238. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1239. ).toBe(`<div class="fade-leave-from fade-leave-active">vapor compB</div>`)
  1240. await nextFrame()
  1241. expect(await html(containerSelector)).toBe(
  1242. `<div class="fade-leave-active fade-leave-to">vapor compB</div>`,
  1243. )
  1244. // compA enter
  1245. await waitForElement(childSelector, 'vapor compA', [
  1246. 'fade-enter-from',
  1247. 'fade-enter-active',
  1248. ])
  1249. await nextFrame()
  1250. expect(await html(containerSelector)).toBe(
  1251. `<div class="fade-enter-active fade-enter-to">vapor compA</div>`,
  1252. )
  1253. await transitionFinish()
  1254. await nextFrame()
  1255. expect(await html(containerSelector)).toBe(
  1256. `<div class="">vapor compA</div>`,
  1257. )
  1258. // compA -> compB
  1259. // compA leave
  1260. expect(
  1261. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1262. ).toBe(`<div class="fade-leave-from fade-leave-active">vapor compA</div>`)
  1263. await nextFrame()
  1264. expect(await html(containerSelector)).toBe(
  1265. `<div class="fade-leave-active fade-leave-to">vapor compA</div>`,
  1266. )
  1267. // compB enter
  1268. await waitForElement(childSelector, 'vapor compB', [
  1269. 'fade-enter-from',
  1270. 'fade-enter-active',
  1271. ])
  1272. await nextFrame()
  1273. expect(await html(containerSelector)).toBe(
  1274. `<div class="fade-enter-active fade-enter-to">vapor compB</div>`,
  1275. )
  1276. await transitionFinish()
  1277. expect(await html(containerSelector)).toBe(
  1278. `<div class="">vapor compB</div>`,
  1279. )
  1280. },
  1281. E2E_TIMEOUT,
  1282. )
  1283. test(
  1284. 'should work with in-out mode',
  1285. async () => {
  1286. const btnSelector = '.in-out > button'
  1287. const containerSelector = '.in-out > div'
  1288. const childSelector = `${containerSelector} > div`
  1289. expect(await html(containerSelector)).toBe(`<div>vapor compB</div>`)
  1290. // compA enter
  1291. expect(
  1292. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1293. ).toBe(
  1294. `<div>vapor compB</div><div class="fade-enter-from fade-enter-active">vapor compA</div>`,
  1295. )
  1296. await nextFrame()
  1297. expect(await html(containerSelector)).toBe(
  1298. `<div>vapor compB</div><div class="fade-enter-active fade-enter-to">vapor compA</div>`,
  1299. )
  1300. // compB leave
  1301. await waitForElement(childSelector, 'vapor compB', [
  1302. 'fade-leave-from',
  1303. 'fade-leave-active',
  1304. ])
  1305. await nextFrame()
  1306. expect(await html(containerSelector)).toBe(
  1307. `<div class="fade-leave-active fade-leave-to">vapor compB</div><div class="">vapor compA</div>`,
  1308. )
  1309. await transitionFinish()
  1310. expect(await html(containerSelector)).toBe(
  1311. `<div class="">vapor compA</div>`,
  1312. )
  1313. },
  1314. E2E_TIMEOUT,
  1315. )
  1316. // tests for using vdom component in createVaporApp + vaporInteropPlugin
  1317. describe('interop', () => {
  1318. test(
  1319. 'render vdom component',
  1320. async () => {
  1321. const btnSelector = '.vdom > button'
  1322. const containerSelector = '.vdom > div'
  1323. expect(await html(containerSelector)).toBe(`<div>vdom comp</div>`)
  1324. // comp leave
  1325. expect(
  1326. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1327. ).toBe(`<div class="v-leave-from v-leave-active">vdom comp</div>`)
  1328. await nextFrame()
  1329. expect(await html(containerSelector)).toBe(
  1330. `<div class="v-leave-active v-leave-to">vdom comp</div>`,
  1331. )
  1332. await transitionFinish()
  1333. expect(await html(containerSelector)).toBe(``)
  1334. // comp enter
  1335. expect(
  1336. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1337. ).toBe(`<div class="v-enter-from v-enter-active">vdom comp</div>`)
  1338. await nextFrame()
  1339. expect(await html(containerSelector)).toBe(
  1340. `<div class="v-enter-active v-enter-to">vdom comp</div>`,
  1341. )
  1342. await transitionFinish()
  1343. expect(await html(containerSelector)).toBe(
  1344. `<div class="">vdom comp</div>`,
  1345. )
  1346. },
  1347. E2E_TIMEOUT,
  1348. )
  1349. test(
  1350. 'switch between vdom/vapor component (out-in mode)',
  1351. async () => {
  1352. const btnSelector = '.vdom-vapor-out-in > button'
  1353. const containerSelector = '.vdom-vapor-out-in > div'
  1354. const childSelector = `${containerSelector} > div`
  1355. expect(await html(containerSelector)).toBe(`<div>vdom comp</div>`)
  1356. // switch to vapor comp
  1357. // vdom comp leave
  1358. expect(
  1359. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1360. ).toBe(`<div class="fade-leave-from fade-leave-active">vdom comp</div>`)
  1361. await nextFrame()
  1362. expect(await html(containerSelector)).toBe(
  1363. `<div class="fade-leave-active fade-leave-to">vdom comp</div>`,
  1364. )
  1365. // vapor comp enter
  1366. await waitForElement(childSelector, 'vapor compA', [
  1367. 'fade-enter-from',
  1368. 'fade-enter-active',
  1369. ])
  1370. await nextFrame()
  1371. expect(await html(containerSelector)).toBe(
  1372. `<div class="fade-enter-active fade-enter-to">vapor compA</div>`,
  1373. )
  1374. await transitionFinish()
  1375. expect(await html(containerSelector)).toBe(
  1376. `<div class="">vapor compA</div>`,
  1377. )
  1378. // switch to vdom comp
  1379. // vapor comp leave
  1380. expect(
  1381. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1382. ).toBe(
  1383. `<div class="fade-leave-from fade-leave-active">vapor compA</div>`,
  1384. )
  1385. await nextFrame()
  1386. expect(await html(containerSelector)).toBe(
  1387. `<div class="fade-leave-active fade-leave-to">vapor compA</div>`,
  1388. )
  1389. // vdom comp enter
  1390. await waitForElement(childSelector, 'vdom comp', [
  1391. 'fade-enter-from',
  1392. 'fade-enter-active',
  1393. ])
  1394. await nextFrame()
  1395. expect(await html(containerSelector)).toBe(
  1396. `<div class="fade-enter-active fade-enter-to">vdom comp</div>`,
  1397. )
  1398. await transitionFinish()
  1399. expect(await html(containerSelector)).toBe(
  1400. `<div class="">vdom comp</div>`,
  1401. )
  1402. },
  1403. E2E_TIMEOUT,
  1404. )
  1405. test(
  1406. 'switch between vdom/vapor component (in-out mode)',
  1407. async () => {
  1408. const btnSelector = '.vdom-vapor-in-out > button'
  1409. const containerSelector = '.vdom-vapor-in-out > div'
  1410. const childSelector = `${containerSelector} > div`
  1411. expect(await html(containerSelector)).toBe(`<div>vapor compA</div>`)
  1412. // switch to vdom comp
  1413. // vdom comp enter
  1414. expect(
  1415. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1416. ).toBe(
  1417. `<div>vapor compA</div><div class="fade-enter-from fade-enter-active">vdom comp</div>`,
  1418. )
  1419. await nextFrame()
  1420. expect(await html(containerSelector)).toBe(
  1421. `<div>vapor compA</div><div class="fade-enter-active fade-enter-to">vdom comp</div>`,
  1422. )
  1423. // vapor comp leave
  1424. await waitForElement(childSelector, 'vapor compA', [
  1425. 'fade-leave-from',
  1426. 'fade-leave-active',
  1427. ])
  1428. await nextFrame()
  1429. expect(await html(containerSelector)).toBe(
  1430. `<div class="fade-leave-active fade-leave-to">vapor compA</div><div class="">vdom comp</div>`,
  1431. )
  1432. await transitionFinish()
  1433. expect(await html(containerSelector)).toBe(
  1434. `<div class="">vdom comp</div>`,
  1435. )
  1436. // switch to vapor comp
  1437. // vapor comp enter
  1438. expect(
  1439. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  1440. ).toBe(
  1441. `<div class="">vdom comp</div><div class="fade-enter-from fade-enter-active">vapor compA</div>`,
  1442. )
  1443. await nextFrame()
  1444. expect(await html(containerSelector)).toBe(
  1445. `<div class="">vdom comp</div><div class="fade-enter-active fade-enter-to">vapor compA</div>`,
  1446. )
  1447. // vdom comp leave
  1448. await waitForElement(childSelector, 'vdom comp', [
  1449. 'fade-leave-from',
  1450. 'fade-leave-active',
  1451. ])
  1452. await nextFrame()
  1453. expect(await html(containerSelector)).toBe(
  1454. `<div class="fade-leave-active fade-leave-to">vdom comp</div><div class="">vapor compA</div>`,
  1455. )
  1456. await transitionFinish()
  1457. expect(await html(containerSelector)).toBe(
  1458. `<div class="">vapor compA</div>`,
  1459. )
  1460. },
  1461. E2E_TIMEOUT,
  1462. )
  1463. })
  1464. })