browser/devtools/debugger/test/browser_dbg_closure-inspection.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/devtools/debugger/test/browser_dbg_closure-inspection.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,156 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 +   http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +const TAB_URL = EXAMPLE_URL + "doc_closures.html";
     1.8 +
     1.9 +// Test that inspecting a closure works as expected.
    1.10 +
    1.11 +function test() {
    1.12 +  let gPanel, gTab, gDebuggee, gDebugger;
    1.13 +
    1.14 +  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
    1.15 +    gTab = aTab;
    1.16 +    gDebuggee = aDebuggee;
    1.17 +    gPanel = aPanel;
    1.18 +    gDebugger = gPanel.panelWin;
    1.19 +    gDebuggee.gRecurseLimit = 2;
    1.20 +
    1.21 +    waitForSourceShown(gPanel, ".html")
    1.22 +      .then(testClosure)
    1.23 +      .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
    1.24 +      .then(null, aError => {
    1.25 +        ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
    1.26 +      });
    1.27 +  });
    1.28 +
    1.29 +  function testClosure() {
    1.30 +    // Spin the event loop before causing the debuggee to pause, to allow
    1.31 +    // this function to return first.
    1.32 +    executeSoon(() => {
    1.33 +      EventUtils.sendMouseEvent({ type: "click" },
    1.34 +        gDebuggee.document.querySelector("button"),
    1.35 +        gDebuggee);
    1.36 +    });
    1.37 +
    1.38 +    return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
    1.39 +      let gVars = gDebugger.DebuggerView.Variables;
    1.40 +      let localScope = gVars.getScopeAtIndex(0);
    1.41 +      let localNodes = localScope.target.querySelector(".variables-view-element-details").childNodes;
    1.42 +
    1.43 +      is(localNodes[4].querySelector(".name").getAttribute("value"), "person",
    1.44 +        "Should have the right property name for |person|.");
    1.45 +      is(localNodes[4].querySelector(".value").getAttribute("value"), "Object",
    1.46 +        "Should have the right property value for |person|.");
    1.47 +
    1.48 +      // Expand the 'person' tree node. This causes its properties to be
    1.49 +      // retrieved and displayed.
    1.50 +      let personNode = gVars.getItemForNode(localNodes[4]);
    1.51 +      let personFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES);
    1.52 +      personNode.expand();
    1.53 +
    1.54 +      return personFetched.then(() => {
    1.55 +        is(personNode.expanded, true,
    1.56 +          "|person| should be expanded at this point.");
    1.57 +
    1.58 +        is(personNode.get("getName").target.querySelector(".name")
    1.59 +           .getAttribute("value"), "getName",
    1.60 +          "Should have the right property name for 'getName' in person.");
    1.61 +        is(personNode.get("getName").target.querySelector(".value")
    1.62 +           .getAttribute("value"), "_pfactory/<.getName()",
    1.63 +          "'getName' in person should have the right value.");
    1.64 +        is(personNode.get("getFoo").target.querySelector(".name")
    1.65 +           .getAttribute("value"), "getFoo",
    1.66 +          "Should have the right property name for 'getFoo' in person.");
    1.67 +        is(personNode.get("getFoo").target.querySelector(".value")
    1.68 +           .getAttribute("value"), "_pfactory/<.getFoo()",
    1.69 +          "'getFoo' in person should have the right value.");
    1.70 +
    1.71 +        // Expand the function nodes. This causes their properties to be
    1.72 +        // retrieved and displayed.
    1.73 +        let getFooNode = personNode.get("getFoo");
    1.74 +        let getNameNode = personNode.get("getName");
    1.75 +        let funcsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
    1.76 +        let funcClosuresFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES, 2);
    1.77 +        getFooNode.expand();
    1.78 +        getNameNode.expand();
    1.79 +
    1.80 +        return funcsFetched.then(() => {
    1.81 +          is(getFooNode.expanded, true,
    1.82 +            "|person.getFoo| should be expanded at this point.");
    1.83 +          is(getNameNode.expanded, true,
    1.84 +            "|person.getName| should be expanded at this point.");
    1.85 +
    1.86 +          is(getFooNode.get("<Closure>").target.querySelector(".name")
    1.87 +             .getAttribute("value"), "<Closure>",
    1.88 +            "Found the closure node for getFoo.");
    1.89 +          is(getFooNode.get("<Closure>").target.querySelector(".value")
    1.90 +             .getAttribute("value"), "",
    1.91 +            "The closure node has no value for getFoo.");
    1.92 +          is(getNameNode.get("<Closure>").target.querySelector(".name")
    1.93 +             .getAttribute("value"), "<Closure>",
    1.94 +            "Found the closure node for getName.");
    1.95 +          is(getNameNode.get("<Closure>").target.querySelector(".value")
    1.96 +             .getAttribute("value"), "",
    1.97 +            "The closure node has no value for getName.");
    1.98 +
    1.99 +          // Expand the closure nodes. This causes their environments to be
   1.100 +          // retrieved and displayed.
   1.101 +          let getFooClosure = getFooNode.get("<Closure>");
   1.102 +          let getNameClosure = getNameNode.get("<Closure>");
   1.103 +          getFooClosure.expand();
   1.104 +          getNameClosure.expand();
   1.105 +
   1.106 +          return funcClosuresFetched.then(() => {
   1.107 +            is(getFooClosure.expanded, true,
   1.108 +              "|person.getFoo| closure should be expanded at this point.");
   1.109 +            is(getNameClosure.expanded, true,
   1.110 +              "|person.getName| closure should be expanded at this point.");
   1.111 +
   1.112 +            is(getFooClosure.get("Function scope [_pfactory]").target.querySelector(".name")
   1.113 +               .getAttribute("value"), "Function scope [_pfactory]",
   1.114 +              "Found the function scope node for the getFoo closure.");
   1.115 +            is(getFooClosure.get("Function scope [_pfactory]").target.querySelector(".value")
   1.116 +               .getAttribute("value"), "",
   1.117 +              "The function scope node has no value for the getFoo closure.");
   1.118 +            is(getNameClosure.get("Function scope [_pfactory]").target.querySelector(".name")
   1.119 +               .getAttribute("value"), "Function scope [_pfactory]",
   1.120 +              "Found the function scope node for the getName closure.");
   1.121 +            is(getNameClosure.get("Function scope [_pfactory]").target.querySelector(".value")
   1.122 +               .getAttribute("value"), "",
   1.123 +              "The function scope node has no value for the getName closure.");
   1.124 +
   1.125 +            // Expand the scope nodes.
   1.126 +            let getFooInnerScope = getFooClosure.get("Function scope [_pfactory]");
   1.127 +            let getNameInnerScope = getNameClosure.get("Function scope [_pfactory]");
   1.128 +            let innerFuncsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
   1.129 +            getFooInnerScope.expand();
   1.130 +            getNameInnerScope.expand();
   1.131 +
   1.132 +            return funcsFetched.then(() => {
   1.133 +              is(getFooInnerScope.expanded, true,
   1.134 +                "|person.getFoo| inner scope should be expanded at this point.");
   1.135 +              is(getNameInnerScope.expanded, true,
   1.136 +                "|person.getName| inner scope should be expanded at this point.");
   1.137 +
   1.138 +              // Only test that each function closes over the necessary variable.
   1.139 +              // We wouldn't want future SpiderMonkey closure space
   1.140 +              // optimizations to break this test.
   1.141 +              is(getFooInnerScope.get("foo").target.querySelector(".name")
   1.142 +                 .getAttribute("value"), "foo",
   1.143 +                "Found the foo node for the getFoo inner scope.");
   1.144 +              is(getFooInnerScope.get("foo").target.querySelector(".value")
   1.145 +                 .getAttribute("value"), "10",
   1.146 +                "The foo node has the expected value.");
   1.147 +              is(getNameInnerScope.get("name").target.querySelector(".name")
   1.148 +                 .getAttribute("value"), "name",
   1.149 +                "Found the name node for the getName inner scope.");
   1.150 +              is(getNameInnerScope.get("name").target.querySelector(".value")
   1.151 +                 .getAttribute("value"), '"Bob"',
   1.152 +                "The name node has the expected value.");
   1.153 +            });
   1.154 +          });
   1.155 +        });
   1.156 +      });
   1.157 +    });
   1.158 +  }
   1.159 +}

mercurial