From f065ad2b7c94aa95f9e3d5b5dc6fcb73e0c74a58 Mon Sep 17 00:00:00 2001 From: Nicolas Chevobbe Date: Tue, 1 Aug 2017 16:27:00 +0200 Subject: [PATCH] Bug 1380709 - Add mochitests and mocha tests to ensure entries are loaded as expected. r=bgrins This adds several tests to make sure we can expand Sets and Maps entries, and that we manage those properties in the store as expected. We also add a stub for a Set object and take this as an opportunity to fix the stub name. MozReview-Commit-ID: ChhIHKMPINF --HG-- extra : rebase_source : 5aba016c0a231032dc411aa4bd01d059e07ebd79 --- .../fixtures/stub-generators/stub-snippets.js | 10 +- .../test/fixtures/stubs/consoleApi.js | 98 +++++++++- .../test/mochitest/browser.ini | 1 + ...ser_webconsole_object_inspector_entries.js | 185 ++++++++++++++++++ .../test/store/messages.test.js | 97 +++++++++ .../test/store/release-actors.test.js | 10 +- .../test/store/search.test.js | 2 +- 7 files changed, 392 insertions(+), 11 deletions(-) create mode 100644 devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector_entries.js diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js index 4ae99b034586..1be66e6c5be3 100644 --- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js +++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js @@ -27,8 +27,8 @@ const consoleApiCommands = [ let consoleApi = new Map(consoleApiCommands.map( cmd => [cmd, {keys: [cmd], code: cmd}])); -consoleApi.set("console.map('mymap')", { - keys: ["console.map('mymap')"], +consoleApi.set("console.log('mymap')", { + keys: ["console.log('mymap')"], code: ` var map = new Map(); map.set("key1", "value1"); @@ -36,6 +36,12 @@ map.set("key2", "value2"); console.log('mymap', map); `}); +consoleApi.set("console.log('myset')", { + keys: ["console.log('myset')"], + code: ` +console.log('myset', new Set(["a", "b"])); +`}); + consoleApi.set("console.trace()", { keys: ["console.trace()"], code: ` diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js index acc05162063b..1066ad9b86a2 100644 --- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js +++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js @@ -558,11 +558,11 @@ stubPreparedMessages.set("console.log('myobject', {red: 'redValue', green: 'gree "indent": 0 })); -stubPreparedMessages.set("console.map('mymap')", new ConsoleMessage({ +stubPreparedMessages.set("console.log('mymap')", new ConsoleMessage({ "id": "1", "allowRepeating": true, "source": "console-api", - "timeStamp": 1493125410207, + "timeStamp": 1501506737042, "type": "log", "helperType": null, "level": "log", @@ -571,7 +571,7 @@ stubPreparedMessages.set("console.map('mymap')", new ConsoleMessage({ "mymap", { "type": "object", - "actor": "server1.conn0.child1/obj36", + "actor": "server1.conn0.child1/obj37", "class": "Map", "extensible": true, "frozen": false, @@ -593,7 +593,7 @@ stubPreparedMessages.set("console.map('mymap')", new ConsoleMessage({ } } ], - "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"mymap\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj36\",\"class\":\"Map\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"kind\":\"MapLike\",\"size\":2,\"entries\":[[\"key1\",\"value1\"],[\"key2\",\"value2\"]]}}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}", + "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"mymap\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj37\",\"class\":\"Map\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"kind\":\"MapLike\",\"size\":2,\"entries\":[[\"key1\",\"value1\"],[\"key2\",\"value2\"]]}}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html", @@ -607,6 +607,49 @@ stubPreparedMessages.set("console.map('mymap')", new ConsoleMessage({ "indent": 0 })); +stubPreparedMessages.set("console.log('myset')", new ConsoleMessage({ + "id": "1", + "allowRepeating": true, + "source": "console-api", + "timeStamp": 1501506737051, + "type": "log", + "helperType": null, + "level": "log", + "messageText": null, + "parameters": [ + "myset", + { + "type": "object", + "actor": "server1.conn0.child1/obj38", + "class": "Set", + "extensible": true, + "frozen": false, + "sealed": false, + "ownPropertyLength": 0, + "preview": { + "kind": "ArrayLike", + "length": 2, + "items": [ + "a", + "b" + ] + } + } + ], + "repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"myset\",{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj38\",\"class\":\"Set\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"kind\":\"ArrayLike\",\"length\":2,\"items\":[\"a\",\"b\"]}}],\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}", + "stacktrace": null, + "frame": { + "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html", + "line": 2, + "column": 1 + }, + "groupId": null, + "exceptionDocURL": null, + "userProvidedStyles": [], + "notes": null, + "indent": 0 +})); + stubPreparedMessages.set("console.trace()", new ConsoleMessage({ "id": "1", "allowRepeating": true, @@ -1689,7 +1732,7 @@ stubPackets.set("console.log('myobject', {red: 'redValue', green: 'greenValue', } }); -stubPackets.set("console.map('mymap')", { +stubPackets.set("console.log('mymap')", { "from": "server1.conn0.child1/consoleActor2", "type": "consoleAPICall", "message": { @@ -1698,7 +1741,7 @@ stubPackets.set("console.map('mymap')", { "mymap", { "type": "object", - "actor": "server1.conn0.child1/obj36", + "actor": "server1.conn0.child1/obj37", "class": "Map", "extensible": true, "frozen": false, @@ -1729,7 +1772,48 @@ stubPackets.set("console.map('mymap')", { "lineNumber": 5, "private": false, "styles": [], - "timeStamp": 1493125410207, + "timeStamp": 1501506737042, + "timer": null, + "workerType": "none", + "category": "webdev" + } +}); + +stubPackets.set("console.log('myset')", { + "from": "server1.conn0.child1/consoleActor2", + "type": "consoleAPICall", + "message": { + "addonId": "", + "arguments": [ + "myset", + { + "type": "object", + "actor": "server1.conn0.child1/obj38", + "class": "Set", + "extensible": true, + "frozen": false, + "sealed": false, + "ownPropertyLength": 0, + "preview": { + "kind": "ArrayLike", + "length": 2, + "items": [ + "a", + "b" + ] + } + } + ], + "columnNumber": 1, + "counter": null, + "filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html", + "functionName": "triggerPacket", + "groupName": "", + "level": "log", + "lineNumber": 2, + "private": false, + "styles": [], + "timeStamp": 1501506737051, "timer": null, "workerType": "none", "category": "webdev" diff --git a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini index 45b618be1ceb..98adfd1af09b 100644 --- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini +++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini @@ -44,6 +44,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 [browser_webconsole_network_messages_click.js] [browser_webconsole_nodes_highlight.js] [browser_webconsole_nodes_select.js] +[browser_webconsole_object_inspector_entries.js] [browser_webconsole_object_inspector.js] [browser_webconsole_observer_notifications.js] [browser_webconsole_shows_reqs_in_netmonitor.js] diff --git a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector_entries.js b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector_entries.js new file mode 100644 index 000000000000..547ac51c2000 --- /dev/null +++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector_entries.js @@ -0,0 +1,185 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Check expanding/collapsing maps and sets in the console. +const TEST_URI = "data:text/html;charset=utf8,

Object Inspector on Maps & Sets

"; + +add_task(async function () { + const hud = await openNewTabAndConsole(TEST_URI); + const store = hud.ui.newConsoleOutput.getStore(); + // Adding logging each time the store is modified in order to check + // the store state in case of failure. + store.subscribe(() => { + const messages = store.getState().messages.messagesById + .reduce(function (res, {id, type, parameters, messageText}) { + res.push({id, type, parameters, messageText}); + return res; + }, []); + info("messages : " + JSON.stringify(messages)); + }); + + await ContentTask.spawn(gBrowser.selectedBrowser, null, function () { + content.wrappedJSObject.console.log( + "oi-entries-test", + new Map( + Array.from({length: 20}).map((el, i) => [Symbol(i), i]) + ), + new Map( + Array.from({length: 331}).map((el, i) => [Symbol(i), i]) + ), + new Set(Array.from({length: 20}).map((el, i) => i)), + new Set(Array.from({length: 222}).map((el, i) => i)), + ); + }); + + let node = await waitFor(() => findMessage(hud, "oi-entries-test")); + const objectInspectors = [...node.querySelectorAll(".tree")]; + is(objectInspectors.length, 4, "There is the expected number of object inspectors"); + + const [ + mapOi, + largeMapOi, + setOi, + largeSetOi, + ] = objectInspectors; + + await testMap(mapOi); + await testLargeMap(largeMapOi); + await testSet(setOi); + await testLargeSet(largeSetOi); +}); + +async function testMap(oi) { + info("Expanding the Map"); + let onMapOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + oi.querySelector(".arrow").click(); + await onMapOiMutation; + + ok(oi.querySelector(".arrow").classList.contains("expanded"), + "The arrow of the node has the expected class after clicking on it"); + + let oiNodes = oi.querySelectorAll(".node"); + // There are 4 nodes: the root, size, entries and the proto. + is(oiNodes.length, 4, "There is the expected number of nodes in the tree"); + + info("Expanding the leaf of the map"); + let entriesNode = oiNodes[2]; + is(entriesNode.textContent, "", "There is the expected node"); + onMapOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + entriesNode.querySelector(".arrow").click(); + await onMapOiMutation; + + oiNodes = oi.querySelectorAll(".node"); + // There are now 24 nodes, the 4 original ones, and the 20 entries. + is(oiNodes.length, 24, "There is the expected number of nodes in the tree"); +} + +async function testLargeMap(oi) { + info("Expanding the large map"); + let onMapOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + oi.querySelector(".arrow").click(); + await onMapOiMutation; + + ok(oi.querySelector(".arrow").classList.contains("expanded"), + "The arrow of the node has the expected class after clicking on it"); + + let oiNodes = oi.querySelectorAll(".node"); + // There are 4 nodes: the root, size, entries and the proto. + is(oiNodes.length, 4, "There is the expected number of nodes in the tree"); + + info("Expanding the leaf of the map"); + let entriesNode = oiNodes[2]; + is(entriesNode.textContent, "", "There is the expected node"); + onMapOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + entriesNode.querySelector(".arrow").click(); + await onMapOiMutation; + + oiNodes = oi.querySelectorAll(".node"); + // There are now 8 nodes, the 4 original ones, and the 4 buckets. + is(oiNodes.length, 8, "There is the expected number of nodes in the tree"); + is(oiNodes[3].textContent, "[0..99]"); + is(oiNodes[4].textContent, "[100..199]"); + is(oiNodes[5].textContent, "[200..299]"); + is(oiNodes[6].textContent, "[300..331]"); +} + +async function testSet(oi) { + info("Expanding the Set"); + let onSetOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + oi.querySelector(".arrow").click(); + await onSetOiMutation; + + ok(oi.querySelector(".arrow").classList.contains("expanded"), + "The arrow of the node has the expected class after clicking on it"); + + let oiNodes = oi.querySelectorAll(".node"); + // There are 4 nodes: the root, size, entries and the proto. + is(oiNodes.length, 4, "There is the expected number of nodes in the tree"); + + info("Expanding the leaf of the Set"); + let entriesNode = oiNodes[2]; + is(entriesNode.textContent, "", "There is the expected node"); + onSetOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + entriesNode.querySelector(".arrow").click(); + await onSetOiMutation; + + oiNodes = oi.querySelectorAll(".node"); + // There are now 24 nodes, the 4 original ones, and the 20 entries. + is(oiNodes.length, 24, "There is the expected number of nodes in the tree"); +} + +async function testLargeSet(oi) { + info("Expanding the large Set"); + let onSetOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + oi.querySelector(".arrow").click(); + await onSetOiMutation; + + ok(oi.querySelector(".arrow").classList.contains("expanded"), + "The arrow of the node has the expected class after clicking on it"); + + let oiNodes = oi.querySelectorAll(".node"); + // There are 4 nodes: the root, size, entries and the proto. + is(oiNodes.length, 4, "There is the expected number of nodes in the tree"); + + info("Expanding the leaf of the Set"); + let entriesNode = oiNodes[2]; + is(entriesNode.textContent, "", "There is the expected node"); + onSetOiMutation = waitForNodeMutation(oi, { + childList: true + }); + + entriesNode.querySelector(".arrow").click(); + await onSetOiMutation; + + oiNodes = oi.querySelectorAll(".node"); + // There are now 7 nodes, the 4 original ones, and the 3 buckets. + is(oiNodes.length, 7, "There is the expected number of nodes in the tree"); + is(oiNodes[3].textContent, "[0..99]"); + is(oiNodes[4].textContent, "[100..199]"); + is(oiNodes[5].textContent, "[200..222]"); +} diff --git a/devtools/client/webconsole/new-console-output/test/store/messages.test.js b/devtools/client/webconsole/new-console-output/test/store/messages.test.js index 3a91c3b9348e..fbada115a04c 100644 --- a/devtools/client/webconsole/new-console-output/test/store/messages.test.js +++ b/devtools/client/webconsole/new-console-output/test/store/messages.test.js @@ -12,6 +12,7 @@ const { getCurrentGroup, getVisibleMessages, getAllMessagesObjectPropertiesById, + getAllMessagesObjectEntriesById, } = require("devtools/client/webconsole/new-console-output/selectors/messages"); const { clonePacket, @@ -869,4 +870,100 @@ describe("Message reducer:", () => { expect(getAllMessagesObjectPropertiesById(getState()).size).toBe(0); }); }); + + describe("messagesObjectEntriesById", () => { + it(`adds messagesObjectEntriesById data in response to + MESSAGE_OBJECT_ENTRIES_RECEIVE action`, () => { + const { dispatch, getState } = setupStore([]); + + // Add 2 log messages with loaded entries. + dispatch(actions.messageAdd(stubPackets.get("console.log('myset')"))); + dispatch(actions.messageAdd(stubPackets.get("console.log('mymap')"))); + + let messages = getAllMessagesById(getState()); + + const setEntries = Symbol(); + const mapEntries = Symbol(); + const mapEntries2 = Symbol(); + + const [id1, id2] = [...messages.keys()]; + dispatch(actions.messageObjectEntriesReceive(id1, "fakeActor1", setEntries)); + dispatch(actions.messageObjectEntriesReceive(id2, "fakeActor2", mapEntries)); + dispatch(actions.messageObjectEntriesReceive(id2, "fakeActor3", mapEntries2)); + + let loadedEntries = getAllMessagesObjectEntriesById(getState()); + expect(loadedEntries.size).toBe(2); + + expect(loadedEntries.get(id1)).toEqual({ + fakeActor1: setEntries, + }); + + expect(loadedEntries.get(id2)).toEqual({ + fakeActor2: mapEntries, + fakeActor3: mapEntries2, + }); + }); + + it("resets messagesObjectEntriesById in response to MESSAGES_CLEAR action", () => { + const { dispatch, getState } = setupStore([ + "console.log('myset')" + ]); + + let messages = getAllMessagesById(getState()); + const entries = Symbol("entries"); + const message = messages.first(); + const {actor} = message.parameters[1]; + + dispatch(actions.messageObjectEntriesReceive(message.id, actor, entries)); + + let loadedEntries = getAllMessagesObjectEntriesById(getState()); + expect(loadedEntries.size).toBe(1); + expect(loadedEntries.get(message.id)).toEqual({ + [actor]: entries + }); + + dispatch(actions.messagesClear()); + + expect(getAllMessagesObjectEntriesById(getState()).size).toBe(0); + }); + + it("cleans messagesObjectPropertiesById when messages are pruned", () => { + const { dispatch, getState } = setupStore([], null, { + logLimit: 2 + }); + + // Add 2 log messages with loaded entries. + dispatch(actions.messageAdd(stubPackets.get("console.log('myset')"))); + dispatch(actions.messageAdd(stubPackets.get("console.log('mymap')"))); + + let messages = getAllMessagesById(getState()); + + const setEntries = Symbol(); + const mapEntries = Symbol(); + const mapEntries2 = Symbol(); + + const [id1, id2] = [...messages.keys()]; + dispatch(actions.messageObjectEntriesReceive(id1, "fakeActor1", setEntries)); + dispatch(actions.messageObjectEntriesReceive(id2, "fakeActor2", mapEntries)); + dispatch(actions.messageObjectEntriesReceive(id2, "fakeActor3", mapEntries2)); + + let loadedEntries = getAllMessagesObjectEntriesById(getState()); + expect(loadedEntries.size).toBe(2); + + // This addition will remove the first message. + dispatch(actions.messageAdd(stubPackets.get("console.log(undefined)"))); + + loadedEntries = getAllMessagesObjectEntriesById(getState()); + expect(loadedEntries.size).toBe(1); + expect(loadedEntries.get(id2)).toEqual({ + fakeActor2: mapEntries, + fakeActor3: mapEntries2, + }); + + // This addition will remove the second table message. + dispatch(actions.messageAdd(stubPackets.get("console.log('foobar', 'test')"))); + + expect(getAllMessagesObjectEntriesById(getState()).size).toBe(0); + }); + }); }); diff --git a/devtools/client/webconsole/new-console-output/test/store/release-actors.test.js b/devtools/client/webconsole/new-console-output/test/store/release-actors.test.js index b7d18370eaa5..ebba2b9030a9 100644 --- a/devtools/client/webconsole/new-console-output/test/store/release-actors.test.js +++ b/devtools/client/webconsole/new-console-output/test/store/release-actors.test.js @@ -85,11 +85,17 @@ describe("Release actor enhancer:", () => { const firstMessageActor = firstMessage.parameters[1].actor; const arrayProperties = Symbol(); const arraySubProperties = Symbol(); + const mapEntries1 = Symbol(); + const mapEntries2 = Symbol(); const [id] = [...messages.keys()]; dispatch(actions.messageObjectPropertiesReceive( id, "fakeActor1", arrayProperties)); dispatch(actions.messageObjectPropertiesReceive( id, "fakeActor2", arraySubProperties)); + dispatch(actions.messageObjectEntriesReceive( + id, "mapActor1", mapEntries1)); + dispatch(actions.messageObjectEntriesReceive( + id, "mapActor2", mapEntries2)); const packet = clonePacket(stubPackets.get( "console.assert(false, {message: 'foobar'})")); @@ -98,10 +104,12 @@ describe("Release actor enhancer:", () => { dispatch(actions.messagesClear()); - expect(releasedActors.length).toBe(4); + expect(releasedActors.length).toBe(6); expect(releasedActors).toInclude(firstMessageActor); expect(releasedActors).toInclude("fakeActor1"); expect(releasedActors).toInclude("fakeActor2"); + expect(releasedActors).toInclude("mapActor1"); + expect(releasedActors).toInclude("mapActor2"); expect(releasedActors).toInclude(secondMessageActor); }); }); diff --git a/devtools/client/webconsole/new-console-output/test/store/search.test.js b/devtools/client/webconsole/new-console-output/test/store/search.test.js index 86440716325c..8aac196948fe 100644 --- a/devtools/client/webconsole/new-console-output/test/store/search.test.js +++ b/devtools/client/webconsole/new-console-output/test/store/search.test.js @@ -88,7 +88,7 @@ function prepareBaseStore() { "console.count('bar')", "console.log('myarray', ['red', 'green', 'blue'])", "console.log('myregex', /a.b.c/)", - "console.map('mymap')", + "console.log('mymap')", "console.log('myobject', {red: 'redValue', green: 'greenValue', blue: 'blueValue'});", "GET request", ]);