From de2d61dbaa79b5811f7e0933c42b92c5f33c11f5 Mon Sep 17 00:00:00 2001 From: LingyuCoder Date: Mon, 9 Sep 2024 15:51:39 +0800 Subject: [PATCH] test(dev-sever): add e2e test cases part 3 --- packages/rspack-dev-server/jest.config.js | 10 +- .../__snapshots__/port.test.js.snap.webpack5 | 61 + ...and-client-transport.test.js.snap.webpack5 | 107 + .../server.test.js.snap.webpack5 | 604 ++++ .../setup-exit-signals.test.js.snap.webpack5 | 25 + .../setup-middlewares.test.js.snap.webpack5 | 39 + .../static-directory.test.js.snap.webpack5 | 149 + .../static-public-path.test.js.snap.webpack5 | 262 ++ .../__snapshots__/stats.test.js.snap.webpack5 | 57 + .../target.test.js.snap.webpack5 | 94 + .../watch-files.test.js.snap.webpack5 | 311 ++ ...socket-communication.test.js.snap.webpack5 | 81 + ...eb-socket-server-url.test.js.snap.webpack5 | 710 +++++ .../web-socket-server.test.js.snap.webpack5 | 9 + .../rspack-dev-server/tests/e2e/port.test.js | 115 + .../tests/e2e/progress.test.js | 90 + .../tests/e2e/range-header.test.js | 111 + .../e2e/server-and-client-transport.test.js | 620 ++++ .../tests/e2e/server.test.js | 1441 +++++++++ .../tests/e2e/setup-exit-signals.test.js | 118 + .../tests/e2e/setup-middlewares.test.js | 171 + .../tests/e2e/static-directory.test.js | 686 ++++ .../tests/e2e/static-public-path.test.js | 1101 +++++++ .../rspack-dev-server/tests/e2e/stats.test.js | 147 + .../tests/e2e/target.test.js | 94 + .../tests/e2e/watch-files.test.js | 682 ++++ .../e2e/web-socket-communication.test.js | 223 ++ .../tests/e2e/web-socket-server-url.test.js | 2765 +++++++++++++++++ .../tests/e2e/web-socket-server.test.js | 68 + .../fixtures/https-certificate/ca-symlink.pem | 1 + .../tests/fixtures/https-certificate/ca.pem | 27 + .../https-certificate/server-symlink.crt | 1 + .../https-certificate/server-symlink.key | 1 + .../https-certificate/server-symlink.pfx | 1 + .../fixtures/https-certificate/server.crt | 21 + .../fixtures/https-certificate/server.key | 28 + .../fixtures/https-certificate/server.pfx | Bin 0 -> 2469 bytes .../provide-plugin-custom copy/foo.js | 8 + .../webpack.config.js | 21 + .../fixtures/provide-plugin-default/foo.js | 9 + .../provide-plugin-default/webpack.config.js | 21 + .../provide-plugin-sockjs-config/foo.js | 9 + .../webpack.config.js | 21 + .../fixtures/provide-plugin-ws-config/foo.js | 9 + .../webpack.config.js | 21 + .../tests/fixtures/reload-config-2/foo.js | 4 + .../reload-config-2/webpack.config.js | 29 + .../tests/fixtures/static-config/foo.js | 3 + .../fixtures/static-config/other/foo.html | 1 + .../static-config/public/assets/example.txt | 0 .../static-config/public/assets/other.txt | 0 .../static-config/public/bar/index.html | 1 + .../fixtures/static-config/public/foo.wasm | 0 .../fixtures/static-config/public/index.html | 1 + .../fixtures/static-config/public/other.html | 1 + .../fixtures/static-config/static/index.html | 1 + .../fixtures/static-config/webpack.config.js | 14 + .../tests/fixtures/watch-files-config/foo.js | 3 + .../watch-files-config/other/foo.html | 1 + .../public/assets/example.txt | 0 .../public/assets/non-exist.txt | 1 + .../public/assets/other.txt | 0 .../watch-files-config/public/bar/index.html | 1 + .../watch-files-config/public/other.html | 1 + .../watch-files-config/static/index.html | 1 + .../watch-files-config/webpack.config.js | 17 + .../tests/helpers/conditional-test.js | 12 + .../tests/helpers/custom-http.js | 5 + .../tests/helpers/normalize-options.js | 38 + .../tests/helpers/test-server.js | 95 + 70 files changed, 11378 insertions(+), 2 deletions(-) create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/port.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/server-and-client-transport.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/server.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/setup-exit-signals.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/setup-middlewares.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/static-directory.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/static-public-path.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/stats.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/target.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/watch-files.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-communication.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server-url.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server.test.js.snap.webpack5 create mode 100644 packages/rspack-dev-server/tests/e2e/port.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/progress.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/range-header.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/server-and-client-transport.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/server.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/setup-exit-signals.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/setup-middlewares.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/static-directory.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/static-public-path.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/stats.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/target.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/watch-files.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/web-socket-communication.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/web-socket-server-url.test.js create mode 100644 packages/rspack-dev-server/tests/e2e/web-socket-server.test.js create mode 120000 packages/rspack-dev-server/tests/fixtures/https-certificate/ca-symlink.pem create mode 100644 packages/rspack-dev-server/tests/fixtures/https-certificate/ca.pem create mode 120000 packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.crt create mode 120000 packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.key create mode 120000 packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.pfx create mode 100644 packages/rspack-dev-server/tests/fixtures/https-certificate/server.crt create mode 100644 packages/rspack-dev-server/tests/fixtures/https-certificate/server.key create mode 100644 packages/rspack-dev-server/tests/fixtures/https-certificate/server.pfx create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/foo.js create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/webpack.config.js create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-default/foo.js create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-default/webpack.config.js create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/foo.js create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/webpack.config.js create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/foo.js create mode 100644 packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/webpack.config.js create mode 100644 packages/rspack-dev-server/tests/fixtures/reload-config-2/foo.js create mode 100644 packages/rspack-dev-server/tests/fixtures/reload-config-2/webpack.config.js create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/foo.js create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/other/foo.html create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/public/assets/example.txt create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/public/assets/other.txt create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/public/bar/index.html create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/public/foo.wasm create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/public/index.html create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/public/other.html create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/static/index.html create mode 100644 packages/rspack-dev-server/tests/fixtures/static-config/webpack.config.js create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/foo.js create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/other/foo.html create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/example.txt create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/non-exist.txt create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/other.txt create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/public/bar/index.html create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/public/other.html create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/static/index.html create mode 100644 packages/rspack-dev-server/tests/fixtures/watch-files-config/webpack.config.js create mode 100644 packages/rspack-dev-server/tests/helpers/conditional-test.js create mode 100644 packages/rspack-dev-server/tests/helpers/custom-http.js create mode 100644 packages/rspack-dev-server/tests/helpers/normalize-options.js create mode 100644 packages/rspack-dev-server/tests/helpers/test-server.js diff --git a/packages/rspack-dev-server/jest.config.js b/packages/rspack-dev-server/jest.config.js index f8b27860bb0..28f5a1a8433 100644 --- a/packages/rspack-dev-server/jest.config.js +++ b/packages/rspack-dev-server/jest.config.js @@ -5,10 +5,16 @@ const config = { url: "http://localhost/" }, testMatch: ["/tests/*.test.ts", "/tests/e2e/*.test.js"], - // TODO: check why these tests throw errors + testPathIgnorePatterns: [ + // TODO: check why http proxy server throw error with websocket server "/tests/e2e/allowed-hosts.test.js", - "/tests/e2e/host.test.js" + // TODO: check why this test timeout + "/tests/e2e/host.test.js", + // TODO: not support progress plugin event yet + "/tests/e2e/progress.test.js", + // TODO: check why this test throw erro when run with other tests + "/tests/e2e/watch-files.test.js" ], cache: false, testTimeout: process.env.CI ? 120000 : 30000, diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/port.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/port.test.js.snap.webpack5 new file mode 100644 index 00000000000..56c9509a19d --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/port.test.js.snap.webpack5 @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`port should work using "" port : console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`port should work using "" port : page errors 1`] = `[]`; + +exports[`port should work using "0" port : console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`port should work using "0" port : page errors 1`] = `[]`; + +exports[`port should work using "8161" port : console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`port should work using "8161" port : console messages 2`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`port should work using "8161" port : page errors 1`] = `[]`; + +exports[`port should work using "8161" port : page errors 2`] = `[]`; + +exports[`port should work using "auto" port : console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`port should work using "auto" port : page errors 1`] = `[]`; + +exports[`port should work using "undefined" port : console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`port should work using "undefined" port : page errors 1`] = `[]`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/server-and-client-transport.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/server-and-client-transport.test.js.snap.webpack5 new file mode 100644 index 00000000000..6fa2cfc536f --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/server-and-client-transport.test.js.snap.webpack5 @@ -0,0 +1,107 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`server and client transport should throw an error on invalid path to client transport 1`] = `"client.webSocketTransport must be a string denoting a default implementation (e.g. 'sockjs', 'ws') or a full path to a JS file via require.resolve(...) which exports a class "`; + +exports[`server and client transport should throw an error on invalid path to server transport 1`] = `"webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) via require.resolve(...), or the class itself which extends BaseServer"`; + +exports[`server and client transport should throw an error on wrong path 1`] = `"webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) via require.resolve(...), or the class itself which extends BaseServer"`; + +exports[`server and client transport should use "sockjs" transport and "sockjs" web socket server 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use "sockjs" transport, when web socket server is not specify 1`] = `[]`; + +exports[`server and client transport should use "sockjs" web socket server when specify "sockjs" value 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use "sockjs" web socket server when specify "sockjs" value using object 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use "ws" transport and "ws" web socket server 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use "ws" transport, when web socket server is not specify 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use "ws" web socket server when specify "ws" value 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use "ws" web socket server when specify "ws" value using object 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use custom transport and "sockjs" web socket server 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "open", + "hot", + "liveReload", + "reconnect", + "overlay", + "hash", + "ok", +] +`; + +exports[`server and client transport should use custom web socket server when specify class 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use custom web socket server when specify class using object 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use custom web socket server when specify path to class 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use custom web socket server when specify path to class using object 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; + +exports[`server and client transport should use default web socket server ("ws") 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", +] +`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/server.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/server.test.js.snap.webpack5 new file mode 100644 index 00000000000..dabcd217098 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/server.test.js.snap.webpack5 @@ -0,0 +1,604 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`server option as object allow to pass more options should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object allow to pass more options should handle GET request to index route (/): https options 1`] = ` +{ + "ca": "", + "cert": "", + "key": "", + "minVersion": "TLSv1.1", + "passphrase": "webpack-dev-server", + "pfx": "", + "requestCert": false, +} +`; + +exports[`server option as object allow to pass more options should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object allow to pass more options should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object allow to pass more options should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are array of buffers should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are array of buffers should handle GET request to index route (/): https options 1`] = ` +{ + "ca": [ + "", + ], + "cert": [ + "", + ], + "key": [ + "", + ], + "passphrase": "webpack-dev-server", + "pfx": [ + "", + ], + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are array of buffers should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are array of buffers should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are array of buffers should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are array of paths to files should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are array of paths to files should handle GET request to index route (/): https options 1`] = ` +{ + "ca": [ + "", + ], + "cert": [ + "", + ], + "key": [ + "", + ], + "passphrase": "webpack-dev-server", + "pfx": [ + "", + ], + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are array of paths to files should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are array of paths to files should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are array of paths to files should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are array of strings should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are array of strings should handle GET request to index route (/): https options 1`] = ` +{ + "ca": [ + "-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kv +C/hf5Ei1J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYu +Dy9WkFuMie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhs +EENnH6sUE9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2sw +duxJTWRINmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+ +T8emgklStASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABAoIBAGqWKPE1QnT3T+3J +G+ITz9P0dDFbvWltlTZmeSJh/s2q+WZloUNtBxdmwbqT/1QecnkyGgyzVCjvSKsu +CgVjWNVAhysgtNtxRT4BVflffBXLVH2qsBjpsLRGU6EcMXuPGTiEp3YRHNuO6Aj8 +oP8fEsCGPc9DlJMGgxQRAKlrVF8TN/0j6Qk+YpS4MZ0YFQfBY+WdKu04Z8TVTplQ +tTkiGpBI+Oj85jF59aQiizglJgADkAZ6zmbrctm/G9jPxh7JLS2cKI0ECZgK5yAc +pk10E1YWhoCksjr9arxy6fS9TiX9P15vv06k+s7c4c5X7XDm3X0GWeSbqBMJb8q7 +BhZQNzECgYEA4kAtymDBvFYiZFq7+lzQBRKAI1RCq7YqxlieumH0PSkie2bba3dW +NVdTi7at8+GDB9/cHUPKzg/skfJllek57MZmusiVwB/Lmp/IlW8YyGShdYZ7zQsV +KMWJljpky3BEDM5sb08wIkfrOkelI/S4Bqqabd9JzOMJzoTiVOlMam8CgYEA3ctN +yonWz2bsnCUstQvQCLdI5a8Q7GJvlH2awephxGXIKGUuRmyyop0AnRnIBEWtOQV7 +yZjW32bU+Wt+2BJ247EyJiIQ4gT+T51t+v/Wt1YNbL3dSj9ttOvwYd4H2W4E7EIO +GKIF4I39FM7r8NfG7YE7S1aVcnrqs01N3nhd9HMCgYEAjepbzpmqbAxLPk97oase +AFB+d6qetz5ozklAJwDSRprKukTmVR5hwMup5/UKX/OQURwl4WVojKCIb3NwLPxC +DTbVsUuoQv6uo6qeEr3A+dHFRQa6GP9eolhl2Ql/t+wPg0jn01oEgzxBXCkceNVD +qUrR2yE4FYBD4nqPzVsZR5kCgYEA1yTi7NkQeldIpZ6Z43T18753A/Xx4JsLyWqd +uAT3mV9x7V1Yqg++qGbLtZjQoPRFt85N6ZxMsqA5b0iK3mXq1auJDdx1rAlT9z6q +9JM/YNAkbZsvEVq9vIYxw31w98T1GYhpzBM+yDhzir+9tv5YhQKa1dXDWi1JhWwz +YN45pWkCgYEAxuVsJ4D4Th5o050ppWpnxM/WuMhIUKqaoFTVucMKFzn+g24y9pv5 +miYdNYIk4Y+4pzHG6ZGZSHJcQ9BLui6H/nLQnqkgCb2lT5nfp7/GKdus7BdcjPGs +fcV46yL7/X0m8nDb3hkwwrDTU4mKFkMrzKpjdZBsttEmW0Aw/3y36gU= +-----END RSA PRIVATE KEY----- +", + ], + "cert": [ + "-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJALz8gD/gAt0OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDIzMTgyMTQ5WhcNMTkxMDIzMTgyMTQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kvC/hf5Ei1 +J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYuDy9WkFuM +ie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhsEENnH6sU +E9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2swduxJTWRI +NmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+T8emgklS +tASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABo1AwTjAdBgNVHQ4EFgQUDZBhVKdb +3BRhLIhuuE522Vsul0IwHwYDVR0jBBgwFoAUDZBhVKdb3BRhLIhuuE522Vsul0Iw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABh9WWZwWLgb9/DcTxL72 +6pI96t4jiF79Q+pPefkaIIi0mE6yodWrTAsBQu9I6bNRaEcCSoiXkP2bqskD/UGg +LwUFgSrDOAA3UjdHw3QU5g2NocduG7mcFwA40TB98sOsxsUyYlzSyWzoiQWwPYwb +hek1djuWkqPXsTjlj54PTPN/SjTFmo4p5Ip6nbRf2nOREl7v0rJpGbJvXiCMYyd+ +Zv+j4mRjCGo8ysMR2HjCUGkYReLAgKyyz3M7i8vevJhKslyOmy6Txn4F0nPVumaU +DDIy4xXPW1STWfsmSYJfYW3wa0wk+pJQ3j2cTzkPQQ8gwpvM3U9DJl43uwb37v6I +7Q== +-----END CERTIFICATE----- +", + ], + "key": [ + "-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEBRUsUz4rdcMt +CQGLvG3SzUinsmgdgOyTNQNA0eOMyRSrmS8L+F/kSLUnqqu4mzdeqDzo2Xj553jK +dRqMCRFGJuGnQ/VIbW2A+ywgrqILuDyF5i4PL1aQW4yJ7TnXfONKfpswQArlN6DF +gBYJtoJlf8XD1sOeJpsv/O46/ix/wngQ+GwQQ2cfqxQT0fE9SBCY23VNt3SPUJ3k +9etJMvJ9U9GHSb1CFdNQe7Gyx7xdKf1TazB27ElNZEg2aF99if47uRskYjvvFivy +7nxGx/ccIwjwNMpk29AsKG++0sn1yTK7tD5Px6aCSVK0BKbdXZS2euJor8hASGBJ +3GpVGJvdAgMBAAECggEAapYo8TVCdPdP7ckb4hPP0/R0MVu9aW2VNmZ5ImH+zar5 +ZmWhQ20HF2bBupP/VB5yeTIaDLNUKO9Iqy4KBWNY1UCHKyC023FFPgFV+V98FctU +faqwGOmwtEZToRwxe48ZOISndhEc247oCPyg/x8SwIY9z0OUkwaDFBEAqWtUXxM3 +/SPpCT5ilLgxnRgVB8Fj5Z0q7ThnxNVOmVC1OSIakEj46PzmMXn1pCKLOCUmAAOQ +BnrOZuty2b8b2M/GHsktLZwojQQJmArnIBymTXQTVhaGgKSyOv1qvHLp9L1OJf0/ +Xm+/TqT6ztzhzlftcObdfQZZ5JuoEwlvyrsGFlA3MQKBgQDiQC3KYMG8ViJkWrv6 +XNAFEoAjVEKrtirGWJ66YfQ9KSJ7Zttrd1Y1V1OLtq3z4YMH39wdQ8rOD+yR8mWV +6Tnsxma6yJXAH8uan8iVbxjIZKF1hnvNCxUoxYmWOmTLcEQMzmxvTzAiR+s6R6Uj +9LgGqppt30nM4wnOhOJU6UxqbwKBgQDdy03KidbPZuycJSy1C9AIt0jlrxDsYm+U +fZrB6mHEZcgoZS5GbLKinQCdGcgERa05BXvJmNbfZtT5a37YEnbjsTImIhDiBP5P +nW36/9a3Vg1svd1KP2206/Bh3gfZbgTsQg4YogXgjf0Uzuvw18btgTtLVpVyeuqz +TU3eeF30cwKBgQCN6lvOmapsDEs+T3uhqx4AUH53qp63PmjOSUAnANJGmsq6ROZV +HmHAy6nn9Qpf85BRHCXhZWiMoIhvc3As/EINNtWxS6hC/q6jqp4SvcD50cVFBroY +/16iWGXZCX+37A+DSOfTWgSDPEFcKRx41UOpStHbITgVgEPieo/NWxlHmQKBgQDX +JOLs2RB6V0ilnpnjdPXzvncD9fHgmwvJap24BPeZX3HtXViqD76oZsu1mNCg9EW3 +zk3pnEyyoDlvSIreZerVq4kN3HWsCVP3Pqr0kz9g0CRtmy8RWr28hjHDfXD3xPUZ +iGnMEz7IOHOKv722/liFAprV1cNaLUmFbDNg3jmlaQKBgQDG5WwngPhOHmjTnSml +amfEz9a4yEhQqpqgVNW5wwoXOf6DbjL2m/maJh01giThj7inMcbpkZlIclxD0Eu6 +Lof+ctCeqSAJvaVPmd+nv8Yp26zsF1yM8ax9xXjrIvv9fSbycNveGTDCsNNTiYoW +QyvMqmN1kGy20SZbQDD/fLfqBQ== +-----END PRIVATE KEY----- +", + ], + "passphrase": "webpack-dev-server", + "pfx": [ + "", + ], + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are array of strings should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are array of strings should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are array of strings should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): console messages 2`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): https options 1`] = ` +{ + "ca": "", + "cert": "", + "key": "", + "passphrase": "webpack-dev-server", + "pfx": "", + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): https options 2`] = ` +{ + "ca": "", + "cert": "", + "key": "", + "passphrase": "webpack-dev-server", + "pfx": "", + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): page errors 2`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): response status 2`] = `200`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are buffer should handle GET request to index route (/): response text 2`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are buffer, key and pfx are objects should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are buffer, key and pfx are objects should handle GET request to index route (/): https options 1`] = ` +{ + "ca": "", + "cert": "", + "key": [ + { + "pem": "", + }, + ], + "passphrase": "webpack-dev-server", + "pfx": [ + { + "buf": "", + }, + ], + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are buffer, key and pfx are objects should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are buffer, key and pfx are objects should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are buffer, key and pfx are objects should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are paths to files should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are paths to files should handle GET request to index route (/): https options 1`] = ` +{ + "ca": "", + "cert": "", + "key": "", + "passphrase": "webpack-dev-server", + "pfx": "", + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are paths to files should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are paths to files should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are paths to files should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are strings should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are strings should handle GET request to index route (/): https options 1`] = ` +{ + "ca": "-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kv +C/hf5Ei1J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYu +Dy9WkFuMie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhs +EENnH6sUE9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2sw +duxJTWRINmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+ +T8emgklStASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABAoIBAGqWKPE1QnT3T+3J +G+ITz9P0dDFbvWltlTZmeSJh/s2q+WZloUNtBxdmwbqT/1QecnkyGgyzVCjvSKsu +CgVjWNVAhysgtNtxRT4BVflffBXLVH2qsBjpsLRGU6EcMXuPGTiEp3YRHNuO6Aj8 +oP8fEsCGPc9DlJMGgxQRAKlrVF8TN/0j6Qk+YpS4MZ0YFQfBY+WdKu04Z8TVTplQ +tTkiGpBI+Oj85jF59aQiizglJgADkAZ6zmbrctm/G9jPxh7JLS2cKI0ECZgK5yAc +pk10E1YWhoCksjr9arxy6fS9TiX9P15vv06k+s7c4c5X7XDm3X0GWeSbqBMJb8q7 +BhZQNzECgYEA4kAtymDBvFYiZFq7+lzQBRKAI1RCq7YqxlieumH0PSkie2bba3dW +NVdTi7at8+GDB9/cHUPKzg/skfJllek57MZmusiVwB/Lmp/IlW8YyGShdYZ7zQsV +KMWJljpky3BEDM5sb08wIkfrOkelI/S4Bqqabd9JzOMJzoTiVOlMam8CgYEA3ctN +yonWz2bsnCUstQvQCLdI5a8Q7GJvlH2awephxGXIKGUuRmyyop0AnRnIBEWtOQV7 +yZjW32bU+Wt+2BJ247EyJiIQ4gT+T51t+v/Wt1YNbL3dSj9ttOvwYd4H2W4E7EIO +GKIF4I39FM7r8NfG7YE7S1aVcnrqs01N3nhd9HMCgYEAjepbzpmqbAxLPk97oase +AFB+d6qetz5ozklAJwDSRprKukTmVR5hwMup5/UKX/OQURwl4WVojKCIb3NwLPxC +DTbVsUuoQv6uo6qeEr3A+dHFRQa6GP9eolhl2Ql/t+wPg0jn01oEgzxBXCkceNVD +qUrR2yE4FYBD4nqPzVsZR5kCgYEA1yTi7NkQeldIpZ6Z43T18753A/Xx4JsLyWqd +uAT3mV9x7V1Yqg++qGbLtZjQoPRFt85N6ZxMsqA5b0iK3mXq1auJDdx1rAlT9z6q +9JM/YNAkbZsvEVq9vIYxw31w98T1GYhpzBM+yDhzir+9tv5YhQKa1dXDWi1JhWwz +YN45pWkCgYEAxuVsJ4D4Th5o050ppWpnxM/WuMhIUKqaoFTVucMKFzn+g24y9pv5 +miYdNYIk4Y+4pzHG6ZGZSHJcQ9BLui6H/nLQnqkgCb2lT5nfp7/GKdus7BdcjPGs +fcV46yL7/X0m8nDb3hkwwrDTU4mKFkMrzKpjdZBsttEmW0Aw/3y36gU= +-----END RSA PRIVATE KEY----- +", + "cert": "-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJALz8gD/gAt0OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDIzMTgyMTQ5WhcNMTkxMDIzMTgyMTQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kvC/hf5Ei1 +J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYuDy9WkFuM +ie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhsEENnH6sU +E9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2swduxJTWRI +NmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+T8emgklS +tASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABo1AwTjAdBgNVHQ4EFgQUDZBhVKdb +3BRhLIhuuE522Vsul0IwHwYDVR0jBBgwFoAUDZBhVKdb3BRhLIhuuE522Vsul0Iw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABh9WWZwWLgb9/DcTxL72 +6pI96t4jiF79Q+pPefkaIIi0mE6yodWrTAsBQu9I6bNRaEcCSoiXkP2bqskD/UGg +LwUFgSrDOAA3UjdHw3QU5g2NocduG7mcFwA40TB98sOsxsUyYlzSyWzoiQWwPYwb +hek1djuWkqPXsTjlj54PTPN/SjTFmo4p5Ip6nbRf2nOREl7v0rJpGbJvXiCMYyd+ +Zv+j4mRjCGo8ysMR2HjCUGkYReLAgKyyz3M7i8vevJhKslyOmy6Txn4F0nPVumaU +DDIy4xXPW1STWfsmSYJfYW3wa0wk+pJQ3j2cTzkPQQ8gwpvM3U9DJl43uwb37v6I +7Q== +-----END CERTIFICATE----- +", + "key": "-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEBRUsUz4rdcMt +CQGLvG3SzUinsmgdgOyTNQNA0eOMyRSrmS8L+F/kSLUnqqu4mzdeqDzo2Xj553jK +dRqMCRFGJuGnQ/VIbW2A+ywgrqILuDyF5i4PL1aQW4yJ7TnXfONKfpswQArlN6DF +gBYJtoJlf8XD1sOeJpsv/O46/ix/wngQ+GwQQ2cfqxQT0fE9SBCY23VNt3SPUJ3k +9etJMvJ9U9GHSb1CFdNQe7Gyx7xdKf1TazB27ElNZEg2aF99if47uRskYjvvFivy +7nxGx/ccIwjwNMpk29AsKG++0sn1yTK7tD5Px6aCSVK0BKbdXZS2euJor8hASGBJ +3GpVGJvdAgMBAAECggEAapYo8TVCdPdP7ckb4hPP0/R0MVu9aW2VNmZ5ImH+zar5 +ZmWhQ20HF2bBupP/VB5yeTIaDLNUKO9Iqy4KBWNY1UCHKyC023FFPgFV+V98FctU +faqwGOmwtEZToRwxe48ZOISndhEc247oCPyg/x8SwIY9z0OUkwaDFBEAqWtUXxM3 +/SPpCT5ilLgxnRgVB8Fj5Z0q7ThnxNVOmVC1OSIakEj46PzmMXn1pCKLOCUmAAOQ +BnrOZuty2b8b2M/GHsktLZwojQQJmArnIBymTXQTVhaGgKSyOv1qvHLp9L1OJf0/ +Xm+/TqT6ztzhzlftcObdfQZZ5JuoEwlvyrsGFlA3MQKBgQDiQC3KYMG8ViJkWrv6 +XNAFEoAjVEKrtirGWJ66YfQ9KSJ7Zttrd1Y1V1OLtq3z4YMH39wdQ8rOD+yR8mWV +6Tnsxma6yJXAH8uan8iVbxjIZKF1hnvNCxUoxYmWOmTLcEQMzmxvTzAiR+s6R6Uj +9LgGqppt30nM4wnOhOJU6UxqbwKBgQDdy03KidbPZuycJSy1C9AIt0jlrxDsYm+U +fZrB6mHEZcgoZS5GbLKinQCdGcgERa05BXvJmNbfZtT5a37YEnbjsTImIhDiBP5P +nW36/9a3Vg1svd1KP2206/Bh3gfZbgTsQg4YogXgjf0Uzuvw18btgTtLVpVyeuqz +TU3eeF30cwKBgQCN6lvOmapsDEs+T3uhqx4AUH53qp63PmjOSUAnANJGmsq6ROZV +HmHAy6nn9Qpf85BRHCXhZWiMoIhvc3As/EINNtWxS6hC/q6jqp4SvcD50cVFBroY +/16iWGXZCX+37A+DSOfTWgSDPEFcKRx41UOpStHbITgVgEPieo/NWxlHmQKBgQDX +JOLs2RB6V0ilnpnjdPXzvncD9fHgmwvJap24BPeZX3HtXViqD76oZsu1mNCg9EW3 +zk3pnEyyoDlvSIreZerVq4kN3HWsCVP3Pqr0kz9g0CRtmy8RWr28hjHDfXD3xPUZ +iGnMEz7IOHOKv722/liFAprV1cNaLUmFbDNg3jmlaQKBgQDG5WwngPhOHmjTnSml +amfEz9a4yEhQqpqgVNW5wwoXOf6DbjL2m/maJh01giThj7inMcbpkZlIclxD0Eu6 +Lof+ctCeqSAJvaVPmd+nv8Yp26zsF1yM8ax9xXjrIvv9fSbycNveGTDCsNNTiYoW +QyvMqmN1kGy20SZbQDD/fLfqBQ== +-----END PRIVATE KEY----- +", + "passphrase": "webpack-dev-server", + "pfx": "", + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are strings should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are strings should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are strings should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object ca, pfx, key and cert are strings, key and pfx are objects should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are strings, key and pfx are objects should handle GET request to index route (/): https options 1`] = ` +{ + "ca": "-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kv +C/hf5Ei1J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYu +Dy9WkFuMie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhs +EENnH6sUE9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2sw +duxJTWRINmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+ +T8emgklStASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABAoIBAGqWKPE1QnT3T+3J +G+ITz9P0dDFbvWltlTZmeSJh/s2q+WZloUNtBxdmwbqT/1QecnkyGgyzVCjvSKsu +CgVjWNVAhysgtNtxRT4BVflffBXLVH2qsBjpsLRGU6EcMXuPGTiEp3YRHNuO6Aj8 +oP8fEsCGPc9DlJMGgxQRAKlrVF8TN/0j6Qk+YpS4MZ0YFQfBY+WdKu04Z8TVTplQ +tTkiGpBI+Oj85jF59aQiizglJgADkAZ6zmbrctm/G9jPxh7JLS2cKI0ECZgK5yAc +pk10E1YWhoCksjr9arxy6fS9TiX9P15vv06k+s7c4c5X7XDm3X0GWeSbqBMJb8q7 +BhZQNzECgYEA4kAtymDBvFYiZFq7+lzQBRKAI1RCq7YqxlieumH0PSkie2bba3dW +NVdTi7at8+GDB9/cHUPKzg/skfJllek57MZmusiVwB/Lmp/IlW8YyGShdYZ7zQsV +KMWJljpky3BEDM5sb08wIkfrOkelI/S4Bqqabd9JzOMJzoTiVOlMam8CgYEA3ctN +yonWz2bsnCUstQvQCLdI5a8Q7GJvlH2awephxGXIKGUuRmyyop0AnRnIBEWtOQV7 +yZjW32bU+Wt+2BJ247EyJiIQ4gT+T51t+v/Wt1YNbL3dSj9ttOvwYd4H2W4E7EIO +GKIF4I39FM7r8NfG7YE7S1aVcnrqs01N3nhd9HMCgYEAjepbzpmqbAxLPk97oase +AFB+d6qetz5ozklAJwDSRprKukTmVR5hwMup5/UKX/OQURwl4WVojKCIb3NwLPxC +DTbVsUuoQv6uo6qeEr3A+dHFRQa6GP9eolhl2Ql/t+wPg0jn01oEgzxBXCkceNVD +qUrR2yE4FYBD4nqPzVsZR5kCgYEA1yTi7NkQeldIpZ6Z43T18753A/Xx4JsLyWqd +uAT3mV9x7V1Yqg++qGbLtZjQoPRFt85N6ZxMsqA5b0iK3mXq1auJDdx1rAlT9z6q +9JM/YNAkbZsvEVq9vIYxw31w98T1GYhpzBM+yDhzir+9tv5YhQKa1dXDWi1JhWwz +YN45pWkCgYEAxuVsJ4D4Th5o050ppWpnxM/WuMhIUKqaoFTVucMKFzn+g24y9pv5 +miYdNYIk4Y+4pzHG6ZGZSHJcQ9BLui6H/nLQnqkgCb2lT5nfp7/GKdus7BdcjPGs +fcV46yL7/X0m8nDb3hkwwrDTU4mKFkMrzKpjdZBsttEmW0Aw/3y36gU= +-----END RSA PRIVATE KEY----- +", + "cert": "-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJALz8gD/gAt0OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDIzMTgyMTQ5WhcNMTkxMDIzMTgyMTQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kvC/hf5Ei1 +J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYuDy9WkFuM +ie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhsEENnH6sU +E9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2swduxJTWRI +NmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+T8emgklS +tASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABo1AwTjAdBgNVHQ4EFgQUDZBhVKdb +3BRhLIhuuE522Vsul0IwHwYDVR0jBBgwFoAUDZBhVKdb3BRhLIhuuE522Vsul0Iw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABh9WWZwWLgb9/DcTxL72 +6pI96t4jiF79Q+pPefkaIIi0mE6yodWrTAsBQu9I6bNRaEcCSoiXkP2bqskD/UGg +LwUFgSrDOAA3UjdHw3QU5g2NocduG7mcFwA40TB98sOsxsUyYlzSyWzoiQWwPYwb +hek1djuWkqPXsTjlj54PTPN/SjTFmo4p5Ip6nbRf2nOREl7v0rJpGbJvXiCMYyd+ +Zv+j4mRjCGo8ysMR2HjCUGkYReLAgKyyz3M7i8vevJhKslyOmy6Txn4F0nPVumaU +DDIy4xXPW1STWfsmSYJfYW3wa0wk+pJQ3j2cTzkPQQ8gwpvM3U9DJl43uwb37v6I +7Q== +-----END CERTIFICATE----- +", + "key": [ + { + "pem": "-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEBRUsUz4rdcMt +CQGLvG3SzUinsmgdgOyTNQNA0eOMyRSrmS8L+F/kSLUnqqu4mzdeqDzo2Xj553jK +dRqMCRFGJuGnQ/VIbW2A+ywgrqILuDyF5i4PL1aQW4yJ7TnXfONKfpswQArlN6DF +gBYJtoJlf8XD1sOeJpsv/O46/ix/wngQ+GwQQ2cfqxQT0fE9SBCY23VNt3SPUJ3k +9etJMvJ9U9GHSb1CFdNQe7Gyx7xdKf1TazB27ElNZEg2aF99if47uRskYjvvFivy +7nxGx/ccIwjwNMpk29AsKG++0sn1yTK7tD5Px6aCSVK0BKbdXZS2euJor8hASGBJ +3GpVGJvdAgMBAAECggEAapYo8TVCdPdP7ckb4hPP0/R0MVu9aW2VNmZ5ImH+zar5 +ZmWhQ20HF2bBupP/VB5yeTIaDLNUKO9Iqy4KBWNY1UCHKyC023FFPgFV+V98FctU +faqwGOmwtEZToRwxe48ZOISndhEc247oCPyg/x8SwIY9z0OUkwaDFBEAqWtUXxM3 +/SPpCT5ilLgxnRgVB8Fj5Z0q7ThnxNVOmVC1OSIakEj46PzmMXn1pCKLOCUmAAOQ +BnrOZuty2b8b2M/GHsktLZwojQQJmArnIBymTXQTVhaGgKSyOv1qvHLp9L1OJf0/ +Xm+/TqT6ztzhzlftcObdfQZZ5JuoEwlvyrsGFlA3MQKBgQDiQC3KYMG8ViJkWrv6 +XNAFEoAjVEKrtirGWJ66YfQ9KSJ7Zttrd1Y1V1OLtq3z4YMH39wdQ8rOD+yR8mWV +6Tnsxma6yJXAH8uan8iVbxjIZKF1hnvNCxUoxYmWOmTLcEQMzmxvTzAiR+s6R6Uj +9LgGqppt30nM4wnOhOJU6UxqbwKBgQDdy03KidbPZuycJSy1C9AIt0jlrxDsYm+U +fZrB6mHEZcgoZS5GbLKinQCdGcgERa05BXvJmNbfZtT5a37YEnbjsTImIhDiBP5P +nW36/9a3Vg1svd1KP2206/Bh3gfZbgTsQg4YogXgjf0Uzuvw18btgTtLVpVyeuqz +TU3eeF30cwKBgQCN6lvOmapsDEs+T3uhqx4AUH53qp63PmjOSUAnANJGmsq6ROZV +HmHAy6nn9Qpf85BRHCXhZWiMoIhvc3As/EINNtWxS6hC/q6jqp4SvcD50cVFBroY +/16iWGXZCX+37A+DSOfTWgSDPEFcKRx41UOpStHbITgVgEPieo/NWxlHmQKBgQDX +JOLs2RB6V0ilnpnjdPXzvncD9fHgmwvJap24BPeZX3HtXViqD76oZsu1mNCg9EW3 +zk3pnEyyoDlvSIreZerVq4kN3HWsCVP3Pqr0kz9g0CRtmy8RWr28hjHDfXD3xPUZ +iGnMEz7IOHOKv722/liFAprV1cNaLUmFbDNg3jmlaQKBgQDG5WwngPhOHmjTnSml +amfEz9a4yEhQqpqgVNW5wwoXOf6DbjL2m/maJh01giThj7inMcbpkZlIclxD0Eu6 +Lof+ctCeqSAJvaVPmd+nv8Yp26zsF1yM8ax9xXjrIvv9fSbycNveGTDCsNNTiYoW +QyvMqmN1kGy20SZbQDD/fLfqBQ== +-----END PRIVATE KEY----- +", + }, + ], + "passphrase": "webpack-dev-server", + "pfx": [ + { + "buf": "", + }, + ], + "requestCert": false, +} +`; + +exports[`server option as object ca, pfx, key and cert are strings, key and pfx are objects should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object ca, pfx, key and cert are strings, key and pfx are objects should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object ca, pfx, key and cert are strings, key and pfx are objects should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object custom server with options should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object custom server with options should handle GET request to index route (/): http options 1`] = ` +{ + "maxHeaderSize": 16384, +} +`; + +exports[`server option as object custom server with options should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object custom server with options should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object custom server with options should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object should support the "requestCert" option should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object should support the "requestCert" option should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as object should support the "requestCert" option should pass options to the 'https.createServer' method: https options 1`] = ` +{ + "cert": "", + "key": "", + "passphrase": "webpack-dev-server", + "pfx": "", + "requestCert": true, +} +`; + +exports[`server option as object spdy server with options should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as object spdy server with options should handle GET request to index route (/): https options 1`] = ` +{ + "ca": [ + "", + ], + "cert": [ + "", + ], + "key": [ + "", + ], + "passphrase": "webpack-dev-server", + "pfx": [ + "", + ], + "requestCert": false, + "spdy": { + "protocols": [ + "h2", + "http/1.1", + ], + }, +} +`; + +exports[`server option as object spdy server with options should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as object spdy server with options should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as object spdy server with options should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as string custom-http should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as string custom-http should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as string custom-http should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as string custom-http should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as string http should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as string http should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as string http should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as string http should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as string https should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as string https should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as string https should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as string https should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; + +exports[`server option as string spdy should handle GET request to index route (/): console messages 1`] = `[]`; + +exports[`server option as string spdy should handle GET request to index route (/): page errors 1`] = `[]`; + +exports[`server option as string spdy should handle GET request to index route (/): response status 1`] = `200`; + +exports[`server option as string spdy should handle GET request to index route (/): response text 1`] = ` +"Heyo. +" +`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/setup-exit-signals.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/setup-exit-signals.test.js.snap.webpack5 new file mode 100644 index 00000000000..79ceb12e6ed --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/setup-exit-signals.test.js.snap.webpack5 @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGINT: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGINT: page errors 1`] = `[]`; + +exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGINT: response status 1`] = `200`; + +exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGTERM: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGTERM: page errors 1`] = `[]`; + +exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGTERM: response status 1`] = `200`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/setup-middlewares.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/setup-middlewares.test.js.snap.webpack5 new file mode 100644 index 00000000000..c22699072a3 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/setup-middlewares.test.js.snap.webpack5 @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: console messages 1`] = `[]`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: page errors 1`] = `[]`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 1`] = `"text/html; charset=utf-8"`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 2`] = `"text/html; charset=utf-8"`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 3`] = `"text/html; charset=utf-8"`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 4`] = `"text/html; charset=utf-8"`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 1`] = `200`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 2`] = `200`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 3`] = `200`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 4`] = `200`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 1`] = `"setup-middlewares option GET"`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 2`] = `"Hello World with path!"`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 3`] = `"Hello World without path!"`; + +exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 4`] = `"Hello World as function!"`; + +exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: console messages 1`] = `[]`; + +exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: page errors 1`] = `[]`; + +exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: response headers content-type 1`] = `"text/html; charset=utf-8"`; + +exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: response status 1`] = `200`; + +exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: response text 1`] = `"setup-middlewares option POST"`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/static-directory.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/static-directory.test.js.snap.webpack5 new file mode 100644 index 00000000000..174cb1de42e --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/static-directory.test.js.snap.webpack5 @@ -0,0 +1,149 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`static.directory option defaults to PWD should handle request to /index.html: console messages 1`] = `[]`; + +exports[`static.directory option defaults to PWD should handle request to /index.html: page errors 1`] = `[]`; + +exports[`static.directory option defaults to PWD should handle request to /index.html: response status 1`] = `200`; + +exports[`static.directory option defaults to PWD should handle request to /index.html: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.directory option disabled should not handle request to /other.html (404): console messages 1`] = ` +[ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`static.directory option disabled should not handle request to /other.html (404): page errors 1`] = `[]`; + +exports[`static.directory option disabled should not handle request to /other.html (404): response status 1`] = `404`; + +exports[`static.directory option disabled should not handle request to /other.html (404): response text 1`] = ` +" + + + +Error + + +
Cannot GET /index.html
+ + +" +`; + +exports[`static.directory option test listing files in folders without index.html using the default static.serveIndex option (true) should list the files inside the assets folder (200): console messages 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the default static.serveIndex option (true) should list the files inside the assets folder (200): page errors 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the default static.serveIndex option (true) should list the files inside the assets folder (200): response status 1`] = `200`; + +exports[`static.directory option test listing files in folders without index.html using the default static.serveIndex option (true) should show Heyo. because bar has index.html inside it (200): console messages 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the default static.serveIndex option (true) should show Heyo. because bar has index.html inside it (200): page errors 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the default static.serveIndex option (true) should show Heyo. because bar has index.html inside it (200): response status 1`] = `200`; + +exports[`static.directory option test listing files in folders without index.html using the default static.serveIndex option (true) should show Heyo. because bar has index.html inside it (200): response text 1`] = ` +"Heyo +" +`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should not list the files inside the assets folder (404): console messages 1`] = ` +[ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should not list the files inside the assets folder (404): page errors 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should not list the files inside the assets folder (404): response status 1`] = `404`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should not list the files inside the assets folder (404): response text 1`] = ` +" + + + +Error + + +
Cannot GET /assets/
+ + +" +`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): console messages 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): page errors 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): response status 1`] = `200`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): response text 1`] = ` +"Heyo +" +`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: true should list the files inside the assets folder (200): console messages 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: true should list the files inside the assets folder (200): page errors 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: true should list the files inside the assets folder (200): response status 1`] = `200`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): console messages 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): page errors 1`] = `[]`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): response status 1`] = `200`; + +exports[`static.directory option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): response text 1`] = ` +"Heyo +" +`; + +exports[`static.directory option to directory should handle request to index route: console messages 1`] = `[]`; + +exports[`static.directory option to directory should handle request to index route: page errors 1`] = `[]`; + +exports[`static.directory option to directory should handle request to index route: response status 1`] = `200`; + +exports[`static.directory option to directory should handle request to index route: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.directory option to directory should handle request to other file: console messages 1`] = `[]`; + +exports[`static.directory option to directory should handle request to other file: page errors 1`] = `[]`; + +exports[`static.directory option to directory should handle request to other file: response status 1`] = `200`; + +exports[`static.directory option to directory should handle request to other file: response text 1`] = ` +"Other html +" +`; + +exports[`static.directory option to multiple directories should handle request first directory: console messages 1`] = `[]`; + +exports[`static.directory option to multiple directories should handle request first directory: page errors 1`] = `[]`; + +exports[`static.directory option to multiple directories should handle request first directory: response status 1`] = `200`; + +exports[`static.directory option to multiple directories should handle request first directory: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.directory option to multiple directories should handle request to second directory: console messages 1`] = `[]`; + +exports[`static.directory option to multiple directories should handle request to second directory: page errors 1`] = `[]`; + +exports[`static.directory option to multiple directories should handle request to second directory: response status 1`] = `200`; + +exports[`static.directory option to multiple directories should handle request to second directory: response text 1`] = ` +"Foo! +" +`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/static-public-path.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/static-public-path.test.js.snap.webpack5 new file mode 100644 index 00000000000..3140335f472 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/static-public-path.test.js.snap.webpack5 @@ -0,0 +1,262 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`static.publicPath option Content type should handle request to example.txt: console messages 1`] = `[]`; + +exports[`static.publicPath option Content type should handle request to example.txt: page errors 1`] = `[]`; + +exports[`static.publicPath option Content type should handle request to example.txt: response header content-type 1`] = `"text/plain; charset=UTF-8"`; + +exports[`static.publicPath option Content type should handle request to example.txt: response status 1`] = `200`; + +exports[`static.publicPath option defaults to CWD should handle request to page: console messages 1`] = `[]`; + +exports[`static.publicPath option defaults to CWD should handle request to page: page errors 1`] = `[]`; + +exports[`static.publicPath option defaults to CWD should handle request to page: response status 1`] = `200`; + +exports[`static.publicPath option defaults to CWD should handle request to page: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the /foo route of second path: console messages 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the /foo route of second path: page errors 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the /foo route of second path: response status 1`] = `200`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the /foo route of second path: response text 1`] = ` +"Foo! +" +`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the index of first path: console messages 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the index of first path: page errors 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the index of first path: response status 1`] = `200`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the index of first path: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the other file of first path: console messages 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the other file of first path: page errors 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the other file of first path: response status 1`] = `200`; + +exports[`static.publicPath option multiple static.publicPath entries should handle request to the other file of first path: response text 1`] = ` +"Other html +" +`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of first path: console messages 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of first path: page errors 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of first path: response status 1`] = `200`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of first path: response text 1`] = ` +"Foo! +" +`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of second path: console messages 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of second path: page errors 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of second path: response status 1`] = `200`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the /foo route of second path: response text 1`] = ` +"Foo! +" +`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the index of first path: console messages 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the index of first path: page errors 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the index of first path: response status 1`] = `200`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the index of first path: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the other file of first path: console messages 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the other file of first path: page errors 1`] = `[]`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the other file of first path: response status 1`] = `200`; + +exports[`static.publicPath option multiple static.publicPath entries with publicPath array should handle request to the other file of first path: response text 1`] = ` +"Other html +" +`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should handle GET request: console messages 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should handle GET request: page errors 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should handle GET request: response status 1`] = `200`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should handle HEAD request: console messages 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should handle HEAD request: page errors 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should handle HEAD request: response status 1`] = `200`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle DELETE request: console messages 1`] = ` +[ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle DELETE request: page errors 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle DELETE request: response status 1`] = `404`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle PATCH request: console messages 1`] = ` +[ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle PATCH request: page errors 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle PATCH request: response status 1`] = `404`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle POST request: console messages 1`] = ` +[ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle POST request: page errors 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle POST request: response status 1`] = `404`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle PUT request: console messages 1`] = ` +[ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle PUT request: page errors 1`] = `[]`; + +exports[`static.publicPath option should ignore methods other than GET and HEAD should not handle PUT request: response status 1`] = `404`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex default (true) should list the files inside the assets folder (200): console messages 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex default (true) should list the files inside the assets folder (200): page errors 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex default (true) should list the files inside the assets folder (200): response status 1`] = `200`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex default (true) should show Heyo. because bar has index.html inside it (200): console messages 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex default (true) should show Heyo. because bar has index.html inside it (200): page errors 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex default (true) should show Heyo. because bar has index.html inside it (200): response status 1`] = `200`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex default (true) should show Heyo. because bar has index.html inside it (200): response text 1`] = ` +"Heyo +" +`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): console messages 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): page errors 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): response status 1`] = `200`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false should show Heyo. because bar has index.html inside it (200): response text 1`] = ` +"Heyo +" +`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false shouldn't list the files inside the assets folder (404): console messages 1`] = ` +[ + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false shouldn't list the files inside the assets folder (404): page errors 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false shouldn't list the files inside the assets folder (404): response status 1`] = `404`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: false shouldn't list the files inside the assets folder (404): response text 1`] = ` +" + + + +Error + + +
Cannot GET /serve-content-at-this-url/assets/
+ + +" +`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: true should list the files inside the assets folder (200): console messages 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: true should list the files inside the assets folder (200): page errors 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: true should list the files inside the assets folder (200): response status 1`] = `200`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): console messages 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): page errors 1`] = `[]`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): response status 1`] = `200`; + +exports[`static.publicPath option test listing files in folders without index.html using the option static.serveIndex: true should show Heyo. because bar has index.html inside it (200): response text 1`] = ` +"Heyo +" +`; + +exports[`static.publicPath option to directory should handle request to index: console messages 1`] = `[]`; + +exports[`static.publicPath option to directory should handle request to index: page errors 1`] = `[]`; + +exports[`static.publicPath option to directory should handle request to index: response status 1`] = `200`; + +exports[`static.publicPath option to directory should handle request to index: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.publicPath option to directory should handle request to other file: console messages 1`] = `[]`; + +exports[`static.publicPath option to directory should handle request to other file: page errors 1`] = `[]`; + +exports[`static.publicPath option to directory should handle request to other file: response status 1`] = `200`; + +exports[`static.publicPath option to directory should handle request to other file: response text 1`] = ` +"Other html +" +`; + +exports[`static.publicPath option to multiple directories should handle request to first directory: console messages 1`] = `[]`; + +exports[`static.publicPath option to multiple directories should handle request to first directory: page errors 1`] = `[]`; + +exports[`static.publicPath option to multiple directories should handle request to first directory: response status 1`] = `200`; + +exports[`static.publicPath option to multiple directories should handle request to first directory: response text 1`] = ` +"Heyo. +" +`; + +exports[`static.publicPath option to multiple directories should handle request to second directory: console messages 1`] = `[]`; + +exports[`static.publicPath option to multiple directories should handle request to second directory: page errors 1`] = `[]`; + +exports[`static.publicPath option to multiple directories should handle request to second directory: response status 1`] = `200`; + +exports[`static.publicPath option to multiple directories should handle request to second directory: response text 1`] = ` +"Foo! +" +`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/stats.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/stats.test.js.snap.webpack5 new file mode 100644 index 00000000000..7d40670ec9e --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/stats.test.js.snap.webpack5 @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`stats should work and respect the "ignoreWarnings" option 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`stats should work using "{ assets: false }" value for the "stats" option 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`stats should work using "{}" value for the "stats" option 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`stats should work using "errors-only" value for the "stats" option 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`stats should work using "false" value for the "stats" option 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`stats should work using "undefined" value for the "stats" option 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`stats should work when "stats" is not specified 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/target.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/target.test.js.snap.webpack5 new file mode 100644 index 00000000000..877b6a1e767 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/target.test.js.snap.webpack5 @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`target should work using "async-node" target: console messages 1`] = ` +[ + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "browserslist:defaults" target: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "electron-main" target: console messages 1`] = ` +[ + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "electron-preload" target: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "electron-renderer" target: console messages 1`] = `[]`; + +exports[`target should work using "es5" target: console messages 1`] = ` +[ + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "false" target: console messages 1`] = ` +[ + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "node" target: console messages 1`] = ` +[ + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "node-webkit" target: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "nwjs" target: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "web" target: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "web,es5" target: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`target should work using "webworker" target: console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/watch-files.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/watch-files.test.js.snap.webpack5 new file mode 100644 index 00000000000..5c63e7b714d --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/watch-files.test.js.snap.webpack5 @@ -0,0 +1,311 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`watchFiles option should not crash if file doesn't exist should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should not crash if file doesn't exist should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should not crash if file doesn't exist should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with array config should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with array config should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with array config should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with object with multiple paths should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with object with multiple paths should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with object with multiple paths should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with object with single path should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with object with single path should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with object with single path should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"interval":400,"poll":200} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": 400, + "persistent": true, + "usePolling": true, +} +`; + +exports[`watchFiles option should work with options {"interval":400,"poll":200} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"interval":400,"poll":200} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"interval":400,"poll":200} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"poll":200} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": 200, + "persistent": true, + "usePolling": true, +} +`; + +exports[`watchFiles option should work with options {"poll":200} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"poll":200} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"poll":200} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"poll":true} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": undefined, + "persistent": true, + "usePolling": true, +} +`; + +exports[`watchFiles option should work with options {"poll":true} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"poll":true} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"poll":true} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"usePolling":false,"interval":200,"poll":400} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": 200, + "persistent": true, + "usePolling": false, +} +`; + +exports[`watchFiles option should work with options {"usePolling":false,"interval":200,"poll":400} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"usePolling":false,"interval":200,"poll":400} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"usePolling":false,"interval":200,"poll":400} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":200} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": 200, + "persistent": true, + "usePolling": false, +} +`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":200} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":200} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":200} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":true} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": undefined, + "persistent": true, + "usePolling": false, +} +`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":true} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":true} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"usePolling":false,"poll":true} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"usePolling":false} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": undefined, + "persistent": true, + "usePolling": false, +} +`; + +exports[`watchFiles option should work with options {"usePolling":false} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"usePolling":false} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"usePolling":false} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"usePolling":true,"interval":200,"poll":400} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": 200, + "persistent": true, + "usePolling": true, +} +`; + +exports[`watchFiles option should work with options {"usePolling":true,"interval":200,"poll":400} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"usePolling":true,"interval":200,"poll":400} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"usePolling":true,"interval":200,"poll":400} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"usePolling":true,"poll":200} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": 200, + "persistent": true, + "usePolling": true, +} +`; + +exports[`watchFiles option should work with options {"usePolling":true,"poll":200} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"usePolling":true,"poll":200} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"usePolling":true,"poll":200} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with options {"usePolling":true} should reload when file content is changed 1`] = ` +{ + "alwaysStat": true, + "atomic": false, + "followSymlinks": false, + "ignoreInitial": true, + "ignorePermissionErrors": true, + "ignored": undefined, + "interval": undefined, + "persistent": true, + "usePolling": true, +} +`; + +exports[`watchFiles option should work with options {"usePolling":true} should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with options {"usePolling":true} should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with options {"usePolling":true} should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with string and glob should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with string and glob should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with string and glob should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with string and path to directory should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with string and path to directory should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with string and path to directory should reload when file content is changed: response status 1`] = `200`; + +exports[`watchFiles option should work with string and path to file should reload when file content is changed: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`watchFiles option should work with string and path to file should reload when file content is changed: page errors 1`] = `[]`; + +exports[`watchFiles option should work with string and path to file should reload when file content is changed: response status 1`] = `200`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-communication.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-communication.test.js.snap.webpack5 new file mode 100644 index 00000000000..6937debfff0 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-communication.test.js.snap.webpack5 @@ -0,0 +1,81 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`web socket communication should work and close web socket client connection when web socket server closed ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", + "[webpack-dev-server] Disconnected!", + "[webpack-dev-server] Trying to reconnect...", +] +`; + +exports[`web socket communication should work and close web socket client connection when web socket server closed ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket communication should work and close web socket client connection when web socket server closed ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", + "[webpack-dev-server] Disconnected!", + "[webpack-dev-server] Trying to reconnect...", +] +`; + +exports[`web socket communication should work and close web socket client connection when web socket server closed ("ws"): page errors 1`] = `[]`; + +exports[`web socket communication should work and reconnect when the connection is lost ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", + "[webpack-dev-server] Disconnected!", + "[webpack-dev-server] Trying to reconnect...", + "[webpack-dev-server] App hot update...", + "[HMR] Checking for updates on the server...", + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "[HMR] Cannot find update. Need to do a full reload!", + "[HMR] (Probably because of restarting the webpack-dev-server)", + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`web socket communication should work and reconnect when the connection is lost ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket communication should work and reconnect when the connection is lost ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", + "[webpack-dev-server] Disconnected!", + "[webpack-dev-server] Trying to reconnect...", + "[webpack-dev-server] App hot update...", + "[HMR] Checking for updates on the server...", + "Failed to load resource: the server responded with a status of 404 (Not Found)", + "[HMR] Cannot find update. Need to do a full reload!", + "[HMR] (Probably because of restarting the webpack-dev-server)", + "Failed to load resource: the server responded with a status of 404 (Not Found)", +] +`; + +exports[`web socket communication should work and reconnect when the connection is lost ("ws"): page errors 1`] = `[]`; + +exports[`web socket communication should work and terminate client that is not alive ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket communication should work and terminate client that is not alive ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket communication should work and terminate client that is not alive ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket communication should work and terminate client that is not alive ("ws"): page errors 1`] = `[]`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server-url.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server-url.test.js.snap.webpack5 new file mode 100644 index 00000000000..68160182e3f --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server-url.test.js.snap.webpack5 @@ -0,0 +1,710 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`web socket server URL should not work and output disconnect wrong web socket URL ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", + "Failed to load resource: net::ERR_NAME_NOT_RESOLVED", + "[webpack-dev-server] Disconnected!", +] +`; + +exports[`web socket server URL should not work and output disconnect wrong web socket URL ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should not work and output disconnect wrong web socket URL ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", + "WebSocket connection to 'ws://unknown.unknown:/unknown' failed: Error in connection establishment: net::ERR_NAME_NOT_RESOLVED", + "[webpack-dev-server] JSHandle@object", + "[webpack-dev-server] Disconnected!", +] +`; + +exports[`web socket server URL should not work and output disconnect wrong web socket URL ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work and throw an error on invalid web socket URL ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", +] +`; + +exports[`web socket server URL should work and throw an error on invalid web socket URL ("sockjs"): page errors 1`] = ` +[ + "The URL's scheme must be either 'http:' or 'https:'. 'unknown:' is not allowed.", +] +`; + +exports[`web socket server URL should work and throw an error on invalid web socket URL ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", +] +`; + +exports[`web socket server URL should work and throw an error on invalid web socket URL ("ws"): page errors 1`] = ` +[ + "SyntaxError: Failed to construct 'WebSocket': The URL's scheme must be either 'http', 'https', 'ws', or 'wss'. 'unknown' is not allowed.", +] +`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are different ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are different ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are different ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are different ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are same ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are same ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are same ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when hostnames are different and ports are same ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work behind proxy, when hostnames are same and ports are different ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when hostnames are same and ports are different ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work behind proxy, when hostnames are same and ports are different ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when hostnames are same and ports are different ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work behind proxy, when the "host" option is "local-ip" and the "port" option is "auto" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when the "host" option is "local-ip" and the "port" option is "auto" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work behind proxy, when the "host" option is "local-ip" and the "port" option is "auto" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work behind proxy, when the "host" option is "local-ip" and the "port" option is "auto" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "host" option is "local-ip" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "host" option is "local-ip" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "host" option is "local-ip" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "host" option is "local-ip" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "host" option is "local-ipv4" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "host" option is "local-ipv4" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "host" option is "local-ipv4" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "host" option is "local-ipv4" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "host" option is IPv4 ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "host" option is IPv4 ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "host" option is IPv4 ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "host" option is IPv4 ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "port" option is "auto" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "port" option is "auto" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work when "port" option is "auto" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work when "port" option is "auto" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "client.webSocketURL.*" options ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "client.webSocketURL.*" options ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "client.webSocketURL.*" options ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "client.webSocketURL.*" options ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "client.webSocketURL.port" and "webSocketServer.options.port" options as string ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "client.webSocketURL.port" and "webSocketServer.options.port" options as string ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "client.webSocketURL.port" and "webSocketServer.options.port" options as string ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "client.webSocketURL.port" and "webSocketServer.options.port" options as string ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "server: 'https'" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "server: 'https'" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "server: 'https'" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "server: 'https'" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "server: 'spdy'" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "server: 'spdy'" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with "server: 'spdy'" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with "server: 'spdy'" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with default "/ws" value of the "client.webSocketURL.pathname" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with default "/ws" value of the "client.webSocketURL.pathname" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with default "/ws" value of the "client.webSocketURL.pathname" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with default "/ws" value of the "client.webSocketURL.pathname" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL" option as "string" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL" option as "string" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL" option as "string" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL" option as "string" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option using "0.0.0.0" value ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option using "0.0.0.0" value ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option using "0.0.0.0" value ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.host" option using "0.0.0.0" value ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.password" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.password" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.password" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.password" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending with slash ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending with slash ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending with slash ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending with slash ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending without slash ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending without slash ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending without slash ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending without slash ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" using empty value ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" using empty value ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" using empty value ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" using empty value ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "prefix" for compatibility with "sockjs" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "prefix" for compatibility with "sockjs" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "prefix" for compatibility with "sockjs" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.pathname" option and the custom web socket server "prefix" for compatibility with "sockjs" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option as string ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option as string ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option as string ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option as string ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option using "0" value ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option using "0" value ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option using "0" value ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.port" option using "0" value ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "auto:" value ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "auto:" value ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "auto:" value ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "auto:" value ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "http:" value and covert to "ws:" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "http:" value and covert to "ws:" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "http:" value and covert to "ws:" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.protocol" option using "http:" value and covert to "ws:" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" and "client.webSocketURL.password" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" and "client.webSocketURL.password" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" and "client.webSocketURL.password" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" and "client.webSocketURL.password" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" option ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" option ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" option ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the "client.webSocketURL.username" option ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the custom web socket server "path" ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the custom web socket server "path" ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the custom web socket server "path" ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the custom web socket server "path" ("ws"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the custom web socket server "path" using empty value ("sockjs"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the custom web socket server "path" using empty value ("sockjs"): page errors 1`] = `[]`; + +exports[`web socket server URL should work with the custom web socket server "path" using empty value ("ws"): console messages 1`] = ` +[ + "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", + "[HMR] Waiting for update signal from WDS...", + "Hey.", +] +`; + +exports[`web socket server URL should work with the custom web socket server "path" using empty value ("ws"): page errors 1`] = `[]`; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server.test.js.snap.webpack5 new file mode 100644 index 00000000000..2efd0f39195 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/web-socket-server.test.js.snap.webpack5 @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`web socket server should work allow to disable: console messages 1`] = ` +[ + "Hey.", +] +`; + +exports[`web socket server should work allow to disable: page errors 1`] = `[]`; diff --git a/packages/rspack-dev-server/tests/e2e/port.test.js b/packages/rspack-dev-server/tests/e2e/port.test.js new file mode 100644 index 00000000000..bebc3c8f6b3 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/port.test.js @@ -0,0 +1,115 @@ +"use strict"; + +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/client-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map").port; + +describe("port", () => { + const ports = [ + "", + // eslint-disable-next-line no-undefined + undefined, + "auto", + port, + `${port}`, + 0, + "-1", + "99999" + ]; + + for (const testedPort of ports) { + it(`should work using "${testedPort}" port `, async () => { + const compiler = webpack(config); + const devServerOptions = {}; + + let usedPort; + + if ( + testedPort === "" || + typeof testedPort === "undefined" + ) { + process.env.WEBPACK_DEV_SERVER_BASE_PORT = port; + usedPort = port; + } else if (testedPort === "auto") { + process.env.WEBPACK_DEV_SERVER_BASE_PORT = port; + devServerOptions.port = testedPort; + usedPort = port; + } else { + devServerOptions.port = testedPort; + usedPort = testedPort; + } + + const server = new Server(devServerOptions, compiler); + + let errored; + + try { + await server.start(); + } catch (error) { + errored = error; + } + + if (testedPort === "-1" || testedPort === "99999") { + const errorMessageRegExp = new RegExp( + `options.port should be >= 0 and < 65536` + ); + + try { + expect(errored.message).toMatch(errorMessageRegExp); + } catch (error) { + throw error; + } finally { + await server.stop(); + } + + return; + } + + const address = server.server.address(); + + if (testedPort === 0) { + expect(typeof address.port).toBe("number"); + } else { + expect(address.port).toBe(Number(usedPort)); + } + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + await page.goto(`http://127.0.0.1:${address.port}/`, { + waitUntil: "networkidle0" + }); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + + if ( + testedPort === "" || + typeof testedPort === "undefined" + ) { + delete process.env.WEBPACK_DEV_SERVER_BASE_PORT; + } + }); + } +}); diff --git a/packages/rspack-dev-server/tests/e2e/progress.test.js b/packages/rspack-dev-server/tests/e2e/progress.test.js new file mode 100644 index 00000000000..87017a55167 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/progress.test.js @@ -0,0 +1,90 @@ +"use strict"; + +const path = require("path"); +const fs = require("graceful-fs"); +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const reloadConfig = require("../fixtures/reload-config-2/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map").progress; + +const cssFilePath = path.resolve( + __dirname, + "../fixtures/reload-config-2/main.css" +); + +describe("progress", () => { + it("should work and log progress in a browser console", async () => { + fs.writeFileSync(cssFilePath, "body { background-color: rgb(0, 0, 255); }"); + + const compiler = webpack(reloadConfig); + const devServerOptions = { + port, + client: { + progress: true + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + try { + const { page, browser } = await runBrowser(); + + const consoleMessages = []; + + try { + let doHotUpdate = false; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("request", interceptedRequest => { + if (interceptedRequest.isInterceptResolutionHandled()) return; + + if (/\.hot-update\.(json|js)$/.test(interceptedRequest.url())) { + doHotUpdate = true; + } + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + fs.writeFileSync( + cssFilePath, + "body { background-color: rgb(255, 0, 0); }" + ); + + await new Promise(resolve => { + const timer = setInterval(() => { + if (doHotUpdate) { + clearInterval(timer); + + resolve(); + } + }, 100); + }); + } catch (error) { + throw error; + } finally { + await browser.close(); + } + + const progressConsoleMessage = consoleMessages.filter(message => + /^\[webpack-dev-server\] (\[[a-zA-Z]+\] )?[0-9]{1,3}% - /.test( + message.text() + ) + ); + + expect(progressConsoleMessage.length > 0).toBe(true); + } catch (error) { + throw error; + } finally { + fs.unlinkSync(cssFilePath); + + await server.stop(); + } + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/range-header.test.js b/packages/rspack-dev-server/tests/e2e/range-header.test.js new file mode 100644 index 00000000000..7679cecd0fa --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/range-header.test.js @@ -0,0 +1,111 @@ +"use strict"; + +const request = require("supertest"); +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/static-config/webpack.config"); +const port = require("../helpers/ports-map")["range-header"]; + +describe("'Range' header", () => { + let compiler; + let server; + + beforeAll(async () => { + compiler = webpack(config); + + server = new Server({ port }, compiler); + + await server.start(); + }); + + afterAll(async () => { + await server.stop(); + }); + + it('should work with "Range" header using "GET" method', async () => { + const response = await request(server.app).get("/main.js"); + + expect(response.status).toBe(200); + expect(response.headers["content-type"]).toBe( + "application/javascript; charset=utf-8" + ); + expect(response.headers["accept-ranges"]).toBe("bytes"); + + const responseContent = response.text; + const responseRange = await request(server.app) + .get("/main.js") + .set("Range", "bytes=0-499"); + + expect(responseRange.status).toBe(206); + expect(responseRange.headers["content-type"]).toBe( + "application/javascript; charset=utf-8" + ); + expect(responseRange.headers["content-length"]).toBe("500"); + expect(responseRange.headers["content-range"]).toMatch(/^bytes 0-499\//); + expect(responseRange.text).toBe(responseContent.slice(0, 500)); + expect(responseRange.text.length).toBe(500); + }); + + it('should work with "Range" header using "HEAD" method', async () => { + const response = await request(server.app).head("/main.js"); + + expect(response.status).toBe(200); + expect(response.headers["content-type"]).toBe( + "application/javascript; charset=utf-8" + ); + expect(response.headers["accept-ranges"]).toBe("bytes"); + + const responseRange = await request(server.app) + .head("/main.js") + .set("Range", "bytes=0-499"); + + expect(responseRange.status).toBe(206); + expect(responseRange.headers["content-type"]).toBe( + "application/javascript; charset=utf-8" + ); + expect(responseRange.headers["content-length"]).toBe("500"); + expect(responseRange.headers["content-range"]).toMatch(/^bytes 0-499\//); + }); + + it('should work with unsatisfiable "Range" header using "GET" method', async () => { + const response = await request(server.app).get("/main.js"); + + expect(response.status).toBe(200); + expect(response.headers["content-type"]).toBe( + "application/javascript; charset=utf-8" + ); + expect(response.headers["accept-ranges"]).toBe("bytes"); + + const responseRange = await request(server.app) + .get("/main.js") + .set("Range", "bytes=99999999999-"); + + expect(responseRange.status).toBe(416); + expect(responseRange.headers["content-type"]).toBe( + "text/html; charset=utf-8" + ); + expect(responseRange.headers["content-range"]).toMatch(/^bytes \*\//); + }); + + it('should work with malformed "Range" header using "GET" method', async () => { + const response = await request(server.app).get("/main.js"); + + expect(response.status).toBe(200); + expect(response.headers["content-type"]).toBe( + "application/javascript; charset=utf-8" + ); + expect(response.headers["accept-ranges"]).toBe("bytes"); + + const responseContent = response.text; + const responseRange = await request(server.app) + .get("/main.js") + .set("Range", "bytes"); + + expect(responseRange.status).toBe(200); + expect(responseRange.headers["content-type"]).toBe( + "application/javascript; charset=utf-8" + ); + expect(responseRange.text).toBe(responseContent); + expect(responseRange.text.length).toBe(responseContent.length); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/server-and-client-transport.test.js b/packages/rspack-dev-server/tests/e2e/server-and-client-transport.test.js new file mode 100644 index 00000000000..25dde36936c --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/server-and-client-transport.test.js @@ -0,0 +1,620 @@ +"use strict"; + +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const WebsocketServer = require("webpack-dev-server/lib/servers/WebsocketServer"); +const defaultConfig = require("../fixtures/provide-plugin-default/webpack.config"); +const sockjsConfig = require("../fixtures/provide-plugin-sockjs-config/webpack.config"); +const wsConfig = require("../fixtures/provide-plugin-ws-config/webpack.config"); +const customConfig = require("../fixtures/provide-plugin-custom/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map")["server-and-client-transport"]; + +describe("server and client transport", () => { + it('should use default web socket server ("ws")', async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use "ws" web socket server when specify "ws" value', async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + webSocketServer: "ws" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use "ws" web socket server when specify "ws" value using object', async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + webSocketServer: { + type: "ws" + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use "sockjs" web socket server when specify "sockjs" value', async () => { + const compiler = webpack(sockjsConfig); + const devServerOptions = { + port, + webSocketServer: "sockjs" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use "sockjs" web socket server when specify "sockjs" value using object', async () => { + const compiler = webpack(sockjsConfig); + const devServerOptions = { + port, + webSocketServer: { + type: "sockjs" + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should use custom web socket server when specify class", async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "ws" + }, + webSocketServer: WebsocketServer + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should use custom web socket server when specify class using object", async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "ws" + }, + webSocketServer: { + type: WebsocketServer + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should use custom web socket server when specify path to class", async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "ws" + }, + webSocketServer: require.resolve( + "webpack-dev-server/lib/servers/WebsocketServer" + ) + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should use custom web socket server when specify path to class using object", async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "ws" + }, + webSocketServer: { + type: require.resolve("webpack-dev-server/lib/servers/WebsocketServer") + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should throw an error on wrong path", async () => { + expect.assertions(1); + + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + webSocketServer: { + type: "/bad/path/to/implementation" + } + }; + const server = new Server(devServerOptions, compiler); + + try { + await server.start(); + } catch (error) { + expect(error.message).toMatchSnapshot(); + } finally { + await server.stop(); + } + }); + + it('should use "sockjs" transport, when web socket server is not specify', async () => { + const compiler = webpack(sockjsConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "sockjs" + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/main.js`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use "ws" transport, when web socket server is not specify', async () => { + const compiler = webpack(wsConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "ws" + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use "sockjs" transport and "sockjs" web socket server', async () => { + const compiler = webpack(sockjsConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "sockjs" + }, + webSocketServer: "sockjs" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use "ws" transport and "ws" web socket server', async () => { + const compiler = webpack(wsConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "ws" + }, + webSocketServer: "ws" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it('should use custom transport and "sockjs" web socket server', async () => { + const compiler = webpack(customConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: require.resolve( + "../fixtures/custom-client/CustomSockJSClient" + ) + }, + webSocketServer: "sockjs" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + const isCorrectTransport = await page.evaluate( + () => window.injectedClient === window.expectedClient + ); + + expect(isCorrectTransport).toBe(true); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should throw an error on invalid path to server transport", async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + webSocketServer: { + type: "invalid/path" + } + }; + const server = new Server(devServerOptions, compiler); + await expect(async () => { + await server.start(); + }).rejects.toThrowErrorMatchingSnapshot(); + + await server.stop(); + }); + + it("should throw an error on invalid path to client transport", async () => { + const compiler = webpack(defaultConfig); + const devServerOptions = { + port, + client: { + webSocketTransport: "invalid/path" + } + }; + const server = new Server(devServerOptions, compiler); + await expect(async () => { + await server.start(); + }).rejects.toThrowErrorMatchingSnapshot(); + + await server.stop(); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/server.test.js b/packages/rspack-dev-server/tests/e2e/server.test.js new file mode 100644 index 00000000000..ed6ef655495 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/server.test.js @@ -0,0 +1,1441 @@ +"use strict"; + +const https = require("https"); +const path = require("path"); +const fs = require("graceful-fs"); +const request = require("supertest"); +const spdy = require("spdy"); +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/static-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const { skipTestOnWindows } = require("../helpers/conditional-test"); +const customHTTP = require("../helpers/custom-http"); +const normalizeOptions = require("../helpers/normalize-options"); +const port = require("../helpers/ports-map")["server-option"]; + +const httpsCertificateDirectory = path.resolve( + __dirname, + "../fixtures/https-certificate" +); + +const staticDirectory = path.resolve( + __dirname, + "../fixtures/static-config/public" +); + +describe("server option", () => { + describe("as string", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + describe("http", () => { + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: "http", + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + const HTTPVersion = await page.evaluate( + () => performance.getEntries()[0].nextHopProtocol + ); + + expect(HTTPVersion).not.toEqual("h2"); + + 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("custom-http", () => { + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: path.resolve(__dirname, "../helpers/custom-http.js"), + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + const HTTPVersion = await page.evaluate( + () => performance.getEntries()[0].nextHopProtocol + ); + + expect(HTTPVersion).not.toEqual("h2"); + + 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("https", () => { + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: "https", + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + const HTTPVersion = await page.evaluate( + () => performance.getEntries()[0].nextHopProtocol + ); + + expect(HTTPVersion).not.toEqual("h2"); + + 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("spdy", () => { + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: "spdy", + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + const HTTPVersion = await page.evaluate( + () => performance.getEntries()[0].nextHopProtocol + ); + + expect(HTTPVersion).toEqual("h2"); + + 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 object", () => { + describe("ca, pfx, key and cert are buffer", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: fs.readFileSync( + path.join(httpsCertificateDirectory, "ca.pem") + ), + pfx: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ), + key: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ), + cert: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are array of buffers", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: [ + fs.readFileSync( + path.join(httpsCertificateDirectory, "ca.pem") + ) + ], + pfx: [ + fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ) + ], + key: [ + fs.readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ) + ], + cert: [ + fs.readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ) + ], + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are strings", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: fs + .readFileSync(path.join(httpsCertificateDirectory, "ca.pem")) + .toString(), + // TODO + // pfx can't be string because it is binary format + pfx: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ), + key: fs + .readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ) + .toString(), + cert: fs + .readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ) + .toString(), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are array of strings", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: [ + fs + .readFileSync( + path.join(httpsCertificateDirectory, "ca.pem") + ) + .toString() + ], + // pfx can't be string because it is binary format + pfx: [ + fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ) + ], + key: [ + fs + .readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ) + .toString() + ], + cert: [ + fs + .readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ) + .toString() + ], + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are paths to files", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: path.join(httpsCertificateDirectory, "ca.pem"), + pfx: path.join(httpsCertificateDirectory, "server.pfx"), + key: path.join(httpsCertificateDirectory, "server.key"), + cert: path.join(httpsCertificateDirectory, "server.crt"), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are array of paths to files", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: [path.join(httpsCertificateDirectory, "ca.pem")], + pfx: [path.join(httpsCertificateDirectory, "server.pfx")], + key: [path.join(httpsCertificateDirectory, "server.key")], + cert: [path.join(httpsCertificateDirectory, "server.crt")], + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are symlinks", () => { + if (skipTestOnWindows("Symlinks are not supported on Windows")) { + return; + } + + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: path.join(httpsCertificateDirectory, "ca-symlink.pem"), + pfx: path.join(httpsCertificateDirectory, "server-symlink.pfx"), + key: path.join(httpsCertificateDirectory, "server-symlink.key"), + cert: path.join( + httpsCertificateDirectory, + "server-symlink.crt" + ), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toEqual(200); + expect(await response.text()).toContain("Heyo"); + expect(consoleMessages.map(message => message.text())).toEqual([]); + expect(pageErrors).toEqual([]); + }); + }); + + describe("ca, pfx, key and cert are buffer", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: fs.readFileSync( + path.join(httpsCertificateDirectory, "ca.pem") + ), + pfx: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ), + key: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ), + cert: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are buffer, key and pfx are objects", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: fs.readFileSync( + path.join(httpsCertificateDirectory, "ca.pem") + ), + pfx: [ + { + buf: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ) + } + ], + key: [ + { + pem: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ) + } + ], + cert: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("ca, pfx, key and cert are strings, key and pfx are objects", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + ca: fs + .readFileSync(path.join(httpsCertificateDirectory, "ca.pem")) + .toString(), + pfx: [ + { + // pfx can't be string because it is binary format + buf: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ) + } + ], + key: [ + { + pem: fs + .readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ) + .toString() + } + ], + cert: fs + .readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ) + .toString(), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("allow to pass more options", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + minVersion: "TLSv1.1", + ca: fs.readFileSync( + path.join(httpsCertificateDirectory, "ca.pem") + ), + pfx: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ), + key: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ), + cert: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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"); + }); + }); + + // puppeteer having issues accepting SSL here, throwing error net::ERR_BAD_SSL_CLIENT_AUTH_CERT, hence testing with supertest + describe('should support the "requestCert" option', () => { + let compiler; + let server; + let createServerSpy; + let req; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(https, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "https", + options: { + requestCert: true, + pfx: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.pfx") + ), + key: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.key") + ), + cert: fs.readFileSync( + path.join(httpsCertificateDirectory, "server.crt") + ), + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + req = request(server.app); + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await server.stop(); + }); + + it("should pass options to the 'https.createServer' method", async () => { + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + }); + + it("should handle GET request to index route (/)", async () => { + const response = await req.get("/"); + + expect(response.status).toMatchSnapshot("response status"); + expect(response.text).toMatchSnapshot("response text"); + }); + }); + + describe("spdy server with options", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(spdy, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: "spdy", + options: { + requestCert: false, + ca: [path.join(httpsCertificateDirectory, "ca.pem")], + pfx: [path.join(httpsCertificateDirectory, "server.pfx")], + key: [path.join(httpsCertificateDirectory, "server.key")], + cert: [path.join(httpsCertificateDirectory, "server.crt")], + passphrase: "webpack-dev-server" + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`https://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + const HTTPVersion = await page.evaluate( + () => performance.getEntries()[0].nextHopProtocol + ); + + expect(HTTPVersion).toEqual("h2"); + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("https options"); + 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("custom server with options", () => { + let compiler; + let server; + let createServerSpy; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + createServerSpy = jest.spyOn(customHTTP, "createServer"); + + server = new Server( + { + static: { + directory: staticDirectory, + watch: false + }, + server: { + type: path.join(__dirname, "../helpers/custom-http.js"), + options: { + maxHeaderSize: 16384 + } + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + createServerSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to index route (/)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + const HTTPVersion = await page.evaluate( + () => performance.getEntries()[0].nextHopProtocol + ); + + expect(HTTPVersion).toEqual("http/1.1"); + expect( + normalizeOptions(createServerSpy.mock.calls[0][0]) + ).toMatchSnapshot("http options"); + 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/packages/rspack-dev-server/tests/e2e/setup-exit-signals.test.js b/packages/rspack-dev-server/tests/e2e/setup-exit-signals.test.js new file mode 100644 index 00000000000..fa4420ea295 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/setup-exit-signals.test.js @@ -0,0 +1,118 @@ +"use strict"; + +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/simple-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map")["setup-exit-signals-option"]; + +describe("setupExitSignals option", () => { + describe("should handle 'SIGINT' and 'SIGTERM' signals", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + let doExit; + let exitSpy; + let stopCallbackSpy; + let stdinResumeSpy; + let closeCallbackSpy; + + const signals = ["SIGINT", "SIGTERM"]; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + setupExitSignals: true, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + doExit = false; + + exitSpy = jest.spyOn(process, "exit").mockImplementation(() => { + doExit = true; + }); + + stdinResumeSpy = jest + .spyOn(process.stdin, "resume") + .mockImplementation(() => {}); + + stopCallbackSpy = jest.spyOn(server, "stopCallback"); + + if (server.compiler.close) { + closeCallbackSpy = jest.spyOn(server.compiler, "close"); + } + }); + + afterEach(async () => { + exitSpy.mockReset(); + stdinResumeSpy.mockReset(); + signals.forEach(signal => { + process.removeAllListeners(signal); + }); + process.stdin.removeAllListeners("end"); + await browser.close(); + await server.stop(); + }); + + it.each(signals)("should close and exit on %s", async signal => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + process.emit(signal); + + await new Promise(resolve => { + const interval = setInterval(() => { + if (doExit) { + expect(stopCallbackSpy.mock.calls.length).toEqual(1); + + if (server.compiler.close) { + expect(closeCallbackSpy.mock.calls.length).toEqual(1); + } + + clearInterval(interval); + + resolve(); + } + }, 100); + }); + + consoleMessages = consoleMessages.filter( + message => + !( + message.text().includes("Trying to reconnect...") || + message.text().includes("Disconnected") + ) + ); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/setup-middlewares.test.js b/packages/rspack-dev-server/tests/e2e/setup-middlewares.test.js new file mode 100644 index 00000000000..2d49c543ff2 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/setup-middlewares.test.js @@ -0,0 +1,171 @@ +"use strict"; + +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/client-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map")["setup-middlewares-option"]; + +describe("setupMiddlewares option", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + server = new Server( + { + setupMiddlewares: (middlewares, devServer) => { + if (!devServer) { + throw new Error("webpack-dev-server is not defined"); + } + + devServer.app.get("/setup-middleware/some/path", (_, response) => { + response.send("setup-middlewares option GET"); + }); + + devServer.app.post("/setup-middleware/some/path", (_, response) => { + response.send("setup-middlewares option POST"); + }); + + middlewares.push({ + name: "hello-world-test-two", + middleware: (req, res, next) => { + if (req.path !== "/foo/bar/baz") { + next(); + + return; + } + + res.send("Hello World without path!"); + } + }); + middlewares.push({ + name: "hello-world-test-one", + path: "/foo/bar", + middleware: (req, res) => { + res.send("Hello World with path!"); + } + }); + middlewares.push((req, res) => { + res.send("Hello World as function!"); + }); + + return middlewares; + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle GET request to /setup-middleware/some/path route", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}/setup-middleware/some/path`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.headers()["content-type"]).toMatchSnapshot( + "response headers content-type" + ); + expect(response.status()).toMatchSnapshot("response status"); + expect(await response.text()).toMatchSnapshot("response text"); + + const response1 = await page.goto(`http://127.0.0.1:${port}/foo/bar`, { + waitUntil: "networkidle0" + }); + + expect(response1.headers()["content-type"]).toMatchSnapshot( + "response headers content-type" + ); + expect(response1.status()).toMatchSnapshot("response status"); + expect(await response1.text()).toMatchSnapshot("response text"); + + const response2 = await page.goto(`http://127.0.0.1:${port}/foo/bar/baz`, { + waitUntil: "networkidle0" + }); + + expect(response2.headers()["content-type"]).toMatchSnapshot( + "response headers content-type" + ); + expect(response2.status()).toMatchSnapshot("response status"); + expect(await response2.text()).toMatchSnapshot("response text"); + + const response3 = await page.goto( + `http://127.0.0.1:${port}/setup-middleware/unknown`, + { + waitUntil: "networkidle0" + } + ); + + expect(response3.headers()["content-type"]).toMatchSnapshot( + "response headers content-type" + ); + expect(response3.status()).toMatchSnapshot("response status"); + expect(await response3.text()).toMatchSnapshot("response text"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should handle POST request to /setup-middleware/some/path route", async () => { + await page.setRequestInterception(true); + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }) + .on("request", interceptedRequest => { + if (interceptedRequest.isInterceptResolutionHandled()) return; + + interceptedRequest.continue({ method: "POST" }); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}/setup-middleware/some/path`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.headers()["content-type"]).toMatchSnapshot( + "response headers content-type" + ); + 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/packages/rspack-dev-server/tests/e2e/static-directory.test.js b/packages/rspack-dev-server/tests/e2e/static-directory.test.js new file mode 100644 index 00000000000..551c7c7f63d --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/static-directory.test.js @@ -0,0 +1,686 @@ +"use strict"; + +const path = require("path"); +const fs = require("graceful-fs"); +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const testServer = require("../helpers/test-server"); +const config = require("../fixtures/static-config/webpack.config"); +const port = require("../helpers/ports-map")["static-directory-option"]; +const runBrowser = require("../helpers/run-browser"); + +const staticDirectory = path.resolve(__dirname, "../fixtures/static-config"); +const publicDirectory = path.resolve(staticDirectory, "public"); +const otherPublicDirectory = path.resolve(staticDirectory, "other"); + +describe("static.directory option", () => { + describe("to directory", () => { + const nestedFile = path.resolve(publicDirectory, "assets/example.txt"); + + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + watch: true + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + fs.truncateSync(nestedFile); + }); + + it("should handle request to index route", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + 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 handle request to other file", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/other.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("Watches folder recursively", done => { + // chokidar emitted a change, + // meaning it watched the file correctly + server.staticWatchers[0].on("change", () => { + done(); + }); + + // change a file manually + setTimeout(() => { + fs.writeFileSync(nestedFile, "Heyo", "utf8"); + }, 1000); + }); + + it("Watches node_modules", done => { + const filePath = path.join(publicDirectory, "node_modules", "index.html"); + + fs.writeFileSync(filePath, "foo", "utf8"); + + // chokidar emitted a change, + // meaning it watched the file correctly + server.staticWatchers[0].on("change", () => { + fs.unlinkSync(filePath); + + done(); + }); + + // change a file manually + setTimeout(() => { + fs.writeFileSync(filePath, "bar", "utf8"); + }, 1000); + }); + }); + + describe("test listing files in folders without index.html using the option static.serveIndex: false", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + watch: true, + serveIndex: false + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should not list the files inside the assets folder (404)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/assets`, { + 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 show Heyo. because bar has index.html inside it (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/bar`, { + 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("test listing files in folders without index.html using the option static.serveIndex: true", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + watch: true, + serveIndex: true + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should list the files inside the assets folder (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/assets/`, { + waitUntil: "networkidle0" + }); + + const text = await response.text(); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(text).toContain("example.txt"); + expect(text).toContain("other.txt"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should show Heyo. because bar has index.html inside it (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/bar/`, { + 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("test listing files in folders without index.html using the default static.serveIndex option (true)", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + watch: true + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should list the files inside the assets folder (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/assets`, { + waitUntil: "networkidle0" + }); + + const text = await response.text(); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(text).toContain("example.txt"); + expect(text).toContain("other.txt"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should show Heyo. because bar has index.html inside it (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/bar`, { + 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("to multiple directories", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: [publicDirectory, otherPublicDirectory], + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle request first directory", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + 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 handle request to second directory", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/foo.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("testing single & multiple external paths", () => { + let server; + + afterEach(done => { + testServer.close(() => { + done(); + }); + }); + + it("Should throw exception (external url)", done => { + expect.assertions(1); + + server = testServer.start( + config, + { + static: "https://example.com/" + }, + error => { + expect(error.message).toBe( + "Using a URL as static.directory is not supported" + ); + + server.stopCallback(done); + } + ); + }); + + it("Should not throw exception (local path with lower case first character)", done => { + testServer.start( + config, + { + static: { + directory: + publicDirectory.charAt(0).toLowerCase() + + publicDirectory.substring(1), + watch: true + }, + port + }, + done + ); + }); + + it("Should not throw exception (local path with lower case first character & has '-')", done => { + testServer.start( + config, + { + static: { + directory: "c:\\absolute\\path\\to\\content-base", + watch: true + }, + port + }, + done + ); + }); + + it("Should not throw exception (local path with upper case first character & has '-')", done => { + testServer.start( + config, + { + static: { + directory: "C:\\absolute\\path\\to\\content-base", + watch: true + }, + port + }, + done + ); + }); + + it("Should throw exception (array with absolute url)", done => { + server = testServer.start( + config, + { + static: [publicDirectory, "https://example.com/"] + }, + error => { + expect(error.message).toBe( + "Using a URL as static.directory is not supported" + ); + + server.stopCallback(done); + } + ); + }); + }); + + describe("defaults to PWD", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + jest + .spyOn(process, "cwd") + .mockImplementation(() => path.resolve(staticDirectory)); + compiler = webpack(config); + + server = new Server( + { + // eslint-disable-next-line no-undefined + static: undefined, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle request to /index.html", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/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("disabled", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + // This is a somewhat weird test, but it is important that we mock + // the PWD here, and test if /other.html in our "fake" PWD really is not requested. + jest.spyOn(process, "cwd").mockImplementation(() => publicDirectory); + + compiler = webpack(config); + + server = new Server( + { + static: false, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should not handle request to /other.html (404)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/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"); + }); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/static-public-path.test.js b/packages/rspack-dev-server/tests/e2e/static-public-path.test.js new file mode 100644 index 00000000000..38e27f50120 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/static-public-path.test.js @@ -0,0 +1,1101 @@ +"use strict"; + +const path = require("path"); +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/static-config/webpack.config"); +const port = require("../helpers/ports-map")["static-public-path-option"]; +const runBrowser = require("../helpers/run-browser"); + +const staticDirectory = path.resolve(__dirname, "../fixtures/static-config"); +const publicDirectory = path.resolve(staticDirectory, "public"); +const otherPublicDirectory = path.resolve(staticDirectory, "other"); +const staticPublicPath = "/serve-content-at-this-url"; +const otherStaticPublicPath = "/serve-other-content-at-this-url"; + +describe("static.publicPath option", () => { + describe("to directory", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + publicPath: staticPublicPath, + watch: true + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle request to index", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + 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 handle request to other file", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/other.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("test listing files in folders without index.html using the option static.serveIndex: false", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + publicPath: staticPublicPath, + watch: true, + serveIndex: false + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("shouldn't list the files inside the assets folder (404)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/assets`, + { + 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 show Heyo. because bar has index.html inside it (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/bar`, + { + 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("test listing files in folders without index.html using the option static.serveIndex: true", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + publicPath: staticPublicPath, + watch: true, + serveIndex: true + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should list the files inside the assets folder (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/assets`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toContain("other.txt"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should show Heyo. because bar has index.html inside it (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/bar`, + { + 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("test listing files in folders without index.html using the option static.serveIndex default (true)", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + publicPath: staticPublicPath, + watch: true, + serveIndex: true + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should list the files inside the assets folder (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/assets`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(await response.text()).toContain("other.txt"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should show Heyo. because bar has index.html inside it (200)", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/bar`, + { + 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("to multiple directories", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: [ + { + directory: publicDirectory, + publicPath: staticPublicPath + }, + { + directory: otherPublicDirectory, + publicPath: staticPublicPath + } + ], + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle request to first directory", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + 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 handle request to second directory", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/foo.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("defaults to CWD", () => { + let cwdSpy; + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + cwdSpy = jest + .spyOn(process, "cwd") + .mockImplementation(() => staticDirectory); + + compiler = webpack(config); + + server = new Server( + { + static: { + publicPath: staticPublicPath + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + cwdSpy.mockRestore(); + + await browser.close(); + await server.stop(); + }); + + it("should handle request to page", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/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("Content type", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + publicPath: staticPublicPath + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle request to example.txt", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/assets/example.txt`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(response.headers()["content-type"]).toMatchSnapshot( + "response header content-type" + ); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("should ignore methods other than GET and HEAD", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: { + directory: publicDirectory, + publicPath: staticPublicPath + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle GET request", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should handle HEAD request", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }) + .on("request", interceptedRequest => { + if (interceptedRequest.isInterceptResolutionHandled()) return; + + interceptedRequest.continue({ method: "HEAD" }); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should not handle POST request", 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" }); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should not handle PUT request", async () => { + await page.setRequestInterception(true); + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }) + .on("request", interceptedRequest => { + interceptedRequest.continue({ method: "PUT" }); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should not handle DELETE request", 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://127.0.0.1:${port}${staticPublicPath}/`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + + it("should not handle PATCH request", async () => { + await page.setRequestInterception(true); + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }) + .on("request", interceptedRequest => { + interceptedRequest.continue({ method: "PATCH" }); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + waitUntil: "networkidle0" + } + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + + describe("multiple static.publicPath entries", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: [ + { + directory: publicDirectory, + publicPath: staticPublicPath, + watch: true + }, + { + directory: otherPublicDirectory, + publicPath: otherStaticPublicPath, + watch: true + } + ], + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle request to the index of first path", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + 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 handle request to the other file of first path", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/other.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 handle request to the /foo route of second path", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${otherStaticPublicPath}/foo.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("multiple static.publicPath entries with publicPath array", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + static: [ + { + directory: publicDirectory, + publicPath: staticPublicPath, + watch: true + }, + { + directory: otherPublicDirectory, + publicPath: [staticPublicPath, otherStaticPublicPath], + watch: true + } + ], + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle request to the index of first path", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/`, + { + 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 handle request to the other file of first path", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/other.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 handle request to the /foo route of first path", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${staticPublicPath}/foo.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 handle request to the /foo route of second path", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto( + `http://127.0.0.1:${port}${otherStaticPublicPath}/foo.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"); + }); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/stats.test.js b/packages/rspack-dev-server/tests/e2e/stats.test.js new file mode 100644 index 00000000000..2ce82602469 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/stats.test.js @@ -0,0 +1,147 @@ +"use strict"; + +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/client-config/webpack.config"); +const HTMLGeneratorPlugin = require("../helpers/html-generator-plugin"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map").stats; + +global.console.log = jest.fn(); + +describe("stats", () => { + const cases = [ + { + title: 'should work when "stats" is not specified', + webpackOptions: {} + }, + { + title: 'should work using "{}" value for the "stats" option', + webpackOptions: { + stats: {} + } + }, + { + title: 'should work using "undefined" value for the "stats" option', + webpackOptions: { + // eslint-disable-next-line no-undefined + stats: undefined + } + }, + { + title: 'should work using "false" value for the "stats" option', + webpackOptions: { + stats: false + } + }, + { + title: 'should work using "errors-only" value for the "stats" option', + webpackOptions: { + stats: "errors-only" + } + }, + { + title: + 'should work using "{ assets: false }" value for the "stats" option', + webpackOptions: { + stats: { + assets: false + } + } + } + // TODO: support object `config.stats.colors` + // { + // title: + // 'should work using "{ assets: false }" value for the "stats" option', + // webpackOptions: { + // stats: { + // colors: { + // green: "\u001b[32m", + // }, + // }, + // }, + // }, + // `config.stats.warningsFilter` is deprecated in favor of config.ignoreWarnings + // { + // title: + // 'should work using "{ warningsFilter: \'test\' }" value for the "stats" option', + // webpackOptions: { + // plugins: [ + // { + // apply(compiler) { + // compiler.hooks.thisCompilation.tap( + // "warnings-webpack-plugin", + // (compilation) => { + // compilation.warnings.push( + // new Error("Warning from compilation"), + // ); + // }, + // ); + // }, + // }, + // new HTMLGeneratorPlugin(), + // ], + // stats: { warningsFilter: /Warning from compilation/ }, + // }, + // }, + ]; + + if (webpack.version.startsWith("5")) { + cases.push({ + title: 'should work and respect the "ignoreWarnings" option', + webpackOptions: { + plugins: [ + { + apply(compiler) { + compiler.hooks.thisCompilation.tap( + "warnings-webpack-plugin", + compilation => { + compilation.warnings.push( + new Error("Warning from compilation") + ); + } + ); + } + }, + new HTMLGeneratorPlugin() + ], + ignoreWarnings: [/Warning from compilation/] + } + }); + } + + cases.forEach(testCase => { + it(testCase.title, async () => { + const compiler = webpack({ ...config, ...testCase.webpackOptions }); + const devServerOptions = { + port + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + consoleMessages.map(message => message.text()) + ).toMatchSnapshot(); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/target.test.js b/packages/rspack-dev-server/tests/e2e/target.test.js new file mode 100644 index 00000000000..0bc47381f08 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/target.test.js @@ -0,0 +1,94 @@ +"use strict"; + +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/client-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map").target; + +describe("target", () => { + const targets = [ + false, + "browserslist:defaults", + "web", + "webworker", + "node", + "async-node", + "electron-main", + "electron-preload", + "electron-renderer", + "nwjs", + "node-webkit", + "es5", + ["web", "es5"] + ]; + + for (const target of targets) { + it(`should work using "${target}" target`, async () => { + const compiler = webpack({ + ...config, + target, + ...(target === false || target === "es5" + ? { + output: { chunkFormat: "array-push", path: "/" } + } + : {}) + }); + const devServerOptions = { + port + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + // TODO: check why require is defined in theses target + // if ( + // target === "node" || + // target === "async-node" || + // target === "electron-main" || + // target === "electron-preload" || + // target === "electron-renderer" || + // target === "nwjs" || + // target === "node-webkit" + // ) { + // console.log(pageErrors); + // const hasRequireOrGlobalError = + // pageErrors.filter((pageError) => + // /require is not defined|global is not defined/.test(pageError), + // ).length === 1; + + // expect(hasRequireOrGlobalError).toBe(true); + // } else { + // expect(pageErrors).toMatchSnapshot("page errors"); + // } + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + } +}); diff --git a/packages/rspack-dev-server/tests/e2e/watch-files.test.js b/packages/rspack-dev-server/tests/e2e/watch-files.test.js new file mode 100644 index 00000000000..0e77d84d399 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/watch-files.test.js @@ -0,0 +1,682 @@ +"use strict"; + +const path = require("path"); +const chokidar = require("chokidar"); +const fs = require("graceful-fs"); +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/watch-files-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map")["watch-files-option"]; + +const watchDir = path.resolve( + __dirname, + "../fixtures/watch-files-config/public" +); + +describe("watchFiles option", () => { + describe("should work with string and path to file", () => { + const file = path.join(watchDir, "assets/example.txt"); + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + watchFiles: file, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + fs.truncateSync(file); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + + // change file content + fs.writeFileSync(file, "Kurosaki Ichigo", "utf8"); + + await new Promise(resolve => { + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(file); + + resolve(); + }); + }); + }); + }); + + describe("should work with string and path to directory", () => { + const file = path.join(watchDir, "assets/example.txt"); + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + watchFiles: watchDir, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + fs.truncateSync(file); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + + // change file content + fs.writeFileSync(file, "Kurosaki Ichigo", "utf8"); + + await new Promise(resolve => { + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(file); + + resolve(); + }); + }); + }); + }); + + describe("should work with string and glob", () => { + const file = path.join(watchDir, "assets/example.txt"); + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + watchFiles: `${watchDir}/**/*`, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + fs.truncateSync(file); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + + // change file content + fs.writeFileSync(file, "Kurosaki Ichigo", "utf8"); + + await new Promise(resolve => { + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(file); + + resolve(); + }); + }); + }); + }); + + describe("should not crash if file doesn't exist", () => { + const nonExistFile = path.join(watchDir, "assets/non-exist.txt"); + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + try { + fs.unlinkSync(nonExistFile); + } catch (error) { + // ignore + } + + compiler = webpack(config); + + server = new Server( + { + watchFiles: nonExistFile, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + + await new Promise(resolve => { + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(nonExistFile); + resolve(); + }); + + // create file content + setTimeout(() => { + fs.writeFileSync(nonExistFile, "Kurosaki Ichigo", "utf8"); + // change file content + setTimeout(() => { + fs.writeFileSync(nonExistFile, "Kurosaki Ichigo", "utf8"); + }, 1000); + }, 1000); + }); + }); + }); + + describe("should work with object with single path", () => { + const file = path.join(watchDir, "assets/example.txt"); + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + watchFiles: { paths: file }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + fs.truncateSync(file); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + + // change file content + fs.writeFileSync(file, "Kurosaki Ichigo", "utf8"); + + await new Promise(resolve => { + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(file); + + resolve(); + }); + }); + }); + }); + + describe("should work with object with multiple paths", () => { + const file = path.join(watchDir, "assets/example.txt"); + const other = path.join(watchDir, "assets/other.txt"); + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + watchFiles: { paths: [file, other] }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + fs.truncateSync(file); + fs.truncateSync(other); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + + // change file content + fs.writeFileSync(file, "foo", "utf8"); + fs.writeFileSync(other, "bar", "utf8"); + + await new Promise(resolve => { + const expected = [file, other]; + let changed = 0; + + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(expected.includes(changedPath)).toBeTruthy(); + + changed += 1; + + if (changed === 2) { + resolve(); + } + }); + }); + }); + }); + + describe("should work with array config", () => { + const file = path.join(watchDir, "assets/example.txt"); + const other = path.join(watchDir, "assets/other.txt"); + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + watchFiles: [{ paths: [file] }, other], + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + fs.truncateSync(file); + fs.truncateSync(other); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + + // change file content + fs.writeFileSync(file, "foo", "utf8"); + fs.writeFileSync(other, "bar", "utf8"); + + await new Promise(resolve => { + let changed = 0; + + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(file); + + changed += 1; + + if (changed === 2) { + resolve(); + } + }); + server.staticWatchers[1].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(other); + + changed += 1; + + if (changed === 2) { + resolve(); + } + }); + }); + }); + }); + + describe("should work with options", () => { + const file = path.join(watchDir, "assets/example.txt"); + + const chokidarMock = jest.spyOn(chokidar, "watch"); + + const optionCases = [ + { + poll: true + }, + { + poll: 200 + }, + { + usePolling: true + }, + { + usePolling: true, + poll: 200 + }, + { + usePolling: false + }, + { + usePolling: false, + poll: 200 + }, + { + usePolling: false, + poll: true + }, + { + interval: 400, + poll: 200 + }, + { + usePolling: true, + interval: 200, + poll: 400 + }, + { + usePolling: false, + interval: 200, + poll: 400 + } + ]; + + optionCases.forEach(optionCase => { + describe(JSON.stringify(optionCase), () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + chokidarMock.mockClear(); + + compiler = webpack(config); + + server = new Server( + { + watchFiles: { + paths: file, + options: optionCase + }, + port + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await server.stop(); + await browser.close(); + fs.truncateSync(file); + }); + + it("should reload when file content is changed", async () => { + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + // should pass correct options to chokidar config + expect(chokidarMock.mock.calls[0][1]).toMatchSnapshot(); + + expect(response.status()).toMatchSnapshot("response status"); + + expect( + consoleMessages.map(message => message.text()) + ).toMatchSnapshot("console messages"); + + expect(pageErrors).toMatchSnapshot("page errors"); + + // change file content + fs.writeFileSync(file, "Kurosaki Ichigo", "utf8"); + + await new Promise(resolve => { + server.staticWatchers[0].on("change", async changedPath => { + // page reload + await page.waitForNavigation({ waitUntil: "networkidle0" }); + + expect(changedPath).toBe(file); + + resolve(); + }); + }); + }); + }); + }); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/web-socket-communication.test.js b/packages/rspack-dev-server/tests/e2e/web-socket-communication.test.js new file mode 100644 index 00000000000..e78eafa2317 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/web-socket-communication.test.js @@ -0,0 +1,223 @@ +"use strict"; + +const WebSocket = require("ws"); +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const WebsocketServer = require("webpack-dev-server/lib/servers/WebsocketServer"); +const config = require("../fixtures/client-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const port = require("../helpers/ports-map")["web-socket-communication"]; + +jest.setTimeout(60000); + +describe("web socket communication", () => { + const webSocketServers = ["ws", "sockjs"]; + + webSocketServers.forEach(websocketServer => { + it(`should work and close web socket client connection when web socket server closed ("${websocketServer}")`, async () => { + WebsocketServer.heartbeatInterval = 100; + + const compiler = webpack(config); + const devServerOptions = { + port, + webSocketServer: websocketServer + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message.text()); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + await server.stop(); + await new Promise(resolve => { + const interval = setInterval(() => { + if ( + consoleMessages.includes("[webpack-dev-server] Disconnected!") + ) { + clearInterval(interval); + + resolve(); + } + }, 100); + }); + + expect(consoleMessages).toMatchSnapshot("console messages"); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + } + }); + + it(`should work and terminate client that is not alive ("${websocketServer}")`, async () => { + WebsocketServer.heartbeatInterval = 100; + + const compiler = webpack(config); + const devServerOptions = { + port, + webSocketServer: websocketServer + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + await browser.close(); + + // Wait heartbeat + await new Promise(resolve => { + setTimeout(() => { + resolve(); + }, 200); + }); + + expect(server.webSocketServer.clients.length).toBe(0); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await server.stop(); + } + }); + + it(`should work and reconnect when the connection is lost ("${websocketServer}")`, async () => { + WebsocketServer.heartbeatInterval = 100; + + const compiler = webpack(config); + const devServerOptions = { + port, + webSocketServer: websocketServer + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + await server.stop(); + await server.start(); + + await page.waitForNavigation({ + waitUntil: "networkidle0" + }); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + }); + + it(`should work and do heartbeat using ("ws" web socket server)`, async () => { + WebsocketServer.heartbeatInterval = 100; + + const compiler = webpack(config); + const devServerOptions = { + port, + webSocketServer: "ws" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + server.webSocketServer.heartbeatInterval = 100; + + await new Promise((resolve, reject) => { + const ws = new WebSocket(`ws://127.0.0.1:${devServerOptions.port}/ws`, { + headers: { + host: `127.0.0.1:${devServerOptions.port}`, + origin: `http://127.0.0.1:${devServerOptions.port}` + } + }); + + let opened = false; + let received = false; + + ws.on("open", () => { + opened = true; + }); + + ws.on("error", error => { + reject(error); + }); + + ws.on("ping", () => { + if (opened && received) { + ws.close(); + } + }); + + ws.on("message", data => { + const message = JSON.parse(data); + + if (message.type === "ok") { + received = true; + } + }); + + ws.on("close", () => { + resolve(); + }); + }); + + await server.stop(); + }); +}); diff --git a/packages/rspack-dev-server/tests/e2e/web-socket-server-url.test.js b/packages/rspack-dev-server/tests/e2e/web-socket-server-url.test.js new file mode 100644 index 00000000000..2ab0c6db5f9 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/web-socket-server-url.test.js @@ -0,0 +1,2765 @@ +"use strict"; + +const express = require("express"); +const webpack = require("@rspack/core"); +const { createProxyMiddleware } = require("http-proxy-middleware"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/client-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const sessionSubscribe = require("../helpers/session-subscribe"); +const [port1, port2] = require("../helpers/ports-map")["web-socket-server-url"]; + +const webSocketServers = ["ws", "sockjs"]; + +describe("web socket server URL", () => { + for (const webSocketServer of webSocketServers) { + const websocketURLProtocol = webSocketServer === "ws" ? "ws" : "http"; + + it(`should work behind proxy, when hostnames are same and ports are different ("${webSocketServer}")`, async () => { + const devServerHost = "127.0.0.1"; + const devServerPort = port1; + const proxyHost = devServerHost; + const proxyPort = port2; + + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: devServerPort, + host: devServerHost, + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + function startProxy(callback) { + const app = express(); + app.use( + "/", + createProxyMiddleware({ + target: `http://${devServerHost}:${devServerPort}`, + ws: true, + changeOrigin: true, + logLevel: "warn" + }) + ); + + return app.listen(proxyPort, proxyHost, callback); + } + + const proxy = await new Promise(resolve => { + const proxyCreated = startProxy(() => { + resolve(proxyCreated); + }); + }); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://${proxyHost}:${proxyPort}/`, { + waitUntil: "networkidle0" + }); + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://${devServerHost}:${devServerPort}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + proxy.close(); + await browser.close(); + await server.stop(); + } + }); + + it(`should work behind proxy, when hostnames are different and ports are same ("${webSocketServer}")`, async () => { + const devServerHost = "127.0.0.1"; + const devServerPort = port1; + const proxyHost = Server.internalIPSync("v4"); + const proxyPort = port1; + + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: devServerPort, + host: devServerHost, + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + function startProxy(callback) { + const app = express(); + app.use( + "/", + createProxyMiddleware({ + target: `http://${devServerHost}:${devServerPort}`, + ws: true, + changeOrigin: true, + logLevel: "warn" + }) + ); + + return app.listen(proxyPort, proxyHost, callback); + } + + const proxy = await new Promise(resolve => { + const proxyCreated = startProxy(() => { + resolve(proxyCreated); + }); + }); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://${proxyHost}:${proxyPort}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://${devServerHost}:${devServerPort}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + proxy.close(); + await browser.close(); + await server.stop(); + } + }); + + it(`should work behind proxy, when hostnames are different and ports are different ("${webSocketServer}")`, async () => { + const devServerHost = "127.0.0.1"; + const devServerPort = port1; + const proxyHost = Server.internalIPSync("v4"); + const proxyPort = port2; + + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + hostname: devServerHost + } + }, + webSocketServer, + port: devServerPort, + host: devServerHost, + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + function startProxy(callback) { + const app = express(); + app.use( + "/", + createProxyMiddleware({ + target: `http://${devServerHost}:${devServerPort}`, + ws: true, + changeOrigin: true, + logLevel: "warn" + }) + ); + + return app.listen(proxyPort, proxyHost, callback); + } + + const proxy = await new Promise(resolve => { + const proxyCreated = startProxy(() => { + resolve(proxyCreated); + }); + }); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://${proxyHost}:${proxyPort}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://${devServerHost}:${devServerPort}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + proxy.close(); + + await browser.close(); + await server.stop(); + } + }); + + it(`should work behind proxy, when the "host" option is "local-ip" and the "port" option is "auto" ("${webSocketServer}")`, async () => { + process.env.WEBPACK_DEV_SERVER_BASE_PORT = 40000; + + const proxyHost = Server.internalIPSync("v4"); + const proxyPort = port2; + + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: "auto", + host: "local-ip", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const resolvedHost = server.options.host; + const resolvedPort = server.options.port; + + function startProxy(callback) { + const app = express(); + + app.use( + "/", + createProxyMiddleware({ + target: `http://${resolvedHost}:${resolvedPort}`, + ws: true, + changeOrigin: true, + logLevel: "warn" + }) + ); + + return app.listen(proxyPort, proxyHost, callback); + } + + const proxy = await new Promise(resolve => { + const proxyCreated = startProxy(() => { + resolve(proxyCreated); + }); + }); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://${proxyHost}:${proxyPort}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://${resolvedHost}:${resolvedPort}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + proxy.close(); + + await browser.close(); + await server.stop(); + + delete process.env.WEBPACK_DEV_SERVER_BASE_PORT; + } + }); + + it(`should work with the "client.webSocketURL.protocol" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + protocol: "ws:" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://localhost:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://localhost:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.protocol" option using "auto:" value ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + protocol: "auto:" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://localhost:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://localhost:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.protocol" option using "http:" value and covert to "ws:" ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + protocol: "http:" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://localhost:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://localhost:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.host" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + hostname: "127.0.0.1" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.host" option using "0.0.0.0" value ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + hostname: "0.0.0.0" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.port" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + port: port1 + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.port" option as string ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + port: `${port1}` + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with "client.webSocketURL.port" and "webSocketServer.options.port" options as string ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + webSocketServer: { + type: webSocketServer, + options: { + host: "0.0.0.0", + // "sockjs" doesn't support external server + port: webSocketServer === "sockjs" ? `${port1}` : `${port2}` + } + }, + port: port1, + host: "0.0.0.0", + client: { + webSocketURL: { + port: webSocketServer === "sockjs" ? `${port1}` : `${port2}` + } + }, + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + webSocketServer === "sockjs" + ? `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + : `${websocketURLProtocol}://127.0.0.1:${port2}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.port" option using "0" value ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + port: 0 + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.pathname" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + pathname: "/ws" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with default "/ws" value of the "client.webSocketURL.pathname" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.username" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + username: "zenitsu" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://zenitsu@127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.password" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: + webSocketServer === "ws" + ? { + username: "foo", + password: "chuntaro" + } + : {} + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + // "sockjs" has bug with parsing URL + webSocketServer === "ws" + ? `${websocketURLProtocol}://foo:chuntaro@127.0.0.1:${port1}/ws` + : `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.username" and "client.webSocketURL.password" option ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + username: "zenitsu", + password: "chuntaro" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://zenitsu:chuntaro@127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the custom web socket server "path" ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + webSocketServer: { + type: webSocketServer, + options: { + path: "/custom-ws/foo/bar" + } + }, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/custom-ws\/foo\/bar/.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/custom-ws/foo/bar` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + // Only works for "ws" server + it(`should work with the custom web socket server "path" using empty value ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + webSocketServer: { + type: webSocketServer, + options: { + path: webSocketServer === "ws" ? "" : "/custom-ws" + } + }, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/custom-ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + webSocketServer === "ws" + ? `${websocketURLProtocol}://127.0.0.1:${port1}` + : `${websocketURLProtocol}://127.0.0.1:${port1}/custom-ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + pathname: "/custom-ws/foo/bar" + } + }, + webSocketServer: { + type: webSocketServer, + options: { + path: "/custom-ws/foo/bar" + } + }, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/custom-ws\/foo\/bar/.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/custom-ws/foo/bar` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending without slash ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + pathname: "/custom-ws" + } + }, + webSocketServer: { + type: webSocketServer, + options: { + path: "/custom-ws" + } + }, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/custom-ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/custom-ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + // Only works for "ws" server, "sockjs" adds "/" be default, because need do requests like "/custom-ws/info?t=1624462615772" + it(`should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" ending with slash ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + pathname: webSocketServer === "ws" ? "/custom-ws/" : "/custom-ws" + } + }, + webSocketServer: { + type: webSocketServer, + options: { + path: webSocketServer === "ws" ? "/custom-ws/" : "/custom-ws" + } + }, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/custom-ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/custom-ws/` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + // Only works for "ws" server + it(`should work with the "client.webSocketURL.pathname" option and the custom web socket server "path" using empty value ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + pathname: webSocketServer === "ws" ? "" : "/custom-ws" + } + }, + webSocketServer: { + type: webSocketServer, + options: { + path: webSocketServer === "ws" ? "" : "/custom-ws" + } + }, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/custom-ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + webSocketServer === "ws" + ? `${websocketURLProtocol}://127.0.0.1:${port1}` + : `${websocketURLProtocol}://127.0.0.1:${port1}/custom-ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + // Only works for "sockjs" server + it(`should work with the "client.webSocketURL.pathname" option and the custom web socket server "prefix" for compatibility with "sockjs" ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + pathname: "/custom-ws" + } + }, + webSocketServer: { + type: webSocketServer, + options: + webSocketServer === "ws" + ? { path: "/custom-ws" } + : { prefix: "/custom-ws" } + }, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/custom-ws/.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/custom-ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work when "host" option is IPv4 ("${webSocketServer}")`, async () => { + const hostname = Server.internalIPSync("v4"); + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: port1, + host: hostname + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://${hostname}:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://${hostname}:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work when "host" option is "local-ip" ("${webSocketServer}")`, async () => { + const hostname = Server.internalIPSync("v4"); + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: port1, + host: "local-ip" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://${hostname}:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://${hostname}:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work when "host" option is "local-ipv4" ("${webSocketServer}")`, async () => { + const hostname = Server.internalIPSync("v4"); + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: port1, + host: "local-ipv4" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + await page.goto(`http://${hostname}:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://${hostname}:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with "server: 'https'" option ("${webSocketServer}")`, async () => { + const hostname = "127.0.0.1"; + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: port1, + server: "https" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`https://${hostname}:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + if (webSocketServer === "ws") { + expect(webSocketRequest.url).toContain( + `wss://${hostname}:${port1}/ws` + ); + } else { + expect(webSocketRequest.url).toContain( + `https://${hostname}:${port1}/ws` + ); + } + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with "server: 'spdy'" option ("${webSocketServer}")`, async () => { + const hostname = "127.0.0.1"; + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: port1, + server: "spdy" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`https://${hostname}:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + if (webSocketServer === "ws") { + expect(webSocketRequest.url).toContain( + `wss://${hostname}:${port1}/ws` + ); + } else { + expect(webSocketRequest.url).toContain( + `https://${hostname}:${port1}/ws` + ); + } + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work when "port" option is "auto" ("${webSocketServer}")`, async () => { + process.env.WEBPACK_DEV_SERVER_BASE_PORT = 50000; + + const compiler = webpack(config); + const devServerOptions = { + webSocketServer, + port: "auto", + host: "0.0.0.0" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const resolvedFreePort = server.options.port; + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${resolvedFreePort}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${resolvedFreePort}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + + delete process.env.WEBPACK_DEV_SERVER_BASE_PORT; + } + }); + + it(`should work with "client.webSocketURL.*" options ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: { + protocol: "ws:", + hostname: "127.0.0.1", + port: port1, + pathname: "/ws" + } + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work with the "client.webSocketURL" option as "string" ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: `ws://127.0.0.1:${port1}/ws` + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + + if (webSocketServer === "ws") { + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + } else { + page.on("request", request => { + if (/\/ws\//.test(request.url())) { + webSocketRequests.push({ url: request.url() }); + } + }); + } + + await page.goto(`http://127.0.0.1:${port1}/`, { + waitUntil: "networkidle0" + }); + + const webSocketRequest = webSocketRequests[0]; + + expect(webSocketRequest.url).toContain( + `${websocketURLProtocol}://127.0.0.1:${port1}/ws` + ); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should work and throw an error on invalid web socket URL ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: "unknown://unknown.unknown/unknown" + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + await page.goto(`http://localhost:${port1}/`, { + waitUntil: "networkidle0" + }); + + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect( + pageErrors.map(pageError => pageError.message.split("\n")[0]) + ).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it(`should not work and output disconnect wrong web socket URL ("${webSocketServer}")`, async () => { + const compiler = webpack(config); + const devServerOptions = { + client: { + webSocketURL: "ws://unknown.unknown/unknown" + }, + webSocketServer, + port: port1, + host: "0.0.0.0", + allowedHosts: "all" + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + let isDisconnected = false; + + page + .on("console", message => { + const text = message.text(); + + if (!isDisconnected) { + isDisconnected = /Disconnected!/.test(text); + consoleMessages.push(text.replace(/:[\d]+/g, ":")); + } + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + await page.goto(`http://localhost:${port1}/`, { + waitUntil: "networkidle0" + }); + + await new Promise(resolve => { + const interval = setInterval(() => { + if ( + consoleMessages.includes("[webpack-dev-server] Disconnected!") + ) { + clearInterval(interval); + + resolve(); + } + }, 100); + }); + + expect(consoleMessages).toMatchSnapshot("console messages"); + expect( + pageErrors.map(pageError => pageError.message.split("\n")[0]) + ).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + } +}); diff --git a/packages/rspack-dev-server/tests/e2e/web-socket-server.test.js b/packages/rspack-dev-server/tests/e2e/web-socket-server.test.js new file mode 100644 index 00000000000..44ba6ac53f8 --- /dev/null +++ b/packages/rspack-dev-server/tests/e2e/web-socket-server.test.js @@ -0,0 +1,68 @@ +"use strict"; + +const webpack = require("@rspack/core"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); +const config = require("../fixtures/client-config/webpack.config"); +const runBrowser = require("../helpers/run-browser"); +const sessionSubscribe = require("../helpers/session-subscribe"); +const port = require("../helpers/ports-map")["web-socket-server-test"]; + +describe("web socket server", () => { + it("should work allow to disable", async () => { + const devServerPort = port; + + const compiler = webpack(config); + const devServerOptions = { + webSocketServer: false, + port: devServerPort + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const pageErrors = []; + const consoleMessages = []; + + page + .on("console", message => { + consoleMessages.push(message); + }) + .on("pageerror", error => { + pageErrors.push(error); + }); + + const webSocketRequests = []; + const session = await page.target().createCDPSession(); + + session.on("Network.webSocketCreated", test => { + webSocketRequests.push(test); + }); + + await session.send("Target.setAutoAttach", { + autoAttach: true, + flatten: true, + waitForDebuggerOnStart: true + }); + + sessionSubscribe(session); + + await page.goto(`http://127.0.0.1:${port}/`, { + waitUntil: "networkidle0" + }); + + expect(webSocketRequests).toHaveLength(0); + expect(consoleMessages.map(message => message.text())).toMatchSnapshot( + "console messages" + ); + expect(pageErrors).toMatchSnapshot("page errors"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); +}); diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/ca-symlink.pem b/packages/rspack-dev-server/tests/fixtures/https-certificate/ca-symlink.pem new file mode 120000 index 00000000000..e375f5ab0d5 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/https-certificate/ca-symlink.pem @@ -0,0 +1 @@ +ca.pem \ No newline at end of file diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/ca.pem b/packages/rspack-dev-server/tests/fixtures/https-certificate/ca.pem new file mode 100644 index 00000000000..05b314535be --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/https-certificate/ca.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kv +C/hf5Ei1J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYu +Dy9WkFuMie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhs +EENnH6sUE9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2sw +duxJTWRINmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+ +T8emgklStASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABAoIBAGqWKPE1QnT3T+3J +G+ITz9P0dDFbvWltlTZmeSJh/s2q+WZloUNtBxdmwbqT/1QecnkyGgyzVCjvSKsu +CgVjWNVAhysgtNtxRT4BVflffBXLVH2qsBjpsLRGU6EcMXuPGTiEp3YRHNuO6Aj8 +oP8fEsCGPc9DlJMGgxQRAKlrVF8TN/0j6Qk+YpS4MZ0YFQfBY+WdKu04Z8TVTplQ +tTkiGpBI+Oj85jF59aQiizglJgADkAZ6zmbrctm/G9jPxh7JLS2cKI0ECZgK5yAc +pk10E1YWhoCksjr9arxy6fS9TiX9P15vv06k+s7c4c5X7XDm3X0GWeSbqBMJb8q7 +BhZQNzECgYEA4kAtymDBvFYiZFq7+lzQBRKAI1RCq7YqxlieumH0PSkie2bba3dW +NVdTi7at8+GDB9/cHUPKzg/skfJllek57MZmusiVwB/Lmp/IlW8YyGShdYZ7zQsV +KMWJljpky3BEDM5sb08wIkfrOkelI/S4Bqqabd9JzOMJzoTiVOlMam8CgYEA3ctN +yonWz2bsnCUstQvQCLdI5a8Q7GJvlH2awephxGXIKGUuRmyyop0AnRnIBEWtOQV7 +yZjW32bU+Wt+2BJ247EyJiIQ4gT+T51t+v/Wt1YNbL3dSj9ttOvwYd4H2W4E7EIO +GKIF4I39FM7r8NfG7YE7S1aVcnrqs01N3nhd9HMCgYEAjepbzpmqbAxLPk97oase +AFB+d6qetz5ozklAJwDSRprKukTmVR5hwMup5/UKX/OQURwl4WVojKCIb3NwLPxC +DTbVsUuoQv6uo6qeEr3A+dHFRQa6GP9eolhl2Ql/t+wPg0jn01oEgzxBXCkceNVD +qUrR2yE4FYBD4nqPzVsZR5kCgYEA1yTi7NkQeldIpZ6Z43T18753A/Xx4JsLyWqd +uAT3mV9x7V1Yqg++qGbLtZjQoPRFt85N6ZxMsqA5b0iK3mXq1auJDdx1rAlT9z6q +9JM/YNAkbZsvEVq9vIYxw31w98T1GYhpzBM+yDhzir+9tv5YhQKa1dXDWi1JhWwz +YN45pWkCgYEAxuVsJ4D4Th5o050ppWpnxM/WuMhIUKqaoFTVucMKFzn+g24y9pv5 +miYdNYIk4Y+4pzHG6ZGZSHJcQ9BLui6H/nLQnqkgCb2lT5nfp7/GKdus7BdcjPGs +fcV46yL7/X0m8nDb3hkwwrDTU4mKFkMrzKpjdZBsttEmW0Aw/3y36gU= +-----END RSA PRIVATE KEY----- diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.crt b/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.crt new file mode 120000 index 00000000000..d23ad4d88e3 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.crt @@ -0,0 +1 @@ +server.crt \ No newline at end of file diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.key b/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.key new file mode 120000 index 00000000000..c26f438dd74 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.key @@ -0,0 +1 @@ +server.key \ No newline at end of file diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.pfx b/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.pfx new file mode 120000 index 00000000000..89adfe8705f --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/https-certificate/server-symlink.pfx @@ -0,0 +1 @@ +server.pfx \ No newline at end of file diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/server.crt b/packages/rspack-dev-server/tests/fixtures/https-certificate/server.crt new file mode 100644 index 00000000000..1992bb16104 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/https-certificate/server.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJALz8gD/gAt0OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDIzMTgyMTQ5WhcNMTkxMDIzMTgyMTQ5WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kvC/hf5Ei1 +J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYuDy9WkFuM +ie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhsEENnH6sU +E9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2swduxJTWRI +NmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+T8emgklS +tASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABo1AwTjAdBgNVHQ4EFgQUDZBhVKdb +3BRhLIhuuE522Vsul0IwHwYDVR0jBBgwFoAUDZBhVKdb3BRhLIhuuE522Vsul0Iw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABh9WWZwWLgb9/DcTxL72 +6pI96t4jiF79Q+pPefkaIIi0mE6yodWrTAsBQu9I6bNRaEcCSoiXkP2bqskD/UGg +LwUFgSrDOAA3UjdHw3QU5g2NocduG7mcFwA40TB98sOsxsUyYlzSyWzoiQWwPYwb +hek1djuWkqPXsTjlj54PTPN/SjTFmo4p5Ip6nbRf2nOREl7v0rJpGbJvXiCMYyd+ +Zv+j4mRjCGo8ysMR2HjCUGkYReLAgKyyz3M7i8vevJhKslyOmy6Txn4F0nPVumaU +DDIy4xXPW1STWfsmSYJfYW3wa0wk+pJQ3j2cTzkPQQ8gwpvM3U9DJl43uwb37v6I +7Q== +-----END CERTIFICATE----- diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/server.key b/packages/rspack-dev-server/tests/fixtures/https-certificate/server.key new file mode 100644 index 00000000000..c002d19e496 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/https-certificate/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEBRUsUz4rdcMt +CQGLvG3SzUinsmgdgOyTNQNA0eOMyRSrmS8L+F/kSLUnqqu4mzdeqDzo2Xj553jK +dRqMCRFGJuGnQ/VIbW2A+ywgrqILuDyF5i4PL1aQW4yJ7TnXfONKfpswQArlN6DF +gBYJtoJlf8XD1sOeJpsv/O46/ix/wngQ+GwQQ2cfqxQT0fE9SBCY23VNt3SPUJ3k +9etJMvJ9U9GHSb1CFdNQe7Gyx7xdKf1TazB27ElNZEg2aF99if47uRskYjvvFivy +7nxGx/ccIwjwNMpk29AsKG++0sn1yTK7tD5Px6aCSVK0BKbdXZS2euJor8hASGBJ +3GpVGJvdAgMBAAECggEAapYo8TVCdPdP7ckb4hPP0/R0MVu9aW2VNmZ5ImH+zar5 +ZmWhQ20HF2bBupP/VB5yeTIaDLNUKO9Iqy4KBWNY1UCHKyC023FFPgFV+V98FctU +faqwGOmwtEZToRwxe48ZOISndhEc247oCPyg/x8SwIY9z0OUkwaDFBEAqWtUXxM3 +/SPpCT5ilLgxnRgVB8Fj5Z0q7ThnxNVOmVC1OSIakEj46PzmMXn1pCKLOCUmAAOQ +BnrOZuty2b8b2M/GHsktLZwojQQJmArnIBymTXQTVhaGgKSyOv1qvHLp9L1OJf0/ +Xm+/TqT6ztzhzlftcObdfQZZ5JuoEwlvyrsGFlA3MQKBgQDiQC3KYMG8ViJkWrv6 +XNAFEoAjVEKrtirGWJ66YfQ9KSJ7Zttrd1Y1V1OLtq3z4YMH39wdQ8rOD+yR8mWV +6Tnsxma6yJXAH8uan8iVbxjIZKF1hnvNCxUoxYmWOmTLcEQMzmxvTzAiR+s6R6Uj +9LgGqppt30nM4wnOhOJU6UxqbwKBgQDdy03KidbPZuycJSy1C9AIt0jlrxDsYm+U +fZrB6mHEZcgoZS5GbLKinQCdGcgERa05BXvJmNbfZtT5a37YEnbjsTImIhDiBP5P +nW36/9a3Vg1svd1KP2206/Bh3gfZbgTsQg4YogXgjf0Uzuvw18btgTtLVpVyeuqz +TU3eeF30cwKBgQCN6lvOmapsDEs+T3uhqx4AUH53qp63PmjOSUAnANJGmsq6ROZV +HmHAy6nn9Qpf85BRHCXhZWiMoIhvc3As/EINNtWxS6hC/q6jqp4SvcD50cVFBroY +/16iWGXZCX+37A+DSOfTWgSDPEFcKRx41UOpStHbITgVgEPieo/NWxlHmQKBgQDX +JOLs2RB6V0ilnpnjdPXzvncD9fHgmwvJap24BPeZX3HtXViqD76oZsu1mNCg9EW3 +zk3pnEyyoDlvSIreZerVq4kN3HWsCVP3Pqr0kz9g0CRtmy8RWr28hjHDfXD3xPUZ +iGnMEz7IOHOKv722/liFAprV1cNaLUmFbDNg3jmlaQKBgQDG5WwngPhOHmjTnSml +amfEz9a4yEhQqpqgVNW5wwoXOf6DbjL2m/maJh01giThj7inMcbpkZlIclxD0Eu6 +Lof+ctCeqSAJvaVPmd+nv8Yp26zsF1yM8ax9xXjrIvv9fSbycNveGTDCsNNTiYoW +QyvMqmN1kGy20SZbQDD/fLfqBQ== +-----END PRIVATE KEY----- diff --git a/packages/rspack-dev-server/tests/fixtures/https-certificate/server.pfx b/packages/rspack-dev-server/tests/fixtures/https-certificate/server.pfx new file mode 100644 index 0000000000000000000000000000000000000000..e5ed9c7988603578422a0aeca51ae535b42949ab GIT binary patch literal 2469 zcmZXUc{CJ?9>>jMm>FcxR`y{CGxp^&8bgt+kwWC!GbD{=EHNWHVeFC-*|L_DFh!Ob zZYW#aEQ5pyS-Zk>&w20Nch39ccYf!5zvq1a`+QI&XbBJiLXn_e5U4`j#kf6A02_cx zf;xan&?_gg6^aCA`=^3XNuYfc3A7Cau$;WLe;NQv3{ZB7nr?ldKnlndSnCy zva>{!KyTGwWU=?tJ6`FqHvXvu^e?Tim!78v)a*dXKDmo5^Z3mjmAEf?&y!ANZ&E;_+sRkuINkOz-Od@Q`C~Ccs>)Qq&@8 zj=|@(g=k7~o*lT(3j7DXHXTQbEnvLNZmzy*flqCoPppt%SF}e8)Am%i`_?U7HCK64 z2Mn+DYFYU~*R_qiy-SAK$hWDS&I{*oUYomZF_Q_RpyIoEq(B$jtJY(a9UkOpLE@2h zIwe>U_`%C;)&G1HI7NTF-Gp00yv%+j5xrf4P{Hs#<^ZPlulCqXV?S~1 zXSlDJCH+dhqh8fsJ1Cyn|Ij9Mi8;jbBKD=hyke+oN6qy7<1?#nTK=I2m(Hq>##2gs zLGHmkpXkQ%w&`(HN*-aN zrxC&Ak+o*R_p#vksojQy#XCEV*5xhlGn_!}uYD4YF-@(o*oQ?ph&YM$6kY0vwcJc? zkGw*?C@iahf$e)~Pch}f|3w|yk-RQ^t>w}Sn_?nWMs-F{BI~wsQVe(b^9?joaZ1EfeL^ei38-)Um{;0-~ zHx#9}H~mfB{b^z@CF8oitqZ*vi(3 z|5k()buF`X{3!mDm34pEbh<|1meo1E26M_)| zaLi0mGy>vdN&HqRB8v^75apGRyS-J+z_bJ-gfxfGK^Gp&H%FL+BAe-913%60{#El- z@|t+vvAWwrH+`#|`TY%NLR}gcU+wsAaM2C_Mg_s^(cV;oyO8Va?h<5Obvlrj%$f&R z4jpp-0u3F;TG(l?3(mhWX*2g)vw1gH{-(8@|L7(;*=|>}XeH*fLagmZXQVF8qO#qP z+vkO=_{?|T1j`UY)d_z z!vH`k3H<#;9V`ED1wIlXWUg3t^KUDFNnm;us%yb zg&x&*;>SmEHQQ+23B-&Fb=1n0XUv8D9493+-SYQQBMIQhkB?&8MYdJ=>w`pSB`!Yp zV2*<6^3!gR6j(Jf5Oovvbv9v}Q3>$59q2peI{C@$<(4r)u$MbMvYq33Fl+|}rMZ05 zY@6aB=~q&I^Ie`v9t(@iX-W32Qc%lyPDHjg+DyD>pIbjI6@1!Kruu`=xMWv!-;(qa zZKCM(<3*=v&UFb@kA+wVxe-mZxzqpw>oFIrrY%<&0*`{17BVf4G1z~MyS&siZ$uw5 zEv&zK9LFTIzzezd#d5Z9CeL0zPTWv8l4Z=A->}Tchd}9o?EssJA5xt-Ue^shVU2<@ zjON&~d>(dfgxPrja*=UH=pb)$2w|~1JFnxSf)oYI)B)skU{9T)Izh z2r>`<>@0(VYvM}9TtB{Bt&(@|jv)^~p%s9)Grr3~1z4jsdATUOSc=yOTCMpw(7>V> z*7T;p!@K-TwJnCSJ46^$ioz>x`jymuTcv^P)@#7H+$tkpNKnzBwZ}dFYy`s)(u3@M zNQ!rJJgni1kzjO_e?5y=n397x`$b=k-55=^hdSt8hEXgf7|+6U31@8IUb%KDfj;c- z;r|5racOV4AV!B~h?U5T3vf5ehet5m=Vgg5K`Kf)y-jMu^`WhZUYXkH%Hha{y*hP& z-3|NT0%_+hsoG(QCld=(ptV+uNaZ*&nh<4kKzrjL_;noWtDW=1UY50Iy zooHrAzR>`GhS2?<9`gX5^VKQt-iM?ECmRanfcIXs3KbKSZQTde!&cco|{nq_(XrPJ4YWB-g4Zj2XDfO@u4&0Iu-7IJG zrfALFXgKshz~K{daa^DCYm0n7euqub0)7F>PfzWvTdghYK7|`LUh42n*f6`?p478D z^ZurG+YLSEmEwE%?Zc>&mUeGV_A`aQE5pPVEn=!k#X-!gAph zUl(&$Vd>G+B6AP5-CBiO`+kpI%I;>qQ-&roF^`uc=lPN2S{mFPdHH&l#IBN!QW;wx z+HsC;umWCo`0%)4tDVT*FO&Vjj(VP1=`d8n5Gl=8>}*UD1vXywcRG0O*=X7rL?f%n zUXYF;rGd>H{~#JvXw?KGw02rKkI3|R& zcd>?M+*qV{N=xQmDC$CuV%hR|aTMVOnpSMqves+=n*EAhwG)q$Rljg?8WUG|_tX|= z0R!q*X2lWDkNWh3S*T}*_}R*mJQ%p&8mIe8KV0naS61%m!6xiTkh|lv>e

v@A;c zzjlNQpasGFWrNeD)tSwCe6X(p#@XY1zOyU@6dEOofRu(Wnd*zsM)@z2m d>y1l8XL5QEAm5`7!R+?&R}~i_)?t5J@?T~ed8PmW literal 0 HcmV?d00001 diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/foo.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/foo.js new file mode 100644 index 00000000000..c28b40f73cb --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/foo.js @@ -0,0 +1,8 @@ +"use strict"; + +// 'npm run prepare' must be run for this to work during testing +const CustomClient = require("../../fixtures/custom-client/CustomSockJSClient"); + +window.expectedClient = CustomClient; +// eslint-disable-next-line camelcase, no-undef +window.injectedClient = __webpack_dev_server_client__; diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/webpack.config.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/webpack.config.js new file mode 100644 index 00000000000..661a14db435 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-custom copy/webpack.config.js @@ -0,0 +1,21 @@ +"use strict"; + +const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin"); + +module.exports = { + mode: "development", + context: __dirname, + stats: "none", + entry: "./foo.js", + output: { + path: "/" + }, + node: false, + infrastructureLogging: { + level: "info", + stream: { + write: () => {} + } + }, + plugins: [new HTMLGeneratorPlugin()] +}; diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-default/foo.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-default/foo.js new file mode 100644 index 00000000000..538ae3e1b1f --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-default/foo.js @@ -0,0 +1,9 @@ +"use strict"; + +// 'npm run prepare' must be run for this to work during testing +const WebsocketClient = + require("webpack-dev-server/client/clients/WebSocketClient").default; + +window.expectedClient = WebsocketClient; +// eslint-disable-next-line camelcase, no-undef +window.injectedClient = __webpack_dev_server_client__.default; diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-default/webpack.config.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-default/webpack.config.js new file mode 100644 index 00000000000..661a14db435 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-default/webpack.config.js @@ -0,0 +1,21 @@ +"use strict"; + +const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin"); + +module.exports = { + mode: "development", + context: __dirname, + stats: "none", + entry: "./foo.js", + output: { + path: "/" + }, + node: false, + infrastructureLogging: { + level: "info", + stream: { + write: () => {} + } + }, + plugins: [new HTMLGeneratorPlugin()] +}; diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/foo.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/foo.js new file mode 100644 index 00000000000..3b43d16ad13 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/foo.js @@ -0,0 +1,9 @@ +"use strict"; + +// 'npm run prepare' must be run for this to work during testing +const SockJSClient = + require("webpack-dev-server/client/clients/SockJSClient").default; + +window.expectedClient = SockJSClient; +// eslint-disable-next-line camelcase, no-undef +window.injectedClient = __webpack_dev_server_client__.default; diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/webpack.config.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/webpack.config.js new file mode 100644 index 00000000000..661a14db435 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-sockjs-config/webpack.config.js @@ -0,0 +1,21 @@ +"use strict"; + +const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin"); + +module.exports = { + mode: "development", + context: __dirname, + stats: "none", + entry: "./foo.js", + output: { + path: "/" + }, + node: false, + infrastructureLogging: { + level: "info", + stream: { + write: () => {} + } + }, + plugins: [new HTMLGeneratorPlugin()] +}; diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/foo.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/foo.js new file mode 100644 index 00000000000..538ae3e1b1f --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/foo.js @@ -0,0 +1,9 @@ +"use strict"; + +// 'npm run prepare' must be run for this to work during testing +const WebsocketClient = + require("webpack-dev-server/client/clients/WebSocketClient").default; + +window.expectedClient = WebsocketClient; +// eslint-disable-next-line camelcase, no-undef +window.injectedClient = __webpack_dev_server_client__.default; diff --git a/packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/webpack.config.js b/packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/webpack.config.js new file mode 100644 index 00000000000..661a14db435 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/provide-plugin-ws-config/webpack.config.js @@ -0,0 +1,21 @@ +"use strict"; + +const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin"); + +module.exports = { + mode: "development", + context: __dirname, + stats: "none", + entry: "./foo.js", + output: { + path: "/" + }, + node: false, + infrastructureLogging: { + level: "info", + stream: { + write: () => {} + } + }, + plugins: [new HTMLGeneratorPlugin()] +}; diff --git a/packages/rspack-dev-server/tests/fixtures/reload-config-2/foo.js b/packages/rspack-dev-server/tests/fixtures/reload-config-2/foo.js new file mode 100644 index 00000000000..37887d25359 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/reload-config-2/foo.js @@ -0,0 +1,4 @@ +"use strict"; + +// eslint-disable-next-line import/no-unresolved +require("./main.css"); diff --git a/packages/rspack-dev-server/tests/fixtures/reload-config-2/webpack.config.js b/packages/rspack-dev-server/tests/fixtures/reload-config-2/webpack.config.js new file mode 100644 index 00000000000..adb992fb269 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/reload-config-2/webpack.config.js @@ -0,0 +1,29 @@ +"use strict"; + +const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin"); + +module.exports = { + mode: "development", + context: __dirname, + stats: "none", + entry: "./foo.js", + output: { + path: "/" + }, + module: { + rules: [ + { + test: /\.css$/, + use: [{ loader: "style-loader" }, { loader: "css-loader" }] + } + ] + }, + node: false, + infrastructureLogging: { + level: "info", + stream: { + write: () => {} + } + }, + plugins: [new HTMLGeneratorPlugin()] +}; diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/foo.js b/packages/rspack-dev-server/tests/fixtures/static-config/foo.js new file mode 100644 index 00000000000..3c915dbcb8e --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/static-config/foo.js @@ -0,0 +1,3 @@ +"use strict"; + +console.log("Hey."); diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/other/foo.html b/packages/rspack-dev-server/tests/fixtures/static-config/other/foo.html new file mode 100644 index 00000000000..c57ed97e227 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/static-config/other/foo.html @@ -0,0 +1 @@ +Foo! diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/public/assets/example.txt b/packages/rspack-dev-server/tests/fixtures/static-config/public/assets/example.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/public/assets/other.txt b/packages/rspack-dev-server/tests/fixtures/static-config/public/assets/other.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/public/bar/index.html b/packages/rspack-dev-server/tests/fixtures/static-config/public/bar/index.html new file mode 100644 index 00000000000..17654db5a15 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/static-config/public/bar/index.html @@ -0,0 +1 @@ +Heyo diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/public/foo.wasm b/packages/rspack-dev-server/tests/fixtures/static-config/public/foo.wasm new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/public/index.html b/packages/rspack-dev-server/tests/fixtures/static-config/public/index.html new file mode 100644 index 00000000000..20f073ee9d7 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/static-config/public/index.html @@ -0,0 +1 @@ +Heyo. diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/public/other.html b/packages/rspack-dev-server/tests/fixtures/static-config/public/other.html new file mode 100644 index 00000000000..6b31da1a64c --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/static-config/public/other.html @@ -0,0 +1 @@ +Other html diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/static/index.html b/packages/rspack-dev-server/tests/fixtures/static-config/static/index.html new file mode 100644 index 00000000000..20f073ee9d7 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/static-config/static/index.html @@ -0,0 +1 @@ +Heyo. diff --git a/packages/rspack-dev-server/tests/fixtures/static-config/webpack.config.js b/packages/rspack-dev-server/tests/fixtures/static-config/webpack.config.js new file mode 100644 index 00000000000..71928769b24 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/static-config/webpack.config.js @@ -0,0 +1,14 @@ +"use strict"; + +module.exports = { + mode: "development", + context: __dirname, + stats: "none", + entry: "./foo.js", + output: { + publicPath: "/" + }, + infrastructureLogging: { + level: "warn" + } +}; diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/foo.js b/packages/rspack-dev-server/tests/fixtures/watch-files-config/foo.js new file mode 100644 index 00000000000..3c915dbcb8e --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/watch-files-config/foo.js @@ -0,0 +1,3 @@ +"use strict"; + +console.log("Hey."); diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/other/foo.html b/packages/rspack-dev-server/tests/fixtures/watch-files-config/other/foo.html new file mode 100644 index 00000000000..c57ed97e227 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/watch-files-config/other/foo.html @@ -0,0 +1 @@ +Foo! diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/example.txt b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/example.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/non-exist.txt b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/non-exist.txt new file mode 100644 index 00000000000..9c6e47bc1f0 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/non-exist.txt @@ -0,0 +1 @@ +Kurosaki Ichigo \ No newline at end of file diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/other.txt b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/assets/other.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/bar/index.html b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/bar/index.html new file mode 100644 index 00000000000..17654db5a15 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/bar/index.html @@ -0,0 +1 @@ +Heyo diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/other.html b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/other.html new file mode 100644 index 00000000000..6b31da1a64c --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/watch-files-config/public/other.html @@ -0,0 +1 @@ +Other html diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/static/index.html b/packages/rspack-dev-server/tests/fixtures/watch-files-config/static/index.html new file mode 100644 index 00000000000..20f073ee9d7 --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/watch-files-config/static/index.html @@ -0,0 +1 @@ +Heyo. diff --git a/packages/rspack-dev-server/tests/fixtures/watch-files-config/webpack.config.js b/packages/rspack-dev-server/tests/fixtures/watch-files-config/webpack.config.js new file mode 100644 index 00000000000..7df3e7e4dbb --- /dev/null +++ b/packages/rspack-dev-server/tests/fixtures/watch-files-config/webpack.config.js @@ -0,0 +1,17 @@ +"use strict"; + +const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin"); + +module.exports = { + mode: "development", + context: __dirname, + stats: "none", + entry: "./foo.js", + output: { + publicPath: "/" + }, + infrastructureLogging: { + level: "warn" + }, + plugins: [new HTMLGeneratorPlugin()] +}; diff --git a/packages/rspack-dev-server/tests/helpers/conditional-test.js b/packages/rspack-dev-server/tests/helpers/conditional-test.js new file mode 100644 index 00000000000..5d0ba713c62 --- /dev/null +++ b/packages/rspack-dev-server/tests/helpers/conditional-test.js @@ -0,0 +1,12 @@ +"use strict"; + +const isWindows = process.platform === "win32"; + +function skipTestOnWindows(reason) { + if (isWindows) { + test.skip(reason, () => {}); + } + return isWindows; +} + +module.exports.skipTestOnWindows = skipTestOnWindows; diff --git a/packages/rspack-dev-server/tests/helpers/custom-http.js b/packages/rspack-dev-server/tests/helpers/custom-http.js new file mode 100644 index 00000000000..0678c55d9a3 --- /dev/null +++ b/packages/rspack-dev-server/tests/helpers/custom-http.js @@ -0,0 +1,5 @@ +"use strict"; + +const customHTTP = require("http"); + +module.exports = customHTTP; diff --git a/packages/rspack-dev-server/tests/helpers/normalize-options.js b/packages/rspack-dev-server/tests/helpers/normalize-options.js new file mode 100644 index 00000000000..46e58720084 --- /dev/null +++ b/packages/rspack-dev-server/tests/helpers/normalize-options.js @@ -0,0 +1,38 @@ +"use strict"; + +function normalizeOptions(options) { + const normalizedOptions = {}; + + // eslint-disable-next-line guard-for-in + for (const propertyName in options) { + let value = options[propertyName]; + + if (Array.isArray(value)) { + value = value.map(item => { + if (Buffer.isBuffer(item)) { + return ""; + } else if ( + typeof item.pem !== "undefined" && + Buffer.isBuffer(item.pem) + ) { + item.pem = ""; + } else if ( + typeof item.buf !== "undefined" && + Buffer.isBuffer(item.buf) + ) { + item.buf = ""; + } + + return item; + }); + } else if (Buffer.isBuffer(value)) { + value = ""; + } + + normalizedOptions[propertyName] = value; + } + + return normalizedOptions; +} + +module.exports = normalizeOptions; diff --git a/packages/rspack-dev-server/tests/helpers/test-server.js b/packages/rspack-dev-server/tests/helpers/test-server.js new file mode 100644 index 00000000000..027acd741b4 --- /dev/null +++ b/packages/rspack-dev-server/tests/helpers/test-server.js @@ -0,0 +1,95 @@ +"use strict"; + +const webpack = require("webpack"); +const { RspackDevServer: Server } = require("@rspack/dev-server"); + +let server; + +// start server, returning the full setup of the server +// (both the server and the compiler) +function startFullSetup(config, options, done) { + // disable watching by default for tests + if (typeof options.static === "undefined") { + options.static = false; + } else if (options.static === null) { + // this provides a way of using the default static value + delete options.static; + } + + const compiler = webpack(config); + + server = new Server(options, compiler); + + server.startCallback(error => { + if (error && done) { + return done(error); + } + + if (done) { + done(); + } + }); + + return { + server, + compiler + }; +} + +function startAwaitingCompilationFullSetup(config, options, done) { + let readyCount = 0; + + const ready = error => { + if (error && done) { + done(error); + + return; + } + + readyCount += 1; + + if (readyCount === 2) { + done(); + } + }; + + const fullSetup = startFullSetup(config, options, ready); + + // wait for compilation, since dev server can start before this + // https://github.com/webpack/webpack-dev-server/issues/847 + fullSetup.compiler.hooks.done.tap("done", () => { + ready(); + }); + + return fullSetup; +} + +function startAwaitingCompilation(config, options, done) { + return startAwaitingCompilationFullSetup(config, options, done).server; +} + +function start(config, options, done) { + // I suspect that almost all tests need to wait for compilation to + // finish, because not doing so leaves open handles for jest, + // in the case where a compilation didn't finish before destroying + // the server and moving on. Thus, the default "start" should wait + // for compilation, and only special cases where you don't expect + // a compilation happen should use startBeforeCompilation + return startAwaitingCompilation(config, options, done); +} + +function close(done) { + if (server) { + server.stopCallback(() => { + server = null; + done(); + }); + } else { + done(); + } +} + +module.exports = { + start, + close +};