todomvc.spec.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import path from 'path'
  2. import puppeteer from 'puppeteer'
  3. const puppeteerOptions = process.env.CI
  4. ? { args: ['--no-sandbox', '--disable-setuid-sandbox'] }
  5. : {}
  6. let browser: puppeteer.Browser
  7. let page: puppeteer.Page
  8. describe('e2e', () => {
  9. beforeEach(async () => {
  10. browser = await puppeteer.launch(puppeteerOptions)
  11. page = await browser.newPage()
  12. })
  13. afterEach(async () => {
  14. await browser.close()
  15. })
  16. test('todomvc', async () => {
  17. await page.goto(
  18. `file://${path.resolve(__dirname, '../classic/todomvc.html')}`
  19. )
  20. expect(await isVisible('.main')).toBe(false)
  21. expect(await isVisible('.footer')).toBe(false)
  22. expect(await count('.filters .selected')).toBe(1)
  23. expect(await text('.filters .selected')).toBe('All')
  24. expect(await count('.todo')).toBe(0)
  25. await createNewItem('test')
  26. expect(await count('.todo')).toBe(1)
  27. expect(await isVisible('.todo .edit')).toBe(false)
  28. expect(await text('.todo label')).toBe('test')
  29. expect(await text('.todo-count strong')).toBe('1')
  30. expect(await isChecked('.todo .toggle')).toBe(false)
  31. expect(await isVisible('.main')).toBe(true)
  32. expect(await isVisible('.footer')).toBe(true)
  33. expect(await isVisible('.clear-completed')).toBe(false)
  34. expect(await value('.new-todo')).toBe('')
  35. await createNewItem('test2')
  36. expect(await count('.todo')).toBe(2)
  37. expect(await text('.todo:nth-child(2) label')).toBe('test2')
  38. expect(await text('.todo-count strong')).toBe('2')
  39. // toggle
  40. await page.click('.todo .toggle')
  41. expect(await count('.todo.completed')).toBe(1)
  42. expect(await classList('.todo:nth-child(1)')).toContain('completed')
  43. expect(await text('.todo-count strong')).toBe('1')
  44. expect(await isVisible('.clear-completed')).toBe(true)
  45. await createNewItem('test3')
  46. expect(await count('.todo')).toBe(3)
  47. expect(await text('.todo:nth-child(3) label')).toBe('test3')
  48. expect(await text('.todo-count strong')).toBe('2')
  49. await createNewItem('test4')
  50. await createNewItem('test5')
  51. expect(await count('.todo')).toBe(5)
  52. expect(await text('.todo-count strong')).toBe('4')
  53. // toggle more
  54. await page.click('.todo:nth-child(4) .toggle')
  55. await page.click('.todo:nth-child(5) .toggle')
  56. expect(await count('.todo.completed')).toBe(3)
  57. expect(await text('.todo-count strong')).toBe('2')
  58. // remove
  59. await removeItemAt(1)
  60. expect(await count('.todo')).toBe(4)
  61. expect(await count('.todo.completed')).toBe(2)
  62. expect(await text('.todo-count strong')).toBe('2')
  63. await removeItemAt(2)
  64. expect(await count('.todo')).toBe(3)
  65. expect(await count('.todo.completed')).toBe(2)
  66. expect(await text('.todo-count strong')).toBe('1')
  67. // remove all
  68. await page.click('.clear-completed')
  69. expect(await count('.todo')).toBe(1)
  70. expect(await text('.todo label')).toBe('test2')
  71. expect(await count('.todo.completed')).toBe(0)
  72. expect(await text('.todo-count strong')).toBe('1')
  73. expect(await isVisible('.clear-completed')).toBe(false)
  74. // prepare to test filters
  75. await createNewItem('test')
  76. await createNewItem('test')
  77. await page.click('.todo:nth-child(2) .toggle')
  78. await page.click('.todo:nth-child(3) .toggle')
  79. // active filter
  80. await page.click('.filters li:nth-child(2) a')
  81. expect(await count('.todo')).toBe(1)
  82. expect(await count('.todo.completed')).toBe(0)
  83. // add item with filter active
  84. await createNewItem('test')
  85. expect(await count('.todo')).toBe(2)
  86. // completed filter
  87. await page.click('.filters li:nth-child(3) a')
  88. expect(await count('.todo')).toBe(2)
  89. expect(await count('.todo.completed')).toBe(2)
  90. // filter on page load
  91. await page.goto(
  92. `file://${path.resolve(__dirname, '../classic/todomvc.html#active')}`
  93. )
  94. expect(await count('.todo')).toBe(2)
  95. expect(await count('.todo.completed')).toBe(0)
  96. expect(await text('.todo-count strong')).toBe('2')
  97. // completed on page load
  98. await page.goto(
  99. `file://${path.resolve(__dirname, '../classic/todomvc.html#completed')}`
  100. )
  101. expect(await count('.todo')).toBe(2)
  102. expect(await count('.todo.completed')).toBe(2)
  103. expect(await text('.todo-count strong')).toBe('2')
  104. // toggling with filter active
  105. await page.click('.todo .toggle')
  106. expect(await count('.todo')).toBe(1)
  107. await page.click('.filters li:nth-child(2) a')
  108. expect(await count('.todo')).toBe(3)
  109. await page.click('.todo .toggle')
  110. expect(await count('.todo')).toBe(2)
  111. // editing triggered by blur
  112. await page.click('.filters li:nth-child(1) a')
  113. await page.click('.todo:nth-child(1) label', { clickCount: 2 })
  114. expect(await count('.todo.editing')).toBe(1)
  115. expect(await isFocused('.todo:nth-child(1) .edit')).toBe(true)
  116. await clearValue('.todo:nth-child(1) .edit')
  117. await page.type('.todo:nth-child(1) .edit', 'edited!')
  118. await page.click('.new-todo') // blur
  119. expect(await count('.todo.editing')).toBe(0)
  120. expect(await text('.todo:nth-child(1) label')).toBe('edited!')
  121. // editing triggered by enter
  122. await page.click('.todo label', { clickCount: 2 })
  123. await enterValue('.todo:nth-child(1) .edit', 'edited again!')
  124. expect(await count('.todo.editing')).toBe(0)
  125. expect(await text('.todo:nth-child(1) label')).toBe('edited again!')
  126. // cancel
  127. await page.click('.todo label', { clickCount: 2 })
  128. await clearValue('.todo:nth-child(1) .edit')
  129. await page.type('.todo:nth-child(1) .edit', 'edited!')
  130. await page.keyboard.press('Escape')
  131. expect(await count('.todo.editing')).toBe(0)
  132. expect(await text('.todo:nth-child(1) label')).toBe('edited again!')
  133. // empty value should remove
  134. await page.click('.todo label', { clickCount: 2 })
  135. await enterValue('.todo:nth-child(1) .edit', ' ')
  136. expect(await count('.todo')).toBe(3)
  137. // toggle all
  138. await page.click('.toggle-all+label')
  139. expect(await count('.todo.completed')).toBe(3)
  140. await page.click('.toggle-all+label')
  141. expect(await count('.todo:not(.completed)')).toBe(3)
  142. })
  143. })
  144. async function isVisible(selector: string) {
  145. const display = await page.$eval(selector, (node: HTMLElement) => {
  146. return window.getComputedStyle(node).display
  147. })
  148. return display !== 'none'
  149. }
  150. async function isChecked(selector: string) {
  151. return await page.$eval(selector, (node: any) => node.checked)
  152. }
  153. async function count(selector: string) {
  154. return (await page.$$(selector)).length
  155. }
  156. async function text(selector: string) {
  157. return await page.$eval(selector, node => node.textContent)
  158. }
  159. async function value(selector: string) {
  160. return await page.$eval(selector, (node: any) => node.value)
  161. }
  162. async function classList(selector: string) {
  163. return await page.$eval(selector, (node: any) => [...node.classList])
  164. }
  165. async function isFocused(selector: string) {
  166. return await page.$eval(selector, node => node === document.activeElement)
  167. }
  168. async function clearValue(selector: string) {
  169. return await page.$eval(selector, (node: any) => (node.value = ''))
  170. }
  171. async function enterValue(selector: string, value: string) {
  172. const el = (await page.$(selector))!
  173. await el.evaluate((node: any) => (node.value = ''))
  174. await el.type(value)
  175. await el.press('Enter')
  176. }
  177. async function createNewItem(text: string) {
  178. const el = (await page.$('.new-todo'))!
  179. await el.type(text)
  180. await el.press('Enter')
  181. }
  182. async function removeItemAt(n: number) {
  183. const item = (await page.$('.todo:nth-child(' + n + ')'))!
  184. const itemBBox = (await item.boundingBox())!
  185. await page.mouse.move(itemBBox.x + 10, itemBBox.y + 10)
  186. await page.click('.todo:nth-child(' + n + ') .destroy')
  187. }