Source code

Revision control

Other Tools

1
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
* You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
"use strict";
8
9
var EXPORTED_SYMBOLS = ["ContentTask"];
10
11
const { Promise } = ChromeUtils.import("resource://gre/modules/Promise.jsm");
12
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
13
14
const FRAME_SCRIPT = "resource://testing-common/content-task.js";
15
16
/**
17
* Keeps track of whether the frame script was already loaded.
18
*/
19
var gFrameScriptLoaded = false;
20
21
/**
22
* Mapping from message id to associated promise.
23
*/
24
var gPromises = new Map();
25
26
/**
27
* Incrementing integer to generate unique message id.
28
*/
29
var gMessageID = 1;
30
31
/**
32
* This object provides the public module functions.
33
*/
34
var ContentTask = {
35
/**
36
* _testScope saves the current testScope from
37
* browser-test.js. This is used to implement SimpleTest functions
38
* like ok() and is() in the content process. The scope is only
39
* valid for tasks spawned in the current test, so we keep track of
40
* the ID of the first task spawned in this test (_scopeValidId).
41
*/
42
_testScope: null,
43
_scopeValidId: 0,
44
45
/**
46
* Creates and starts a new task in a browser's content.
47
*
48
* @param browser A xul:browser
49
* @param arg A single serializable argument that will be passed to the
50
* task when executed on the content process.
51
* @param task
52
* - A generator or function which will be serialized and sent to
53
* the remote browser to be executed. Unlike Task.spawn, this
54
* argument may not be an iterator as it will be serialized and
55
* sent to the remote browser.
56
* @return A promise object where you can register completion callbacks to be
57
* called when the task terminates.
58
* @resolves With the final returned value of the task if it executes
59
* successfully.
60
* @rejects An error message if execution fails.
61
*/
62
spawn: function ContentTask_spawn(browser, arg, task) {
63
// Load the frame script if needed.
64
if (!gFrameScriptLoaded) {
65
Services.mm.loadFrameScript(FRAME_SCRIPT, true);
66
gFrameScriptLoaded = true;
67
}
68
69
let deferred = {};
70
deferred.promise = new Promise((resolve, reject) => {
71
deferred.resolve = resolve;
72
deferred.reject = reject;
73
});
74
75
let id = gMessageID++;
76
gPromises.set(id, deferred);
77
78
browser.messageManager.sendAsyncMessage("content-task:spawn", {
79
id,
80
runnable: task.toString(),
81
arg,
82
});
83
84
return deferred.promise;
85
},
86
87
setTestScope(scope) {
88
this._testScope = scope;
89
this._scopeValidId = gMessageID;
90
},
91
};
92
93
var ContentMessageListener = {
94
receiveMessage(aMessage) {
95
let id = aMessage.data.id;
96
97
if (id < ContentTask._scopeValidId) {
98
throw new Error("test result returned after test finished");
99
}
100
101
if (aMessage.name == "content-task:complete") {
102
let deferred = gPromises.get(id);
103
gPromises.delete(id);
104
105
if (aMessage.data.error) {
106
deferred.reject(aMessage.data.error);
107
} else {
108
deferred.resolve(aMessage.data.result);
109
}
110
} else if (aMessage.name == "content-task:test-result") {
111
let data = aMessage.data;
112
ContentTask._testScope.record(
113
data.condition,
114
data.name,
115
null,
116
data.stack
117
);
118
} else if (aMessage.name == "content-task:test-info") {
119
ContentTask._testScope.info(aMessage.data.name);
120
} else if (aMessage.name == "content-task:test-todo") {
121
ContentTask._testScope.todo(aMessage.data.expr, aMessage.data.name);
122
} else if (aMessage.name == "content-task:test-todo_is") {
123
ContentTask._testScope.todo_is(
124
aMessage.data.a,
125
aMessage.data.b,
126
aMessage.data.name
127
);
128
}
129
},
130
};
131
132
Services.mm.addMessageListener("content-task:complete", ContentMessageListener);
133
Services.mm.addMessageListener(
134
"content-task:test-result",
135
ContentMessageListener
136
);
137
Services.mm.addMessageListener(
138
"content-task:test-info",
139
ContentMessageListener
140
);
141
Services.mm.addMessageListener(
142
"content-task:test-todo",
143
ContentMessageListener
144
);
145
Services.mm.addMessageListener(
146
"content-task:test-todo_is",
147
ContentMessageListener
148
);