-
-
Notifications
You must be signed in to change notification settings - Fork 6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(cli): add playground with tests for cli
- Loading branch information
Showing
7 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { port } from './serve' | ||
|
||
test('cli should work', async () => { | ||
// this test uses a custom serve implementation, so regular helpers for browserLogs and goto don't work | ||
// do the same thing manually | ||
const logs = [] | ||
const onConsole = (msg) => { | ||
logs.push(msg.text()) | ||
} | ||
try { | ||
page.on('console', onConsole) | ||
await page.goto(`http://localhost:${port}/`) | ||
expect(await page.textContent('.app')).toBe('vite cli works!') | ||
expect(logs.some((msg) => msg.match('vite cli works!'))).toBe(true) | ||
} finally { | ||
page.off('console', onConsole) | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// @ts-check | ||
// this is automtically detected by scripts/jestPerTestSetup.ts and will replace | ||
// the default e2e test serve behavior | ||
|
||
// eslint-disable-next-line node/no-restricted-require | ||
const execa = require('execa') | ||
|
||
// make sure this port is unique | ||
const port = (exports.port = 9510) | ||
|
||
/** | ||
* @param {string} root | ||
* @param {boolean} isProd | ||
*/ | ||
exports.serve = async function serve(root, isProd) { | ||
// collect stdout and stderr streams from child processes here to avoid interfering with regular jest output | ||
const streams = { | ||
build: { out: [], err: [] }, | ||
server: { out: [], err: [] } | ||
} | ||
// helpers to collect streams | ||
const collectStreams = (name, process) => { | ||
process.stdout.on('data', (d) => streams[name].out.push(d.toString())) | ||
process.stderr.on('data', (d) => streams[name].err.push(d.toString())) | ||
} | ||
const collectErrorStreams = (name, e) => { | ||
e.stdout && streams[name].out.push(e.stdout) | ||
e.stderr && streams[name].err.push(e.stderr) | ||
} | ||
|
||
// helper to output stream content on error | ||
const printStreamsToConsole = async (name) => { | ||
const std = streams[name] | ||
if (std.out && std.out.length > 0) { | ||
console.log(`stdout of ${name}\n${std.out.join('\n')}\n`) | ||
} | ||
if (std.err && std.err.length > 0) { | ||
console.log(`stderr of ${name}\n${std.err.join('\n')}\n`) | ||
} | ||
} | ||
|
||
// only run `vite build` when needed | ||
if (isProd) { | ||
try { | ||
const buildProcess = execa('vite', ['build'], { | ||
preferLocal: true, | ||
cwd: root, | ||
stdio: 'pipe' | ||
}) | ||
collectStreams('build', buildProcess) | ||
await buildProcess | ||
} catch (e) { | ||
collectErrorStreams('build', e) | ||
await printStreamsToConsole('build') | ||
throw e | ||
} | ||
} | ||
|
||
// run `vite --port x` or `vite preview --port x` to start server | ||
const serverProcess = execa( | ||
'vite', | ||
[isProd ? 'preview' : '', '--port', `${port}`], | ||
{ | ||
preferLocal: true, | ||
cwd: root, | ||
stdio: 'pipe' | ||
} | ||
) | ||
collectStreams('server', serverProcess) | ||
|
||
// close server helper, send SIGTERM followed by SIGKILL if needed, give up after 3sec | ||
const close = async () => { | ||
if (serverProcess) { | ||
let timer | ||
const timerPromise = new Promise( | ||
(_, reject) => | ||
(timer = setTimeout(() => { | ||
reject(`server process still alive after 3s`) | ||
}, 3000)) | ||
) | ||
|
||
serverProcess.kill('SIGTERM', { forceKillAfterTimeout: 2000 }) | ||
|
||
try { | ||
await Promise.race([serverProcess, timerPromise]).finally(() => { | ||
clearTimeout(timer) | ||
}) | ||
} catch (e) { | ||
if (!e.killed) { | ||
collectErrorStreams('server', e) | ||
console.error('failed to end vite cli process', e) | ||
await printStreamsToConsole('server') | ||
} | ||
} | ||
} | ||
} | ||
|
||
try { | ||
await startedOnPort(serverProcess, port, 3000) | ||
return { | ||
close | ||
} | ||
} catch (e) { | ||
console.error('failed to start server', e) | ||
try { | ||
await close() | ||
} catch (e1) { | ||
console.error('failed to close server process', e1) | ||
} | ||
} | ||
} | ||
|
||
// helper to validate that server was started on the correct port | ||
async function startedOnPort(serverProcess, port, timeout) { | ||
let id | ||
let checkPort | ||
const timerPromise = new Promise( | ||
(_, reject) => | ||
(id = setTimeout(() => { | ||
reject(`timeout for server start after ${timeout}`) | ||
}, timeout)) | ||
) | ||
const startedPromise = new Promise((resolve, reject) => { | ||
checkPort = (data) => { | ||
const str = data.toString() | ||
// hack, console output may contain color code gibberish | ||
// skip gibberish between localhost: and port number | ||
const match = str.match(/(http:\/\/localhost:)(?:.*)(\d{4})/) | ||
if (match) { | ||
const startedPort = parseInt(match[2], 10) | ||
if (startedPort === port) { | ||
resolve() | ||
} else { | ||
const msg = `test server started on ${startedPort} instead of ${port}` | ||
console.log(msg) | ||
reject(msg) | ||
} | ||
} | ||
} | ||
|
||
serverProcess.stdout.on('data', checkPort) | ||
}) | ||
|
||
return Promise.race([timerPromise, startedPromise]).finally(() => { | ||
serverProcess.stdout.off('data', checkPort) | ||
clearTimeout(id) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<script type="module" src="./index.js"></script> | ||
|
||
<div class="app">vite cli works!</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
console.log('vite cli works!') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"name": "test-cli", | ||
"private": true, | ||
"version": "0.0.0", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "vite build", | ||
"debug": "node --inspect-brk ../../vite/bin/vite", | ||
"serve": "vite preview" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const { defineConfig } = require('vite') | ||
|
||
module.exports = defineConfig({ | ||
build: { | ||
//speed up build | ||
minify: false, | ||
target: 'esnext' | ||
} | ||
}) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.