Commit 301d6345 301d63454d0f1bd9a337ce02f585d2a7d23828dd by Nicolas Perriault

continued migration to a full require() based layout

1 parent d5ff7c42
...@@ -106,6 +106,28 @@ phantom.casperArgs = (function(cliArgs) { ...@@ -106,6 +106,28 @@ phantom.casperArgs = (function(cliArgs) {
106 return extract; 106 return extract;
107 })(phantom.args); 107 })(phantom.args);
108 108
109 var sourceIds = {};
110
111 // Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/
112 // TODO: remoive when phantomjs has js engine upgrade
113 if (!new Error().hasOwnProperty('stack')) {
114 Object.defineProperty(Error.prototype, 'stack', {
115 set: function(string) {
116 this._stack = string;
117 },
118 get: function() {
119 if (this._stack) {
120 return this._stack;
121 } else if (this.fileName || this.sourceId) {
122 return this.toString() + '\nat ' + getErrorMessage(this);
123 }
124 return this.toString() + '\nat unknown';
125 },
126 configurable: true,
127 enumerable: true
128 });
129 }
130
109 // Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/ 131 // Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/
110 // TODO: remove when PhantomJS has full module support 132 // TODO: remove when PhantomJS has full module support
111 require = (function(require, requireDir) { 133 require = (function(require, requireDir) {
...@@ -159,7 +181,14 @@ require = (function(require, requireDir) { ...@@ -159,7 +181,14 @@ require = (function(require, requireDir) {
159 return requireCache[file].exports; 181 return requireCache[file].exports;
160 } 182 }
161 code = fs.read(file); 183 code = fs.read(file);
162 if (file.match(/\.coffee$/)) { 184 if (file.match(/\.js$/i)) {
185 try {
186 // TODO: esprima syntax check
187 } catch (e) {
188 e.fileName = file;
189 throw e;
190 }
191 } else if (file.match(/\.coffee$/i)) {
163 try { 192 try {
164 code = CoffeeScript.compile(code); 193 code = CoffeeScript.compile(code);
165 } catch (e) { 194 } catch (e) {
...@@ -168,12 +197,12 @@ require = (function(require, requireDir) { ...@@ -168,12 +197,12 @@ require = (function(require, requireDir) {
168 } 197 }
169 } 198 }
170 // a trick to associate Error's sourceId with file 199 // a trick to associate Error's sourceId with file
171 //code += ";throw new Error('__sourceId__');"; 200 code += ";throw new Error('__sourceId__');";
172 try { 201 try {
173 fn = new Function('module', 'exports', code); 202 fn = new Function('module', 'exports', code);
174 fn(module, module.exports); 203 fn(module, module.exports);
175 } catch (e) { 204 } catch (e) {
176 if (typeof sourceIds === "object" && !sourceIds.hasOwnProperty(e.sourceId)) { 205 if (!sourceIds.hasOwnProperty(e.sourceId)) {
177 sourceIds[e.sourceId] = file; 206 sourceIds[e.sourceId] = file;
178 } 207 }
179 if (e.message !== '__sourceId__') { 208 if (e.message !== '__sourceId__') {
......
...@@ -26,12 +26,9 @@ ...@@ -26,12 +26,9 @@
26 * 26 *
27 */ 27 */
28 28
29 exports.create = create; 29 exports.create = function() {
30 exports.Colorizer = Colorizer;
31
32 function create() {
33 return new Colorizer(); 30 return new Colorizer();
34 } 31 };
35 32
36 /** 33 /**
37 * This is a port of lime colorizer. 34 * This is a port of lime colorizer.
...@@ -95,3 +92,4 @@ var Colorizer = function() { ...@@ -95,3 +92,4 @@ var Colorizer = function() {
95 return "\033[" + codes.join(';') + 'm' + text + "\033[0m"; 92 return "\033[" + codes.join(';') + 'm' + text + "\033[0m";
96 }; 93 };
97 }; 94 };
95 exports.Colorizer = Colorizer;
......
...@@ -27,15 +27,15 @@ ...@@ -27,15 +27,15 @@
27 */ 27 */
28 28
29 exports.create = create; 29 exports.create = create;
30 exports.FunctionArgsInjector = FunctionArgsInjector;
31 30
32 function create(fn) { 31 exports.create = function(fn) {
33 return new FunctionArgsInjector(fn); 32 return new FunctionArgsInjector(fn);
34 } 33 };
35 34
36 /** 35 /**
37 * Function argument injector. 36 * Function argument injector.
38 * 37 *
38 * FIXME: use new Function() instead of eval()
39 */ 39 */
40 var FunctionArgsInjector = function(fn) { 40 var FunctionArgsInjector = function(fn) {
41 if (!isType(fn, "function")) { 41 if (!isType(fn, "function")) {
...@@ -82,3 +82,4 @@ var FunctionArgsInjector = function(fn) { ...@@ -82,3 +82,4 @@ var FunctionArgsInjector = function(fn) {
82 return inject.join('\n') + '\n'; 82 return inject.join('\n') + '\n';
83 }; 83 };
84 }; 84 };
85 exports.FunctionArgsInjector = FunctionArgsInjector;
......
...@@ -27,10 +27,11 @@ ...@@ -27,10 +27,11 @@
27 */ 27 */
28 28
29 var fs = require('fs'); 29 var fs = require('fs');
30 var utils = require('./lib/utils');
30 31
31 function create(casper, options) { 32 exports.create = function(casper, options) {
32 return new Tester(casper, options); 33 return new Tester(casper, options);
33 } 34 };
34 35
35 /** 36 /**
36 * Casper tester: makes assertions, stores test results and display then. 37 * Casper tester: makes assertions, stores test results and display then.
...@@ -39,9 +40,9 @@ function create(casper, options) { ...@@ -39,9 +40,9 @@ function create(casper, options) {
39 var Tester = function(casper, options) { 40 var Tester = function(casper, options) {
40 this.running = false; 41 this.running = false;
41 this.suites = []; 42 this.suites = [];
42 this.options = isType(options, "object") ? options : {}; 43 this.options = utils.isType(options, "object") ? options : {};
43 44
44 if (!casper instanceof require('./lib/casper').Casper) { 45 if (!utils.isCasperObject(casper)) {
45 throw new Error("Tester needs a Casper instance"); 46 throw new Error("Tester needs a Casper instance");
46 } 47 }
47 48
...@@ -219,7 +220,7 @@ var Tester = function(casper, options) { ...@@ -219,7 +220,7 @@ var Tester = function(casper, options) {
219 * @param String message Test description 220 * @param String message Test description
220 */ 221 */
221 this.assertType = function(input, type, message) { 222 this.assertType = function(input, type, message) {
222 return this.assertEquals(betterTypeOf(input), type, message); 223 return this.assertEquals(utils.betterTypeOf(input), type, message);
223 }; 224 };
224 225
225 /** 226 /**
...@@ -368,7 +369,7 @@ var Tester = function(casper, options) { ...@@ -368,7 +369,7 @@ var Tester = function(casper, options) {
368 * @param Boolean exit 369 * @param Boolean exit
369 */ 370 */
370 this.renderResults = function(exit, status, save) { 371 this.renderResults = function(exit, status, save) {
371 save = isType(save, "string") ? save : this.options.save; 372 save = utils.isType(save, "string") ? save : this.options.save;
372 var total = this.testResults.passed + this.testResults.failed, statusText, style, result; 373 var total = this.testResults.passed + this.testResults.failed, statusText, style, result;
373 if (this.testResults.failed > 0) { 374 if (this.testResults.failed > 0) {
374 statusText = FAIL; 375 statusText = FAIL;
...@@ -379,7 +380,7 @@ var Tester = function(casper, options) { ...@@ -379,7 +380,7 @@ var Tester = function(casper, options) {
379 } 380 }
380 result = statusText + ' ' + total + ' tests executed, ' + this.testResults.passed + ' passed, ' + this.testResults.failed + ' failed.'; 381 result = statusText + ' ' + total + ' tests executed, ' + this.testResults.passed + ' passed, ' + this.testResults.failed + ' failed.';
381 casper.echo(this.colorize(fillBlanks(result), style)); 382 casper.echo(this.colorize(fillBlanks(result), style));
382 if (save && isType(require, "function")) { 383 if (save && utils.isType(require, "function")) {
383 try { 384 try {
384 fs.write(save, exporter.getXML(), 'w'); 385 fs.write(save, exporter.getXML(), 'w');
385 casper.echo('result log stored in ' + save, 'INFO'); 386 casper.echo('result log stored in ' + save, 'INFO');
...@@ -455,10 +456,10 @@ var Tester = function(casper, options) { ...@@ -455,10 +456,10 @@ var Tester = function(casper, options) {
455 * @param Boolean 456 * @param Boolean
456 */ 457 */
457 this.testEquals = function(v1, v2) { 458 this.testEquals = function(v1, v2) {
458 if (betterTypeOf(v1) !== betterTypeOf(v2)) { 459 if (utils.betterTypeOf(v1) !== utils.betterTypeOf(v2)) {
459 return false; 460 return false;
460 } 461 }
461 if (isType(v1, "function")) { 462 if (utils.isType(v1, "function")) {
462 return v1.toString() === v2.toString(); 463 return v1.toString() === v2.toString();
463 } 464 }
464 if (v1 instanceof Object && v2 instanceof Object) { 465 if (v1 instanceof Object && v2 instanceof Object) {
...@@ -475,3 +476,4 @@ var Tester = function(casper, options) { ...@@ -475,3 +476,4 @@ var Tester = function(casper, options) {
475 return v1 === v2; 476 return v1 === v2;
476 }; 477 };
477 }; 478 };
479 exports.Tester = Tester;
......
...@@ -41,105 +41,7 @@ function betterTypeOf(input) { ...@@ -41,105 +41,7 @@ function betterTypeOf(input) {
41 return typeof input; 41 return typeof input;
42 } 42 }
43 } 43 }
44 44 exports.betterTypeOf = betterTypeOf;
45 /**
46 * Creates a new WebPage instance for Casper use.
47 *
48 * @param Casper casper A Casper instance
49 * @return WebPage
50 */
51 function createPage(casper) {
52 var page;
53 if (phantom.version.major <= 1 && phantom.version.minor < 3 && isType(require, "function")) {
54 page = new WebPage();
55 } else {
56 page = require('webpage').create();
57 }
58 page.onAlert = function(message) {
59 casper.log('[alert] ' + message, "info", "remote");
60 if (isType(casper.options.onAlert, "function")) {
61 casper.options.onAlert.call(casper, casper, message);
62 }
63 };
64 page.onConsoleMessage = function(msg) {
65 var level = "info", test = /^\[casper:(\w+)\]\s?(.*)/.exec(msg);
66 if (test && test.length === 3) {
67 level = test[1];
68 msg = test[2];
69 }
70 casper.log(msg, level, "remote");
71 };
72 page.onLoadStarted = function() {
73 casper.resources = [];
74 casper.loadInProgress = true;
75 };
76 page.onLoadFinished = function(status) {
77 if (status !== "success") {
78 var message = 'Loading resource failed with status=' + status;
79 if (casper.currentHTTPStatus) {
80 message += ' (HTTP ' + casper.currentHTTPStatus + ')';
81 }
82 message += ': ' + casper.requestUrl;
83 casper.log(message, "warning");
84 if (isType(casper.options.onLoadError, "function")) {
85 casper.options.onLoadError.call(casper, casper, casper.requestUrl, status);
86 }
87 }
88 if (casper.options.clientScripts) {
89 if (betterTypeOf(casper.options.clientScripts) !== "array") {
90 casper.log("The clientScripts option must be an array", "error");
91 } else {
92 for (var i = 0; i < casper.options.clientScripts.length; i++) {
93 var script = casper.options.clientScripts[i];
94 if (casper.page.injectJs(script)) {
95 casper.log('Automatically injected ' + script + ' client side', "debug");
96 } else {
97 casper.log('Failed injecting ' + script + ' client side', "warning");
98 }
99 }
100 }
101 }
102 // Client-side utils injection
103 var injected = page.evaluate(replaceFunctionPlaceholders(function() {
104 eval("var ClientUtils = " + decodeURIComponent("%utils%"));
105 __utils__ = new ClientUtils();
106 return __utils__ instanceof ClientUtils;
107 }, {
108 utils: encodeURIComponent(require('./lib/clientutils').ClientUtils.toString())
109 }));
110 if (!injected) {
111 casper.log("Failed to inject Casper client-side utilities!", "warning");
112 } else {
113 casper.log("Successfully injected Casper client-side utilities", "debug");
114 }
115 // history
116 casper.history.push(casper.getCurrentUrl());
117 casper.loadInProgress = false;
118 };
119 page.onResourceReceived = function(resource) {
120 if (isType(casper.options.onResourceReceived, "function")) {
121 casper.options.onResourceReceived.call(casper, casper, resource);
122 }
123 if (resource.stage === "end") {
124 casper.resources.push(resource);
125 }
126 if (resource.url === casper.requestUrl && resource.stage === "start") {
127 casper.currentHTTPStatus = resource.status;
128 if (isType(casper.options.httpStatusHandlers, "object") &&
129 resource.status in casper.options.httpStatusHandlers &&
130 isType(casper.options.httpStatusHandlers[resource.status], "function")) {
131 casper.options.httpStatusHandlers[resource.status].call(casper, casper, resource);
132 }
133 casper.currentUrl = resource.url;
134 }
135 };
136 page.onResourceRequested = function(request) {
137 if (isType(casper.options.onResourceRequested, "function")) {
138 casper.options.onResourceRequested.call(casper, casper, request);
139 }
140 };
141 return page;
142 }
143 45
144 /** 46 /**
145 * Dumps a JSON representation of passed value to the console. Used for 47 * Dumps a JSON representation of passed value to the console. Used for
...@@ -150,6 +52,7 @@ function createPage(casper) { ...@@ -150,6 +52,7 @@ function createPage(casper) {
150 function dump(value) { 52 function dump(value) {
151 console.log(serialize(value)); 53 console.log(serialize(value));
152 } 54 }
55 exports.dump = dump;
153 56
154 /** 57 /**
155 * Returns the file extension in lower case. 58 * Returns the file extension in lower case.
...@@ -164,6 +67,7 @@ function fileExt(file) { ...@@ -164,6 +67,7 @@ function fileExt(file) {
164 return ''; 67 return '';
165 } 68 }
166 } 69 }
70 exports.fileExt = fileExt;
167 71
168 /** 72 /**
169 * Takes a string and append blank until the pad value is reached. 73 * Takes a string and append blank until the pad value is reached.
...@@ -179,6 +83,18 @@ function fillBlanks(text, pad) { ...@@ -179,6 +83,18 @@ function fillBlanks(text, pad) {
179 } 83 }
180 return text; 84 return text;
181 } 85 }
86 exports.fillBlanks = fillBlanks;
87
88 /**
89 * Checks if passed argument is an instance of Capser object.
90 *
91 * @param mixed value
92 * @return Boolean
93 */
94 function isCasperObject(value) {
95 return value instanceof require('./lib/casper').Casper;
96 }
97 exports.isCasperObject = isCasperObject;
182 98
183 /** 99 /**
184 * Checks if a file is apparently javascript compatible (.js or .coffee). 100 * Checks if a file is apparently javascript compatible (.js or .coffee).
...@@ -190,6 +106,7 @@ function isJsFile(file) { ...@@ -190,6 +106,7 @@ function isJsFile(file) {
190 var ext = fileExt(file); 106 var ext = fileExt(file);
191 return isType(ext, "string") && ['js', 'coffee'].indexOf(ext) !== -1; 107 return isType(ext, "string") && ['js', 'coffee'].indexOf(ext) !== -1;
192 } 108 }
109 exports.isJsFile = isJsFile;
193 110
194 /** 111 /**
195 * Shorthands for checking if a value is of the given type. Can check for 112 * Shorthands for checking if a value is of the given type. Can check for
...@@ -202,6 +119,7 @@ function isJsFile(file) { ...@@ -202,6 +119,7 @@ function isJsFile(file) {
202 function isType(what, typeName) { 119 function isType(what, typeName) {
203 return betterTypeOf(what) === typeName; 120 return betterTypeOf(what) === typeName;
204 } 121 }
122 exports.isType = isType;
205 123
206 /** 124 /**
207 * Checks if the provided var is a WebPage instance 125 * Checks if the provided var is a WebPage instance
...@@ -219,6 +137,7 @@ function isWebPage(what) { ...@@ -219,6 +137,7 @@ function isWebPage(what) {
219 return what.toString().indexOf('WebPage(') === 0; 137 return what.toString().indexOf('WebPage(') === 0;
220 } 138 }
221 } 139 }
140 exports.isWebPage = isWebPage;
222 141
223 /** 142 /**
224 * Object recursive merging utility. 143 * Object recursive merging utility.
...@@ -241,6 +160,7 @@ function mergeObjects(obj1, obj2) { ...@@ -241,6 +160,7 @@ function mergeObjects(obj1, obj2) {
241 } 160 }
242 return obj1; 161 return obj1;
243 } 162 }
163 exports.mergeObjects = mergeObjects;
244 164
245 /** 165 /**
246 * Replaces a function string contents with placeholders provided by an 166 * Replaces a function string contents with placeholders provided by an
...@@ -262,6 +182,7 @@ function replaceFunctionPlaceholders(fn, replacements) { ...@@ -262,6 +182,7 @@ function replaceFunctionPlaceholders(fn, replacements) {
262 } 182 }
263 return fn; 183 return fn;
264 } 184 }
185 exports.replaceFunctionPlaceholders = replaceFunctionPlaceholders;
265 186
266 /** 187 /**
267 * Serializes a value using JSON. 188 * Serializes a value using JSON.
...@@ -277,3 +198,4 @@ function serialize(value) { ...@@ -277,3 +198,4 @@ function serialize(value) {
277 } 198 }
278 return JSON.stringify(value, null, 4); 199 return JSON.stringify(value, null, 4);
279 } 200 }
201 exports.serialize = serialize;
......
...@@ -26,12 +26,9 @@ ...@@ -26,12 +26,9 @@
26 * 26 *
27 */ 27 */
28 28
29 exports.create = create; 29 exports.create = function() {
30 exports.XUnitExporter = XUnitExporter;
31
32 function create() {
33 return new XUnitExporter(); 30 return new XUnitExporter();
34 } 31 };
35 32
36 /** 33 /**
37 * JUnit XML (xUnit) exporter for test results. 34 * JUnit XML (xUnit) exporter for test results.
...@@ -97,3 +94,5 @@ XUnitExporter = function() { ...@@ -97,3 +94,5 @@ XUnitExporter = function() {
97 return xml; 94 return xml;
98 }; 95 };
99 }; 96 };
97
98 exports.XUnitExporter = XUnitExporter;
......