summaryrefslogtreecommitdiffstats
path: root/devtools/client/framework/test/browser_browser_toolbox_debugger.js
blob: c0971cc7c26f944598a1153bb847781621ba5aa4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

// On debug test runner, it takes about 50s to run the test.
requestLongerTimeout(4);

const { setInterval, clearInterval } = require("sdk/timers");

add_task(function* runTest() {
  yield new Promise(done => {
    let options = {"set": [
      ["devtools.debugger.prompt-connection", false],
      ["devtools.debugger.remote-enabled", true],
      ["devtools.chrome.enabled", true],
      // Test-only pref to allow passing `testScript` argument to the browser
      // toolbox
      ["devtools.browser-toolbox.allow-unsafe-script", true],
      // On debug test runner, it takes more than the default time (20s)
      // to get a initialized console
      ["devtools.debugger.remote-timeout", 120000]
    ]};
    SpecialPowers.pushPrefEnv(options, done);
  });

  let s = Cu.Sandbox("http://mozilla.org");
  // Pass a fake URL to evalInSandbox. If we just pass a filename,
  // Debugger is going to fail and only display root folder (`/`) listing.
  // But it won't try to fetch this url and use sandbox content as expected.
  let testUrl = "http://mozilla.org/browser-toolbox-test.js";
  Cu.evalInSandbox("(" + function () {
    this.plop = function plop() {
      return 1;
    };
  } + ").call(this)", s, "1.8", testUrl, 0);

  // Execute the function every second in order to trigger the breakpoint
  let interval = setInterval(s.plop, 1000);

  // Be careful, this JS function is going to be executed in the browser toolbox,
  // which lives in another process. So do not try to use any scope variable!
  let env = Components.classes["@mozilla.org/process/environment;1"]
                      .getService(Components.interfaces.nsIEnvironment);
  let testScript = function () {
    const { Task } = Components.utils.import("resource://gre/modules/Task.jsm", {});
    dump("Opening the browser toolbox and debugger panel\n");
    let window, document;
    let testUrl = "http://mozilla.org/browser-toolbox-test.js";
    Task.spawn(function* () {
      dump("Waiting for debugger load\n");
      let panel = yield toolbox.selectTool("jsdebugger");
      let window = panel.panelWin;
      let document = window.document;

      yield window.once(window.EVENTS.SOURCE_SHOWN);

      dump("Loaded, selecting the test script to debug\n");
      let item = document.querySelector(`.dbg-source-item[tooltiptext="${testUrl}"]`);
      let onSourceShown = window.once(window.EVENTS.SOURCE_SHOWN);
      item.click();
      yield onSourceShown;

      dump("Selected, setting a breakpoint\n");
      let { Sources, editor } = window.DebuggerView;
      let onBreak = window.once(window.EVENTS.FETCHED_SCOPES);
      editor.emit("gutterClick", 1);
      yield onBreak;

      dump("Paused, asserting breakpoint position\n");
      let url = Sources.selectedItem.attachment.source.url;
      if (url != testUrl) {
        throw new Error("Breaking on unexpected script: " + url);
      }
      let cursor = editor.getCursor();
      if (cursor.line != 1) {
        throw new Error("Breaking on unexpected line: " + cursor.line);
      }

      dump("Now, stepping over\n");
      let stepOver = window.document.querySelector("#step-over");
      let onFetchedScopes = window.once(window.EVENTS.FETCHED_SCOPES);
      stepOver.click();
      yield onFetchedScopes;

      dump("Stepped, asserting step position\n");
      url = Sources.selectedItem.attachment.source.url;
      if (url != testUrl) {
        throw new Error("Stepping on unexpected script: " + url);
      }
      cursor = editor.getCursor();
      if (cursor.line != 2) {
        throw new Error("Stepping on unexpected line: " + cursor.line);
      }

      dump("Resume script execution\n");
      let resume = window.document.querySelector("#resume");
      let onResume = toolbox.target.once("thread-resumed");
      resume.click();
      yield onResume;

      dump("Close the browser toolbox\n");
      toolbox.destroy();

    }).catch(error => {
      dump("Error while running code in the browser toolbox process:\n");
      dump(error + "\n");
      dump("stack:\n" + error.stack + "\n");
    });
  };
  env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
  registerCleanupFunction(() => {
    env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
  });

  let { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
  // Use two promises, one for each BrowserToolboxProcess.init callback
  // arguments, to ensure that we wait for toolbox run and close events.
  let closePromise;
  yield new Promise(onRun => {
    closePromise = new Promise(onClose => {
      info("Opening the browser toolbox\n");
      BrowserToolboxProcess.init(onClose, onRun);
    });
  });
  ok(true, "Browser toolbox started\n");

  yield closePromise;
  ok(true, "Browser toolbox process just closed");

  clearInterval(interval);
});