transition-group.spec.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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 { expect } from 'vitest'
  9. const { page, nextFrame, timeout, html, transitionStart } = setupPuppeteer()
  10. const duration = process.env.CI ? 200 : 50
  11. const buffer = process.env.CI ? 50 : 20
  12. const transitionFinish = (time = duration) => timeout(time + buffer)
  13. describe('vapor transition-group', () => {
  14. let server: any
  15. const port = '8196'
  16. beforeAll(() => {
  17. server = connect()
  18. .use(sirv(path.resolve(import.meta.dirname, '../dist')))
  19. .listen(port)
  20. process.on('SIGTERM', () => server && server.close())
  21. })
  22. afterAll(() => {
  23. server.close()
  24. })
  25. beforeEach(async () => {
  26. const baseUrl = `http://localhost:${port}/transition-group/`
  27. await page().goto(baseUrl)
  28. await page().waitForSelector('#app')
  29. })
  30. test(
  31. 'enter',
  32. async () => {
  33. const btnSelector = '.enter > button'
  34. const containerSelector = '.enter > div'
  35. expect(await html(containerSelector)).toBe(
  36. `<div class="test">a</div>` +
  37. `<div class="test">b</div>` +
  38. `<div class="test">c</div>`,
  39. )
  40. expect(
  41. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  42. ).toBe(
  43. `<div class="test">a</div>` +
  44. `<div class="test">b</div>` +
  45. `<div class="test">c</div>` +
  46. `<div class="test test-enter-from test-enter-active">d</div>` +
  47. `<div class="test test-enter-from test-enter-active">e</div>`,
  48. )
  49. await nextFrame()
  50. expect(await html(containerSelector)).toBe(
  51. `<div class="test">a</div>` +
  52. `<div class="test">b</div>` +
  53. `<div class="test">c</div>` +
  54. `<div class="test test-enter-active test-enter-to">d</div>` +
  55. `<div class="test test-enter-active test-enter-to">e</div>`,
  56. )
  57. await transitionFinish()
  58. expect(await html(containerSelector)).toBe(
  59. `<div class="test">a</div>` +
  60. `<div class="test">b</div>` +
  61. `<div class="test">c</div>` +
  62. `<div class="test">d</div>` +
  63. `<div class="test">e</div>`,
  64. )
  65. },
  66. E2E_TIMEOUT,
  67. )
  68. test(
  69. 'leave',
  70. async () => {
  71. const btnSelector = '.leave > button'
  72. const containerSelector = '.leave > div'
  73. expect(await html(containerSelector)).toBe(
  74. `<div class="test">a</div>` +
  75. `<div class="test">b</div>` +
  76. `<div class="test">c</div>`,
  77. )
  78. expect(
  79. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  80. ).toBe(
  81. `<div class="test test-leave-from test-leave-active">a</div>` +
  82. `<div class="test">b</div>` +
  83. `<div class="test test-leave-from test-leave-active">c</div>`,
  84. )
  85. await nextFrame()
  86. expect(await html(containerSelector)).toBe(
  87. `<div class="test test-leave-active test-leave-to">a</div>` +
  88. `<div class="test">b</div>` +
  89. `<div class="test test-leave-active test-leave-to">c</div>`,
  90. )
  91. await transitionFinish()
  92. expect(await html(containerSelector)).toBe(`<div class="test">b</div>`)
  93. },
  94. E2E_TIMEOUT,
  95. )
  96. test(
  97. 'enter + leave',
  98. async () => {
  99. const btnSelector = '.enter-leave > button'
  100. const containerSelector = '.enter-leave > div'
  101. expect(await html(containerSelector)).toBe(
  102. `<div class="test">a</div>` +
  103. `<div class="test">b</div>` +
  104. `<div class="test">c</div>`,
  105. )
  106. expect(
  107. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  108. ).toBe(
  109. `<div class="test test-leave-from test-leave-active">a</div>` +
  110. `<div class="test">b</div>` +
  111. `<div class="test">c</div>` +
  112. `<div class="test test-enter-from test-enter-active">d</div>`,
  113. )
  114. await nextFrame()
  115. expect(await html(containerSelector)).toBe(
  116. `<div class="test test-leave-active test-leave-to">a</div>` +
  117. `<div class="test">b</div>` +
  118. `<div class="test">c</div>` +
  119. `<div class="test test-enter-active test-enter-to">d</div>`,
  120. )
  121. await transitionFinish()
  122. expect(await html(containerSelector)).toBe(
  123. `<div class="test">b</div>` +
  124. `<div class="test">c</div>` +
  125. `<div class="test">d</div>`,
  126. )
  127. },
  128. E2E_TIMEOUT,
  129. )
  130. test(
  131. 'appear',
  132. async () => {
  133. const btnSelector = '.appear > button'
  134. const containerSelector = '.appear > div'
  135. expect(await html('.appear')).toBe(`<button>appear button</button>`)
  136. await page().evaluate(() => {
  137. return (window as any).setAppear()
  138. })
  139. // appear
  140. expect(await html(containerSelector)).toBe(
  141. `<div class="test test-appear-from test-appear-active">a</div>` +
  142. `<div class="test test-appear-from test-appear-active">b</div>` +
  143. `<div class="test test-appear-from test-appear-active">c</div>`,
  144. )
  145. await nextFrame()
  146. expect(await html(containerSelector)).toBe(
  147. `<div class="test test-appear-active test-appear-to">a</div>` +
  148. `<div class="test test-appear-active test-appear-to">b</div>` +
  149. `<div class="test test-appear-active test-appear-to">c</div>`,
  150. )
  151. await transitionFinish()
  152. expect(await html(containerSelector)).toBe(
  153. `<div class="test">a</div>` +
  154. `<div class="test">b</div>` +
  155. `<div class="test">c</div>`,
  156. )
  157. // enter
  158. expect(
  159. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  160. ).toBe(
  161. `<div class="test">a</div>` +
  162. `<div class="test">b</div>` +
  163. `<div class="test">c</div>` +
  164. `<div class="test test-enter-from test-enter-active">d</div>` +
  165. `<div class="test test-enter-from test-enter-active">e</div>`,
  166. )
  167. await nextFrame()
  168. expect(await html(containerSelector)).toBe(
  169. `<div class="test">a</div>` +
  170. `<div class="test">b</div>` +
  171. `<div class="test">c</div>` +
  172. `<div class="test test-enter-active test-enter-to">d</div>` +
  173. `<div class="test test-enter-active test-enter-to">e</div>`,
  174. )
  175. await transitionFinish()
  176. expect(await html(containerSelector)).toBe(
  177. `<div class="test">a</div>` +
  178. `<div class="test">b</div>` +
  179. `<div class="test">c</div>` +
  180. `<div class="test">d</div>` +
  181. `<div class="test">e</div>`,
  182. )
  183. },
  184. E2E_TIMEOUT,
  185. )
  186. test(
  187. 'move',
  188. async () => {
  189. const btnSelector = '.move > button'
  190. const containerSelector = '.move > div'
  191. expect(await html(containerSelector)).toBe(
  192. `<div class="test">a</div>` +
  193. `<div class="test">b</div>` +
  194. `<div class="test">c</div>`,
  195. )
  196. expect(
  197. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  198. ).toBe(
  199. `<div class="test group-enter-from group-enter-active">d</div>` +
  200. `<div class="test">b</div>` +
  201. `<div class="test group-move" style="">a</div>` +
  202. `<div class="test group-leave-from group-leave-active group-move" style="">c</div>`,
  203. )
  204. await nextFrame()
  205. expect(await html(containerSelector)).toBe(
  206. `<div class="test group-enter-active group-enter-to">d</div>` +
  207. `<div class="test">b</div>` +
  208. `<div class="test group-move" style="">a</div>` +
  209. `<div class="test group-leave-active group-move group-leave-to" style="">c</div>`,
  210. )
  211. await transitionFinish(duration * 2)
  212. expect(await html(containerSelector)).toBe(
  213. `<div class="test">d</div>` +
  214. `<div class="test">b</div>` +
  215. `<div class="test" style="">a</div>`,
  216. )
  217. },
  218. E2E_TIMEOUT,
  219. )
  220. test('dynamic name', async () => {
  221. const btnSelector = '.dynamic-name button.toggleBtn'
  222. const btnChangeName = '.dynamic-name button.changeNameBtn'
  223. const containerSelector = '.dynamic-name > div'
  224. expect(await html(containerSelector)).toBe(
  225. `<div>a</div>` + `<div>b</div>` + `<div>c</div>`,
  226. )
  227. // invalid name
  228. expect(
  229. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  230. ).toBe(`<div>b</div>` + `<div>c</div>` + `<div>a</div>`)
  231. // change name
  232. expect(
  233. (await transitionStart(btnChangeName, containerSelector)).innerHTML,
  234. ).toBe(
  235. `<div class="group-move" style="">a</div>` +
  236. `<div class="group-move" style="">b</div>` +
  237. `<div class="group-move" style="">c</div>`,
  238. )
  239. await transitionFinish()
  240. expect(await html(containerSelector)).toBe(
  241. `<div class="" style="">a</div>` +
  242. `<div class="" style="">b</div>` +
  243. `<div class="" style="">c</div>`,
  244. )
  245. })
  246. test('events', async () => {
  247. const btnSelector = '.events > button'
  248. const containerSelector = '.events > div'
  249. expect(await html('.events')).toBe(`<button>events button</button>`)
  250. await page().evaluate(() => {
  251. return (window as any).setAppear()
  252. })
  253. // appear
  254. expect(await html(containerSelector)).toBe(
  255. `<div class="test test-appear-from test-appear-active">a</div>` +
  256. `<div class="test test-appear-from test-appear-active">b</div>` +
  257. `<div class="test test-appear-from test-appear-active">c</div>`,
  258. )
  259. await nextFrame()
  260. expect(await html(containerSelector)).toBe(
  261. `<div class="test test-appear-active test-appear-to">a</div>` +
  262. `<div class="test test-appear-active test-appear-to">b</div>` +
  263. `<div class="test test-appear-active test-appear-to">c</div>`,
  264. )
  265. let calls = await page().evaluate(() => {
  266. return (window as any).getCalls()
  267. })
  268. expect(calls).toContain('beforeAppear')
  269. expect(calls).toContain('onAppear')
  270. expect(calls).not.toContain('afterAppear')
  271. await transitionFinish()
  272. expect(await html(containerSelector)).toBe(
  273. `<div class="test">a</div>` +
  274. `<div class="test">b</div>` +
  275. `<div class="test">c</div>`,
  276. )
  277. expect(
  278. await page().evaluate(() => {
  279. return (window as any).getCalls()
  280. }),
  281. ).toContain('afterAppear')
  282. // enter + leave
  283. expect(
  284. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  285. ).toBe(
  286. `<div class="test test-leave-from test-leave-active">a</div>` +
  287. `<div class="test">b</div>` +
  288. `<div class="test">c</div>` +
  289. `<div class="test test-enter-from test-enter-active">d</div>`,
  290. )
  291. calls = await page().evaluate(() => {
  292. return (window as any).getCalls()
  293. })
  294. expect(calls).toContain('beforeLeave')
  295. expect(calls).toContain('onLeave')
  296. expect(calls).not.toContain('afterLeave')
  297. expect(calls).toContain('beforeEnter')
  298. expect(calls).toContain('onEnter')
  299. expect(calls).not.toContain('afterEnter')
  300. await nextFrame()
  301. expect(await html(containerSelector)).toBe(
  302. `<div class="test test-leave-active test-leave-to">a</div>` +
  303. `<div class="test">b</div>` +
  304. `<div class="test">c</div>` +
  305. `<div class="test test-enter-active test-enter-to">d</div>`,
  306. )
  307. calls = await page().evaluate(() => {
  308. return (window as any).getCalls()
  309. })
  310. expect(calls).not.toContain('afterLeave')
  311. expect(calls).not.toContain('afterEnter')
  312. await transitionFinish()
  313. expect(await html(containerSelector)).toBe(
  314. `<div class="test">b</div>` +
  315. `<div class="test">c</div>` +
  316. `<div class="test">d</div>`,
  317. )
  318. calls = await page().evaluate(() => {
  319. return (window as any).getCalls()
  320. })
  321. expect(calls).toContain('afterLeave')
  322. expect(calls).toContain('afterEnter')
  323. })
  324. test(
  325. 'reusable transition group',
  326. async () => {
  327. const btnSelector = '.reusable-transition-group > button'
  328. const containerSelector = '.reusable-transition-group > div'
  329. expect(await html(containerSelector)).toBe(
  330. `<div class="test">a</div>` +
  331. `<div class="test">b</div>` +
  332. `<div class="test">c</div>`,
  333. )
  334. expect(
  335. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  336. ).toBe(
  337. `<div class="test group-enter-from group-enter-active">d</div>` +
  338. `<div class="test">b</div>` +
  339. `<div class="test group-move" style="">a</div>` +
  340. `<div class="test group-leave-from group-leave-active group-move" style="">c</div>`,
  341. )
  342. await nextFrame()
  343. expect(await html(containerSelector)).toBe(
  344. `<div class="test group-enter-active group-enter-to">d</div>` +
  345. `<div class="test">b</div>` +
  346. `<div class="test group-move" style="">a</div>` +
  347. `<div class="test group-leave-active group-move group-leave-to" style="">c</div>`,
  348. )
  349. await transitionFinish(duration * 2)
  350. expect(await html(containerSelector)).toBe(
  351. `<div class="test">d</div>` +
  352. `<div class="test">b</div>` +
  353. `<div class="test" style="">a</div>`,
  354. )
  355. },
  356. E2E_TIMEOUT,
  357. )
  358. test('interop: render vdom component', async () => {
  359. const btnSelector = '.interop > button'
  360. const containerSelector = '.interop > div'
  361. expect(await html(containerSelector)).toBe(
  362. `<div><div>a</div></div>` +
  363. `<div><div>b</div></div>` +
  364. `<div><div>c</div></div>`,
  365. )
  366. expect(
  367. (await transitionStart(btnSelector, containerSelector)).innerHTML,
  368. ).toBe(
  369. `<div class="test-leave-from test-leave-active"><div>a</div></div>` +
  370. `<div class="test-move" style=""><div>b</div></div>` +
  371. `<div class="test-move" style=""><div>c</div></div>` +
  372. `<div class="test-enter-from test-enter-active"><div>d</div></div>`,
  373. )
  374. await nextFrame()
  375. expect(await html(containerSelector)).toBe(
  376. `<div class="test-leave-active test-leave-to"><div>a</div></div>` +
  377. `<div class="test-move" style=""><div>b</div></div>` +
  378. `<div class="test-move" style=""><div>c</div></div>` +
  379. `<div class="test-enter-active test-enter-to"><div>d</div></div>`,
  380. )
  381. await transitionFinish()
  382. expect(await html(containerSelector)).toBe(
  383. `<div class="" style=""><div>b</div></div>` +
  384. `<div class="" style=""><div>c</div></div>` +
  385. `<div class=""><div>d</div></div>`,
  386. )
  387. })
  388. })