Docs: add gitter badge to README.md
[jquery.git] / test / middleware-mockserver.js
blob35623761de0cb3a0f50dedcea191203e09a5a2d0
1 /* eslint-env node */
2 var url = require( "url" );
3 var fs = require( "fs" );
4 var getRawBody = require( "raw-body" );
6 var cspLog = "";
7 /**
8 * Keep in sync with /test/mock.php
9 */
10 var mocks = {
11 contentType: function( req, resp ) {
12 resp.writeHead( 200, {
13 "content-type": req.query.contentType
14 } );
15 resp.end( req.query.response );
17 wait: function( req, resp ) {
18 var wait = Number( req.query.wait ) * 1000;
19 setTimeout( function() {
20 if ( req.query.script ) {
21 resp.writeHead( 200, { "content-type": "text/javascript" } );
22 } else {
23 resp.writeHead( 200, { "content-type": "text/html" } );
24 resp.end( "ERROR <script>ok( true, \"mock executed\" );</script>" );
26 }, wait );
28 name: function( req, resp, next ) {
29 resp.writeHead( 200 );
30 if ( req.query.name === "foo" ) {
31 resp.end( "bar" );
32 return;
34 getBody( req ).then( function( body ) {
35 if ( body === "name=peter" ) {
36 resp.end( "pan" );
37 } else {
38 resp.end( "ERROR" );
40 }, next );
42 xml: function( req, resp, next ) {
43 var content = "<math><calculation>5-2</calculation><result>3</result></math>";
44 resp.writeHead( 200, { "content-type": "text/xml" } );
46 if ( req.query.cal === "5-2" ) {
47 resp.end( content );
48 return;
50 getBody( req ).then( function( body ) {
51 if ( body === "cal=5-2" ) {
52 resp.end( content );
53 } else {
54 resp.end( "<error>ERROR</error>" );
56 }, next );
58 atom: function( req, resp, next ) {
59 resp.writeHead( 200, { "content-type": "atom+xml" } );
60 resp.end( "<root><element /></root>" );
62 script: function( req, resp ) {
63 if ( req.query.header === "ecma" ) {
64 resp.writeHead( 200, { "content-type": "application/ecmascript" } );
65 } else if ( req.query.header ) {
66 resp.writeHead( 200, { "content-type": "text/javascript" } );
67 } else {
68 resp.writeHead( 200, { "content-type": "text/html" } );
70 resp.end( "ok( true, \"mock executed\" );" );
72 testbar: function( req, resp ) {
73 resp.writeHead( 200 );
74 resp.end(
75 "this.testBar = 'bar'; " +
76 "jQuery('#ap').html('bar'); " +
77 "ok( true, 'mock executed');"
80 json: function( req, resp ) {
81 if ( req.query.header ) {
82 resp.writeHead( 200, { "content-type": "application/json" } );
84 if ( req.query.array ) {
85 resp.end( JSON.stringify(
86 [ { name: "John", age: 21 }, { name: "Peter", age: 25 } ]
87 ) );
88 } else {
89 resp.end( JSON.stringify(
90 { data: { lang: "en", length: 25 } }
91 ) );
94 jsonp: function( req, resp, next ) {
95 var callback;
96 if ( req.query.callback ) {
97 callback = Promise.resolve( req.query.callback );
98 } else if ( req.method === "GET" ) {
99 callback = Promise.resolve( req.url.match( /^.+\/([^\/?.]+)\?.+$/ )[ 1 ] );
100 } else {
101 callback = getBody( req ).then( function( body ) {
102 return body.trim().replace( "callback=", "" );
103 } );
105 var json = req.query.array ?
106 JSON.stringify(
107 [ { name: "John", age: 21 }, { name: "Peter", age: 25 } ]
109 JSON.stringify(
110 { data: { lang: "en", length: 25 } }
112 callback.then( function( cb ) {
113 resp.end( cb + "(" + json + ")" );
114 }, next );
116 xmlOverJsonp: function( req, resp ) {
117 var callback = req.query.callback;
118 var body = fs.readFileSync( __dirname + "/data/with_fries.xml" ).toString();
119 resp.writeHead( 200 );
120 resp.end( callback + "(" + JSON.stringify( body ) + ")\n" );
122 error: function( req, resp ) {
123 if ( req.query.json ) {
124 resp.writeHead( 400, { "content-type": "application/json" } );
125 resp.end( "{ \"code\": 40, \"message\": \"Bad Request\" }" );
126 } else {
127 resp.writeHead( 400 );
128 resp.end( "plain text message" );
131 headers: function( req, resp ) {
132 resp.writeHead( 200, {
133 "Sample-Header": "Hello World",
134 "Empty-Header": "",
135 "Sample-Header2": "Hello World 2"
136 } );
137 req.query.keys.split( "|" ).forEach( function( key ) {
138 if ( req.headers[ key.toLowerCase() ] ) {
139 resp.write( key + ": " + req.headers[ key.toLowerCase() ] + "\n" );
141 } );
142 resp.end();
144 echoData: function( req, resp, next ) {
145 getBody( req ).then( function( body ) {
146 resp.end( body );
147 }, next );
149 echoQuery: function( req, resp ) {
150 resp.end( req.parsed.search.slice( 1 ) );
152 echoMethod: function( req, resp ) {
153 resp.end( req.method );
155 echoHtml: function( req, resp, next ) {
156 resp.writeHead( 200, { "Content-Type": "text/html" } );
157 resp.write( "<div id='method'>" + req.method + "</div>" );
158 resp.write( "<div id='query'>" + req.parsed.search.slice( 1 ) + "</div>" );
159 getBody( req ).then( function( body ) {
160 resp.write( "<div id='data'>" + body + "</div>" );
161 resp.end( body );
162 }, next );
164 etag: function( req, resp ) {
165 var hash = Number( req.query.ts ).toString( 36 );
166 var etag = "W/\"" + hash + "\"";
167 if ( req.headers[ "if-none-match" ] === etag ) {
168 resp.writeHead( 304 );
169 resp.end();
170 return;
172 resp.writeHead( 200, {
173 "Etag": etag
174 } );
175 resp.end();
177 ims: function( req, resp, next ) {
178 var ts = req.query.ts;
179 if ( req.headers[ "if-modified-since" ] === ts ) {
180 resp.writeHead( 304 );
181 resp.end();
182 return;
184 resp.writeHead( 200, {
185 "Last-Modified": ts
186 } );
187 resp.end();
189 status: function( req, resp, next ) {
190 resp.writeHead( Number( req.query.code ) );
191 resp.end();
193 testHTML: function( req, resp ) {
194 resp.writeHead( 200, { "Content-Type": "text/html" } );
195 var body = fs.readFileSync( __dirname + "/data/test.include.html" ).toString();
196 body = body.replace( /{{baseURL}}/g, req.query.baseURL );
197 resp.end( body );
199 cspFrame: function( req, resp ) {
200 resp.writeHead( 200, {
201 "Content-Type": "text/html",
202 "Content-Security-Policy": "default-src 'self'; report-uri /base/test/data/mock.php?action=cspLog"
203 } );
204 var body = fs.readFileSync( __dirname + "/data/csp.include.html" ).toString();
205 resp.end( body );
207 cspLog: function( req, resp ) {
208 cspLog = "error";
209 resp.writeHead( 200 );
210 resp.end();
212 cspClean: function( req, resp ) {
213 cspLog = "";
214 resp.writeHead( 200 );
215 resp.end();
218 var handlers = {
219 "test/data/mock.php": function( req, resp, next ) {
220 if ( !mocks[ req.query.action ] ) {
221 resp.writeHead( 400 );
222 resp.end( "Invalid action query.\n" );
223 console.log( "Invalid action query:", req.method, req.url );
224 return;
226 mocks[ req.query.action ]( req, resp, next );
228 "test/data/support/csp.log": function( req, resp ) {
229 resp.writeHead( 200 );
230 resp.end( cspLog );
232 "test/data/404.txt": function( req, resp ) {
233 resp.writeHead( 404 );
234 resp.end( "" );
239 * Connect-compatible middleware factory for mocking server responses.
240 * Used by Ajax unit tests when run via Karma.
242 * Despite Karma using Express, it uses Connect to deal with custom middleware,
243 * which passes the raw Node Request and Response objects instead of the
244 * Express versions of these (e.g. no req.path, req.query, resp.set).
246 function MockserverMiddlewareFactory() {
248 * @param {http.IncomingMessage} req
249 * @param {http.ServerResponse} resp
250 * @param {Function} next Continue request handling
252 return function( req, resp, next ) {
253 var method = req.method,
254 parsed = url.parse( req.url, /* parseQuery */ true ),
255 path = parsed.pathname.replace( /^\/base\//, "" ),
256 query = parsed.query,
257 subReq = Object.assign( Object.create( req ), {
258 query: query,
259 parsed: parsed
260 } );
262 if ( /^test\/data\/mock.php\//.test( path ) ) {
263 // Support REST-like Apache PathInfo
264 path = "test\/data\/mock.php";
267 if ( !handlers[ path ] ) {
268 next();
269 return;
272 handlers[ path ]( subReq, resp, next );
276 function getBody( req ) {
277 return req.method !== "POST" ?
278 Promise.resolve( "" ) :
279 getRawBody( req, {
280 encoding: true
281 } );
284 module.exports = MockserverMiddlewareFactory;