diff --git a/test/e2e/__snapshots__/proxy.test.js.snap.webpack4 b/test/e2e/__snapshots__/proxy.test.js.snap.webpack4 new file mode 100644 index 0000000000..c4172fc9c8 --- /dev/null +++ b/test/e2e/__snapshots__/proxy.test.js.snap.webpack4 @@ -0,0 +1,335 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`proxy option as an array respects a proxy option of function: console messages 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option of function: page errors 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option of function: response status 1`] = `200`; + +exports[`proxy option as an array respects a proxy option of function: response text 1`] = `"from proxy2"`; + +exports[`proxy option as an array respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an array respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an array should allow req, res, and next: console messages 1`] = `Array []`; + +exports[`proxy option as an array should allow req, res, and next: page errors 1`] = `Array []`; + +exports[`proxy option as an array should allow req, res, and next: response status 1`] = `200`; + +exports[`proxy option as an array should allow req, res, and next: response text 1`] = `"foo+next+function"`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: console messages 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: page errors 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: response status 1`] = `200`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: response text 1`] = `"from proxy2"`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: console messages 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: response status 1`] = `200`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: response status 1`] = `200`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: response text 1`] = ` +"Hello +" +`; + +exports[`proxy option proxy with byPass can rewrite a request path: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path: response status 1`] = `200`; + +exports[`proxy option proxy with byPass can rewrite a request path: response text 1`] = ` +"Hello +" +`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: response status 1`] = `404`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: response text 1`] = ` +" + + + +Error + + +
Cannot GET /proxyfalse
+ + +" +`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: response status 1`] = `200`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: response text 1`] = ` +"\\"use strict\\"; + +console.log(\\"Hey.\\"); +" +`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: response status 1`] = `200`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: response text 1`] = `"proxy async response"`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: response status 1`] = `200`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: response text 1`] = ` +"Hello +" +`; + +exports[`proxy option proxy with byPass should work with the 'target' option: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`proxy option proxy with byPass should work with the 'target' option: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should work with the 'target' option: response status 1`] = `404`; + +exports[`proxy option proxy with byPass should work with the 'target' option: response text 1`] = ` +" + + + +Error + + +
Cannot GET /bypass-with-target/foo.js
+ + +" +`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 426 (Upgrade Required)", +] +`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: page errors 1`] = `Array []`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: response status 1`] = `426`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: response text 1`] = `"Upgrade Required"`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 426 (Upgrade Required)", +] +`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: page errors 1`] = `Array []`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: response status 1`] = `426`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: response text 1`] = `"Upgrade Required"`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: console messages 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: page errors 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: response status 1`] = `200`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: response text 1`] = `"from proxy"`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: console messages 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: page errors 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: response status 1`] = `200`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: response text 1`] = `"from proxy"`; + +exports[`proxy option should supports http methods DELETE method: console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods DELETE method: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods DELETE method: response status 1`] = `200`; + +exports[`proxy option should supports http methods DELETE method: response text 1`] = `"DELETE method from proxy"`; + +exports[`proxy option should supports http methods GET method: console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods GET method: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods GET method: response status 1`] = `200`; + +exports[`proxy option should supports http methods GET method: response text 1`] = `"GET method from proxy"`; + +exports[`proxy option should supports http methods HEAD method: console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods HEAD method: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods HEAD method: response status 1`] = `200`; + +exports[`proxy option should supports http methods HEAD method: response text 1`] = `""`; + +exports[`proxy option should supports http methods POST method (application/json): console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/json): page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/json): response headers content-type 1`] = `"application/json; charset=utf-8"`; + +exports[`proxy option should supports http methods POST method (application/json): response status 1`] = `200`; + +exports[`proxy option should supports http methods POST method (application/json): response text 1`] = `"{\\"answer\\":\\"POST method from proxy (id: 1)\\"}"`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): response headers content-type 1`] = `"text/html; charset=utf-8"`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): response status 1`] = `200`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): response text 1`] = `"POST method from proxy (id: 1)"`; + +exports[`proxy option should supports http methods errors: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 500 (Internal Server Error)", +] +`; + +exports[`proxy option should supports http methods errors: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods errors: response status 1`] = `500`; + +exports[`proxy option should supports http methods errors: response text 1`] = `"error from proxy"`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: response status 1`] = `200`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: response text 1`] = `"from proxy1"`; diff --git a/test/e2e/__snapshots__/proxy.test.js.snap.webpack5 b/test/e2e/__snapshots__/proxy.test.js.snap.webpack5 new file mode 100644 index 0000000000..c4172fc9c8 --- /dev/null +++ b/test/e2e/__snapshots__/proxy.test.js.snap.webpack5 @@ -0,0 +1,335 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`proxy option as an array respects a proxy option of function: console messages 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option of function: page errors 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option of function: response status 1`] = `200`; + +exports[`proxy option as an array respects a proxy option of function: response text 1`] = `"from proxy2"`; + +exports[`proxy option as an array respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an array respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an array respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an array should allow req, res, and next: console messages 1`] = `Array []`; + +exports[`proxy option as an array should allow req, res, and next: page errors 1`] = `Array []`; + +exports[`proxy option as an array should allow req, res, and next: response status 1`] = `200`; + +exports[`proxy option as an array should allow req, res, and next: response text 1`] = `"foo+next+function"`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an array without the \`route\` option respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: console messages 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: page errors 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: response status 1`] = `200`; + +exports[`proxy option as an object of paths with properties respects a pathRewrite option: response text 1`] = `"from proxy2"`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: console messages 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: response status 1`] = `200`; + +exports[`proxy option as an object of paths with properties respects a proxy option when a request path is matched: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with \`context\` and \`target\` as string respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with the \`context\` option respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with the \`path\` option (\`context\` alias) respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: response status 1`] = `200`; + +exports[`proxy option as an option is an object with the \`router\` option respects a proxy option: response text 1`] = `"from proxy1"`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: response status 1`] = `200`; + +exports[`proxy option proxy with byPass can rewrite a request path regardless of the target defined a bypass option: response text 1`] = ` +"Hello +" +`; + +exports[`proxy option proxy with byPass can rewrite a request path: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass can rewrite a request path: response status 1`] = `200`; + +exports[`proxy option proxy with byPass can rewrite a request path: response text 1`] = ` +"Hello +" +`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: response status 1`] = `404`; + +exports[`proxy option proxy with byPass should not pass through a proxy when a bypass function returns false: response text 1`] = ` +" + + + +Error + + +
Cannot GET /proxyfalse
+ + +" +`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: response status 1`] = `200`; + +exports[`proxy option proxy with byPass should pass through a proxy when a bypass function returns null: response text 1`] = ` +"\\"use strict\\"; + +console.log(\\"Hey.\\"); +" +`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: response status 1`] = `200`; + +exports[`proxy option proxy with byPass should wait if bypass returns promise: response text 1`] = `"proxy async response"`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: console messages 1`] = `Array []`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: response status 1`] = `200`; + +exports[`proxy option proxy with byPass should work with the 'target' option #2: response text 1`] = ` +"Hello +" +`; + +exports[`proxy option proxy with byPass should work with the 'target' option: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`proxy option proxy with byPass should work with the 'target' option: page errors 1`] = `Array []`; + +exports[`proxy option proxy with byPass should work with the 'target' option: response status 1`] = `404`; + +exports[`proxy option proxy with byPass should work with the 'target' option: response text 1`] = ` +" + + + +Error + + +
Cannot GET /bypass-with-target/foo.js
+ + +" +`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 426 (Upgrade Required)", +] +`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: page errors 1`] = `Array []`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: response status 1`] = `426`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: sockjs Should receive response: response text 1`] = `"Upgrade Required"`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 426 (Upgrade Required)", +] +`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: page errors 1`] = `Array []`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: response status 1`] = `426`; + +exports[`proxy option should handles external websocket upgrade with webSocketServerType: ws Should receive response: response text 1`] = `"Upgrade Required"`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: console messages 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: page errors 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: response status 1`] = `200`; + +exports[`proxy option should sharing a proxy option respects proxy1 option: response text 1`] = `"from proxy"`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: console messages 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: page errors 1`] = `Array []`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: response status 1`] = `200`; + +exports[`proxy option should sharing a proxy option respects proxy2 option: response text 1`] = `"from proxy"`; + +exports[`proxy option should supports http methods DELETE method: console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods DELETE method: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods DELETE method: response status 1`] = `200`; + +exports[`proxy option should supports http methods DELETE method: response text 1`] = `"DELETE method from proxy"`; + +exports[`proxy option should supports http methods GET method: console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods GET method: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods GET method: response status 1`] = `200`; + +exports[`proxy option should supports http methods GET method: response text 1`] = `"GET method from proxy"`; + +exports[`proxy option should supports http methods HEAD method: console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods HEAD method: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods HEAD method: response status 1`] = `200`; + +exports[`proxy option should supports http methods HEAD method: response text 1`] = `""`; + +exports[`proxy option should supports http methods POST method (application/json): console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/json): page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/json): response headers content-type 1`] = `"application/json; charset=utf-8"`; + +exports[`proxy option should supports http methods POST method (application/json): response status 1`] = `200`; + +exports[`proxy option should supports http methods POST method (application/json): response text 1`] = `"{\\"answer\\":\\"POST method from proxy (id: 1)\\"}"`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): console messages 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): response headers content-type 1`] = `"text/html; charset=utf-8"`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): response status 1`] = `200`; + +exports[`proxy option should supports http methods POST method (application/x-www-form-urlencoded): response text 1`] = `"POST method from proxy (id: 1)"`; + +exports[`proxy option should supports http methods errors: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 500 (Internal Server Error)", +] +`; + +exports[`proxy option should supports http methods errors: page errors 1`] = `Array []`; + +exports[`proxy option should supports http methods errors: response status 1`] = `500`; + +exports[`proxy option should supports http methods errors: response text 1`] = `"error from proxy"`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect \`logProvider\` and \`logLevel\` options with \`silent\` value target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: console messages 1`] = ` +Array [ + "Failed to load resource: the server responded with a status of 504 (Gateway Timeout)", +] +`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: page errors 1`] = `Array []`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: response status 1`] = `504`; + +exports[`proxy option should work and respect the \`infrastructureLogging.level\` option with \`none\` value target respects a proxy option when a request path is matched: response text 1`] = `"Error occured while trying to proxy: localhost:8123/my-path"`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: console messages 1`] = `Array []`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: page errors 1`] = `Array []`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: response status 1`] = `200`; + +exports[`proxy option should work in multi compiler mode respects a proxy option: response text 1`] = `"from proxy1"`; diff --git a/test/e2e/proxy.test.js b/test/e2e/proxy.test.js new file mode 100644 index 0000000000..3d8297d8f2 --- /dev/null +++ b/test/e2e/proxy.test.js @@ -0,0 +1,1765 @@ +"use strict"; + +const path = require("path"); +const express = require("express"); +const bodyParser = require("body-parser"); +const WebSocket = require("ws"); +const webpack = require("webpack"); +const runBrowser = require("../helpers/run-browser"); +const Server = require("../../lib/Server"); +const config = require("../fixtures/proxy-config/webpack.config"); +const [port1, port2, port3, port4] = require("../ports-map")["proxy-option"]; + +const WebSocketServer = WebSocket.Server; +const staticDirectory = path.resolve(__dirname, "../fixtures/proxy-config"); + +const proxyOptionsObject = { + "/proxy1": { + target: `http://localhost:${port1}`, + }, + "/api/proxy2": { + target: `http://localhost:${port2}`, + pathRewrite: { "^/api": "" }, + }, + "/foo": { + bypass(req) { + if (/\.html$/.test(req.path)) { + return "/index.html"; + } + + return null; + }, + }, + "/proxyfalse": { + bypass(req) { + if (/\/proxyfalse$/.test(req.path)) { + return false; + } + }, + }, + "/proxy/async": { + bypass(req, res) { + if (/\/proxy\/async$/.test(req.path)) { + return new Promise((resolve) => { + setTimeout(() => { + res.end("proxy async response"); + resolve(true); + }, 10); + }); + } + }, + }, + "/bypass-with-target": { + target: `http://localhost:${port1}`, + changeOrigin: true, + secure: false, + bypass(req) { + if (/\.(html)$/i.test(req.url)) { + return req.url; + } + }, + }, +}; + +const proxyOption = { + context: () => true, + target: `http://localhost:${port1}`, +}; + +const proxyOptionOfArray = [ + { context: "/proxy1", target: proxyOption.target }, + function proxy(req, res, next) { + return { + context: "/api/proxy2", + target: `http://localhost:${port2}`, + pathRewrite: { "^/api": "" }, + bypass: () => { + if (req && req.query.foo) { + res.end(`foo+${next.name}+${typeof next}`); + + return false; + } + }, + }; + }, +]; + +const proxyOptionOfArrayWithoutTarget = [ + { + router: () => `http://localhost:${port1}`, + }, +]; + +const proxyWithPath = { + "/proxy1": { + path: `http://localhost:${port1}`, + target: `http://localhost:${port1}`, + }, +}; + +const proxyWithString = { + "/proxy1": `http://localhost:${port1}`, +}; + +const proxyWithRouterAsObject = { + router: () => `http://localhost:${port1}`, +}; + +describe("proxy option", () => { + let proxyServer1; + let proxyServer2; + + async function listenProxyServers() { + const proxyApp1 = express(); + const proxyApp2 = express(); + + proxyApp1.get("/proxy1", (req, res) => { + res.send("from proxy1"); + }); + proxyApp1.get("/api", (req, res) => { + res.send("api response from proxy1"); + }); + proxyApp2.get("/proxy2", (req, res) => { + res.send("from proxy2"); + }); + + await new Promise((resolve) => { + proxyServer1 = proxyApp1.listen(port1, () => { + resolve(); + }); + }); + + await new Promise((resolve) => { + proxyServer2 = proxyApp2.listen(port2, () => { + resolve(); + }); + }); + } + + async function closeProxyServers() { + await new Promise((resolve) => { + proxyServer1.close(() => { + resolve(); + }); + }); + + await new Promise((resolve) => { + proxyServer2.close(() => { + resolve(); + }); + }); + } + + describe("as an object of paths with properties", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false, + }, + proxy: proxyOptionsObject, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option when a request path is matched", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("respects a pathRewrite option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/api/proxy2`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("as an array", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: proxyOptionOfArray, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("respects a proxy option of function", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/api/proxy2`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should allow req, res, and next", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://localhost:${port3}/api/proxy2?foo=true`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("as an array without the `route` option", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: proxyOptionOfArrayWithoutTarget, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("as an option is an object with the `context` option", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: proxyOption, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("as an option is an object with the `path` option (`context` alias)", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: proxyWithPath, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("as an option is an object with `context` and `target` as string", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: proxyWithString, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("as an option is an object with the `router` option", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: proxyWithRouterAsObject, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("proxy with byPass", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false, + }, + proxy: proxyOptionsObject, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("can rewrite a request path", async () => { + pageErrors = []; + consoleMessages = []; + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://localhost:${port3}/foo/bar.html`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("can rewrite a request path regardless of the target defined a bypass option", async () => { + pageErrors = []; + consoleMessages = []; + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://localhost:${port3}/baz/hoge.html`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should pass through a proxy when a bypass function returns null", async () => { + pageErrors = []; + consoleMessages = []; + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/foo.js`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should not pass through a proxy when a bypass function returns false", async () => { + pageErrors = []; + consoleMessages = []; + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxyfalse`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should wait if bypass returns promise", async () => { + pageErrors = []; + consoleMessages = []; + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://localhost:${port3}/proxy/async`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should work with the 'target' option", async () => { + pageErrors = []; + consoleMessages = []; + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://localhost:${port3}/bypass-with-target/foo.js`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should work with the 'target' option #2", async () => { + pageErrors = []; + consoleMessages = []; + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://localhost:${port3}/bypass-with-target/index.html`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("should sharing a proxy option", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let listener; + + const proxyTarget = { + target: `http://localhost:${port1}`, + }; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: { + "/proxy1": proxyTarget, + "/proxy2": proxyTarget, + }, + port: port3, + }, + compiler + ); + + await server.start(); + + const proxy = express(); + + proxy.get("*", (proxyReq, res) => { + res.send("from proxy"); + }); + + listener = proxy.listen(port1); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await new Promise((resolve) => { + listener.close(() => { + resolve(); + }); + }); + }); + + it("respects proxy1 option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("respects proxy2 option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy2`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("should handles external websocket upgrade", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let ws; + let webSocketServer; + let responseMessage; + + const webSocketServerTypes = ["sockjs", "ws"]; + + webSocketServerTypes.forEach((webSocketServerType) => { + describe(`with webSocketServerType: ${webSocketServerType}`, () => { + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + webSocketServer: webSocketServerType, + proxy: [ + { + context: "/", + target: `http://localhost:${port4}`, + ws: true, + }, + ], + port: port3, + }, + compiler + ); + + await server.start(); + + webSocketServer = new WebSocketServer({ port: port4 }); + webSocketServer.on("connection", (connection) => { + connection.on("message", (message) => { + connection.send(message); + }); + }); + + ws = new WebSocket(`ws://localhost:${port3}/proxy3/socket`); + + ws.on("message", (message) => { + responseMessage = message.toString(); + }); + + ws.on("open", () => { + ws.send("foo"); + }); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + webSocketServer.close(); + + for (const client of webSocketServer.clients) { + client.terminate(); + } + + await browser.close(); + await server.stop(); + }); + + it("Should receive response", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://localhost:${port3}/proxy3/socket`, + { + waitUntil: "networkidle0", + } + ); + + expect(responseMessage).toEqual("foo"); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect( + consoleMessages.map((message) => message.text()) + ).toMatchSnapshot("console messages"); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + }); + }); + + describe("should supports http methods", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let listener; + + const proxyTarget = { + target: `http://localhost:${port1}`, + }; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: { + "**": proxyTarget, + }, + port: port3, + }, + compiler + ); + + await server.start(); + + const proxy = express(); + + // Parse application/x-www-form-urlencoded + proxy.use(bodyParser.urlencoded({ extended: false })); + + // Parse application/json + proxy.use(bodyParser.json()); + + // This forces Express to try to decode URLs, which is needed for the test + // associated with the middleware below. + proxy.all("*", (_req, res, next) => { + next(); + }); + // We must define all 4 params in order for this to be detected as an + // error handling middleware. + // eslint-disable-next-line no-unused-vars + proxy.use((error, proxyReq, res, next) => { + res.status(500); + res.send("error from proxy"); + }); + + proxy.get("/get", (proxyReq, res) => { + res.send("GET method from proxy"); + }); + + proxy.head("/head", (proxyReq, res) => { + res.send("HEAD method from proxy"); + }); + + proxy.post("/post-x-www-form-urlencoded", (proxyReq, res) => { + const id = proxyReq.body.id; + + res.status(200).send(`POST method from proxy (id: ${id})`); + }); + + proxy.post("/post-application-json", (proxyReq, res) => { + const id = proxyReq.body.id; + + res.status(200).send({ answer: `POST method from proxy (id: ${id})` }); + }); + + proxy.delete("/delete", (proxyReq, res) => { + res.send("DELETE method from proxy"); + }); + + listener = proxy.listen(port1); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await new Promise((resolve) => { + listener.close(() => { + resolve(); + }); + }); + }); + + it("errors", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/%`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("GET method", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/get`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("HEAD method", async () => { + await page.setRequestInterception(true); + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }) + .on("request", (interceptedRequest) => { + interceptedRequest.continue({ method: "HEAD" }); + }); + + const response = await page.goto(`http://localhost:${port3}/head`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("POST method (application/x-www-form-urlencoded)", async () => { + await page.setRequestInterception(true); + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }) + .on("request", (interceptedRequest) => { + interceptedRequest.continue({ + method: "POST", + postData: "id=1", + headers: { + ...interceptedRequest.headers(), + "Content-Type": "application/x-www-form-urlencoded", + }, + }); + }); + + const response = await page.goto( + `http://localhost:${port3}/post-x-www-form-urlencoded`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(response.headers()["content-type"]).toMatchSnapshot( + "response headers content-type" + ); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("POST method (application/json)", async () => { + await page.setRequestInterception(true); + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }) + .on("request", (interceptedRequest) => { + interceptedRequest.continue({ + method: "POST", + postData: JSON.stringify({ id: "1" }), + headers: { + ...interceptedRequest.headers(), + "Content-Type": "application/json", + }, + }); + }); + + const response = await page.goto( + `http://localhost:${port3}/post-application-json`, + { + waitUntil: "networkidle0", + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(response.headers()["content-type"]).toMatchSnapshot( + "response headers content-type" + ); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("DELETE method", async () => { + await page.setRequestInterception(true); + + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }) + .on("request", (interceptedRequest) => { + interceptedRequest.continue({ method: "DELETE" }); + }); + + const response = await page.goto(`http://localhost:${port3}/delete`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("should work in multi compiler mode", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + proxy: { + "*": { + context: () => true, + target: `http://localhost:${port1}`, + }, + }, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + it("respects a proxy option", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/proxy1`, { + waitUntil: "networkidle0", + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("should work and respect `logProvider` and `logLevel` options", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let customLogProvider; + + beforeEach(async () => { + customLogProvider = { + log: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + compiler = webpack(config); + + server = new Server( + { + proxy: { + "/my-path": { + target: "http://unknown:1234", + logProvider: () => customLogProvider, + logLevel: "error", + }, + }, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + describe("target", () => { + it("respects a proxy option when a request path is matched", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/my-path`, { + waitUntil: "networkidle0", + }); + + expect(customLogProvider.error).toHaveBeenCalledTimes(1); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect( + consoleMessages.map((message) => message.text()) + ).toMatchSnapshot("console messages"); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + }); + + describe("should work and respect `logProvider` and `logLevel` options with `silent` value", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let customLogProvider; + + beforeEach(async () => { + customLogProvider = { + log: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + compiler = webpack(config); + + server = new Server( + { + proxy: { + "/my-path": { + target: "http://unknown:1234", + logProvider: () => customLogProvider, + logLevel: "silent", + }, + }, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + describe("target", () => { + it("respects a proxy option when a request path is matched", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/my-path`, { + waitUntil: "networkidle0", + }); + + expect(customLogProvider.error).toHaveBeenCalledTimes(0); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect( + consoleMessages.map((message) => message.text()) + ).toMatchSnapshot("console messages"); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + }); + + describe("should work and respect the `infrastructureLogging.level` option", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let customLogProvider; + + beforeEach(async () => { + customLogProvider = { + log: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + compiler = webpack({ + ...config, + infrastructureLogging: { level: "error" }, + }); + + server = new Server( + { + proxy: { + "/my-path": { + target: "http://unknown:1234", + logProvider: () => customLogProvider, + }, + }, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + describe("target", () => { + it("respects a proxy option when a request path is matched", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/my-path`, { + waitUntil: "networkidle0", + }); + + expect(customLogProvider.error).toHaveBeenCalledTimes(1); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect( + consoleMessages.map((message) => message.text()) + ).toMatchSnapshot("console messages"); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + }); + + describe("should work and respect the `infrastructureLogging.level` option with `none` value", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let customLogProvider; + + beforeEach(async () => { + customLogProvider = { + log: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + compiler = webpack({ + ...config, + infrastructureLogging: { level: "none" }, + }); + + server = new Server( + { + proxy: { + "/my-path": { + target: "http://unknown:1234", + logProvider: () => customLogProvider, + }, + }, + port: port3, + }, + compiler + ); + + await server.start(); + + await listenProxyServers(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + await closeProxyServers(); + }); + + describe("target", () => { + it("respects a proxy option when a request path is matched", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://localhost:${port3}/my-path`, { + waitUntil: "networkidle0", + }); + + expect(customLogProvider.error).toHaveBeenCalledTimes(0); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toMatchSnapshot("response text"); + + expect( + consoleMessages.map((message) => message.text()) + ).toMatchSnapshot("console messages"); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + }); +}); diff --git a/test/server/proxy-option.test.js b/test/server/proxy-option.test.js deleted file mode 100644 index f5ffcf2857..0000000000 --- a/test/server/proxy-option.test.js +++ /dev/null @@ -1,980 +0,0 @@ -"use strict"; - -const path = require("path"); -const request = require("supertest"); -const express = require("express"); -const bodyParser = require("body-parser"); -const WebSocket = require("ws"); -const webpack = require("webpack"); -const Server = require("../../lib/Server"); -const config = require("../fixtures/proxy-config/webpack.config"); -const [port1, port2, port3, port4] = require("../ports-map")["proxy-option"]; - -const WebSocketServer = WebSocket.Server; -const staticDirectory = path.resolve(__dirname, "../fixtures/proxy-config"); - -const proxyOptionPathsAsProperties = { - "/proxy1": { - target: `http://localhost:${port1}`, - }, - "/api/proxy2": { - target: `http://localhost:${port2}`, - pathRewrite: { "^/api": "" }, - }, - "/foo": { - bypass(req) { - if (/\.html$/.test(req.path)) { - return "/index.html"; - } - - return null; - }, - }, - "/proxyfalse": { - bypass(req) { - if (/\/proxyfalse$/.test(req.path)) { - return false; - } - }, - }, - "/proxy/async": { - bypass(req, res) { - if (/\/proxy\/async$/.test(req.path)) { - return new Promise((resolve) => { - setTimeout(() => { - res.end("proxy async response"); - resolve(true); - }, 10); - }); - } - }, - }, - "/bypass-with-target": { - target: `http://localhost:${port1}`, - changeOrigin: true, - secure: false, - bypass(req) { - if (/\.(html)$/i.test(req.url)) { - return req.url; - } - }, - }, -}; - -const proxyOption = { - context: () => true, - target: `http://localhost:${port1}`, -}; - -const proxyOptionOfArray = [ - { context: "/proxy1", target: proxyOption.target }, - function proxy(req, res, next) { - return { - context: "/api/proxy2", - target: `http://localhost:${port2}`, - pathRewrite: { "^/api": "" }, - bypass: () => { - if (req && req.query.foo) { - res.end(`foo+${next.name}+${typeof next}`); - - return false; - } - }, - }; - }, -]; - -const proxyOptionOfArrayWithoutTarget = [ - { - router: () => `http://localhost:${port1}`, - }, -]; - -const proxyWithPath = { - "/proxy1": { - path: `http://localhost:${port1}`, - target: `http://localhost:${port1}`, - }, -}; - -const proxyWithString = { - "/proxy1": `http://localhost:${port1}`, -}; - -const proxyWithRouterAsObject = { - router: () => `http://localhost:${port1}`, -}; - -describe("proxy option", () => { - let proxyServer1; - let proxyServer2; - - async function listenProxyServers() { - const proxyApp1 = express(); - const proxyApp2 = express(); - - proxyApp1.get("/proxy1", (req, res) => { - res.send("from proxy1"); - }); - proxyApp1.get("/api", (req, res) => { - res.send("api response from proxy1"); - }); - proxyApp2.get("/proxy2", (req, res) => { - res.send("from proxy2"); - }); - - await new Promise((resolve) => { - proxyServer1 = proxyApp1.listen(port1, () => { - resolve(); - }); - }); - - await new Promise((resolve) => { - proxyServer2 = proxyApp2.listen(port2, () => { - resolve(); - }); - }); - } - - async function closeProxyServers() { - await new Promise((resolve) => { - proxyServer1.close(() => { - resolve(); - }); - }); - - await new Promise((resolve) => { - proxyServer2.close(() => { - resolve(); - }); - }); - } - - describe("as an object of paths with properties", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - static: { - directory: staticDirectory, - watch: false, - }, - proxy: proxyOptionPathsAsProperties, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - describe("target", () => { - it("respects a proxy option when a request path is matched", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - }); - - describe("pathRewrite", () => { - it("respects a pathRewrite option", async () => { - const response = await req.get("/api/proxy2"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy2"); - }); - }); - - describe("bypass", () => { - it("can rewrite a request path", async () => { - const response = await req.get("/foo/bar.html"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("Hello"); - }); - - it("can rewrite a request path regardless of the target defined a bypass option", async () => { - const response = await req.get("/baz/hoge.html"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("Hello"); - }); - - it("should pass through a proxy when a bypass function returns null", async () => { - const response = await req.get("/foo.js"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("Hey"); - }); - - it("should not pass through a proxy when a bypass function returns false", async () => { - const response = await req.get("/proxyfalse"); - - expect(response.status).toEqual(404); - }); - - it("should wait if bypass returns promise", async () => { - const response = await req.get("/proxy/async"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("proxy async response"); - }); - - it("should work with the 'target' option", async () => { - const response = await req.get("/bypass-with-target/foo.js"); - - expect(response.status).toEqual(404); - }); - - it("should work with the 'target' option #2", async () => { - const response = await req.get("/bypass-with-target/index.html"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("Hello"); - }); - }); - }); - - describe("as an option is an object with the `context` option", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: proxyOption, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - it("respects a proxy option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - }); - - describe("as an option is an object with `context` and `target` as string", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: proxyWithString, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - it("respects a proxy option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - }); - - describe("as an option is an object with the `path` option (`context` alias)", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: proxyWithPath, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - it("respects a proxy option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - }); - - describe("as an option is an object with the `router` option", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: proxyWithRouterAsObject, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - it("respects a proxy option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - }); - - describe("as an array", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: proxyOptionOfArray, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - it("respects a proxy option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - - it("respects a proxy option of function", async () => { - const response = await req.get("/api/proxy2"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy2"); - }); - - it("should allow req, res, and next", async () => { - const response = await req.get("/api/proxy2?foo=true"); - - expect(response.statusCode).toEqual(200); - expect(response.text).toEqual("foo+next+function"); - }); - }); - - describe("as an array without the `route` option", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: proxyOptionOfArrayWithoutTarget, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - it("respects a proxy option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - }); - - describe("should sharing a proxy option", () => { - let server; - let req; - let listener; - - const proxyTarget = { - target: `http://localhost:${port1}`, - }; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: { - "/proxy1": proxyTarget, - "/proxy2": proxyTarget, - }, - port: port3, - }, - compiler - ); - - await server.start(); - - const proxy = express(); - - proxy.get("*", (proxyReq, res) => { - res.send("from proxy"); - }); - - listener = proxy.listen(port1); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await new Promise((resolve) => { - listener.close(() => { - resolve(); - }); - }); - }); - - it("respects proxy1 option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy"); - }); - - it("respects proxy2 option", async () => { - const response = await req.get("/proxy2"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy"); - }); - }); - - describe("should handles external websocket upgrade", () => { - let ws; - let server; - let webSocketServer; - let responseMessage; - - const webSocketServerTypes = ["sockjs", "ws"]; - - webSocketServerTypes.forEach((webSocketServerType) => { - describe(`with webSocketServerType: ${webSocketServerType}`, () => { - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - webSocketServer: webSocketServerType, - proxy: [ - { - context: "/", - target: `http://localhost:${port4}`, - ws: true, - }, - ], - port: port3, - }, - compiler - ); - - await server.start(); - - webSocketServer = new WebSocketServer({ port: port4 }); - webSocketServer.on("connection", (connection) => { - connection.on("message", (message) => { - connection.send(message); - }); - }); - }); - - beforeEach((done) => { - ws = new WebSocket(`ws://localhost:${port3}/proxy3/socket`); - - ws.on("message", (message) => { - responseMessage = message.toString(); - done(); - }); - - ws.on("open", () => { - ws.send("foo"); - }); - }); - - it("Should receive response", () => { - expect(responseMessage).toEqual("foo"); - }); - - afterAll(async () => { - webSocketServer.close(); - - for (const client of webSocketServer.clients) { - client.terminate(); - } - - await server.stop(); - }); - }); - }); - }); - - describe("should supports http methods", () => { - let server; - let req; - let listener; - const proxyTarget = { - target: `http://localhost:${port1}`, - }; - - beforeAll(async () => { - const compiler = webpack(config); - - server = new Server( - { - proxy: { - "**": proxyTarget, - }, - port: port3, - }, - compiler - ); - - await server.start(); - - const proxy = express(); - - // Parse application/x-www-form-urlencoded - proxy.use(bodyParser.urlencoded({ extended: false })); - - // Parse application/json - proxy.use(bodyParser.json()); - - // This forces Express to try to decode URLs, which is needed for the test - // associated with the middleware below. - proxy.all("*", (_req, res, next) => { - next(); - }); - // We must define all 4 params in order for this to be detected as an - // error handling middleware. - // eslint-disable-next-line no-unused-vars - proxy.use((error, proxyReq, res, next) => { - res.status(500); - res.send("error from proxy"); - }); - - proxy.get("/get", (proxyReq, res) => { - res.send("GET method from proxy"); - }); - - proxy.head("/head", (proxyReq, res) => { - res.send("HEAD method from proxy"); - }); - - proxy.post("/post-x-www-form-urlencoded", (proxyReq, res) => { - const id = proxyReq.body.id; - - res.status(200).send(`POST method from proxy (id: ${id})`); - }); - - proxy.post("/post-application-json", (proxyReq, res) => { - const id = proxyReq.body.id; - - res.status(200).send({ answer: `POST method from proxy (id: ${id})` }); - }); - - proxy.delete("/delete", (proxyReq, res) => { - res.send("DELETE method from proxy"); - }); - - listener = proxy.listen(port1); - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - - await new Promise((resolve) => { - listener.close(() => { - resolve(); - }); - }); - }); - - it("errors", async () => { - const response = await req.get("/%"); - - expect(response.status).toEqual(500); - expect(response.text).toContain("error from proxy"); - }); - - it("GET method", async () => { - const response = await req.get("/get"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("GET method from proxy"); - }); - - it("HEAD method", async () => { - const response = await req.head("/head"); - - expect(response.status).toEqual(200); - }); - - it("POST method (application/x-www-form-urlencoded)", async () => { - const response = await req - .post("/post-x-www-form-urlencoded") - .send("id=1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("POST method from proxy (id: 1)"); - }); - - it("POST method (application/json)", async () => { - const response = await req - .post("/post-application-json") - .send({ id: "1" }) - .set("Accept", "application/json"); - - expect(response.status).toEqual(200); - expect(response.headers["content-type"]).toEqual( - "application/json; charset=utf-8" - ); - expect(response.text).toContain("POST method from proxy (id: 1)"); - }); - - it("DELETE method", async () => { - const response = await req.delete("/delete"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("DELETE method from proxy"); - }); - }); - - describe("should work in multi compiler mode", () => { - let server; - let req; - - beforeAll(async () => { - const compiler = webpack([config, config]); - - server = new Server( - { - proxy: { - "*": { - context: () => true, - target: `http://localhost:${port1}`, - }, - }, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - it("respects a proxy option", async () => { - const response = await req.get("/proxy1"); - - expect(response.status).toEqual(200); - expect(response.text).toContain("from proxy1"); - }); - }); - - describe("should work and respect `logProvider` and `logLevel` options", () => { - let server; - let req; - let customLogProvider; - - beforeAll(async () => { - customLogProvider = { - log: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - const compiler = webpack([config, config]); - - server = new Server( - { - proxy: { - "/my-path": { - target: "http://unknown:1234", - logProvider: () => customLogProvider, - logLevel: "error", - }, - }, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - describe("target", () => { - it("respects a proxy option when a request path is matched", async () => { - await req.get("/my-path"); - - expect(customLogProvider.error).toHaveBeenCalledTimes(1); - }); - }); - }); - - describe("should work and respect the `logLevel` option with `silent` value", () => { - let server; - let req; - let customLogProvider; - - beforeAll(async () => { - customLogProvider = { - log: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - const compiler = webpack([config, config]); - - server = new Server( - { - proxy: { - "/my-path": { - target: "http://unknown:1234", - logProvider: () => customLogProvider, - logLevel: "silent", - }, - }, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - describe("target", () => { - it("respects a proxy option when a request path is matched", async () => { - await req.get("/my-path"); - - expect(customLogProvider.error).toHaveBeenCalledTimes(0); - }); - }); - }); - - describe("should work and respect the `infrastructureLogging.level` option", () => { - let server; - let req; - let customLogProvider; - - beforeAll(async () => { - customLogProvider = { - log: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - const compiler = webpack({ - ...config, - infrastructureLogging: { level: "error" }, - }); - - server = new Server( - { - proxy: { - "/my-path": { - target: "http://unknown:1234", - logProvider: () => customLogProvider, - }, - }, - port: port3, - }, - compiler - ); - - await server.start(); - - await listenProxyServers(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - await closeProxyServers(); - }); - - describe("target", () => { - it("respects a proxy option when a request path is matched", async () => { - await req.get("/my-path"); - - expect(customLogProvider.error).toHaveBeenCalledTimes(1); - }); - }); - }); - - describe("should work and respect the `infrastructureLogging.level` option with `none` value", () => { - let server; - let req; - let customLogProvider; - - beforeAll(async () => { - customLogProvider = { - log: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - const compiler = webpack({ - ...config, - infrastructureLogging: { level: "none" }, - }); - - server = new Server( - { - proxy: { - "/my-path": { - target: "http://unknown:1234", - logProvider: () => customLogProvider, - }, - }, - port: port3, - }, - compiler - ); - - await server.start(); - - req = request(server.app); - }); - - afterAll(async () => { - await server.stop(); - }); - - describe("target", () => { - it("respects a proxy option when a request path is matched", async () => { - await req.get("/my-path"); - - expect(customLogProvider.error).toHaveBeenCalledTimes(0); - }); - }); - }); -});