adobe/helix-shared

dom#equalizeNode fails to process textarea / input combo

kptdobe opened this issue · 10 comments

Failing test: https://app.circleci.com/pipelines/github/adobe/helix-publish/2472/workflows/20a43bdb-d537-4d61-a65d-8d10a5a6b2fb/jobs/3991

I could isolate the piece of the DOM causes the issue:

<form>
        <textarea id="rating-comments" name="rating-comments"></textarea>
        <input type="submit" value="Send">
    </form>

Performing the dom#equalizeNode method on that node throws the following exception:

TypeError: Cannot read property 'insertAdjacentHTML' of undefined
      at /Users/acapt/work/dev/helix/helix-shared/src/dom.js:303:17
      at /Users/acapt/work/dev/helix/helix-shared/node_modules/ferrum/src/sequence.js:604:5
      at each [CURRY] (node_modules/ferrum/src/functional.js:175:12)
      at collapseTextAcrossInlineNodes (src/dom.js:244:5)
      at Function.equalizeNode.impl (src/dom.js:392:5)
      at /Users/acapt/work/dev/helix/helix-shared/src/dom.js:364:20
      at /Users/acapt/work/dev/helix/helix-shared/node_modules/ferrum/src/sequence.js:604:5
      at each [CURRY] (node_modules/ferrum/src/functional.js:175:12)
      at Function.equalizeNode.impl (src/dom.js:357:3)
      at /Users/acapt/work/dev/helix/helix-shared/src/dom.js:364:20
      at /Users/acapt/work/dev/helix/helix-shared/node_modules/ferrum/src/sequence.js:604:5
      at each [CURRY] (node_modules/ferrum/src/functional.js:175:12)
      at Function.equalizeNode.impl (src/dom.js:357:3)
      at equalizeNode (src/dom.js:180:45)
      at Function.equalizeNode.impl (src/dom.js:207:12)
      at equalizeNode (src/dom.js:180:45)
      at Context.<anonymous> (test/dom.test.js:93:9)
      at processImmediate (internal/timers.js:439:21)

In the case of the failing test, the entry point is dom#dumpDOM method which catch the exception but does not expose it. Even worst, it continues to execute while one of the node (nodeA or nodeB) has been partially processed already:

https://github.com/adobe/helix-shared/blob/main/src/dom.js#L687-L693

#413 contains now the test that reveals the issue.

Wow, great find!

koraa commented

I think it's unlikely that this is caused by the input being non-closed. equalizeNode operates on the dom tree and both alternate forms (, ) normalize to during the dom parsing stage.

insertAdjacentHTML is not defined on all nodes, only elements, so I suspect this is caused by after in line 303 being a text node instead of an element…how this happens is unclear.

What sort of browser environment are the tests executed in?

koraa commented

I am kind of proud it took so long for this function to have a bug…this is complex as heck…
This bug is part of the cross element space normalization feature of the normalizer (cases like <b>foo <b>bar turning into <b>foo</b> bar.

It might be possible to fix this by adding an if statement testing whether after is a text node and changing the text node directly instead of adding a space directly to the dom node…however I don't think this situation was ever intended so I'll have to wrap my brain around this for a while…

koraa commented

What does the test fail with? The exception?

I am not sure the test is entirely correct; it discards whitespaces instead of collapsing them…the normalizer explicitly handles whitespace between elements…

koraa commented

New minimal example:

<span style="white-space: pre"></span>`,

The issue has nothing to do with form elements; it just happens to be about the handling of elements that are both inline (like span) and use <pre> style rendering. display: inline; white-space: pre in CSS terms.

This is handled as a special case because a <pre> </pre> b must collapse to a <pre> </pre> b not a<pre> </pre>b. This is a special case and must be handled as such.

I will add a selection of tests covering elements that are both inline and pre.

koraa commented

There's a fix in the branch :)

Thanks @koraa !
Even if the root cause is not the form element, the form element fired an exception, I would still keep it as a test case to make sure the test is correct. The test output can be adjusted, I could never validate the output since it failed before.

koraa commented

Sure! Feel free to re-add the test; optimally with a pointer to the issue so people know it's a regression test!

🎉 This issue has been resolved in version 7.19.1 🎉

The release is available on:

Your semantic-release bot 📦🚀