From 1c55b894c9853bb6c8c2ac26d310482128088740 Mon Sep 17 00:00:00 2001 From: Miel Truyen Date: Sat, 27 Jan 2024 20:54:59 +0100 Subject: [PATCH] test: refactoring tests --- src/index.ts | 1 + test/evaluated-web-bundle/test.js | 2 +- test/jsx-web-app/test.js | 6 +- test/util/index.ts | 4 +- test/util/misc.js | 2 + ...-browser-test.ts => puppeteer-run-test.ts} | 3 +- test/util/{test-server.ts => serve-test.ts} | 106 ++++++++++++------ 7 files changed, 86 insertions(+), 38 deletions(-) rename test/util/{run-browser-test.ts => puppeteer-run-test.ts} (98%) rename test/util/{test-server.ts => serve-test.ts} (68%) diff --git a/src/index.ts b/src/index.ts index 3dcae65..1b253e8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -265,6 +265,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin { } while (nodeQueue.length > 0); } + // Beware leak of AST (we're starting MagicString on a parsed and modified version of the HTML file, sourcemappings in the HTML file will be off. (can't add a sourcemap for a html file anyway, unless it is outputted as JS module) let htmlJS = new MagicString(serializeHtml(htmlModule.document)); htmlJS.replaceAll(/`/g,'\\\`').replaceAll(/\$\{/g,'\\${'); diff --git a/test/evaluated-web-bundle/test.js b/test/evaluated-web-bundle/test.js index 82219a3..fe18652 100644 --- a/test/evaluated-web-bundle/test.js +++ b/test/evaluated-web-bundle/test.js @@ -5,7 +5,7 @@ import { rollup } from "rollup"; import urlPlugin from "@rollup/plugin-url"; import html from "../../src/index.ts"; -import serveTest from "../util/test-server.ts"; +import serveTest from "../util/serve-test.ts"; /** * @type {OutputOptions} diff --git a/test/jsx-web-app/test.js b/test/jsx-web-app/test.js index 2a76ef6..b0897c5 100644 --- a/test/jsx-web-app/test.js +++ b/test/jsx-web-app/test.js @@ -12,7 +12,7 @@ import typescriptPlugin from "@rollup/plugin-typescript"; import replacePlugin from "@rollup/plugin-replace"; import html from "../../src/index.ts"; -import serveTest from "../util/test-server.ts"; +import serveTest from "../util/serve-test.ts"; @@ -30,6 +30,7 @@ const output= { import {fileURLToPath} from "node:url"; import handlebars from "handlebars"; +import {debugPrintOutput, getCode} from "../util/index.ts"; const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(join(__dirname, 'fixtures')); @@ -86,5 +87,8 @@ test.serial('web-bundle', async (t) => { ], }); const generated = await bundle.generate(output); + + // const code = await getCode(bundle, output); + // debugPrintOutput('jsx-web-app',code); }); diff --git a/test/util/index.ts b/test/util/index.ts index 8b95f2a..f838874 100644 --- a/test/util/index.ts +++ b/test/util/index.ts @@ -1,6 +1,6 @@ export * from "./code-output.ts"; export * from "./print-code-output.ts"; -export * from "./test-server.ts"; +export * from "./serve-test.ts"; -export * from './misc.js'; +// export * from './misc.js'; diff --git a/test/util/misc.js b/test/util/misc.js index c721774..68b0e02 100644 --- a/test/util/misc.js +++ b/test/util/misc.js @@ -1,3 +1,5 @@ +// This is still from the old rollup plugin we forked from. For now not used. + import path from "node:path"; import process from "node:process"; diff --git a/test/util/run-browser-test.ts b/test/util/puppeteer-run-test.ts similarity index 98% rename from test/util/run-browser-test.ts rename to test/util/puppeteer-run-test.ts index f7571c5..f1281f7 100644 --- a/test/util/run-browser-test.ts +++ b/test/util/puppeteer-run-test.ts @@ -10,6 +10,7 @@ import {isInDebugMode} from "./debug-mode.ts"; export type PageTestCallback = (page: Page)=>Promise; + export interface TestFilterOptions{ html?: boolean console?: ('log'|'error'|'warn')[] | true @@ -56,7 +57,7 @@ export interface TestOutput{ * @param opts * @param hostUrl */ -export async function runTest(opts: Partial, hostUrl: string){ +export async function puppeteerRunTest(opts: Partial, hostUrl: string){ const options : TestOptions = ({ ...defaultOptions, ...opts, diff --git a/test/util/test-server.ts b/test/util/serve-test.ts similarity index 68% rename from test/util/test-server.ts rename to test/util/serve-test.ts index 1900865..b074263 100644 --- a/test/util/test-server.ts +++ b/test/util/serve-test.ts @@ -4,10 +4,12 @@ */ -import {runTest, TestFilterOptions, PageTestCallback} from "./run-browser-test.ts"; +import {puppeteerRunTest, TestFilterOptions, PageTestCallback} from "./puppeteer-run-test.ts"; import {isInDebugMode} from "./debug-mode.ts"; import {resolve, posix} from "node:path"; +import fs from "node:fs/promises"; +import type {Stats} from "node:fs"; import { createServer as createHttpsServer } from 'https' import { createServer} from 'http' @@ -26,6 +28,9 @@ import type { } from 'http' import type { ServerOptions } from 'https' +import type {ExecutionContext} from "ava"; +import {createReadStream} from "fs"; + type TypeMap = { [key: string]: string[]; @@ -45,6 +50,11 @@ export interface RollupServeTestOptions { */ filterOutput?: TestFilterOptions; + /** + * Fallback to serving from a specified srcDir + */ + srcDir?: string|boolean; + /** * A callback to manually take control of the page and simulate user interactions */ @@ -52,7 +62,7 @@ export interface RollupServeTestOptions { /** * The AVA context used to test (ie t.snapshot(..) ) */ - t: any + t: ExecutionContext /** * Set to `true` to return index.html (200) instead of error page (404) @@ -97,6 +107,7 @@ export interface RollupServeTestOptions { onListening?: (server: Server) => void } + /** * Serve your rolled up bundle like webpack-dev-server * @param {import('..').RollupServeOptions} options @@ -107,6 +118,7 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin { port: 0, headers: {}, historyApiFallback: true, + srcDir: '', // Serve source dir as fallback (for sourcemaps / debugging) onListening: function noop (){}, ...options||{}, https: options.https??false, @@ -116,7 +128,19 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin { let server : Server; let bundle : OutputBundle = {}; - const requestListener = (request: IncomingMessage, response: ServerResponse) => { + const logTest = (msg: string, mode: 'info'|'warn' = 'info')=>{ + if(isInDebugMode()){ + console.log(msg); + } + const modeColor = { + green: 32, + info: 34, + warn: 33, + }[mode]; + testOptions.t.log(`\u001b[${modeColor}m${msg}\u001b[0m`); + } + + const requestListener = async (request: IncomingMessage, response: ServerResponse) => { // Remove querystring const unsafePath = decodeURI(request.url!.split('?')[0]) @@ -130,22 +154,56 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin { function urlToFilePath(url:string){ return url[0]==='/'?url.slice(1):url; } - let filePath = urlToFilePath(urlPath); // Todo check if we need to strip '/' - let file: OutputChunk|OutputAsset; - if(!bundle[filePath] && testOptions.historyApiFallback) { - const fallbackPath = typeof testOptions.historyApiFallback === 'string' + let filePath = urlToFilePath(urlPath); + let absPath: string | undefined = undefined; + let stats: Stats | undefined = undefined; + + if(!bundle[filePath]){ + if(testOptions.srcDir || testOptions.srcDir===''){ + try{ + absPath = resolve(testOptions.srcDir||'',filePath); + stats = await fs.stat(absPath); + }catch(err){ + // File not found + } + } + if(!(stats?.isFile()) && testOptions.historyApiFallback) { + const fallbackPath = typeof testOptions.historyApiFallback === 'string' ? testOptions.historyApiFallback : '/index.html'; - if(bundle[urlToFilePath(fallbackPath)]){ - filePath = urlToFilePath(fallbackPath); + if(bundle[urlToFilePath(fallbackPath)]){ + filePath = urlToFilePath(fallbackPath); + } } } - file = bundle[filePath]; - if(!file){ - return notFound(response, filePath); - }else{ + + const mimeType = mime.getType(filePath!); + if(bundle[filePath]) { + let file: OutputChunk | OutputAsset = bundle[filePath]; const content = (file).code || (file).source; // Todo might need to read a source file; - return found(response, mime.getType(filePath!), content); + response.writeHead(200, {'Content-Type': mimeType || 'text/plain'}); + response.end(content, 'utf-8'); + logTest(`[200] ${request.url}`); + return; + }else if(stats?.isFile()){ + response.writeHead(200, { + 'Content-Type': mimeType || 'text/plain', + 'Content-Length': stats.size, + 'Last-Modified': stats.mtime.toUTCString() + }); + const content = await fs.readFile(absPath!); + response.end(content); + response.end(); + logTest(`[200] ${request.url} (src)`); + }else{ + response.writeHead(404) + response.end( + '404 Not Found' + '\n\n' + filePath, + 'utf-8' + ) + + logTest(`[404] ${request.url}`, "warn"); + return; } } @@ -207,7 +265,7 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin { if (first) { first = false - const testOutput = await runTest({ + const testOutput = await puppeteerRunTest({ page: testOptions.path!, cb: testOptions.cb, filterOutput: testOptions.filterOutput, @@ -221,21 +279,3 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin { } } } - - -function notFound (response: ServerResponse, filePath: string) { - response.writeHead(404) - response.end( - '404 Not Found' + '\n\n' + filePath, - 'utf-8' - ) -} - -function found (response: ServerResponse, mimeType: string|null, content: any) { - response.writeHead(200, { 'Content-Type': mimeType || 'text/plain' }) - response.end(content, 'utf-8') -} - -function green (text: string) { - return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m' -}