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: {
|
rules: {
|
||||||
...jqueryConfig.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/node_smoke_tests/**",
|
||||||
"test/bundler_smoke_tests/**/*",
|
"test/bundler_smoke_tests/**/*",
|
||||||
"test/promises_aplus_adapters/**",
|
"test/promises_aplus_adapters/**",
|
||||||
"test/middleware-mockserver.js"
|
"test/middleware-mockserver.cjs"
|
||||||
],
|
],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
ecmaVersion: "latest",
|
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",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "7.24.8",
|
"@babel/cli": "7.24.8",
|
||||||
"@babel/core": "7.24.9",
|
"@babel/core": "7.25.2",
|
||||||
"@babel/plugin-transform-for-of": "7.24.7",
|
"@babel/plugin-transform-for-of": "7.24.7",
|
||||||
"@prantlf/jsonlint": "14.0.3",
|
"@prantlf/jsonlint": "14.0.3",
|
||||||
"@types/selenium-webdriver": "4.1.24",
|
"@types/selenium-webdriver": "4.1.24",
|
||||||
"body-parser": "1.20.2",
|
"archiver": "7.0.1",
|
||||||
"bootstrap": "5.3.3",
|
"bootstrap": "5.3.3",
|
||||||
"browserstack-local": "1.5.5",
|
"browserstack-local": "1.5.5",
|
||||||
"chalk": "5.3.0",
|
"chalk": "5.3.0",
|
||||||
"colors": "1.4.0",
|
"colors": "1.4.0",
|
||||||
"commitplease": "3.2.0",
|
"commitplease": "3.2.0",
|
||||||
"concurrently": "8.2.2",
|
"concurrently": "8.2.2",
|
||||||
"core-js-bundle": "3.37.1",
|
"core-js-bundle": "3.38.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"diff": "5.2.0",
|
"diff": "5.2.0",
|
||||||
"eslint": "9.4.0",
|
"eslint": "9.8.0",
|
||||||
"eslint-config-jquery": "3.0.2",
|
"eslint-config-jquery": "3.0.2",
|
||||||
"exit-hook": "4.0.0",
|
"exit-hook": "4.0.0",
|
||||||
"express": "4.19.2",
|
"globals": "15.9.0",
|
||||||
"express-body-parser-error-handler": "1.0.7",
|
"husky": "9.1.4",
|
||||||
"globals": "15.8.0",
|
|
||||||
"husky": "9.1.1",
|
|
||||||
"jsdom": "24.1.1",
|
"jsdom": "24.1.1",
|
||||||
"marked": "13.0.2",
|
"marked": "14.0.0",
|
||||||
"native-promise-only": "0.8.1",
|
"native-promise-only": "0.8.1",
|
||||||
"nodemon": "3.1.4",
|
"nodemon": "3.1.4",
|
||||||
"promises-aplus-tests": "2.1.2",
|
"promises-aplus-tests": "2.1.2",
|
||||||
"q": "1.5.1",
|
"q": "1.5.1",
|
||||||
"qunit": "2.21.1",
|
"qunit": "2.21.1",
|
||||||
"raw-body": "2.5.2",
|
"raw-body": "3.0.0",
|
||||||
"release-it": "17.6.0",
|
"release-it": "17.6.0",
|
||||||
"requirejs": "2.3.7",
|
"requirejs": "2.3.7",
|
||||||
"rimraf": "6.0.1",
|
"rimraf": "6.0.1",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep in sync with /test/middleware-mockserver.js
|
* Keep in sync with /test/middleware-mockserver.cjs
|
||||||
*/
|
*/
|
||||||
function cleanCallback( $callback ) {
|
function cleanCallback( $callback ) {
|
||||||
return preg_replace( '/[^a-z0-9_]/i', '', $callback );
|
return preg_replace( '/[^a-z0-9_]/i', '', $callback );
|
||||||
|
@ -165,16 +165,7 @@ const mocks = {
|
|||||||
"constructor": "prototype collision (constructor)"
|
"constructor": "prototype collision (constructor)"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use resp.append in express to
|
resp.writeHead( 200, headers );
|
||||||
// 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 ) {
|
req.query.keys.split( "|" ).forEach( function( key ) {
|
||||||
if ( key.toLowerCase() in req.headers ) {
|
if ( key.toLowerCase() in req.headers ) {
|
||||||
resp.write( `${ key }: ${ req.headers[ key.toLowerCase() ] }\n` );
|
resp.write( `${ key }: ${ req.headers[ key.toLowerCase() ] }\n` );
|
||||||
@ -305,11 +296,7 @@ const handlers = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect-compatible middleware factory for mocking server responses.
|
* Connect-compatible middleware factory for mocking server responses.
|
||||||
* Used by Ajax unit tests when run via Karma.
|
* Used by Ajax tests run in Node.
|
||||||
*
|
|
||||||
* 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).
|
|
||||||
*/
|
*/
|
||||||
function MockserverMiddlewareFactory() {
|
function MockserverMiddlewareFactory() {
|
||||||
|
|
@ -1,70 +1,192 @@
|
|||||||
import bodyParser from "body-parser";
|
import http from "node:http";
|
||||||
import express from "express";
|
import { readFile, stat } from "node:fs/promises";
|
||||||
import bodyParserErrorHandler from "express-body-parser-error-handler";
|
import { createReadStream } from "node:fs";
|
||||||
import { readFile } from "node:fs/promises";
|
import mockServer from "../middleware-mockserver.cjs";
|
||||||
import mockServer from "../middleware-mockserver.js";
|
import getRawBody from "raw-body";
|
||||||
|
|
||||||
export async function createTestServer( report ) {
|
export async function createTestServer( report, { quiet } = {} ) {
|
||||||
const nameHTML = await readFile( "./test/data/name.html", "utf8" );
|
|
||||||
const indexHTML = await readFile( "./test/index.html", "utf8" );
|
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
|
// Redirect home to test page
|
||||||
app.get( "/", ( _req, res ) => {
|
use( ( req, res, next ) => {
|
||||||
res.redirect( "/test/" );
|
if ( req.parsedUrl.pathname === "/" ) {
|
||||||
|
res.redirect( "/test/" );
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Redirect to trailing slash
|
// Redirect to trailing slash
|
||||||
app.use( ( req, res, next ) => {
|
use( ( req, res, next ) => {
|
||||||
if ( req.path === "/test" ) {
|
if ( req.parsedUrl.pathname === "/test" ) {
|
||||||
const query = req.url.slice( req.path.length );
|
res.redirect( 308, `${ req.parsedUrl.pathname }/${ req.parsedUrl.search }` );
|
||||||
res.redirect( 301, `${ req.path }/${ query }` );
|
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Add a script tag to the index.html to load the QUnit listeners
|
// Add a script tag to the index.html to load the QUnit listeners
|
||||||
app.use( /\/test(?:\/index.html)?\//, ( _req, res ) => {
|
use( ( req, res, next ) => {
|
||||||
res.send(
|
if (
|
||||||
indexHTML.replace(
|
( req.method === "GET" || req.method === "HEAD" ) &&
|
||||||
"</head>",
|
( req.parsedUrl.pathname === "/test/" ||
|
||||||
"<script src=\"/test/runner/listeners.js\"></script></head>"
|
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
|
// Bind the reporter
|
||||||
app.post(
|
use( async( req, res, next ) => {
|
||||||
"/api/report",
|
if ( req.url !== "/api/report" || req.method !== "POST" ) {
|
||||||
bodyParser.json( { limit: "50mb" } ),
|
return next();
|
||||||
async( req, res ) => {
|
}
|
||||||
if ( report ) {
|
let body;
|
||||||
const response = await report( req.body );
|
try {
|
||||||
if ( response ) {
|
body = JSON.parse( await getRawBody( req ) );
|
||||||
res.json( response );
|
} catch ( error ) {
|
||||||
return;
|
if ( error.code === "ECONNABORTED" ) {
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
res.sendStatus( 204 );
|
console.error( error );
|
||||||
|
res.writeHead( 400, { "Content-Type": "application/json" } );
|
||||||
|
res.end( JSON.stringify( { error: "Invalid JSON" } ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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" ) );
|
// Hook up mock server
|
||||||
app.use( "/src", express.static( "src" ) );
|
use( mockServer() );
|
||||||
app.use( "/test", express.static( "test" ) );
|
|
||||||
app.use( "/external", express.static( "external" ) );
|
|
||||||
|
|
||||||
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:
|
default:
|
||||||
console.warn( "Received unknown message type:", message.type );
|
console.warn( "Received unknown message type:", message.type );
|
||||||
}
|
}
|
||||||
} );
|
|
||||||
|
// Hide test server request logs in CLI output
|
||||||
|
}, { quiet: true } );
|
||||||
|
|
||||||
// Start up local test server
|
// Start up local test server
|
||||||
let server;
|
let server;
|
||||||
|
Loading…
Reference in New Issue
Block a user