e2eUtils.ts 4.3 KB

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