e2eUtils.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import puppeteer from 'puppeteer'
  2. export const E2E_TIMEOUT = 30 * 1000
  3. const puppeteerOptions = process.env.CI
  4. ? { args: ['--no-sandbox', '--disable-setuid-sandbox'] }
  5. : {}
  6. const maxTries = 30
  7. export const timeout = (n: number) => new Promise(r => setTimeout(r, n))
  8. export async function expectByPolling(
  9. poll: () => Promise<any>,
  10. expected: string
  11. ) {
  12. for (let tries = 0; tries < maxTries; tries++) {
  13. const actual = (await poll()) || ''
  14. if (actual.indexOf(expected) > -1 || tries === maxTries - 1) {
  15. expect(actual).toMatch(expected)
  16. break
  17. } else {
  18. await timeout(50)
  19. }
  20. }
  21. }
  22. export function setupPuppeteer() {
  23. let browser: puppeteer.Browser
  24. let page: puppeteer.Page
  25. beforeAll(async () => {
  26. browser = await puppeteer.launch(puppeteerOptions)
  27. })
  28. beforeEach(async () => {
  29. page = await browser.newPage()
  30. await page.evaluateOnNewDocument(() => {
  31. localStorage.clear()
  32. })
  33. page.on('console', e => {
  34. if (e.type() === 'error') {
  35. const err = e.args()[0] as any
  36. console.error(
  37. `Error from Puppeteer-loaded page:\n`,
  38. err._remoteObject.description
  39. )
  40. }
  41. })
  42. })
  43. afterEach(async () => {
  44. await page.close()
  45. })
  46. afterAll(async () => {
  47. await browser.close()
  48. })
  49. async function click(selector: string, options?: puppeteer.ClickOptions) {
  50. await page.click(selector, options)
  51. }
  52. async function count(selector: string) {
  53. return (await page.$$(selector)).length
  54. }
  55. async function text(selector: string) {
  56. return await page.$eval(selector, node => node.textContent)
  57. }
  58. async function value(selector: string) {
  59. return await page.$eval(selector, node => (node as HTMLInputElement).value)
  60. }
  61. async function html(selector: string) {
  62. return await page.$eval(selector, node => node.innerHTML)
  63. }
  64. async function classList(selector: string) {
  65. return await page.$eval(selector, (node: any) => [...node.classList])
  66. }
  67. async function children(selector: string) {
  68. return await page.$eval(selector, (node: any) => [...node.children])
  69. }
  70. async function isVisible(selector: string) {
  71. const display = await page.$eval(selector, node => {
  72. return window.getComputedStyle(node).display
  73. })
  74. return display !== 'none'
  75. }
  76. async function isChecked(selector: string) {
  77. return await page.$eval(
  78. selector,
  79. node => (node as HTMLInputElement).checked
  80. )
  81. }
  82. async function isFocused(selector: string) {
  83. return await page.$eval(selector, node => node === document.activeElement)
  84. }
  85. async function setValue(selector: string, value: string) {
  86. await page.$eval(
  87. selector,
  88. (node, value) => {
  89. ;(node as HTMLInputElement).value = value as string
  90. node.dispatchEvent(new Event('input'))
  91. },
  92. value
  93. )
  94. }
  95. async function typeValue(selector: string, value: string) {
  96. const el = (await page.$(selector))!
  97. await el.evaluate(node => ((node as HTMLInputElement).value = ''))
  98. await el.type(value)
  99. }
  100. async function enterValue(selector: string, value: string) {
  101. const el = (await page.$(selector))!
  102. await el.evaluate(node => ((node as HTMLInputElement).value = ''))
  103. await el.type(value)
  104. await el.press('Enter')
  105. }
  106. async function clearValue(selector: string) {
  107. return await page.$eval(
  108. selector,
  109. node => ((node as HTMLInputElement).value = '')
  110. )
  111. }
  112. function timeout(time: number) {
  113. return page.evaluate(time => {
  114. return new Promise(r => {
  115. setTimeout(r, time)
  116. })
  117. }, time)
  118. }
  119. function nextFrame() {
  120. return page.evaluate(() => {
  121. return new Promise(resolve => {
  122. requestAnimationFrame(() => {
  123. requestAnimationFrame(resolve)
  124. })
  125. })
  126. })
  127. }
  128. return {
  129. page: () => page,
  130. click,
  131. count,
  132. text,
  133. value,
  134. html,
  135. classList,
  136. children,
  137. isVisible,
  138. isChecked,
  139. isFocused,
  140. setValue,
  141. typeValue,
  142. enterValue,
  143. clearValue,
  144. timeout,
  145. nextFrame
  146. }
  147. }