e2eUtils.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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 = 20
  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. beforeEach(async () => {
  26. browser = await puppeteer.launch(puppeteerOptions)
  27. page = await browser.newPage()
  28. page.on('console', e => {
  29. if (e.type() === 'error') {
  30. const err = e.args()[0] as any
  31. console.error(
  32. `Error from Puppeteer-loaded page:\n`,
  33. err._remoteObject.description
  34. )
  35. }
  36. })
  37. })
  38. afterEach(async () => {
  39. await browser.close()
  40. })
  41. async function click(selector: string, options?: puppeteer.ClickOptions) {
  42. await page.click(selector, options)
  43. }
  44. async function count(selector: string) {
  45. return (await page.$$(selector)).length
  46. }
  47. async function text(selector: string) {
  48. return await page.$eval(selector, node => node.textContent)
  49. }
  50. async function value(selector: string) {
  51. return await page.$eval(selector, node => (node as HTMLInputElement).value)
  52. }
  53. async function html(selector: string) {
  54. return await page.$eval(selector, node => node.innerHTML)
  55. }
  56. async function classList(selector: string) {
  57. return await page.$eval(selector, (node: any) => [...node.classList])
  58. }
  59. async function children(selector: string) {
  60. return await page.$eval(selector, (node: any) => [...node.children])
  61. }
  62. async function isVisible(selector: string) {
  63. const display = await page.$eval(selector, node => {
  64. return window.getComputedStyle(node).display
  65. })
  66. return display !== 'none'
  67. }
  68. async function isChecked(selector: string) {
  69. return await page.$eval(
  70. selector,
  71. node => (node as HTMLInputElement).checked
  72. )
  73. }
  74. async function isFocused(selector: string) {
  75. return await page.$eval(selector, node => node === document.activeElement)
  76. }
  77. async function setValue(selector: string, value: string) {
  78. await page.$eval(
  79. selector,
  80. (node, value) => {
  81. ;(node as HTMLInputElement).value = value
  82. node.dispatchEvent(new Event('input'))
  83. },
  84. value
  85. )
  86. }
  87. async function typeValue(selector: string, value: string) {
  88. const el = (await page.$(selector))!
  89. await el.evaluate(node => ((node as HTMLInputElement).value = ''))
  90. await el.type(value)
  91. }
  92. async function enterValue(selector: string, value: string) {
  93. const el = (await page.$(selector))!
  94. await el.evaluate(node => ((node as HTMLInputElement).value = ''))
  95. await el.type(value)
  96. await el.press('Enter')
  97. }
  98. async function clearValue(selector: string) {
  99. return await page.$eval(
  100. selector,
  101. node => ((node as HTMLInputElement).value = '')
  102. )
  103. }
  104. function timeout(time: number) {
  105. return page.evaluate(time => {
  106. return new Promise(r => {
  107. setTimeout(r, time)
  108. })
  109. }, time)
  110. }
  111. function nextFrame() {
  112. return page.evaluate(() => {
  113. return new Promise(resolve => {
  114. requestAnimationFrame(() => {
  115. requestAnimationFrame(resolve)
  116. })
  117. })
  118. })
  119. }
  120. return {
  121. page: () => page,
  122. click,
  123. count,
  124. text,
  125. value,
  126. html,
  127. classList,
  128. children,
  129. isVisible,
  130. isChecked,
  131. isFocused,
  132. setValue,
  133. typeValue,
  134. enterValue,
  135. clearValue,
  136. timeout,
  137. nextFrame
  138. }
  139. }