Commit c8a534cd c8a534cd131a9de8a1a7b2117ddaded3386640a3 by Nicolas Perriault

refs #26 - code modularization

1 parent 83ca92a6
1 /*!
2 * Casper is a navigation utility for PhantomJS.
3 *
4 * Documentation: http://n1k0.github.com/casperjs/
5 * Repository: http://github.com/n1k0/casperjs
6 *
7 * Copyright (c) 2011 Nicolas Perriault
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 */
28 (function(phantom){
29 /**
30 * This is a port of lime colorizer.
31 * http://trac.symfony-project.org/browser/tools/lime/trunk/lib/lime.php)
32 *
33 * (c) Fabien Potencier, Symfony project, MIT license
34 */
35 phantom.Casper.Colorizer = function() {
36 var options = { bold: 1, underscore: 4, blink: 5, reverse: 7, conceal: 8 };
37 var foreground = { black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37 };
38 var background = { black: 40, red: 41, green: 42, yellow: 43, blue: 44, magenta: 45, cyan: 46, white: 47 };
39 var styles = {
40 'ERROR': { bg: 'red', fg: 'white', bold: true },
41 'INFO': { fg: 'green', bold: true },
42 'TRACE': { fg: 'green', bold: true },
43 'PARAMETER': { fg: 'cyan' },
44 'COMMENT': { fg: 'yellow' },
45 'WARNING': { fg: 'red', bold: true },
46 'GREEN_BAR': { fg: 'white', bg: 'green', bold: true },
47 'RED_BAR': { fg: 'white', bg: 'red', bold: true },
48 'INFO_BAR': { fg: 'cyan', bold: true }
49 };
50
51 /**
52 * Adds a style to provided text.
53 *
54 * @params String text
55 * @params String styleName
56 * @return String
57 */
58 this.colorize = function(text, styleName) {
59 if (styleName in styles) {
60 return this.format(text, styles[styleName]);
61 }
62 return text;
63 };
64
65 /**
66 * Formats a text using a style declaration object.
67 *
68 * @param String text
69 * @param Object style
70 * @return String
71 */
72 this.format = function(text, style) {
73 if (typeof style !== "object") {
74 return text;
75 }
76 var codes = [];
77 if (style.fg && foreground[style.fg]) {
78 codes.push(foreground[style.fg]);
79 }
80 if (style.bg && background[style.bg]) {
81 codes.push(background[style.bg]);
82 }
83 for (var option in options) {
84 if (style[option] === true) {
85 codes.push(options[option]);
86 }
87 }
88 return "\033[" + codes.join(';') + 'm' + text + "\033[0m";
89 };
90 };
91 })(phantom);
...\ No newline at end of file ...\ No newline at end of file
1 /*!
2 * Casper is a navigation utility for PhantomJS.
3 *
4 * Documentation: http://n1k0.github.com/casperjs/
5 * Repository: http://github.com/n1k0/casperjs
6 *
7 * Copyright (c) 2011 Nicolas Perriault
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 */
28 (function(phantom) {
29 /**
30 * Function argument injector.
31 *
32 */
33 phantom.Casper.FunctionArgsInjector = function(fn) {
34 if (!isType(fn, "function")) {
35 throw "FunctionArgsInjector() can only process functions";
36 }
37 this.fn = fn;
38
39 this.extract = function(fn) {
40 var match = /^function\s?(\w+)?\s?\((.*)\)\s?\{([\s\S]*)\}/i.exec(fn.toString().trim());
41 if (match && match.length > 1) {
42 var args = match[2].split(',').map(function(arg) {
43 return arg.replace(new RegExp(/\/\*+.*\*\//ig), "").trim();
44 }).filter(function(arg) {
45 return arg;
46 }) || [];
47 return {
48 name: match[1] ? match[1].trim() : null,
49 args: args,
50 body: match[3] ? match[3].trim() : ''
51 };
52 }
53 };
54
55 this.process = function(values) {
56 var fnObj = this.extract(this.fn);
57 if (!isType(fnObj, "object")) {
58 throw "Unable to process function " + this.fn.toString();
59 }
60 var inject = this.getArgsInjectionString(fnObj.args, values);
61 return 'function ' + (fnObj.name || '') + '(){' + inject + fnObj.body + '}';
62 };
63
64 this.getArgsInjectionString = function(args, values) {
65 values = typeof values === "object" ? values : {};
66 var jsonValues = escape(encodeURIComponent(JSON.stringify(values)));
67 var inject = [
68 'var __casper_params__ = JSON.parse(decodeURIComponent(unescape(\'' + jsonValues + '\')));'
69 ];
70 args.forEach(function(arg) {
71 if (arg in values) {
72 inject.push('var ' + arg + '=__casper_params__["' + arg + '"];');
73 }
74 });
75 return inject.join('\n') + '\n';
76 };
77 };
78 })(phantom);
...\ No newline at end of file ...\ No newline at end of file
1 /*!
2 * Casper is a navigation utility for PhantomJS.
3 *
4 * Documentation: http://n1k0.github.com/casperjs/
5 * Repository: http://github.com/n1k0/casperjs
6 *
7 * Copyright (c) 2011 Nicolas Perriault
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 */
28
29 /**
30 * Provides a better typeof operator equivalent, able to retrieve the array
31 * type.
32 *
33 * @param mixed input
34 * @return String
35 * @see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
36 */
37 function betterTypeOf(input) {
38 try {
39 return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1].toLowerCase();
40 } catch (e) {
41 return typeof input;
42 }
43 }
44
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.loadInProgress = true;
74 };
75 page.onLoadFinished = function(status) {
76 if (status !== "success") {
77 var message = 'Loading resource failed with status=' + status;
78 if (casper.currentHTTPStatus) {
79 message += ' (HTTP ' + casper.currentHTTPStatus + ')';
80 }
81 message += ': ' + casper.requestUrl;
82 casper.log(message, "warning");
83 if (isType(casper.options.onLoadError, "function")) {
84 casper.options.onLoadError.call(casper, casper, casper.requestUrl, status);
85 }
86 }
87 if (casper.options.clientScripts) {
88 if (betterTypeOf(casper.options.clientScripts) !== "array") {
89 casper.log("The clientScripts option must be an array", "error");
90 } else {
91 for (var i = 0; i < casper.options.clientScripts.length; i++) {
92 var script = casper.options.clientScripts[i];
93 if (casper.page.injectJs(script)) {
94 casper.log('Automatically injected ' + script + ' client side', "debug");
95 } else {
96 casper.log('Failed injecting ' + script + ' client side', "warning");
97 }
98 }
99 }
100 }
101 // Client-side utils injection
102 var injected = page.evaluate(replaceFunctionPlaceholders(function() {
103 eval("var ClientUtils = " + decodeURIComponent("%utils%"));
104 __utils__ = new ClientUtils();
105 return __utils__ instanceof ClientUtils;
106 }, {
107 utils: encodeURIComponent(phantom.Casper.ClientUtils.toString())
108 }));
109 if (!injected) {
110 casper.log("Failed to inject Casper client-side utilities!", "warning");
111 } else {
112 casper.log("Successfully injected Casper client-side utilities", "debug");
113 }
114 // history
115 casper.history.push(casper.getCurrentUrl());
116 casper.loadInProgress = false;
117 };
118 page.onResourceReceived = function(resource) {
119 if (isType(casper.options.onResourceReceived, "function")) {
120 casper.options.onResourceReceived.call(casper, casper, resource);
121 }
122 if (resource.url === casper.requestUrl && resource.stage === "start") {
123 casper.currentHTTPStatus = resource.status;
124 if (isType(casper.options.httpStatusHandlers, "object") && resource.status in casper.options.httpStatusHandlers) {
125 casper.options.httpStatusHandlers[resource.status](casper, resource);
126 }
127 casper.currentUrl = resource.url;
128 }
129 };
130 page.onResourceRequested = function(request) {
131 if (isType(casper.options.onResourceRequested, "function")) {
132 casper.options.onResourceRequested.call(casper, casper, request);
133 }
134 };
135 return page;
136 }
137
138 /**
139 * Shorthands for checking if a value is of the given type. Can check for
140 * arrays.
141 *
142 * @param mixed what The value to check
143 * @param String typeName The type name ("string", "number", "function", etc.)
144 * @return Boolean
145 */
146 function isType(what, typeName) {
147 return betterTypeOf(what) === typeName;
148 }
149
150 /**
151 * Checks if the provided var is a WebPage instance
152 *
153 * @param mixed what
154 * @return Boolean
155 */
156 function isWebPage(what) {
157 if (!what || !isType(what, "object")) {
158 return false;
159 }
160 if (phantom.version.major <= 1 && phantom.version.minor < 3 && isType(require, "function")) {
161 return what instanceof WebPage;
162 } else {
163 return what.toString().indexOf('WebPage(') === 0;
164 }
165 }
166
167 /**
168 * Object recursive merging utility.
169 *
170 * @param Object obj1 the destination object
171 * @param Object obj2 the source object
172 * @return Object
173 */
174 function mergeObjects(obj1, obj2) {
175 for (var p in obj2) {
176 try {
177 if (obj2[p].constructor == Object) {
178 obj1[p] = mergeObjects(obj1[p], obj2[p]);
179 } else {
180 obj1[p] = obj2[p];
181 }
182 } catch(e) {
183 obj1[p] = obj2[p];
184 }
185 }
186 return obj1;
187 }
188
189 /**
190 * Replaces a function string contents with placeholders provided by an
191 * Object.
192 *
193 * @param Function fn The function
194 * @param Object replacements Object containing placeholder replacements
195 * @return String A function string representation
196 */
197 function replaceFunctionPlaceholders(fn, replacements) {
198 if (replacements && isType(replacements, "object")) {
199 fn = fn.toString();
200 for (var placeholder in replacements) {
201 var match = '%' + placeholder + '%';
202 do {
203 fn = fn.replace(match, replacements[placeholder]);
204 } while(fn.indexOf(match) !== -1);
205 }
206 }
207 return fn;
208 }
1 /*!
2 * Casper is a navigation utility for PhantomJS.
3 *
4 * Documentation: http://n1k0.github.com/casperjs/
5 * Repository: http://github.com/n1k0/casperjs
6 *
7 * Copyright (c) 2011 Nicolas Perriault
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 */
28 (function(phantom) {
29 /**
30 * JUnit XML (xUnit) exporter for test results.
31 *
32 */
33 phantom.Casper.XUnitExporter = function() {
34 var node = function(name, attributes) {
35 var node = document.createElement(name);
36 for (var attrName in attributes) {
37 var value = attributes[attrName];
38 if (attributes.hasOwnProperty(attrName) && isType(attrName, "string")) {
39 node.setAttribute(attrName, value);
40 }
41 }
42 return node;
43 };
44
45 var xml = node('testsuite');
46 xml.toString = function() {
47 return this.outerHTML; // ouch
48 };
49
50 /**
51 * Adds a successful test result
52 *
53 * @param String classname
54 * @param String name
55 */
56 this.addSuccess = function(classname, name) {
57 xml.appendChild(node('testcase', {
58 classname: classname,
59 name: name
60 }));
61 };
62
63 /**
64 * Adds a failed test result
65 *
66 * @param String classname
67 * @param String name
68 * @param String message
69 * @param String type
70 */
71 this.addFailure = function(classname, name, message, type) {
72 var fnode = node('testcase', {
73 classname: classname,
74 name: name
75 });
76 var failure = node('failure', {
77 type: type || "unknown"
78 });
79 failure.appendChild(document.createTextNode(message || "no message left"));
80 fnode.appendChild(failure);
81 xml.appendChild(fnode);
82 };
83
84 /**
85 * Retrieves generated XML object - actually an HTMLElement.
86 *
87 * @return HTMLElement
88 */
89 this.getXML = function() {
90 return xml;
91 };
92 };
93 })(phantom);
...\ No newline at end of file ...\ No newline at end of file