summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/test/mochitest/browser_dbg-backgroundtask-debugging.js
blob: 6e0f62deb9547c479ee53b5cf6ebef8e8c7ee401 (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */

/**
 * Tests that `--backgroundtask` debugging works.
 *
 * This test is subtle.  We launch a `--backgroundtask` with `--jsdebugger` and
 * `--wait-for-jsdebugger` within the test.  The background task infrastructure
 * launches a browser toolbox, and the test connects to that browser toolbox
 * instance.  The test drives the instance, verifying that the automatically
 * placed breakpoint paused execution.  It then closes the browser toolbox,
 * which resumes the execution and the task exits.
 *
 * In the future, it would be nice to change the task's running environment, for
 * example by redefining a failing exit code to exit code 0.  Attempts to do
 * this have so far not been robust in automation.
 */

"use strict";

requestLongerTimeout(4);

Services.scriptloader.loadSubScript(
  "chrome://mochitests/content/browser/devtools/client/framework/browser-toolbox/test/helpers-browser-toolbox.js",
  this
);

const { BackgroundTasksTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/BackgroundTasksTestUtils.sys.mjs"
);
BackgroundTasksTestUtils.init(this);
const do_backgroundtask = BackgroundTasksTestUtils.do_backgroundtask.bind(
  BackgroundTasksTestUtils
);

add_task(async function test_backgroundtask_debugger() {
  // In this test, the background task infrastructure launches the browser
  // toolbox.  The browser toolbox profile prefs are taken from the default
  // profile (which is the standard place for background tasks to look for
  // task-specific configuration).  The current test profile will be
  // considered the default profile by the background task apparatus, so this
  // is how we configure the browser toolbox profile prefs.
  //
  // These prefs are not set for the background task under test directly: the
  // relevant prefs are set in the background task defaults.
  await pushPref("devtools.chrome.enabled", true);
  await pushPref("devtools.debugger.remote-enabled", true);
  await pushPref("devtools.browsertoolbox.enable-test-server", true);
  await pushPref("devtools.debugger.prompt-connection", false);

  // Before we start the background task, the preference file must be flushed to disk.
  Services.prefs.savePrefFile(null);

  // This invokes the test-only background task `BackgroundTask_jsdebugger.jsm`.
  const p = do_backgroundtask("jsdebugger", {
    extraArgs: [`--jsdebugger`, "--wait-for-jsdebugger"],
    extraEnv: {
      // Force the current test profile to be considered the default profile.
      MOZ_BACKGROUNDTASKS_DEFAULT_PROFILE_PATH: Services.dirsvc.get(
        "ProfD",
        Ci.nsIFile
      ).path,
    },
  });

  ok(true, "Launched background task");

  const existingProcessClose = async () => {
    const exitCode = await p;
    return { exitCode };
  };
  const ToolboxTask = await initBrowserToolboxTask({ existingProcessClose });

  await ToolboxTask.spawn(selectors, () => {
    const {
      LocalizationHelper,
    } = require("resource://devtools/shared/l10n.js");
    // We have to expose this symbol as global for waitForSelectedSource
    this.DEBUGGER_L10N = new LocalizationHelper(
      "devtools/client/locales/debugger.properties"
    );
  });

  await ToolboxTask.importFunctions({
    checkEvaluateInTopFrame,
    evaluateInTopFrame,
    createDebuggerContext,
    expandAllScopes,
    findElement,
    findElementWithSelector,
    getSelector,
    getVisibleSelectedFrameLine,
    isPaused,
    resume,
    stepOver,
    toggleObjectInspectorNode,
    toggleScopeNode,
    waitForElement,
    waitForLoadedScopes,
    waitForPaused,
    waitForResumed,
    waitForSelectedSource,
    waitForState,
    waitUntil,
    createLocation,
    getCM,
    log: (msg, data) =>
      console.log(`${msg} ${!data ? "" : JSON.stringify(data)}`),
    info: (msg, data) =>
      console.info(`${msg} ${!data ? "" : JSON.stringify(data)}`),
  });

  // ToolboxTask.spawn passes input arguments by stringify-ing them via string
  // concatenation.  But functions do not survive this process, so we manually
  // recreate (in the toolbox process) the single function the `expandAllScopes`
  // invocation in this test needs.
  await ToolboxTask.spawn(selectors, async _selectors => {
    this.selectors = _selectors;
    this.selectors.scopeNode = i =>
      `.scopes-list .tree-node:nth-child(${i}) .object-label`;
  });

  // The debugger should automatically be selected.
  await ToolboxTask.spawn(null, async () => {
    await waitUntil(() => gToolbox.currentToolId == "jsdebugger");
  });
  ok(true, "Debugger selected");

  // The debugger should automatically pause.
  await ToolboxTask.spawn(null, async () => {
    try {
      /* global gToolbox */
      // Wait for the debugger to finish loading.
      await gToolbox.getPanelWhenReady("jsdebugger");

      const dbg = createDebuggerContext(gToolbox);

      // Scopes are supposed to be automatically expanded, but with
      // `setBreakpointOnLoad` that doesn't seem to be happening.  Explicitly
      // expand scopes so that they are expanded for `waitForPaused`.
      await expandAllScopes(dbg);

      await waitForPaused(dbg);

      if (!gToolbox.isHighlighted("jsdebugger")) {
        throw new Error("Debugger not highlighted");
      }
    } catch (e) {
      console.log("Caught exception in spawn", e);
      throw e;
    }
  });
  ok(true, "Paused in backgroundtask script");

  // If we `resume`, then the task completes and the Browser Toolbox exits,
  // which isn't handled cleanly by `spawn`, resulting in a test time out.  This
  // closes the toolbox "from the inside", which continues execution.  The test
  // then waits for the background task to terminate with exit code 0.
  await ToolboxTask.destroy();
});