vitest/test/ui/setup.ts
yoho 4ea1f1d974
test: ui e2e (#2710)
* feat: ui test

* test: ui

* feat: no auto open browser

* fix: lint

* fix: test timeout

* fix: timeout

* fix: test

* fix: wait more times

* fix: kill

* fix: exit process

* fix: kill

* chore: update

* chore: update

* chore: update

* fix: lint

* fix: await page load

* chore: update

* fix: test

* fix: test

* fix: test

* feat: must had content

* chore: update

* chore: update

* chore: update

* fix: times

* fix: ports

* chore: update config

* fix: catch

* feat: asset command no error

* feat: log the command stdout

* fix: error

* chore: update

* chore: use the same port

* chore: update pnpm

* fix: error

* chore: update

* feat: test

* chore: update page register

* chore: ignore not close process

* fix: params

* fix: port

* feat: pipe

* feat: catch error

* feat: test report

* chore: update

* chore: update

* chore: update sna

* test: ui

* chore: update

* chore: update

* test: untilUpdated

* chore: untilUpdated

* test: format named

* test: url should update

* chore: update

* chore: fix lockfile

* chore: upate snapshot

---------

Co-authored-by: Vladimir Sheremet <sleuths.slews0s@icloud.com>
2023-02-11 21:16:23 +01:00

166 lines
3.5 KiB
TypeScript

/* eslint-disable import/no-mutable-exports */
import path from 'node:path'
import os from 'node:os'
import fs from 'fs-extra'
import fetch from 'node-fetch-native'
import { chromium } from 'playwright-chromium'
import type { Browser, Page } from 'playwright-chromium'
import { expect } from 'vitest'
import type { ExecaChildProcess } from 'execa'
import { execaCommand } from 'execa'
export let page!: Page
export let browser!: Browser
export const browserErrors: Error[] = []
export const ports = {
ui: 9000,
report: 9001,
}
const DIR = path.join(os.tmpdir(), 'vitest_playwright_global_setup')
export const isWindows = process.platform === 'win32'
export function timeout(time: number) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(null)
}, time)
})
}
export async function withRetry(
func: () => Promise<void>,
): Promise<void> {
const maxTries = 300
for (let tries = 0; tries < maxTries; tries++) {
try {
await func()
return
}
catch {}
await timeout(50)
}
await func()
}
export async function withLoadUrl(url: string): Promise<void> {
return withRetry(async () => {
const res = await fetch(url)
if (!res.ok)
throw new Error('url not loaded')
})
}
export async function killProcess(
serverProcess: ExecaChildProcess,
): Promise<void> {
if (isWindows) {
try {
const { execaCommandSync } = await import('execa')
execaCommandSync(`taskkill /pid ${serverProcess.pid} /T /F`)
}
catch (e) {
console.error('failed to taskkill:', e)
}
}
else {
serverProcess.kill('SIGTERM', { forceKillAfterTimeout: 2000 })
}
}
export async function startChromium() {
const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf-8')
if (!wsEndpoint)
throw new Error('wsEndpoint not found')
browser = await chromium.connect(wsEndpoint)
page = await browser.newPage()
try {
page.on('pageerror', (error) => {
browserErrors.push(error)
})
}
catch (e) {
await page.close()
throw e
}
return async () => {
await page?.close()
if (browser)
await browser.close()
}
}
export async function startServerCommand(root: string, command: string, url: string) {
let error: any
const exitChromium = await startChromium()
const subProcess = execaCommand(command, {
cwd: root,
env: {
...process.env,
CI: 'true',
NO_COLOR: 'true',
},
stdio: 'pipe',
})
subProcess.catch((e) => {
error = e
})
const killSubProcess = () => killProcess(subProcess)
subProcess.stdout?.on('data', (d) => {
// eslint-disable-next-line no-console
console.log(d.toString())
})
expect(error).not.toBeTruthy()
async function exit() {
try {
await killSubProcess()
await exitChromium()
}
catch (e) {
console.error(
`error while killing process ${command}:`,
e,
)
}
}
try {
await withLoadUrl(url)
await page.goto(url)
}
catch (e) {
await exit()
throw e
}
return exit
}
/**
* Poll a getter until the value it returns includes the expected value.
*/
export async function untilUpdated(
poll: () => string | Promise<string | null> | null,
expected: string,
): Promise<void> {
const maxTries = process.env.CI ? 200 : 50
for (let tries = 0; tries < maxTries; tries++) {
const actual = (await poll()) ?? ''
if (actual.includes(expected) || tries === maxTries - 1) {
expect(actual).toMatch(expected)
break
}
else {
await timeout(50)
}
}
}