test_NodeCache.js (8834B)
1 const { NodeCache } = ChromeUtils.importESModule( 2 "chrome://remote/content/shared/webdriver/NodeCache.sys.mjs" 3 ); 4 5 function setupTest() { 6 const browser = Services.appShell.createWindowlessBrowser(false); 7 8 browser.document.body.innerHTML = ` 9 <div id="foo" style="margin: 50px"> 10 <iframe></iframe> 11 <video></video> 12 <svg xmlns="http://www.w3.org/2000/svg"></svg> 13 <textarea></textarea> 14 </div> 15 <div id="with-comment"><!-- Comment --></div> 16 `; 17 18 const divEl = browser.document.querySelector("div"); 19 const svgEl = browser.document.querySelector("svg"); 20 const textareaEl = browser.document.querySelector("textarea"); 21 const videoEl = browser.document.querySelector("video"); 22 23 const iframeEl = browser.document.querySelector("iframe"); 24 const childEl = iframeEl.contentDocument.createElement("div"); 25 iframeEl.contentDocument.body.appendChild(childEl); 26 27 const shadowRoot = videoEl.openOrClosedShadowRoot; 28 29 return { 30 browser, 31 nodeCache: new NodeCache(), 32 childEl, 33 divEl, 34 iframeEl, 35 shadowRoot, 36 seenNodeIds: new Map(), 37 svgEl, 38 textareaEl, 39 videoEl, 40 }; 41 } 42 43 add_task(function getOrCreateNodeReference_invalid() { 44 const { nodeCache, seenNodeIds } = setupTest(); 45 46 const invalidValues = [null, undefined, "foo", 42, true, [], {}]; 47 48 for (const value of invalidValues) { 49 info(`Testing value: ${value}`); 50 Assert.throws( 51 () => nodeCache.getOrCreateNodeReference(value, seenNodeIds), 52 /TypeError/ 53 ); 54 } 55 }); 56 57 add_task(function getOrCreateNodeReference_supportedNodeTypes() { 58 const { browser, divEl, nodeCache, seenNodeIds } = setupTest(); 59 60 // Bug 1820734: No ownerGlobal is available in XPCShell tests 61 // const xmlDocument = new DOMParser().parseFromString( 62 // "<xml></xml>", 63 // "application/xml" 64 // ); 65 66 const values = [ 67 { node: divEl, type: Node.ELEMENT_NODE }, 68 { node: divEl.attributes[0], type: Node.ATTRIBUTE_NODE }, 69 { node: browser.document.createTextNode("foo"), type: Node.TEXT_NODE }, 70 // Bug 1820734: No ownerGlobal is available in XPCShell tests 71 // { 72 // node: xmlDocument.createCDATASection("foo"), 73 // type: Node.CDATA_SECTION_NODE, 74 // }, 75 { 76 node: browser.document.createProcessingInstruction( 77 "xml-stylesheet", 78 "href='foo.css'" 79 ), 80 type: Node.PROCESSING_INSTRUCTION_NODE_NODE, 81 }, 82 { node: browser.document.createComment("foo"), type: Node.COMMENT_NODE }, 83 { node: browser.document, type: Node.Document_NODE }, 84 { 85 node: browser.document.implementation.createDocumentType( 86 "foo", 87 "bar", 88 "dtd" 89 ), 90 type: Node.DOCUMENT_TYPE_NODE_NODE, 91 }, 92 { 93 node: browser.document.createDocumentFragment(), 94 type: Node.DOCUMENT_FRAGMENT_NODE, 95 }, 96 ]; 97 98 values.forEach((value, index) => { 99 info(`Testing value: ${value.type}`); 100 const nodeRef = nodeCache.getOrCreateNodeReference(value.node, seenNodeIds); 101 equal(nodeCache.size, index + 1); 102 equal(typeof nodeRef, "string"); 103 ok(seenNodeIds.get(browser.browsingContext).includes(nodeRef)); 104 }); 105 }); 106 107 add_task(function getOrCreateNodeReference_referenceAlreadyCreated() { 108 const { browser, divEl, nodeCache, seenNodeIds } = setupTest(); 109 110 const divElRef = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 111 const divElRefOther = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 112 113 equal(divElRefOther, divElRef); 114 equal(nodeCache.size, 1); 115 equal(seenNodeIds.size, 1); 116 ok(seenNodeIds.get(browser.browsingContext).includes(divElRef)); 117 }); 118 119 add_task(function getOrCreateNodeReference_differentReference() { 120 const { browser, divEl, nodeCache, seenNodeIds, shadowRoot } = setupTest(); 121 122 const divElRef = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 123 equal(nodeCache.size, 1); 124 equal(seenNodeIds.size, 1); 125 ok(seenNodeIds.get(browser.browsingContext).includes(divElRef)); 126 127 const shadowRootRef = nodeCache.getOrCreateNodeReference( 128 shadowRoot, 129 seenNodeIds 130 ); 131 equal(nodeCache.size, 2); 132 equal(seenNodeIds.size, 1); 133 ok(seenNodeIds.get(browser.browsingContext).includes(divElRef)); 134 ok(seenNodeIds.get(browser.browsingContext).includes(shadowRootRef)); 135 136 notEqual(divElRef, shadowRootRef); 137 }); 138 139 add_task(function getOrCreateNodeReference_differentReferencePerNodeCache() { 140 const { browser, divEl, nodeCache, seenNodeIds } = setupTest(); 141 const nodeCache2 = new NodeCache(); 142 143 const divElRef1 = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 144 const divElRef2 = nodeCache2.getOrCreateNodeReference(divEl, seenNodeIds); 145 146 notEqual(divElRef1, divElRef2); 147 equal( 148 nodeCache.getNode(browser.browsingContext, divElRef1), 149 nodeCache2.getNode(browser.browsingContext, divElRef2) 150 ); 151 152 equal(seenNodeIds.size, 1); 153 ok(seenNodeIds.get(browser.browsingContext).includes(divElRef1)); 154 ok(seenNodeIds.get(browser.browsingContext).includes(divElRef2)); 155 156 equal(nodeCache.getNode(browser.browsingContext, divElRef2), null); 157 }); 158 159 add_task(function clear() { 160 const { browser, divEl, nodeCache, seenNodeIds, svgEl } = setupTest(); 161 162 nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 163 nodeCache.getOrCreateNodeReference(svgEl, seenNodeIds); 164 equal(nodeCache.size, 2); 165 equal(seenNodeIds.size, 1); 166 167 // Clear requires explicit arguments. 168 Assert.throws(() => nodeCache.clear(), /Error/); 169 170 // Clear references for a different browsing context 171 const browser2 = Services.appShell.createWindowlessBrowser(false); 172 const imgEl = browser2.document.createElement("img"); 173 const imgElRef = nodeCache.getOrCreateNodeReference(imgEl, seenNodeIds); 174 equal(nodeCache.size, 3); 175 equal(seenNodeIds.size, 2); 176 177 nodeCache.clear({ browsingContext: browser.browsingContext }); 178 equal(nodeCache.size, 1); 179 equal(nodeCache.getNode(browser2.browsingContext, imgElRef), imgEl); 180 181 // Clear all references 182 nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 183 equal(nodeCache.size, 2); 184 equal(seenNodeIds.size, 2); 185 186 nodeCache.clear({ all: true }); 187 equal(nodeCache.size, 0); 188 }); 189 190 add_task(function getNode_multiple_nodes() { 191 const { browser, divEl, nodeCache, seenNodeIds, svgEl } = setupTest(); 192 193 const divElRef = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 194 const svgElRef = nodeCache.getOrCreateNodeReference(svgEl, seenNodeIds); 195 196 equal(nodeCache.getNode(browser.browsingContext, svgElRef), svgEl); 197 equal(nodeCache.getNode(browser.browsingContext, divElRef), divEl); 198 }); 199 200 add_task(function getNode_differentBrowsingContextInSameGroup() { 201 const { iframeEl, divEl, nodeCache, seenNodeIds } = setupTest(); 202 203 const divElRef = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 204 equal(nodeCache.size, 1); 205 206 equal( 207 nodeCache.getNode(iframeEl.contentWindow.browsingContext, divElRef), 208 divEl 209 ); 210 }); 211 212 add_task(function getNode_differentBrowsingContextInOtherGroup() { 213 const { divEl, nodeCache, seenNodeIds } = setupTest(); 214 215 const divElRef = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 216 equal(nodeCache.size, 1); 217 218 const browser2 = Services.appShell.createWindowlessBrowser(false); 219 equal(nodeCache.getNode(browser2.browsingContext, divElRef), null); 220 }); 221 222 add_task(async function getNode_nodeDeleted() { 223 const { browser, nodeCache, seenNodeIds } = setupTest(); 224 let el = browser.document.createElement("div"); 225 226 const elRef = nodeCache.getOrCreateNodeReference(el, seenNodeIds); 227 228 // Delete element and force a garbage collection 229 el = null; 230 231 await doGC(); 232 233 equal(nodeCache.getNode(browser.browsingContext, elRef), null); 234 }); 235 236 add_task(function getNodeDetails_forTopBrowsingContext() { 237 const { browser, divEl, nodeCache, seenNodeIds } = setupTest(); 238 239 const divElRef = nodeCache.getOrCreateNodeReference(divEl, seenNodeIds); 240 241 const nodeDetails = nodeCache.getReferenceDetails(divElRef); 242 equal(nodeDetails.browserId, browser.browsingContext.browserId); 243 equal(nodeDetails.browsingContextGroupId, browser.browsingContext.group.id); 244 equal(nodeDetails.browsingContextId, browser.browsingContext.id); 245 ok(nodeDetails.isTopBrowsingContext); 246 ok(nodeDetails.nodeWeakRef); 247 equal(nodeDetails.nodeWeakRef.get(), divEl); 248 }); 249 250 add_task(async function getNodeDetails_forChildBrowsingContext() { 251 const { browser, iframeEl, childEl, nodeCache, seenNodeIds } = setupTest(); 252 253 const childElRef = nodeCache.getOrCreateNodeReference(childEl, seenNodeIds); 254 255 const nodeDetails = nodeCache.getReferenceDetails(childElRef); 256 equal(nodeDetails.browserId, browser.browsingContext.browserId); 257 equal(nodeDetails.browsingContextGroupId, browser.browsingContext.group.id); 258 equal( 259 nodeDetails.browsingContextId, 260 iframeEl.contentWindow.browsingContext.id 261 ); 262 ok(!nodeDetails.isTopBrowsingContext); 263 ok(nodeDetails.nodeWeakRef); 264 equal(nodeDetails.nodeWeakRef.get(), childEl); 265 });