refs #26 - code modularization
Showing
8 changed files
with
470 additions
and
0 deletions
This diff is collapsed.
Click to expand it.
lib/casper.js
0 → 100644
This diff is collapsed.
Click to expand it.
lib/clientutils.js
0 → 100644
This diff is collapsed.
Click to expand it.
lib/colorizer.js
0 → 100644
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 |
lib/injector.js
0 → 100644
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 |
lib/tester.js
0 → 100644
This diff is collapsed.
Click to expand it.
lib/utils.js
0 → 100644
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 | } |
lib/xunit.js
0 → 100644
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 |
-
Please register or sign in to post a comment