Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: browsertests.js

Issue 29373596: Issue 4838 - Use nodeunit framework for integration tests running in browser (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Left Patch Set: Created Jan. 24, 2017, 4:35 p.m.
Right Patch Set: Addressed comments and added additional minor changes Created Feb. 24, 2017, 9:17 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « README.md ('k') | package.json » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH 3 * Copyright (C) 2006-2017 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 try 20 (function()
21 { 21 {
22 var fs = require("fs"); 22 // We are currently limited to ECMAScript 5 in this file, because it is being
23 var system = require("system"); 23 // used in the browser tests. See https://issues.adblockplus.org/ticket/4796
24 var webpage = require("webpage"); 24 // Once this is resolved we should use promises here.
25 function safeCall(callback)
26 {
27 return function()
28 {
29 try
30 {
31 callback.apply(this, arguments);
32 }
33 catch (e)
34 {
35 var message = String(e);
36 if (e.stack)
37 message += "\n" + e.stack;
38 console.log(message);
39 phantom.exit(1);
40 }
41 };
42 }
25 43
26 var nodeunitUrl = system.args[1]; 44 function loadScript(doc, url, callback)
27 var urls = system.args.slice(2); 45 {
46 var script = doc.createElement("script");
47 script.src = url;
48 script.async = false;
49 doc.head.appendChild(script);
50 if (callback)
51 window.setTimeout(callback, 0);
52 }
28 53
29 // No need to load anything, about:blank will do for us 54 function loadModules(urls, callback)
30 var page = webpage.create();
31 page.evaluate(initPage, nodeunitUrl);
32 window.setTimeout(function()
33 { 55 {
34 runTests(urls, function() 56 var modules = {};
57
58 var loadNext = safeCall(function()
35 { 59 {
36 phantom.exit(); 60 if (urls.length)
61 {
62 // Load each module into a new frame so that their scopes don't clash
63 var frame = document.createElement("iframe");
64 document.body.appendChild(frame);
65
66 var wnd = frame.contentWindow;
67 wnd.loadScript = loadScript.bind(null, wnd.document);
68 wnd.console = console;
69 wnd.require = require;
70 wnd.exports = {};
71 wnd.module = {exports: wnd.exports};
72
73 var url = urls.shift();
74 var name = url.split("/").pop();
75 wnd.loadScript(url, safeCall(function()
76 {
77 modules[name] = nodeunit.testCase(wnd.module.exports);
78 loadNext();
79 }));
80 }
81 else
82 callback(modules);
37 }); 83 });
38 }, 0);
39 }
40 catch(e)
41 {
42 console.error(e);
43 phantom.exit();
44 }
45 84
46 function runTests(urls, callback) 85 loadNext();
47 { 86 }
48 page.onError = function(msg, trace)
49 {
50 var message = "Error: " + msg + "\n";
51 if (trace)
52 {
53 for (var i = 0; i < trace.length; i++)
54 {
55 message += "\n " + trace[i].file + ":" + trace[i].line +
56 (trace[i].function ? " in function " + trace[i].function
57 : " in global code");
58 }
59 }
60 console.error(message);
61 };
62 87
63 page.onCallback = function(data) 88 function runTests(modules, callback)
64 { 89 {
65 function bold(str) 90 function bold(str)
66 { 91 {
67 return "\u001B[1m" + str + "\u001B[22m"; 92 return "\u001B[1m" + str + "\u001B[22m";
68 } 93 }
69 94
70 function ok(str) 95 function ok(str)
71 { 96 {
72 return "\u001B[32m" + str + "\u001B[39m"; 97 return "\u001B[32m" + str + "\u001B[39m";
73 } 98 }
74 99
75 function error(str) 100 function error(str)
76 { 101 {
77 return "\u001B[31m" + str + "\u001B[39m"; 102 return "\u001B[31m" + str + "\u001B[39m";
78 } 103 }
79 104
80 if (data.type == "moduleStart") 105 nodeunit.runModules(modules, {
81 console.log(bold(data.name)); 106 moduleStart: function(name)
82 else if (data.type == "testDone")
83 {
84 if (data.failures.length == 0)
85 console.log("\u2714 " + data.name);
86 else
87 { 107 {
88 console.log(error("\u2716 " + data.name) + "\n"); 108 console.log(bold(name));
89 data.failures.forEach(function(failure) 109 },
110 testDone: function(name, assertions)
111 {
112 var errors = assertions.filter(function(assertion)
90 { 113 {
91 console.log(failure.join("\n") + "\n"); 114 return assertion.failed();
92 }) 115 }).map(function(assertion)
116 {
117 return assertion.error;
118 });
119
120 if (errors.length == 0)
121 console.log("\u2714 " + name);
122 else
123 {
124 console.log(error("\u2716 " + name) + "\n");
125 errors.forEach(function(error)
126 {
127 console.log(String(error));
128 if (error.stack)
129 console.log(error.stack);
130 console.log("");
131 });
132 }
133 },
134 done: function(assertions)
135 {
136 var failures = assertions.filter(function(assertion)
137 {
138 return assertion.failed();
139 });
140 if (failures.length)
141 {
142 console.log(
143 "\n" +
144 bold(error("FAILURES: ")) +
145 failures.length + "/" + assertions.length + " assertions failed"
146 );
147 }
148 else
149 {
150 console.log(
151 "\n" + bold(ok("OK: ")) +
152 assertions.length + " assertions"
153 );
154 }
155
156 callback(!failures.length);
93 } 157 }
94 } 158 });
95 else if (data.type == "done")
96 {
97 if (data.failures)
98 {
99 console.log(
100 "\n" +
101 bold(error("FAILURES: ")) +
102 data.failures + "/" + data.assertions + " assertions failed"
103 );
104 }
105 else
106 {
107 console.log("\n" + bold(ok("OK: ")) + data.assertions + " assertions");
108 }
109
110 page.close();
111 callback();
112 }
113 else if (data.type == "log")
114 {
115 console.log(data.args.join(" "));
116 }
117 else if (data.type == "error")
118 {
119 console.error(data.args.join(" "));
120 }
121 };
122
123 page.evaluate(runTestsContent, urls);
124 }
125
126 function initPage(nodeunitUrl)
127 {
128 function normalizeArgs(args)
129 {
130 var normalized = [];
131 for (var i = 0; i < args.length; i++)
132 {
133 try
134 {
135 if (typeof args[i] == "string")
136 normalized.push(args[i]);
137 else
138 normalized.push(JSON.stringify(args[i]));
139 }
140 catch (e)
141 {
142 normalized.push(String(args[i]));
143 }
144 }
145 return normalized;
146 } 159 }
147 160
148 window.console = { 161 function run()
149 log: function() 162 {
163 var system = require("system");
164 var nodeunitUrl = system.args[1];
165 var urls = system.args.slice(2);
166
167 loadScript(document, nodeunitUrl, safeCall(function()
150 { 168 {
151 window.callPhantom({type: "log", args: normalizeArgs(arguments)}); 169 loadModules(urls, safeCall(function(modules)
152 }, 170 {
153 error: function() 171 runTests(modules, function(success)
154 { 172 {
155 window.callPhantom({type: "error", args: normalizeArgs(arguments)}); 173 phantom.exit(success ? 0 : 1);
156 } 174 });
157 }; 175 }));
176 }));
177 }
158 178
159 window.loadScript = function(url, callback) 179 safeCall(run)();
160 { 180 })();
161 var script = document.createElement("script");
162 script.src = url;
163 script.async = false;
164 document.head.appendChild(script);
165 if (callback)
166 window.setTimeout(callback, 0);
167 };
168
169 loadScript(nodeunitUrl);
170 }
171
172 function runTestsContent(urls)
173 {
174 var modules = {};
175
176 var loadNext = function()
177 {
178 if (urls.length)
179 {
180 window.exports = {};
181 window.module = {exports: window.exports};
182
183 var url = urls.shift();
184 var name = url.split("/").pop();
185 loadScript(url, function()
186 {
187 modules[name] = nodeunit.testCase(window.module.exports);
188 loadNext();
189 });
190 }
191 else
192 {
193 nodeunit.runModules(modules, {
194 moduleStart: function(name)
195 {
196 window.callPhantom({type: "moduleStart", name: name});
197 },
198 testDone: function(name, assertions)
199 {
200 var failures = assertions.filter(function(assertion)
201 {
202 return assertion.failed();
203 }).map(function(assertion)
204 {
205 return [String(assertion.error), assertion.error.stack];
206 });
207 window.callPhantom({
208 type: "testDone",
209 name: name,
210 failures: failures
211 });
212 },
213 done: function(assertions)
214 {
215 window.callPhantom({
216 type: "done",
217 assertions: assertions.length,
218 failures: assertions.filter(function(assertion)
219 {
220 return assertion.failed();
221 }).length
222 });
223 }
224 });
225 }
226 }
227 loadNext();
228 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld