diff --git a/package.json b/package.json index 378673e..d9c7f80 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "globals": "^15.3.0", "prettier": "^3.2.5", "release-plan": "^0.9.0", + "strip-ansi": "^7.1.0", "tmp-promise": "^3.0.3", "vitest": "^1.6.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84f3238..98e5c64 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,6 +42,9 @@ importers: release-plan: specifier: ^0.9.0 version: 0.9.0(encoding@0.1.13) + strip-ansi: + specifier: ^7.1.0 + version: 7.1.0 tmp-promise: specifier: ^3.0.3 version: 3.0.3 diff --git a/tests/default.test.mjs b/tests/default.test.mjs index 30e74fc..cd607c8 100644 --- a/tests/default.test.mjs +++ b/tests/default.test.mjs @@ -3,7 +3,8 @@ import { join } from 'path'; import tmp from 'tmp-promise'; import { execa } from 'execa'; import copyWithTemplate from '../lib/copy-with-template'; -import { existsSync } from 'fs'; +import { existsSync, writeFileSync } from 'fs'; +import stripAnsi from 'strip-ansi'; const blueprintPath = join(__dirname, '..'); const appName = 'fancy-app-in-test'; @@ -35,7 +36,11 @@ describe('basic functionality', function () { }); afterAll(async () => { - return tmpDir.cleanup(); + try { + await tmpDir.cleanup(); + } catch { + // if it fails to cleaup we don't want to break CI + } }); it('verify files', async function () { @@ -79,6 +84,74 @@ describe('basic functionality', function () { console.log(result.stdout); }); + it('successfully runs tests in dev mode', async function () { + await execa({ + cwd: join(tmpDir.path, appName), + })`pnpm install --save-dev testem http-proxy`; + let appURL; + + let server; + + try { + server = execa('pnpm', ['start'], { + cwd: join(tmpDir.path, appName), + }); + + await new Promise((resolve) => { + server.stdout.on('data', (line) => { + let result = /Local:\s+(https?:\/\/.*)\//g.exec( + stripAnsi(line.toString()), + ); + + if (result) { + appURL = result[1]; + resolve(); + } + }); + }); + + writeFileSync( + join(tmpDir.path, appName, 'testem-dev.js'), + `module.exports = { + test_page: 'tests/index.html?hidepassed', + disable_watching: true, + launch_in_ci: ['Chrome'], + launch_in_dev: ['Chrome'], + browser_start_timeout: 120, + browser_args: { + Chrome: { + ci: [ + // --no-sandbox is needed when running Chrome inside a container + process.env.CI ? '--no-sandbox' : null, + '--headless', + '--disable-dev-shm-usage', + '--disable-software-rasterizer', + '--mute-audio', + '--remote-debugging-port=0', + '--window-size=1440,900', + ].filter(Boolean), + }, + }, + middleware: [ + require(__dirname + '/testem-proxy.js')('${appURL}') + ], +}; +`, + ); + + let testResult = await execa( + 'pnpm', + ['testem', '--file', 'testem-dev.js', 'ci'], + { + cwd: join(tmpDir.path, appName), + }, + ); + expect(testResult.exitCode).to.eq(0, testResult.output); + } finally { + server?.kill('SIGINT'); + } + }); + it('successfully optimizes deps', function () { return execa('pnpm', ['vite', 'optimize', '--force'], { cwd: join(tmpDir.path, appName), diff --git a/tests/fixture/testem-proxy.js b/tests/fixture/testem-proxy.js new file mode 100644 index 0000000..c8c2b39 --- /dev/null +++ b/tests/fixture/testem-proxy.js @@ -0,0 +1,35 @@ +const httpProxy = require('http-proxy'); + +/* + This can be installed as a testem middleware to make testem run against an + arbitrary real webserver at targetURL. + + It allows testem to handle the well-known testem-specific paths and proxies + everything else, while rewriting the testem-added prefix out of your + "/tests/index.html" URL. +*/ + +module.exports = function testemProxy(targetURL) { + return function testemProxyHandler(app) { + const proxy = httpProxy.createProxyServer({ + changeOrigin: true, + ignorePath: true, + }); + + proxy.on('error', (err, _req, res) => { + res && res.status && res.status(500).json(err); + }); + + app.all('*', (req, res, next) => { + let url = req.url; + if (url === '/testem.js' || url.startsWith('/testem/')) { + return next(); + } + let m = /^(\/\d+)\/tests\/index.html/.exec(url); + if (m) { + url = url.slice(m[1].length); + } + proxy.web(req, res, { target: targetURL + url }); + }); + }; +}