2020-12-20 03:33:13 +00:00
|
|
|
import fs from 'fs-extra'
|
|
|
|
import * as http from 'http'
|
2021-01-25 22:07:57 +00:00
|
|
|
import { resolve, dirname } from 'path'
|
2020-12-20 03:33:13 +00:00
|
|
|
import sirv from 'sirv'
|
2021-06-21 15:50:26 +00:00
|
|
|
import {
|
|
|
|
createServer,
|
|
|
|
build,
|
|
|
|
ViteDevServer,
|
|
|
|
UserConfig,
|
|
|
|
PluginOption,
|
|
|
|
ResolvedConfig
|
|
|
|
} from 'vite'
|
2020-12-20 03:33:13 +00:00
|
|
|
import { Page } from 'playwright-chromium'
|
2021-06-21 15:50:26 +00:00
|
|
|
// eslint-disable-next-line node/no-extraneous-import
|
|
|
|
import { RollupWatcher, RollupWatcherEvent } from 'rollup'
|
2020-12-20 03:33:13 +00:00
|
|
|
|
|
|
|
const isBuildTest = !!process.env.VITE_TEST_BUILD
|
|
|
|
|
2021-05-29 14:04:32 +00:00
|
|
|
export function slash(p: string): string {
|
|
|
|
return p.replace(/\\/g, '/')
|
|
|
|
}
|
|
|
|
|
2020-12-20 03:33:13 +00:00
|
|
|
// injected by the test env
|
2021-01-25 20:02:57 +00:00
|
|
|
declare global {
|
2021-05-05 03:34:14 +00:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
2021-01-25 20:02:57 +00:00
|
|
|
namespace NodeJS {
|
|
|
|
interface Global {
|
|
|
|
page?: Page
|
|
|
|
viteTestUrl?: string
|
2021-06-21 15:50:26 +00:00
|
|
|
watcher?: RollupWatcher
|
2021-01-25 20:02:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-20 03:33:13 +00:00
|
|
|
|
|
|
|
let server: ViteDevServer | http.Server
|
|
|
|
let tempDir: string
|
|
|
|
let err: Error
|
|
|
|
|
2020-12-24 04:28:17 +00:00
|
|
|
const logs = ((global as any).browserLogs = [])
|
2020-12-23 23:15:09 +00:00
|
|
|
const onConsole = (msg) => {
|
|
|
|
logs.push(msg.text())
|
|
|
|
}
|
2020-12-23 04:07:57 +00:00
|
|
|
|
2020-12-20 03:33:13 +00:00
|
|
|
beforeAll(async () => {
|
2021-01-25 20:02:57 +00:00
|
|
|
const page = global.page
|
|
|
|
if (!page) {
|
|
|
|
return
|
|
|
|
}
|
2020-12-20 03:33:13 +00:00
|
|
|
try {
|
2020-12-23 23:15:09 +00:00
|
|
|
page.on('console', onConsole)
|
|
|
|
|
2020-12-20 03:33:13 +00:00
|
|
|
const testPath = expect.getState().testPath
|
2020-12-24 17:09:38 +00:00
|
|
|
const testName = slash(testPath).match(/playground\/([\w-]+)\//)?.[1]
|
2020-12-20 03:33:13 +00:00
|
|
|
|
|
|
|
// if this is a test placed under playground/xxx/__tests__
|
|
|
|
// start a vite server in that directory.
|
|
|
|
if (testName) {
|
|
|
|
const playgroundRoot = resolve(__dirname, '../packages/playground')
|
|
|
|
const srcDir = resolve(playgroundRoot, testName)
|
|
|
|
tempDir = resolve(__dirname, '../temp', testName)
|
|
|
|
await fs.copy(srcDir, tempDir, {
|
2020-12-21 23:37:04 +00:00
|
|
|
dereference: true,
|
2020-12-20 03:33:13 +00:00
|
|
|
filter(file) {
|
2020-12-23 23:15:09 +00:00
|
|
|
file = slash(file)
|
2020-12-25 23:16:54 +00:00
|
|
|
return (
|
|
|
|
!file.includes('__tests__') &&
|
|
|
|
!file.includes('node_modules') &&
|
|
|
|
!file.match(/dist(\/|$)/)
|
|
|
|
)
|
2020-12-20 03:33:13 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-01-25 22:07:57 +00:00
|
|
|
const testCustomServe = resolve(dirname(testPath), 'serve.js')
|
|
|
|
if (fs.existsSync(testCustomServe)) {
|
|
|
|
// test has custom server configuration.
|
|
|
|
const { serve } = require(testCustomServe)
|
|
|
|
server = await serve(tempDir, isBuildTest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-12-22 03:00:54 +00:00
|
|
|
const options: UserConfig = {
|
|
|
|
root: tempDir,
|
2021-04-28 16:50:44 +00:00
|
|
|
logLevel: 'silent',
|
2020-12-22 04:15:38 +00:00
|
|
|
server: {
|
|
|
|
watch: {
|
2020-12-22 20:34:02 +00:00
|
|
|
// During tests we edit the files too fast and sometimes chokidar
|
|
|
|
// misses change events, so enforce polling for consistency
|
|
|
|
usePolling: true,
|
2020-12-22 21:27:36 +00:00
|
|
|
interval: 100
|
2021-05-05 03:30:43 +00:00
|
|
|
},
|
2021-05-15 10:32:37 +00:00
|
|
|
host: true,
|
|
|
|
fsServe: {
|
|
|
|
strict: !isBuildTest
|
|
|
|
}
|
2021-01-08 23:33:15 +00:00
|
|
|
},
|
|
|
|
build: {
|
2021-05-05 14:05:51 +00:00
|
|
|
// skip transpilation during tests to make it faster
|
2021-01-08 23:33:15 +00:00
|
|
|
target: 'esnext'
|
2020-12-22 04:15:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-20 03:33:13 +00:00
|
|
|
|
|
|
|
if (!isBuildTest) {
|
2021-01-06 04:13:30 +00:00
|
|
|
process.env.VITE_INLINE = 'inline-serve'
|
2020-12-22 03:00:54 +00:00
|
|
|
server = await (await createServer(options)).listen()
|
2021-01-22 22:45:51 +00:00
|
|
|
// use resolved port/base from server
|
|
|
|
const base = server.config.base === '/' ? '' : server.config.base
|
2021-05-12 17:13:44 +00:00
|
|
|
const url =
|
|
|
|
(global.viteTestUrl = `http://localhost:${server.config.server.port}${base}`)
|
2020-12-20 03:33:13 +00:00
|
|
|
await page.goto(url)
|
|
|
|
} else {
|
2021-01-06 04:13:30 +00:00
|
|
|
process.env.VITE_INLINE = 'inline-build'
|
2021-06-21 15:50:26 +00:00
|
|
|
// determine build watch
|
|
|
|
let resolvedConfig: ResolvedConfig
|
|
|
|
const resolvedPlugin: () => PluginOption = () => ({
|
|
|
|
name: 'vite-plugin-watcher',
|
|
|
|
configResolved(config) {
|
|
|
|
resolvedConfig = config
|
|
|
|
}
|
|
|
|
})
|
|
|
|
options.plugins = [resolvedPlugin()]
|
|
|
|
const rollupOutput = await build(options)
|
|
|
|
const isWatch = !!resolvedConfig!.build.watch
|
|
|
|
// in build watch,call startStaticServer after the build is complete
|
|
|
|
if (isWatch) {
|
|
|
|
global.watcher = rollupOutput as RollupWatcher
|
|
|
|
await notifyRebuildComplete(global.watcher)
|
|
|
|
}
|
2021-01-25 20:02:57 +00:00
|
|
|
const url = (global.viteTestUrl = await startStaticServer())
|
2020-12-20 03:33:13 +00:00
|
|
|
await page.goto(url)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
// jest doesn't exit if our setup has error here
|
|
|
|
// https://github.com/facebook/jest/issues/2713
|
|
|
|
err = e
|
2021-04-28 16:50:44 +00:00
|
|
|
|
2021-05-05 03:34:14 +00:00
|
|
|
// Closing the page since an error in the setup, for example a runtime error
|
2021-04-28 16:50:44 +00:00
|
|
|
// when building the playground should skip further tests.
|
|
|
|
// If the page remains open, a command like `await page.click(...)` produces
|
|
|
|
// a timeout with an exception that hides the real error in the console.
|
|
|
|
await page.close()
|
2020-12-20 03:33:13 +00:00
|
|
|
}
|
2021-03-27 08:43:48 +00:00
|
|
|
}, 30000)
|
2020-12-20 03:33:13 +00:00
|
|
|
|
|
|
|
afterAll(async () => {
|
2021-04-22 19:26:40 +00:00
|
|
|
global.page?.off('console', onConsole)
|
|
|
|
await global.page?.close()
|
|
|
|
await server?.close()
|
2020-12-20 03:33:13 +00:00
|
|
|
if (err) {
|
|
|
|
throw err
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
function startStaticServer(): Promise<string> {
|
2020-12-22 21:27:36 +00:00
|
|
|
// check if the test project has base config
|
|
|
|
const configFile = resolve(tempDir, 'vite.config.js')
|
|
|
|
let config: UserConfig
|
|
|
|
try {
|
|
|
|
config = require(configFile)
|
|
|
|
} catch (e) {}
|
2021-01-22 22:45:51 +00:00
|
|
|
const base = (config?.base || '/') === '/' ? '' : config.base
|
2020-12-22 21:27:36 +00:00
|
|
|
|
2021-01-07 01:46:47 +00:00
|
|
|
// @ts-ignore
|
|
|
|
if (config && config.__test__) {
|
|
|
|
// @ts-ignore
|
|
|
|
config.__test__()
|
|
|
|
}
|
|
|
|
|
2020-12-20 03:33:13 +00:00
|
|
|
// start static file server
|
2020-12-27 05:47:18 +00:00
|
|
|
const serve = sirv(resolve(tempDir, 'dist'))
|
|
|
|
const httpServer = (server = http.createServer((req, res) => {
|
|
|
|
if (req.url === '/ping') {
|
|
|
|
res.statusCode = 200
|
|
|
|
res.end('pong')
|
|
|
|
} else {
|
|
|
|
serve(req, res)
|
|
|
|
}
|
|
|
|
}))
|
2020-12-20 03:33:13 +00:00
|
|
|
let port = 5000
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const onError = (e: any) => {
|
|
|
|
if (e.code === 'EADDRINUSE') {
|
|
|
|
httpServer.close()
|
|
|
|
httpServer.listen(++port)
|
|
|
|
} else {
|
|
|
|
reject(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
httpServer.on('error', onError)
|
|
|
|
httpServer.listen(port, () => {
|
|
|
|
httpServer.removeListener('error', onError)
|
2020-12-22 21:27:36 +00:00
|
|
|
resolve(`http://localhost:${port}${base}`)
|
2020-12-20 03:33:13 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2021-06-21 15:50:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Send the rebuild complete message in build watch
|
|
|
|
*/
|
|
|
|
export async function notifyRebuildComplete(
|
|
|
|
watcher: RollupWatcher
|
|
|
|
): Promise<RollupWatcher> {
|
|
|
|
let callback: (event: RollupWatcherEvent) => void
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
callback = (event) => {
|
|
|
|
if (event.code === 'END') {
|
|
|
|
resolve(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
watcher.on('event', callback)
|
|
|
|
})
|
|
|
|
return watcher.removeListener('event', callback)
|
|
|
|
}
|