diff options
Diffstat (limited to 'remote/marionette/test/xpcshell/test_json.js')
-rw-r--r-- | remote/marionette/test/xpcshell/test_json.js | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/remote/marionette/test/xpcshell/test_json.js b/remote/marionette/test/xpcshell/test_json.js new file mode 100644 index 0000000000..479e1fe473 --- /dev/null +++ b/remote/marionette/test/xpcshell/test_json.js @@ -0,0 +1,275 @@ +const { json } = ChromeUtils.importESModule( + "chrome://remote/content/marionette/json.sys.mjs" +); +const { NodeCache } = ChromeUtils.importESModule( + "chrome://remote/content/shared/webdriver/NodeCache.sys.mjs" +); +const { ShadowRoot, WebElement, WebReference } = ChromeUtils.importESModule( + "chrome://remote/content/marionette/element.sys.mjs" +); + +function setupTest() { + const browser = Services.appShell.createWindowlessBrowser(false); + const nodeCache = new NodeCache(); + + const htmlEl = browser.document.createElement("video"); + browser.document.body.appendChild(htmlEl); + + const svgEl = browser.document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + browser.document.body.appendChild(svgEl); + + const shadowRoot = htmlEl.openOrClosedShadowRoot; + + const iframeEl = browser.document.createElement("iframe"); + browser.document.body.appendChild(iframeEl); + const childEl = iframeEl.contentDocument.createElement("div"); + + return { browser, nodeCache, childEl, iframeEl, htmlEl, shadowRoot, svgEl }; +} + +add_task(function test_clone_generalTypes() { + const { nodeCache } = setupTest(); + + // null + equal(json.clone(undefined, nodeCache), null); + equal(json.clone(null, nodeCache), null); + + // primitives + equal(json.clone(true, nodeCache), true); + equal(json.clone(42, nodeCache), 42); + equal(json.clone("foo", nodeCache), "foo"); + + // toJSON + equal( + json.clone({ + toJSON() { + return "foo"; + }, + }), + "foo" + ); +}); + +add_task(function test_clone_ShadowRoot() { + const { nodeCache, shadowRoot } = setupTest(); + + const shadowRootRef = nodeCache.getOrCreateNodeReference(shadowRoot); + deepEqual( + json.clone(shadowRoot, nodeCache), + WebReference.from(shadowRoot, shadowRootRef).toJSON() + ); +}); + +add_task(function test_clone_WebElement() { + const { htmlEl, nodeCache, svgEl } = setupTest(); + + const htmlElRef = nodeCache.getOrCreateNodeReference(htmlEl); + deepEqual( + json.clone(htmlEl, nodeCache), + WebReference.from(htmlEl, htmlElRef).toJSON() + ); + + // Check an element with a different namespace + const svgElRef = nodeCache.getOrCreateNodeReference(svgEl); + deepEqual( + json.clone(svgEl, nodeCache), + WebReference.from(svgEl, svgElRef).toJSON() + ); +}); + +add_task(function test_clone_Sequences() { + const { htmlEl, nodeCache } = setupTest(); + + const htmlElRef = nodeCache.getOrCreateNodeReference(htmlEl); + + const input = [ + null, + true, + [], + htmlEl, + { + toJSON() { + return "foo"; + }, + }, + { bar: "baz" }, + ]; + + const actual = json.clone(input, nodeCache); + + equal(actual[0], null); + equal(actual[1], true); + deepEqual(actual[2], []); + deepEqual(actual[3], { [WebElement.Identifier]: htmlElRef }); + equal(actual[4], "foo"); + deepEqual(actual[5], { bar: "baz" }); +}); + +add_task(function test_clone_objects() { + const { htmlEl, nodeCache } = setupTest(); + + const htmlElRef = nodeCache.getOrCreateNodeReference(htmlEl); + + const input = { + null: null, + boolean: true, + array: [42], + element: htmlEl, + toJSON: { + toJSON() { + return "foo"; + }, + }, + object: { bar: "baz" }, + }; + + const actual = json.clone(input, nodeCache); + + equal(actual.null, null); + equal(actual.boolean, true); + deepEqual(actual.array, [42]); + deepEqual(actual.element, { [WebElement.Identifier]: htmlElRef }); + equal(actual.toJSON, "foo"); + deepEqual(actual.object, { bar: "baz" }); +}); + +add_task(function test_clone_ÑyclicReference() { + const { nodeCache } = setupTest(); + + // object + Assert.throws(() => { + const obj = {}; + obj.reference = obj; + json.clone(obj, nodeCache); + }, /JavaScriptError/); + + // array + Assert.throws(() => { + const array = []; + array.push(array); + json.clone(array, nodeCache); + }, /JavaScriptError/); + + // array in object + Assert.throws(() => { + const array = []; + array.push(array); + json.clone({ array }, nodeCache); + }, /JavaScriptError/); + + // object in array + Assert.throws(() => { + const obj = {}; + obj.reference = obj; + json.clone([obj], nodeCache); + }, /JavaScriptError/); +}); + +add_task(function test_deserialize_generalTypes() { + const { browser, nodeCache } = setupTest(); + const win = browser.document.ownerGlobal; + + // null + equal(json.deserialize(undefined, nodeCache, win), undefined); + equal(json.deserialize(null, nodeCache, win), null); + + // primitives + equal(json.deserialize(true, nodeCache, win), true); + equal(json.deserialize(42, nodeCache, win), 42); + equal(json.deserialize("foo", nodeCache, win), "foo"); +}); + +add_task(function test_deserialize_ShadowRoot() { + const { browser, nodeCache, shadowRoot } = setupTest(); + const win = browser.document.ownerGlobal; + + // Fails to resolve for unknown elements + const unknownShadowRootId = { [ShadowRoot.Identifier]: "foo" }; + Assert.throws(() => { + json.deserialize(unknownShadowRootId, nodeCache, win); + }, /NoSuchShadowRootError/); + + const shadowRootRef = nodeCache.getOrCreateNodeReference(shadowRoot); + const shadowRootEl = { [ShadowRoot.Identifier]: shadowRootRef }; + + // Fails to resolve for missing window reference + Assert.throws(() => json.deserialize(shadowRootEl, nodeCache), /TypeError/); + + // Previously seen element is associated with original web element reference + const root = json.deserialize(shadowRootEl, nodeCache, win); + deepEqual(root, shadowRoot); + deepEqual(root, nodeCache.getNode(browser.browsingContext, shadowRootRef)); +}); + +add_task(function test_deserialize_WebElement() { + const { browser, htmlEl, nodeCache } = setupTest(); + const win = browser.document.ownerGlobal; + + // Fails to resolve for unknown elements + const unknownWebElId = { [WebElement.Identifier]: "foo" }; + Assert.throws(() => { + json.deserialize(unknownWebElId, nodeCache, win); + }, /NoSuchElementError/); + + const htmlElRef = nodeCache.getOrCreateNodeReference(htmlEl); + const htmlWebEl = { [WebElement.Identifier]: htmlElRef }; + + // Fails to resolve for missing window reference + Assert.throws(() => json.deserialize(htmlWebEl, nodeCache), /TypeError/); + + // Previously seen element is associated with original web element reference + const el = json.deserialize(htmlWebEl, nodeCache, win); + deepEqual(el, htmlEl); + deepEqual(el, nodeCache.getNode(browser.browsingContext, htmlElRef)); +}); + +add_task(function test_deserialize_Sequences() { + const { browser, htmlEl, nodeCache } = setupTest(); + const win = browser.document.ownerGlobal; + + const htmlElRef = nodeCache.getOrCreateNodeReference(htmlEl); + + const input = [ + null, + true, + [42], + { [WebElement.Identifier]: htmlElRef }, + { bar: "baz" }, + ]; + + const actual = json.deserialize(input, nodeCache, win); + + equal(actual[0], null); + equal(actual[1], true); + deepEqual(actual[2], [42]); + deepEqual(actual[3], htmlEl); + deepEqual(actual[4], { bar: "baz" }); +}); + +add_task(function test_deserialize_objects() { + const { browser, htmlEl, nodeCache } = setupTest(); + const win = browser.document.ownerGlobal; + + const htmlElRef = nodeCache.getOrCreateNodeReference(htmlEl); + + const input = { + null: null, + boolean: true, + array: [42], + element: { [WebElement.Identifier]: htmlElRef }, + object: { bar: "baz" }, + }; + + const actual = json.deserialize(input, nodeCache, win); + + equal(actual.null, null); + equal(actual.boolean, true); + deepEqual(actual.array, [42]); + deepEqual(actual.element, htmlEl); + deepEqual(actual.object, { bar: "baz" }); + + nodeCache.clear({ all: true }); +}); |