From bde209bbbad4f5cc0f15a9688558f076fd070a85 Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Tue, 6 Aug 2024 15:40:45 +0200 Subject: [PATCH] fix(client): parse learner code with DOMParser (#55763) --- .../Challenges/rechallenge/transformers.js | 41 ++++--------------- curriculum/test/test-challenges.js | 1 + 2 files changed, 10 insertions(+), 32 deletions(-) diff --git a/client/src/templates/Challenges/rechallenge/transformers.js b/client/src/templates/Challenges/rechallenge/transformers.js index 55b4e2356a3..76a448cff18 100644 --- a/client/src/templates/Challenges/rechallenge/transformers.js +++ b/client/src/templates/Challenges/rechallenge/transformers.js @@ -213,13 +213,11 @@ export const embedFilesInHtml = async function (challengeFiles) { script.removeAttribute('src'); script.setAttribute('data-src', 'script.js'); } - return { - contents: documentElement.innerHTML - }; + return documentElement.innerHTML; }; if (indexHtml) { - const { contents } = await transformWithFrame( + const contents = await parseAndTransform( embedStylesAndScript, indexHtml.contents ); @@ -243,32 +241,11 @@ function challengeFilesToObject(challengeFiles) { return { indexHtml, indexJsx, stylesCss, scriptJs }; } -const transformWithFrame = async function (transform, contents) { - // we use iframe here since file.contents is destined to be be inserted into - // the root of an iframe. - const frame = document.createElement('iframe'); - frame.style = 'display: none'; - let out = { contents }; - try { - // the frame needs to be inserted into the document to create the html - // element - document.body.appendChild(frame); - // replace the root element with user code - frame.contentDocument.documentElement.innerHTML = contents; - // grab the contents now, in case the transformation fails - out = { contents: frame.contentDocument.documentElement.innerHTML }; - // it's important to pass around the documentElement and NOT the frame - // itself. It appears that the frame's documentElement can get replaced by a - // blank documentElement without the contents. This seems only to happen on - // Firefox. - out = await transform( - frame.contentDocument.documentElement, - frame.contentDocument - ); - } finally { - document.body.removeChild(frame); - } - return out; +const parseAndTransform = async function (transform, contents) { + const parser = new DOMParser(); + const newDoc = parser.parseFromString(contents, 'text/html'); + + return await transform(newDoc.documentElement, newDoc); }; const transformHtml = async function (file) { @@ -277,10 +254,10 @@ const transformHtml = async function (file) { transformSASS(documentElement), transformScript(documentElement) ]); - return { contents: documentElement.innerHTML }; + return documentElement.innerHTML; }; - const { contents } = await transformWithFrame(transform, file.contents); + const contents = await parseAndTransform(transform, file.contents); return transformContents(() => contents, file); }; diff --git a/curriculum/test/test-challenges.js b/curriculum/test/test-challenges.js index ccf2a5f11d7..11a0fcef839 100644 --- a/curriculum/test/test-challenges.js +++ b/curriculum/test/test-challenges.js @@ -77,6 +77,7 @@ const handleRejection = err => { const dom = new jsdom.JSDOM(''); global.document = dom.window.document; +global.DOMParser = dom.window.DOMParser; const oldRunnerFail = Mocha.Runner.prototype.fail; Mocha.Runner.prototype.fail = function (test, err) {