error handling now mainly relies on phantom.onError()
Showing
3 changed files
with
33 additions
and
106 deletions
... | @@ -28,6 +28,9 @@ | ... | @@ -28,6 +28,9 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /** | ||
32 | * Loads and initialize the CasperJS environment. | ||
33 | */ | ||
31 | phantom.loadCasper = function loadCasper() { | 34 | phantom.loadCasper = function loadCasper() { |
32 | // Patching fs | 35 | // Patching fs |
33 | // TODO: watch for these methods being implemented in official fs module | 36 | // TODO: watch for these methods being implemented in official fs module |
... | @@ -78,9 +81,6 @@ phantom.loadCasper = function loadCasper() { | ... | @@ -78,9 +81,6 @@ phantom.loadCasper = function loadCasper() { |
78 | // Embedded, up-to-date, validatable & controlable CoffeeScript | 81 | // Embedded, up-to-date, validatable & controlable CoffeeScript |
79 | phantom.injectJs(fs.pathJoin(phantom.casperPath, 'modules', 'vendors', 'coffee-script.js')); | 82 | phantom.injectJs(fs.pathJoin(phantom.casperPath, 'modules', 'vendors', 'coffee-script.js')); |
80 | 83 | ||
81 | // Index of file sources, for error localization | ||
82 | phantom.sourceIds = {}; | ||
83 | |||
84 | // custom global CasperError | 84 | // custom global CasperError |
85 | window.CasperError = function CasperError(msg) { | 85 | window.CasperError = function CasperError(msg) { |
86 | Error.call(this); | 86 | Error.call(this); |
... | @@ -97,34 +97,6 @@ phantom.loadCasper = function loadCasper() { | ... | @@ -97,34 +97,6 @@ phantom.loadCasper = function loadCasper() { |
97 | // standard Error prototype inheritance | 97 | // standard Error prototype inheritance |
98 | window.CasperError.prototype = Object.getPrototypeOf(new Error()); | 98 | window.CasperError.prototype = Object.getPrototypeOf(new Error()); |
99 | 99 | ||
100 | // Stack formatting | ||
101 | window.CasperError.prototype.formatStack = function formatStack() { | ||
102 | var location = this.fileName || phantom.sourceIds[this.sourceId] || "unknown"; | ||
103 | location += ':' + (this.line ? this.line : 0); | ||
104 | return this.toString() + '\n ' + (this._from || "anonymous") + '() at ' + location; | ||
105 | }; | ||
106 | |||
107 | /** | ||
108 | * Adding pseudo stack traces to CasperError | ||
109 | * Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/ | ||
110 | * TODO: remove when phantomjs has js engine upgrade | ||
111 | */ | ||
112 | if (!new CasperError().hasOwnProperty('stack')) { | ||
113 | Object.defineProperty(CasperError.prototype, 'stack', { | ||
114 | set: function set(string) { | ||
115 | this._stack = string; | ||
116 | }, | ||
117 | get: function get() { | ||
118 | if (this._stack) { | ||
119 | return this._stack; | ||
120 | } | ||
121 | return this.formatStack(); | ||
122 | }, | ||
123 | configurable: true, | ||
124 | enumerable: true | ||
125 | }); | ||
126 | } | ||
127 | |||
128 | // CasperJS version, extracted from package.json - see http://semver.org/ | 100 | // CasperJS version, extracted from package.json - see http://semver.org/ |
129 | phantom.casperVersion = (function getVersion(path) { | 101 | phantom.casperVersion = (function getVersion(path) { |
130 | var parts, patchPart, pkg, pkgFile; | 102 | var parts, patchPart, pkg, pkgFile; |
... | @@ -167,46 +139,12 @@ phantom.loadCasper = function loadCasper() { | ... | @@ -167,46 +139,12 @@ phantom.loadCasper = function loadCasper() { |
167 | phantom.getScriptCode = function getScriptCode(file, onError) { | 139 | phantom.getScriptCode = function getScriptCode(file, onError) { |
168 | var scriptCode = fs.read(file); | 140 | var scriptCode = fs.read(file); |
169 | if (/\.coffee$/i.test(file)) { | 141 | if (/\.coffee$/i.test(file)) { |
170 | try { | 142 | scriptCode = CoffeeScript.compile(scriptCode); |
171 | scriptCode = CoffeeScript.compile(scriptCode); | ||
172 | } catch (e) { | ||
173 | this.processScriptError(e, file, onError); | ||
174 | } | ||
175 | } | 143 | } |
176 | // trick to locate source file location on error | ||
177 | scriptCode += ";var __fe__ = new CasperError('__sourceId__')"; | ||
178 | scriptCode += ";__fe__.fileName = '" + file.replace(/\\+/g, '/') + "'"; | ||
179 | scriptCode += ";throw __fe__;"; | ||
180 | return scriptCode; | 144 | return scriptCode; |
181 | }; | 145 | }; |
182 | 146 | ||
183 | /** | 147 | /** |
184 | * Processes a given thrown Error; handles special cases and provides an | ||
185 | * optional callback argument. | ||
186 | * | ||
187 | * By default, the standard behavior on uncaught error is to print the | ||
188 | * error stack trace to the console and exit PhantomJS. | ||
189 | * | ||
190 | * @param Error error The Error instance | ||
191 | * @param String file A file path to associate to this error | ||
192 | * @param Function callback An optional callback | ||
193 | */ | ||
194 | phantom.processScriptError = function processScriptError(error, file, callback) { | ||
195 | if (error.sourceId && !this.sourceIds.hasOwnProperty(error.sourceId)) { | ||
196 | this.sourceIds[error.sourceId] = file; | ||
197 | } | ||
198 | if (error.message === "__sourceId__") { | ||
199 | return; | ||
200 | } | ||
201 | if (typeof callback === "function") { | ||
202 | callback(error, file); | ||
203 | } else { | ||
204 | console.error(error.stack); | ||
205 | this.exit(1); | ||
206 | } | ||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * Patching require() to allow loading of other modules than PhantomJS' | 148 | * Patching require() to allow loading of other modules than PhantomJS' |
211 | * builtin ones. | 149 | * builtin ones. |
212 | * Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/ | 150 | * Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/ |
... | @@ -266,13 +204,9 @@ phantom.loadCasper = function loadCasper() { | ... | @@ -266,13 +204,9 @@ phantom.loadCasper = function loadCasper() { |
266 | if (file in requireCache) { | 204 | if (file in requireCache) { |
267 | return requireCache[file].exports; | 205 | return requireCache[file].exports; |
268 | } | 206 | } |
269 | try { | 207 | var scriptCode = phantom.getScriptCode(file); |
270 | var scriptCode = phantom.getScriptCode(file); | 208 | var fn = new Function('require', 'module', 'exports', scriptCode); |
271 | var fn = new Function('require', 'module', 'exports', scriptCode); | 209 | fn(_require, module, module.exports); |
272 | fn(_require, module, module.exports); | ||
273 | } catch (e) { | ||
274 | phantom.processScriptError(e, file); | ||
275 | } | ||
276 | requireCache[file] = module; | 210 | requireCache[file] = module; |
277 | return module.exports; | 211 | return module.exports; |
278 | }; | 212 | }; |
... | @@ -288,6 +222,27 @@ phantom.loadCasper = function loadCasper() { | ... | @@ -288,6 +222,27 @@ phantom.loadCasper = function loadCasper() { |
288 | phantom.casperLoaded = true; | 222 | phantom.casperLoaded = true; |
289 | }; | 223 | }; |
290 | 224 | ||
225 | /** | ||
226 | * Custom global error handler. | ||
227 | */ | ||
228 | phantom.onError = function phantom_onError(msg, backtrace) { | ||
229 | var c = require('colorizer').create(); | ||
230 | if (msg) { | ||
231 | console.error(c.colorize(msg, 'RED_BAR', 80)); | ||
232 | } | ||
233 | backtrace.forEach(function(item) { | ||
234 | var message = require('fs').absolute(item.file) + ":" + c.colorize(item.line, "COMMENT"); | ||
235 | if (item['function']) { | ||
236 | message += " in " + c.colorize(item['function'], "PARAMETER"); | ||
237 | } | ||
238 | console.error(" " + message); | ||
239 | }); | ||
240 | phantom.exit(1); | ||
241 | }; | ||
242 | |||
243 | /** | ||
244 | * Initializes the CasperJS Command Line Interface. | ||
245 | */ | ||
291 | phantom.initCasperCli = function initCasperCli() { | 246 | phantom.initCasperCli = function initCasperCli() { |
292 | var fs = require("fs"); | 247 | var fs = require("fs"); |
293 | 248 | ||
... | @@ -317,16 +272,11 @@ phantom.initCasperCli = function initCasperCli() { | ... | @@ -317,16 +272,11 @@ phantom.initCasperCli = function initCasperCli() { |
317 | phantom.exit(1); | 272 | phantom.exit(1); |
318 | } | 273 | } |
319 | 274 | ||
320 | |||
321 | // filter out the called script name from casper args | 275 | // filter out the called script name from casper args |
322 | phantom.casperArgs.drop(phantom.casperScript); | 276 | phantom.casperArgs.drop(phantom.casperScript); |
323 | 277 | ||
324 | // passed casperjs script execution | 278 | // passed casperjs script execution |
325 | try { | 279 | phantom.injectJs(phantom.casperScript); |
326 | new Function(phantom.getScriptCode(phantom.casperScript))(); | ||
327 | } catch (e) { | ||
328 | phantom.processScriptError(e, phantom.casperScript); | ||
329 | } | ||
330 | }; | 280 | }; |
331 | 281 | ||
332 | if (!phantom.casperLoaded) { | 282 | if (!phantom.casperLoaded) { | ... | ... |
... | @@ -366,13 +366,10 @@ var Tester = function Tester(casper, options) { | ... | @@ -366,13 +366,10 @@ var Tester = function Tester(casper, options) { |
366 | try { | 366 | try { |
367 | new Function('casper', phantom.getScriptCode(file))(casper); | 367 | new Function('casper', phantom.getScriptCode(file))(casper); |
368 | } catch (e) { | 368 | } catch (e) { |
369 | var self = this; | 369 | // do not abort the whole suite, just fail fast displaying the |
370 | phantom.processScriptError(e, file, function onTestScriptError(error) { | 370 | // caught error and process next suite |
371 | // do not abort the whole suite, just fail fast displaying the | 371 | this.fail(e); |
372 | // caught error and process next suite | 372 | this.done(); |
373 | self.fail(e); | ||
374 | self.done(); | ||
375 | }); | ||
376 | } | 373 | } |
377 | }; | 374 | }; |
378 | 375 | ... | ... |
tests/suites/error.js
deleted
100644 → 0
1 | var error; | ||
2 | |||
3 | function foo() { | ||
4 | bar(); | ||
5 | } | ||
6 | |||
7 | function bar() { | ||
8 | throw new CasperError('bar'); | ||
9 | } | ||
10 | |||
11 | try { | ||
12 | foo(); | ||
13 | } catch (e) { | ||
14 | error = e; | ||
15 | } | ||
16 | |||
17 | casper.test.assertType(error.stack, "string", "CasperError() has a stack string property set"); | ||
18 | casper.test.assertMatch(error.stack, /^CasperError: bar\s/, "CasperError() has the expected stack value"); | ||
19 | |||
20 | casper.test.done(); |
-
Please register or sign in to post a comment