diff --git a/.changeset/empty-cooks-roll.md b/.changeset/empty-cooks-roll.md new file mode 100644 index 00000000..7cf40937 --- /dev/null +++ b/.changeset/empty-cooks-roll.md @@ -0,0 +1,7 @@ +--- +'pleasantest': patch +--- + +[bugfix] Don't override `` when using `utils.injectHTML` + +This was a bug introduced in `3.0.0`. This change fixes that behavior to match what is documented. The documented behavior is that `injectHTML` replaces the content of the body _only_. The behavior introduced in `3.0.0` also resets the `` to the default; that was unintended behavior that is now removed. diff --git a/src/index.ts b/src/index.ts index fe26fdcd..a4b6dbcb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,6 @@ import { createBuildStatusTracker } from './module-server/build-status-tracker.j import { cleanupClientRuntimeServer } from './module-server/client-runtime-server.js'; import type { ModuleServerOpts } from './module-server/index.js'; import { createModuleServer } from './module-server/index.js'; -import { defaultHTML } from './module-server/middleware/index-html.js'; import type { BoundQueries, WaitForOptions } from './pptr-testing-library.js'; import { getQueriesForElement, @@ -417,15 +416,23 @@ const createTab = async ({ () => page.evaluate( (html, executeScriptTags) => { + document.body.innerHTML = html; if (executeScriptTags) { - document.open(); - document.write(html); - document.close(); - } else { - document.documentElement.innerHTML = html; + // Scripts injected with innerHTML are not executed by default; + // To get the browser to execute them we must manually create the script tags + // and replace them + const scripts = document.body.querySelectorAll('script'); + for (const script of scripts) { + const newScript = document.createElement('script'); + newScript.text = script.innerHTML; + for (const attribute of script.attributes) { + newScript.setAttribute(attribute.name, attribute.value); + } + script.replaceWith(newScript); + } } }, - defaultHTML(html), + html, executeScriptTags, ), injectHTML, diff --git a/tests/utils/injectHTML.test.ts b/tests/utils/injectHTML.test.ts index a31f6f74..fde4e998 100644 --- a/tests/utils/injectHTML.test.ts +++ b/tests/utils/injectHTML.test.ts @@ -3,14 +3,31 @@ import { withBrowser } from 'pleasantest'; test( 'injectHTML', withBrowser(async ({ utils, page }) => { - const getHTML = () => page.evaluate(() => document.body.innerHTML.trim()); + const getHTML = () => + page.evaluate(() => document.documentElement.innerHTML.trim()); await utils.injectHTML('
Hi
'); - expect(await getHTML()).toEqual('
Hi
'); + expect(await getHTML()).toMatchInlineSnapshot(` + " + + + + pleasantest + +
Hi
" + `); // It should fully override existing content await utils.injectHTML('
Hiya
'); - expect(await getHTML()).toEqual('
Hiya
'); + expect(await getHTML()).toMatchInlineSnapshot(` + " + + + + pleasantest + +
Hiya
" + `); // Executes scripts by default await utils.injectHTML(` @@ -18,21 +35,76 @@ test( `); expect(await getHTML()).toMatchInlineSnapshot(` - "
changed
- " + " + + + + pleasantest + + +
changed
+ + " `); // Can pass option to not execute await utils.injectHTML( `
hello
- + `, { executeScriptTags: false }, ); expect(await getHTML()).toMatchInlineSnapshot(` - "
hello
- " + " + + + + pleasantest + + +
hello
+ + " + `); + + // Stuff in should be left as-is and not re-executed after injectHTML is called again below + await page.evaluate(() => { + const script = document.createElement('script'); + script.text = + 'document.body.querySelector("div").innerHTML = "changed from script in head"'; + document.head.append(script); + }); + + expect(await getHTML()).toMatchInlineSnapshot(` + " + + + + pleasantest + + +
changed from script in head
+ + " + `); + + await utils.injectHTML( + ` +
injected HTML
+ `, + ); + + expect(await getHTML()).toMatchInlineSnapshot(` + " + + + + pleasantest + + +
injected HTML
+ " `); }), );