summaryrefslogtreecommitdiff
path: root/devtools/client/scratchpad/test/head.js
blob: 2c1ae632d7b991412a1b2a4922dd9651ae8156d8 (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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
const {console} = Cu.import("resource://gre/modules/Console.jsm", {});
const {ScratchpadManager} = Cu.import("resource://devtools/client/scratchpad/scratchpad-manager.jsm", {});
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const {gDevTools} = require("devtools/client/framework/devtools");
const Services = require("Services");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const flags = require("devtools/shared/flags");
const promise = require("promise");


var gScratchpadWindow; // Reference to the Scratchpad chrome window object

flags.testing = true;
SimpleTest.registerCleanupFunction(() => {
  flags.testing = false;
});

/**
 * Open a Scratchpad window.
 *
 * @param function aReadyCallback
 *        Optional. The function you want invoked when the Scratchpad instance
 *        is ready.
 * @param object aOptions
 *        Optional. Options for opening the scratchpad:
 *        - window
 *          Provide this if there's already a Scratchpad window you want to wait
 *          loading for.
 *        - state
 *          Scratchpad state object. This is used when Scratchpad is open.
 *        - noFocus
 *          Boolean that tells you do not want the opened window to receive
 *          focus.
 * @return nsIDOMWindow
 *         The new window object that holds Scratchpad. Note that the
 *         gScratchpadWindow global is also updated to reference the new window
 *         object.
 */
function openScratchpad(aReadyCallback, aOptions = {})
{
  let win = aOptions.window ||
            ScratchpadManager.openScratchpad(aOptions.state);
  if (!win) {
    return;
  }

  let onLoad = function () {
    win.removeEventListener("load", onLoad, false);

    win.Scratchpad.addObserver({
      onReady: function (aScratchpad) {
        aScratchpad.removeObserver(this);

        if (aOptions.noFocus) {
          aReadyCallback(win, aScratchpad);
        } else {
          waitForFocus(aReadyCallback.bind(null, win, aScratchpad), win);
        }
      }
    });
  };

  if (aReadyCallback) {
    win.addEventListener("load", onLoad, false);
  }

  gScratchpadWindow = win;
  return gScratchpadWindow;
}

/**
 * Open a new tab and then open a scratchpad.
 * @param object aOptions
 *        Optional. Options for opening the tab and scratchpad. In addition
 *        to the options supported by openScratchpad, the following options
 *        are supported:
 *        - tabContent
 *          A string providing the html content of the tab.
 * @return Promise
 */
function openTabAndScratchpad(aOptions = {})
{
  waitForExplicitFinish();
  return new promise(resolve => {
    gBrowser.selectedTab = gBrowser.addTab();
    let {selectedBrowser} = gBrowser;
    selectedBrowser.addEventListener("load", function onLoad() {
      selectedBrowser.removeEventListener("load", onLoad, true);
      openScratchpad((win, sp) => resolve([win, sp]), aOptions);
    }, true);
    content.location = "data:text/html;charset=utf8," + (aOptions.tabContent || "");
  });
}

/**
 * Create a temporary file, write to it and call a callback
 * when done.
 *
 * @param string aName
 *        Name of your temporary file.
 * @param string aContent
 *        Temporary file's contents.
 * @param function aCallback
 *        Optional callback to be called when we're done writing
 *        to the file. It will receive two parameters: status code
 *        and a file object.
 */
function createTempFile(aName, aContent, aCallback = function () {})
{
  // Create a temporary file.
  let file = FileUtils.getFile("TmpD", [aName]);
  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8));

  // Write the temporary file.
  let fout = Cc["@mozilla.org/network/file-output-stream;1"].
             createInstance(Ci.nsIFileOutputStream);
  fout.init(file.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20,
            parseInt("644", 8), fout.DEFER_OPEN);

  let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
                  createInstance(Ci.nsIScriptableUnicodeConverter);
  converter.charset = "UTF-8";
  let fileContentStream = converter.convertToInputStream(aContent);

  NetUtil.asyncCopy(fileContentStream, fout, function (aStatus) {
    aCallback(aStatus, file);
  });
}

/**
 * Run a set of asychronous tests sequentially defined by input and output.
 *
 * @param Scratchpad aScratchpad
 *        The scratchpad to use in running the tests.
 * @param array aTests
 *        An array of test objects, each with the following properties:
 *        - method
 *          Scratchpad method to use, one of "run", "display", or "inspect".
 *        - code
 *          Code to run in the scratchpad.
 *        - result
 *          Expected code that will be in the scratchpad upon completion.
 *        - label
 *          The tests label which will be logged in the test runner output.
 * @return Promise
 *         The promise that will be resolved when all tests are finished.
 */
function runAsyncTests(aScratchpad, aTests)
{
  let deferred = promise.defer();

  (function runTest() {
    if (aTests.length) {
      let test = aTests.shift();
      aScratchpad.setText(test.code);
      aScratchpad[test.method]().then(function success() {
        is(aScratchpad.getText(), test.result, test.label);
        runTest();
      }, function failure(error) {
        ok(false, error.stack + " " + test.label);
        runTest();
      });
    } else {
      deferred.resolve();
    }
  })();

  return deferred.promise;
}

/**
 * Run a set of asychronous tests sequentially with callbacks to prepare each
 * test and to be called when the test result is ready.
 *
 * @param Scratchpad aScratchpad
 *        The scratchpad to use in running the tests.
 * @param array aTests
 *        An array of test objects, each with the following properties:
 *        - method
 *          Scratchpad method to use, one of "run", "display", or "inspect".
 *        - prepare
 *          The callback to run just prior to executing the scratchpad method.
 *        - then
 *          The callback to run when the scratchpad execution promise resolves.
 * @return Promise
 *         The promise that will be resolved when all tests are finished.
 */
var runAsyncCallbackTests = Task.async(function* (aScratchpad, aTests) {
  for (let {prepare, method, then} of aTests) {
    yield prepare();
    let res = yield aScratchpad[method]();
    yield then(res);
  }
});

/**
 * A simple wrapper for ContentTask.spawn for more compact code.
 */
function inContent(generator) {
  return ContentTask.spawn(gBrowser.selectedBrowser, {}, generator);
}

function cleanup()
{
  if (gScratchpadWindow) {
    gScratchpadWindow.close();
    gScratchpadWindow = null;
  }
  while (gBrowser.tabs.length > 1) {
    gBrowser.removeCurrentTab();
  }
}

registerCleanupFunction(cleanup);