From 47f28d20ac88f9503064df17359938db51a70fde Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Tue, 13 Feb 2024 15:43:58 +0300 Subject: [PATCH 1/2] fix: overlay and `require-trusted-types-for` --- .eslintignore | 1 + .prettierignore | 1 + client-src/overlay.js | 4 +++- examples/client/trusted-types-overlay/app.js | 3 +++ examples/client/trusted-types-overlay/webpack.config.js | 5 ++++- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.eslintignore b/.eslintignore index 861faf369b..42e97a7634 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,3 +3,4 @@ !/test/client coverage node_modules +examples/client/trusted-types-overlay/app.js diff --git a/.prettierignore b/.prettierignore index 236cbcb571..65cd2f21a9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,4 @@ coverage node_modules CHANGELOG.md +examples/client/trusted-types-overlay/app.js diff --git a/client-src/overlay.js b/client-src/overlay.js index 7c20687749..04670df2c0 100644 --- a/client-src/overlay.js +++ b/client-src/overlay.js @@ -189,7 +189,9 @@ const createOverlay = (options) => { */ function ensureOverlayExists(callback, trustedTypesPolicyName) { if (containerElement) { - containerElement.innerHTML = ""; + containerElement.innerHTML = overlayTrustedTypesPolicy + ? overlayTrustedTypesPolicy.createHTML("") + : ""; // Everything is ready, call the callback right away. callback(containerElement); diff --git a/examples/client/trusted-types-overlay/app.js b/examples/client/trusted-types-overlay/app.js index 0c5dbd0635..130fdcd715 100644 --- a/examples/client/trusted-types-overlay/app.js +++ b/examples/client/trusted-types-overlay/app.js @@ -4,3 +4,6 @@ const target = document.querySelector("#target"); target.classList.add("pass"); target.textContent = "Success!"; + +// To display an overlay with an error +( diff --git a/examples/client/trusted-types-overlay/webpack.config.js b/examples/client/trusted-types-overlay/webpack.config.js index 3009abed0c..7399f26646 100644 --- a/examples/client/trusted-types-overlay/webpack.config.js +++ b/examples/client/trusted-types-overlay/webpack.config.js @@ -9,11 +9,14 @@ const { setup } = require("../../util"); const config = setup({ context: __dirname, // create error for overlay - entry: "./invalid.js", + entry: "./app.js", output: { trustedTypes: { policyName: "webpack" }, }, devServer: { + headers: { + "Content-Security-Policy": "require-trusted-types-for 'script'", + }, client: { overlay: { trustedTypesPolicyName: "webpack#dev-overlay", From 83fbe45ff51915fec201db55c7fff7708da1e0b0 Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Tue, 13 Feb 2024 17:06:51 +0300 Subject: [PATCH 2/2] test: added --- .../overlay.test.js.snap.webpack4 | 2517 ----------------- .../overlay.test.js.snap.webpack5 | 315 +++ test/e2e/overlay.test.js | 150 +- 3 files changed, 463 insertions(+), 2519 deletions(-) delete mode 100644 test/e2e/__snapshots__/overlay.test.js.snap.webpack4 diff --git a/test/e2e/__snapshots__/overlay.test.js.snap.webpack4 b/test/e2e/__snapshots__/overlay.test.js.snap.webpack4 deleted file mode 100644 index f61db0a050..0000000000 --- a/test/e2e/__snapshots__/overlay.test.js.snap.webpack4 +++ /dev/null @@ -1,2517 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`overlay should not show a warning when "client.overlay" is "false": page html 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show a warning when "client.overlay.warnings" is "false": page html 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show an error when "client.overlay" is "false": page html 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show an error when "client.overlay.errors" is "false": page html 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show initially, then show on an error and allow to close: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- ./foo.js 1:1 Module parse failed: Unterminated template (1:1) You may - need an appropriate loader to handle this file type, currently no - loaders are configured to process this file. See - https://webpack.js.org/concepts#loaders > \`; -
-
-
-
- -" -`; - -exports[`overlay should not show initially, then show on an error and allow to close: page html after close 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show initially, then show on an error and allow to close: page html initial 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show initially, then show on an error and allow to close: page html with error 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should not show initially, then show on an error, then hide on fix: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- ./foo.js 1:1 Module parse failed: Unterminated template (1:1) You may - need an appropriate loader to handle this file type, currently no - loaders are configured to process this file. See - https://webpack.js.org/concepts#loaders > \`; -
-
-
-
- -" -`; - -exports[`overlay should not show initially, then show on an error, then hide on fix: page html after fix error 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show initially, then show on an error, then hide on fix: page html initial 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show initially, then show on an error, then hide on fix: page html with error 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should not show initially, then show on an error, then show other error, then hide on fix: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- ./foo.js 1:1 Module parse failed: Unterminated template (1:1) You may - need an appropriate loader to handle this file type, currently no - loaders are configured to process this file. See - https://webpack.js.org/concepts#loaders > \`; -
-
-
-
- -" -`; - -exports[`overlay should not show initially, then show on an error, then show other error, then hide on fix: overlay html 2`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- ./foo.js 1:1 Module parse failed: Unterminated template (1:1) You may - need an appropriate loader to handle this file type, currently no - loaders are configured to process this file. See - https://webpack.js.org/concepts#loaders > \`;a -
-
-
-
- -" -`; - -exports[`overlay should not show initially, then show on an error, then show other error, then hide on fix: page html after fix error 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show initially, then show on an error, then show other error, then hide on fix: page html initial 1`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should not show initially, then show on an error, then show other error, then hide on fix: page html with error 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should not show initially, then show on an error, then show other error, then hide on fix: page html with other error 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning after invalidation: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Warning from compilation -
-
-
-
- -" -`; - -exports[`overlay should show a warning after invalidation: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning and error for initial compilation and protects against xss: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- <strong>strong</strong> -
-
-
-
- ERROR -
-
- <strong>strong</strong> -
-
-
-
- -" -`; - -exports[`overlay should show a warning and error for initial compilation and protects against xss: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning and error for initial compilation: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- Warning from compilation -
-
-
-
- ERROR -
-
- Warning from compilation -
-
-
-
- ERROR -
-
- Error from compilation. Can't find 'test' module. -
-
-
-
- ERROR -
-
- Error from compilation. Can't find 'test' module. -
-
-
-
- ERROR -
-
- Error from compilation. Can't find 'test' module. -
-
-
-
- -" -`; - -exports[`overlay should show a warning and error for initial compilation: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning and hide them after closing connection: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Warning from compilation -
-
-
-
- -" -`; - -exports[`overlay should show a warning and hide them after closing connection: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning and hide them after closing connection: page html 2`] = ` -" -

webpack-dev-server is running...

- - -" -`; - -exports[`overlay should show a warning for initial compilation: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Warning from compilation -
-
-
-
- -" -`; - -exports[`overlay should show a warning for initial compilation: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning when "client.overlay" is "true": overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Warning from compilation -
-
-
-
- -" -`; - -exports[`overlay should show a warning when "client.overlay" is "true": page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning when "client.overlay.errors" is "true": overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Warning from compilation -
-
-
-
- -" -`; - -exports[`overlay should show a warning when "client.overlay.errors" is "true": page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show a warning when "client.overlay.warnings" is "true": overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Warning from compilation -
-
-
-
- -" -`; - -exports[`overlay should show a warning when "client.overlay.warnings" is "true": page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show an ansi formatted error for initial compilation: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- - 18 | - Render - ansi formatted text -
-
-
-
- -" -`; - -exports[`overlay should show an ansi formatted error for initial compilation: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show an error after invalidation: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- Error from compilation -
-
-
-
- -" -`; - -exports[`overlay should show an error after invalidation: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show an error for initial compilation: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- Error from compilation. Can't find 'test' module. -
-
-
-
- -" -`; - -exports[`overlay should show an error for initial compilation: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show an error when "client.overlay" is "true": overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- Error from compilation. Can't find 'test' module. -
-
-
-
- -" -`; - -exports[`overlay should show an error when "client.overlay" is "true": page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show an error when "client.overlay.errors" is "true": overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- Error from compilation. Can't find 'test' module. -
-
-
-
- -" -`; - -exports[`overlay should show an error when "client.overlay.errors" is "true": page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show an error when "client.overlay.warnings" is "true": overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Warning from compilation -
-
-
-
- -" -`; - -exports[`overlay should show an error when "client.overlay.warnings" is "true": page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show error for uncaught promise rejection: overlay html 1`] = ` -" -
-
- Uncaught runtime errors: -
- -
-
-
- ERROR -
-
- Async error at <anonymous>:3:26 -
-
-
-
- -" -`; - -exports[`overlay should show error for uncaught runtime error: overlay html 1`] = ` -" -
-
- Uncaught runtime errors: -
- -
-
-
- ERROR -
-
- Injected error at throwError (<anonymous>:2:15) at - <anonymous>:3:9 at addScriptContent - (__puppeteer_evaluation_script__:9:27) -
-
-
-
- -" -`; - -exports[`overlay should show error when it is not filtered: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- ERROR -
-
- Unfiltered error -
-
-
-
- -" -`; - -exports[`overlay should show error when it is not filtered: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; - -exports[`overlay should show warning when it is not filtered: overlay html 1`] = ` -" -
-
- Compiled with problems: -
- -
-
-
- WARNING -
-
- Unfiltered warning -
-
-
-
- -" -`; - -exports[`overlay should show warning when it is not filtered: page html 1`] = ` -" -

webpack-dev-server is running...

- - - - -" -`; diff --git a/test/e2e/__snapshots__/overlay.test.js.snap.webpack5 b/test/e2e/__snapshots__/overlay.test.js.snap.webpack5 index 11b52c82a1..2a5c43b68d 100644 --- a/test/e2e/__snapshots__/overlay.test.js.snap.webpack5 +++ b/test/e2e/__snapshots__/overlay.test.js.snap.webpack5 @@ -2426,6 +2426,321 @@ exports[`overlay should show error when it is not filtered: page html 1`] = ` " `; +exports[`overlay should show overlay when "Content-Security-Policy" is "default-src 'self'" was used: overlay html 1`] = ` +" +
+
+ Compiled with problems: +
+ +
+
+
+ ERROR +
+
+ Error from compilation. Can't find 'test' module. +
+
+
+
+ +" +`; + +exports[`overlay should show overlay when "Content-Security-Policy" is "default-src 'self'" was used: page html 1`] = ` +" +

webpack-dev-server is running...

+ + + + +" +`; + +exports[`overlay should show overlay when Trusted Types are enabled and the "require-trusted-types-for 'script'" header was used: overlay html 1`] = ` +" +
+
+ Compiled with problems: +
+ +
+
+
+ ERROR +
+
+ Error from compilation. Can't find 'test' module. +
+
+
+
+ +" +`; + +exports[`overlay should show overlay when Trusted Types are enabled and the "require-trusted-types-for 'script'" header was used: page html 1`] = ` +" +

webpack-dev-server is running...

+ + + + +" +`; + +exports[`overlay should show overlay when Trusted Types are enabled: overlay html 1`] = ` +" +
+
+ Compiled with problems: +
+ +
+
+
+ ERROR +
+
+ Error from compilation. Can't find 'test' module. +
+
+
+
+ +" +`; + +exports[`overlay should show overlay when Trusted Types are enabled: page html 1`] = ` +" +

webpack-dev-server is running...

+ + + + +" +`; + exports[`overlay should show warning when it is not filtered: overlay html 1`] = ` "
{ } }); - // TODO fix me https://github.com/webpack/webpack-dev-server/issues/4966 - it.skip("should show overlay when Trusted Types are enabled", async () => { + it("should show overlay when Trusted Types are enabled", async () => { const compiler = webpack(trustedTypesConfig); new ErrorPlugin().apply(compiler); @@ -1270,6 +1269,83 @@ describe("overlay", () => { const { page, browser } = await runBrowser(); try { + const consoleMessages = []; + + page.on("console", (message) => { + consoleMessages.push(message.text()); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0", + }); + + // Delay for the overlay to appear + await delay(1000); + + const pageHtml = await page.evaluate(() => document.body.outerHTML); + const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); + const overlayFrame = await overlayHandle.contentFrame(); + const overlayHtml = await overlayFrame.evaluate( + () => document.body.outerHTML, + ); + + expect( + consoleMessages.filter((item) => + /requires 'TrustedHTML' assignment/.test(item), + ), + ).toHaveLength(0); + expect( + await prettier.format(pageHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS], + }), + ).toMatchSnapshot("page html"); + expect( + await prettier.format(overlayHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS], + }), + ).toMatchSnapshot("overlay html"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should show overlay when Trusted Types are enabled and the \"require-trusted-types-for 'script'\" header was used", async () => { + const compiler = webpack(trustedTypesConfig); + + new ErrorPlugin().apply(compiler); + + const devServerOptions = { + port, + headers: [ + { + key: "Content-Security-Policy", + value: "require-trusted-types-for 'script'", + }, + ], + client: { + overlay: { + trustedTypesPolicyName: "webpack#dev-overlay", + }, + }, + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", (message) => { + consoleMessages.push(message.text()); + }); + await page.goto(`http://localhost:${port}/`, { waitUntil: "networkidle0", }); @@ -1284,6 +1360,15 @@ describe("overlay", () => { () => document.body.outerHTML, ); + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0", + }); + + expect( + consoleMessages.filter((item) => + /requires 'TrustedHTML' assignment/.test(item), + ), + ).toHaveLength(0); expect( await prettier.format(pageHtml, { parser: "html", @@ -1844,4 +1929,65 @@ describe("overlay", () => { await server.stop(); } }); + + it('should show overlay when "Content-Security-Policy" is "default-src \'self\'" was used', async () => { + const compiler = webpack({ ...config, devtool: false }); + + new ErrorPlugin().apply(compiler); + + const devServerOptions = { + port, + headers: [ + { + key: "Content-Security-Policy", + value: "default-src 'self'", + }, + ], + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", (message) => { + consoleMessages.push(message.text()); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0", + }); + + // Delay for the overlay to appear + await delay(1000); + + const pageHtml = await page.evaluate(() => document.body.outerHTML); + const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); + const overlayFrame = await overlayHandle.contentFrame(); + const overlayHtml = await overlayFrame.evaluate( + () => document.body.outerHTML, + ); + + expect( + await prettier.format(pageHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS], + }), + ).toMatchSnapshot("page html"); + expect( + await prettier.format(overlayHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS], + }), + ).toMatchSnapshot("overlay html"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); });