From 7f66ee86ceca3f97a31578385a6dd11b969f8e12 Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Thu, 31 Aug 2017 15:02:20 +0200 Subject: [PATCH] fix: Ignore shadowRoots on elements that don't allow them --- lib/checks/.DS_Store | Bin 0 -> 8196 bytes lib/core/utils/flattened-tree.js | 18 ++++++++++-- test/core/utils/flattened-tree.js | 46 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 lib/checks/.DS_Store diff --git a/lib/checks/.DS_Store b/lib/checks/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6a583cd791c947cc0fa884746b4e83e310416d9d GIT binary patch literal 8196 zcmeHMTWl0n7(QPqFl(nUKr3aT*##mHX=JNVE=JhixDy(7X$utB*_}ffna(sjvs<8& z)EF-$28|joPlgyT0UwM)d@y*wfW`+6Mj`PDFENq$Ii`dftwNm@qS3sC1g63BTC9w2URi!ASqG+ zS?Hef0O^wqWjd52N=jFXsj>%zt_V{MD0k8)g*nM|C`Xi3?hMMEAsiWDh5|V{`6Z<} zLt4qGju40t7>|J1J{ofN=p(Q9jJ z4ZWteW^ZP{Hk2E4dO7-v1tAp>=9 z=DTe^lr!quJvT6ImltI`6{D}mb}etH%`3T<-*Ynq{jTtj%)#>_fdNgie@3VPv=a6{DyG*~pUCVa+d&=TDI6Ui`1AGRWVlnB}Fek3} zSv1@>&k}x?aavQF#yRo$9-(P3a;hy&lMeG2#PzICOEt{UaM5C2&mJH$7=9RZX_Fq` z>6m%$7*(Z?>rHR(HOZc=}mYArvaFhxQ(@R3Q3~_=rvPEnaomg46k9q7t_BeZyonmL$yX+kM zntjhMvCHgt_6Pfu{l)%?!Ypnuo`QTMl0H|1zp&I46@jZ0yy@eAA>lE z!x+W`co@g<1fIkTcnv3T60hSl-oYpM65rxGT);(K!mqfjrdBmd;7y~mRuaFF9Jlw0 zz=I)yk5(pdV#CG_^?LgaPv8sF6m9Eooh^C1dTrYkGK^us)jX8sQ|ywg8)cOw_BB*K zPvo9EuTf9zBy#eD6EVk_Dz<|rt>-UDBn(XwPB<@GOwB6V5=y(YDWMyaB=LooIGr#i zONxu;iWXfrs^umS%{6zEc8cV>Xs&A{Eu#%08tscI5a_j5fvEpV)34Y?_KTn>7$&0@ zGm*d&BIj}<=6Y--T5iQQbfXu$u?Kxb%zoIo9|sViO!PcN1bv9;`6wR4Q9Olb@GPFg z^Ei%|@G@S(t9S!%;w_xQ8N7%0@c}->7dStLsGG+S^_xmWEoX|ZK`(GPf7p) literal 0 HcmV?d00001 diff --git a/lib/core/utils/flattened-tree.js b/lib/core/utils/flattened-tree.js index 0c5189f325..ec618bbcb1 100644 --- a/lib/core/utils/flattened-tree.js +++ b/lib/core/utils/flattened-tree.js @@ -51,6 +51,20 @@ function getSlotChildren(node) { return retVal; } +const possibleShadowRoots = ['article', 'aside', 'blockquote', + 'body', 'div', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'header', 'main', 'nav', 'p', 'section', 'span']; +axe.utils.isShadowRoot = function isShadowRoot (node) { + const nodeName = node.nodeName.toLowerCase(); + if (node.shadowRoot) { + if (/^[a-z][a-z0-9_.-]*-[a-z0-9_.-]*$/.test(nodeName) || + possibleShadowRoots.includes(nodeName)) { + return true; + } + } + return false; +}; + /** * Recursvely returns an array of the virtual DOM nodes at this level * excluding comment nodes and the shadow DOM nodes and @@ -75,8 +89,8 @@ axe.utils.getFlattenedTree = function (node, shadowId) { node = node.documentElement; } nodeName = node.nodeName.toLowerCase(); - // for some reason Chrome's marquee element has an open shadow DOM - if (node.shadowRoot && nodeName !== 'marquee') { + + if (axe.utils.isShadowRoot(node)) { // generate an ID for this shadow root and overwrite the current // closure shadowId with this value so that it cascades down the tree retVal = virtualDOMfromNode(node, shadowId); diff --git a/test/core/utils/flattened-tree.js b/test/core/utils/flattened-tree.js index 279a4af8a6..4d29057588 100644 --- a/test/core/utils/flattened-tree.js +++ b/test/core/utils/flattened-tree.js @@ -66,6 +66,32 @@ function shadowIdAssertions () { } +describe('isShadowRoot', function () { + 'use strict'; + var isShadowRoot = axe.utils.isShadowRoot; + + it('returns false if the node has no shadowRoot', function () { + assert.isFalse(isShadowRoot({ nodeName: 'DIV', shadowRoot: undefined })); + }); + it('returns true if the native element allows shadow DOM', function () { + assert.isTrue(isShadowRoot({ nodeName: 'DIV', shadowRoot: {} })); + assert.isTrue(isShadowRoot({ nodeName: 'H1', shadowRoot: {} })); + assert.isTrue(isShadowRoot({ nodeName: 'ASIDE', shadowRoot: {} })); + }); + it('returns true if a custom element with shadowRoot', function () { + assert.isTrue(isShadowRoot({ nodeName: 'X-BUTTON', shadowRoot: {} })); + assert.isTrue(isShadowRoot({ nodeName: 'T1000-SCHWARZENEGGER', shadowRoot: {} })); + }); + it('returns true if an invalid custom element with shadowRoot', function () { + assert.isFalse(isShadowRoot({ nodeName: '0-BUZZ', shadowRoot: {} })); + assert.isFalse(isShadowRoot({ nodeName: '--ELM--', shadowRoot: {} })); + }); + it('returns false if the native element does not allow shadow DOM', function () { + assert.isFalse(isShadowRoot({ nodeName: 'IFRAME', shadowRoot: {} })); + assert.isFalse(isShadowRoot({ nodeName: 'STRONG', shadowRoot: {} })); + }); +}); + if (shadowSupport.v0) { describe('flattened-tree shadow DOM v0', function () { 'use strict'; @@ -154,6 +180,26 @@ if (shadowSupport.v1) { assert.isTrue(virtualDOM[0].children[2].children[1].children[0].children[0].actualNode.textContent === 'fallback content'); assert.isTrue(virtualDOM[0].children[2].children[1].children[0].children[1].actualNode.nodeName === 'LI'); }); + it('calls isShadowRoot to identify a shadow root', function () { + var isShadowRoot = axe.utils.isShadowRoot; + fixture.innerHTML = '
'; + var div = fixture.querySelector('div'); + var shadowRoot = div.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = '

Just a man in the back

'; + + // Test without isShqdowRoot overwritten + assert.equal(axe.utils.getFlattenedTree(div)[0].children.length, 1); + + var called = false; + axe.utils.isShadowRoot = function () { + called = true; + return false; + }; + // Test with isShadowRoot overwritten + assert.equal(axe.utils.getFlattenedTree(div)[0].children.length, 0); + assert.isTrue(called); + axe.utils.isShadowRoot = isShadowRoot; + }); }); describe('flattened-tree shadow DOM v1: boxed slots', function () { 'use strict';