e2eUtils.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import path from 'path'
  2. import puppeteer from 'puppeteer'
  3. export function getExampleUrl(
  4. name: string,
  5. apiType: 'classic' | 'composition'
  6. ) {
  7. return `file://${path.resolve(
  8. __dirname,
  9. `../../examples/${apiType}/${name}/index.html`
  10. )}`
  11. }
  12. export const E2E_TIMEOUT = 30 * 1000
  13. const puppeteerOptions = process.env.CI
  14. ? { args: ['--no-sandbox', '--disable-setuid-sandbox'] }
  15. : { headless: !process.env.DEBUG }
  16. const maxTries = 30
  17. export const timeout = (n: number) => new Promise(r => setTimeout(r, n))
  18. export async function expectByPolling(
  19. poll: () => Promise<any>,
  20. expected: string
  21. ) {
  22. for (let tries = 0; tries < maxTries; tries++) {
  23. const actual = (await poll()) || ''
  24. if (actual.indexOf(expected) > -1 || tries === maxTries - 1) {
  25. expect(actual).toMatch(expected)
  26. break
  27. } else {
  28. await timeout(50)
  29. }
  30. }
  31. }
  32. export function setupPuppeteer() {
  33. let browser: puppeteer.Browser
  34. let page: puppeteer.Page
  35. beforeAll(async () => {
  36. browser = await puppeteer.launch(puppeteerOptions)
  37. })
  38. beforeEach(async () => {
  39. page = await browser.newPage()
  40. await page.evaluateOnNewDocument(() => {
  41. localStorage.clear()
  42. })
  43. page.on('console', e => {
  44. if (e.type() === 'error') {
  45. const err = e.args()[0]
  46. console.error(
  47. `Error from Puppeteer-loaded page:\n`,
  48. err._remoteObject.description
  49. )
  50. }
  51. })
  52. })
  53. afterEach(async () => {
  54. await page.close()
  55. })
  56. afterAll(async () => {
  57. await browser.close()
  58. })
  59. async function click(selector: string, options?: puppeteer.ClickOptions) {
  60. await page.click(selector, options)
  61. }
  62. async function count(selector: string) {
  63. return (await page.$$(selector)).length
  64. }
  65. async function text(selector: string) {
  66. return await page.$eval(selector, node => node.textContent)
  67. }
  68. async function value(selector: string) {
  69. return await page.$eval(selector, node => (node as HTMLInputElement).value)
  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. }