e2eUtils.ts 4.3 KB

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