mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
Tests: replace express with basic Node server
Closes gh-5531
This commit is contained in:
parent
af599d0d63
commit
b4ab47afd7
@ -205,7 +205,15 @@ module.exports = [
|
||||
},
|
||||
rules: {
|
||||
...jqueryConfig.rules,
|
||||
"no-implicit-globals": "error"
|
||||
"no-implicit-globals": "error",
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
args: "after-used",
|
||||
argsIgnorePattern: "^_",
|
||||
caughtErrorsIgnorePattern: "^_"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@ -271,7 +279,7 @@ module.exports = [
|
||||
"test/node_smoke_tests/**",
|
||||
"test/bundler_smoke_tests/**/*",
|
||||
"test/promises_aplus_adapters/**",
|
||||
"test/middleware-mockserver.js"
|
||||
"test/middleware-mockserver.cjs"
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: "latest",
|
||||
|
2414
package-lock.json
generated
2414
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@ -61,35 +61,33 @@
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.24.8",
|
||||
"@babel/core": "7.24.9",
|
||||
"@babel/core": "7.25.2",
|
||||
"@babel/plugin-transform-for-of": "7.24.7",
|
||||
"@prantlf/jsonlint": "14.0.3",
|
||||
"@types/selenium-webdriver": "4.1.24",
|
||||
"body-parser": "1.20.2",
|
||||
"archiver": "7.0.1",
|
||||
"bootstrap": "5.3.3",
|
||||
"browserstack-local": "1.5.5",
|
||||
"chalk": "5.3.0",
|
||||
"colors": "1.4.0",
|
||||
"commitplease": "3.2.0",
|
||||
"concurrently": "8.2.2",
|
||||
"core-js-bundle": "3.37.1",
|
||||
"core-js-bundle": "3.38.0",
|
||||
"cross-env": "7.0.3",
|
||||
"diff": "5.2.0",
|
||||
"eslint": "9.4.0",
|
||||
"eslint": "9.8.0",
|
||||
"eslint-config-jquery": "3.0.2",
|
||||
"exit-hook": "4.0.0",
|
||||
"express": "4.19.2",
|
||||
"express-body-parser-error-handler": "1.0.7",
|
||||
"globals": "15.8.0",
|
||||
"husky": "9.1.1",
|
||||
"globals": "15.9.0",
|
||||
"husky": "9.1.4",
|
||||
"jsdom": "24.1.1",
|
||||
"marked": "13.0.2",
|
||||
"marked": "14.0.0",
|
||||
"native-promise-only": "0.8.1",
|
||||
"nodemon": "3.1.4",
|
||||
"promises-aplus-tests": "2.1.2",
|
||||
"q": "1.5.1",
|
||||
"qunit": "2.21.1",
|
||||
"raw-body": "2.5.2",
|
||||
"raw-body": "3.0.0",
|
||||
"release-it": "17.6.0",
|
||||
"requirejs": "2.3.7",
|
||||
"rimraf": "6.0.1",
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Keep in sync with /test/middleware-mockserver.js
|
||||
* Keep in sync with /test/middleware-mockserver.cjs
|
||||
*/
|
||||
function cleanCallback( $callback ) {
|
||||
return preg_replace( '/[^a-z0-9_]/i', '', $callback );
|
||||
|
@ -165,16 +165,7 @@ const mocks = {
|
||||
"constructor": "prototype collision (constructor)"
|
||||
};
|
||||
|
||||
// Use resp.append in express to
|
||||
// avoid overwriting List-Header
|
||||
if ( resp.append ) {
|
||||
|
||||
for ( const key in headers ) {
|
||||
resp.append( key, headers[ key ] );
|
||||
}
|
||||
} else {
|
||||
resp.writeHead( 200, headers );
|
||||
}
|
||||
req.query.keys.split( "|" ).forEach( function( key ) {
|
||||
if ( key.toLowerCase() in req.headers ) {
|
||||
resp.write( `${ key }: ${ req.headers[ key.toLowerCase() ] }\n` );
|
||||
@ -305,11 +296,7 @@ const handlers = {
|
||||
|
||||
/**
|
||||
* Connect-compatible middleware factory for mocking server responses.
|
||||
* Used by Ajax unit tests when run via Karma.
|
||||
*
|
||||
* Despite Karma using Express, it uses Connect to deal with custom middleware,
|
||||
* which passes the raw Node Request and Response objects instead of the
|
||||
* Express versions of these (e.g. no req.path, req.query, resp.set).
|
||||
* Used by Ajax tests run in Node.
|
||||
*/
|
||||
function MockserverMiddlewareFactory() {
|
||||
|
@ -1,70 +1,192 @@
|
||||
import bodyParser from "body-parser";
|
||||
import express from "express";
|
||||
import bodyParserErrorHandler from "express-body-parser-error-handler";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import mockServer from "../middleware-mockserver.js";
|
||||
import http from "node:http";
|
||||
import { readFile, stat } from "node:fs/promises";
|
||||
import { createReadStream } from "node:fs";
|
||||
import mockServer from "../middleware-mockserver.cjs";
|
||||
import getRawBody from "raw-body";
|
||||
|
||||
export async function createTestServer( report ) {
|
||||
const nameHTML = await readFile( "./test/data/name.html", "utf8" );
|
||||
export async function createTestServer( report, { quiet } = {} ) {
|
||||
const indexHTML = await readFile( "./test/index.html", "utf8" );
|
||||
const app = express();
|
||||
|
||||
// Support connect-style middleware
|
||||
const middlewares = [];
|
||||
function use( middleware ) {
|
||||
middlewares.push( middleware );
|
||||
}
|
||||
|
||||
function run( req, res ) {
|
||||
let i = 0;
|
||||
|
||||
// Log responses unless quiet is set
|
||||
if ( !quiet ) {
|
||||
const originalEnd = res.end;
|
||||
res.end = function( ...args ) {
|
||||
console.log( `${ req.method } ${ req.url } ${ this.statusCode }` );
|
||||
originalEnd.call( this, ...args );
|
||||
};
|
||||
}
|
||||
|
||||
// Add a parsed URL object to the request object
|
||||
req.parsedUrl = new URL(
|
||||
`http://${ process.env.HOST ?? "localhost" }${ req.url }`
|
||||
);
|
||||
|
||||
// Add a simplified redirect helper to the response object
|
||||
res.redirect = ( status, location ) => {
|
||||
if ( !location ) {
|
||||
location = status;
|
||||
status = 303;
|
||||
}
|
||||
|
||||
res.writeHead( status, { Location: location } );
|
||||
res.end();
|
||||
};
|
||||
|
||||
const next = () => {
|
||||
const middleware = middlewares[ i++ ];
|
||||
if ( middleware ) {
|
||||
try {
|
||||
middleware( req, res, next );
|
||||
} catch ( error ) {
|
||||
console.error( error );
|
||||
res.writeHead( 500, { "Content-Type": "application/json" } );
|
||||
res.end( "Internal Server Error" );
|
||||
}
|
||||
} else {
|
||||
res.writeHead( 404 );
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
// Redirect home to test page
|
||||
app.get( "/", ( _req, res ) => {
|
||||
use( ( req, res, next ) => {
|
||||
if ( req.parsedUrl.pathname === "/" ) {
|
||||
res.redirect( "/test/" );
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} );
|
||||
|
||||
// Redirect to trailing slash
|
||||
app.use( ( req, res, next ) => {
|
||||
if ( req.path === "/test" ) {
|
||||
const query = req.url.slice( req.path.length );
|
||||
res.redirect( 301, `${ req.path }/${ query }` );
|
||||
use( ( req, res, next ) => {
|
||||
if ( req.parsedUrl.pathname === "/test" ) {
|
||||
res.redirect( 308, `${ req.parsedUrl.pathname }/${ req.parsedUrl.search }` );
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} );
|
||||
|
||||
// Add a script tag to the index.html to load the QUnit listeners
|
||||
app.use( /\/test(?:\/index.html)?\//, ( _req, res ) => {
|
||||
res.send(
|
||||
use( ( req, res, next ) => {
|
||||
if (
|
||||
( req.method === "GET" || req.method === "HEAD" ) &&
|
||||
( req.parsedUrl.pathname === "/test/" ||
|
||||
req.parsedUrl.pathname === "/test/index.html" )
|
||||
) {
|
||||
res.writeHead( 200, { "Content-Type": "text/html" } );
|
||||
res.end(
|
||||
indexHTML.replace(
|
||||
"</head>",
|
||||
"<script src=\"/test/runner/listeners.js\"></script></head>"
|
||||
)
|
||||
);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} );
|
||||
|
||||
// Bind the reporter
|
||||
app.post(
|
||||
"/api/report",
|
||||
bodyParser.json( { limit: "50mb" } ),
|
||||
async( req, res ) => {
|
||||
if ( report ) {
|
||||
const response = await report( req.body );
|
||||
if ( response ) {
|
||||
res.json( response );
|
||||
use( async( req, res, next ) => {
|
||||
if ( req.url !== "/api/report" || req.method !== "POST" ) {
|
||||
return next();
|
||||
}
|
||||
let body;
|
||||
try {
|
||||
body = JSON.parse( await getRawBody( req ) );
|
||||
} catch ( error ) {
|
||||
if ( error.code === "ECONNABORTED" ) {
|
||||
return;
|
||||
}
|
||||
console.error( error );
|
||||
res.writeHead( 400, { "Content-Type": "application/json" } );
|
||||
res.end( JSON.stringify( { error: "Invalid JSON" } ) );
|
||||
return;
|
||||
}
|
||||
res.sendStatus( 204 );
|
||||
const response = await report( body );
|
||||
if ( response ) {
|
||||
res.writeHead( 200, { "Content-Type": "application/json" } );
|
||||
res.end( JSON.stringify( response ) );
|
||||
} else {
|
||||
res.writeHead( 204 );
|
||||
res.end();
|
||||
}
|
||||
);
|
||||
|
||||
// Handle errors from the body parser
|
||||
app.use( bodyParserErrorHandler() );
|
||||
|
||||
// Hook up mock server
|
||||
app.use( mockServer() );
|
||||
|
||||
// Serve static files
|
||||
app.post( "/test/data/name.html", ( _req, res ) => {
|
||||
res.send( nameHTML );
|
||||
} );
|
||||
|
||||
app.use( "/dist", express.static( "dist" ) );
|
||||
app.use( "/src", express.static( "src" ) );
|
||||
app.use( "/test", express.static( "test" ) );
|
||||
app.use( "/external", express.static( "external" ) );
|
||||
// Hook up mock server
|
||||
use( mockServer() );
|
||||
|
||||
return app;
|
||||
// Serve static files
|
||||
const validMimeTypes = {
|
||||
|
||||
// No .mjs or .cjs files are used in tests
|
||||
".js": "application/javascript",
|
||||
".css": "text/css",
|
||||
".html": "text/html",
|
||||
".xml": "application/xml",
|
||||
".xhtml": "application/xhtml+xml",
|
||||
".jpg": "image/jpeg",
|
||||
".png": "image/png",
|
||||
".svg": "image/svg+xml",
|
||||
".ico": "image/x-icon",
|
||||
".map": "application/json",
|
||||
".txt": "text/plain",
|
||||
".log": "text/plain"
|
||||
};
|
||||
use( async( req, res, next ) => {
|
||||
if (
|
||||
!req.url.startsWith( "/dist/" ) &&
|
||||
!req.url.startsWith( "/src/" ) &&
|
||||
!req.url.startsWith( "/test/" ) &&
|
||||
!req.url.startsWith( "/external/" )
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
const file = req.parsedUrl.pathname.slice( 1 );
|
||||
const ext = file.slice( file.lastIndexOf( "." ) );
|
||||
|
||||
// Allow POST to .html files in tests
|
||||
if (
|
||||
req.method !== "GET" &&
|
||||
req.method !== "HEAD" &&
|
||||
( ext !== ".html" || req.method !== "POST" )
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
const mimeType = validMimeTypes[ ext ];
|
||||
if ( mimeType ) {
|
||||
try {
|
||||
await stat( file );
|
||||
} catch ( _ ) {
|
||||
res.writeHead( 404 );
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
res.writeHead( 200, { "Content-Type": mimeType } );
|
||||
createReadStream( file )
|
||||
.pipe( res )
|
||||
.on( "error", ( error ) => {
|
||||
console.error( error );
|
||||
res.writeHead( 500 );
|
||||
res.end();
|
||||
} );
|
||||
} else {
|
||||
console.error( `Invalid file extension: ${ ext }` );
|
||||
res.writeHead( 404 );
|
||||
res.end();
|
||||
}
|
||||
} );
|
||||
|
||||
return http.createServer( run );
|
||||
}
|
||||
|
@ -137,7 +137,9 @@ export async function run( {
|
||||
default:
|
||||
console.warn( "Received unknown message type:", message.type );
|
||||
}
|
||||
} );
|
||||
|
||||
// Hide test server request logs in CLI output
|
||||
}, { quiet: true } );
|
||||
|
||||
// Start up local test server
|
||||
let server;
|
||||
|
Loading…
Reference in New Issue
Block a user