merged with master
Showing
26 changed files
with
1118 additions
and
703 deletions
1 | CasperJS Changelog | 1 | CasperJS Changelog |
2 | ================== | 2 | ================== |
3 | 3 | ||
4 | XXXX-XX-XX, v0.6.11 | ||
5 | ------------------- | ||
6 | |||
7 | - fixed [#132](https://github.com/n1k0/casperjs/issues/132) - added ability to include js/coffee files using a dedicated option when using the [`casper test` command](http://casperjs.org/testing.html) | ||
8 | - fixed [#140](https://github.com/n1k0/casperjs/issues/140) - `casper test` now resolves local paths urls | ||
9 | - fixed [#148](https://github.com/n1k0/casperjs/issues/148) - [`utils.isWebPage()`](http://casperjs.org/api.html#utils.isWebPage) was broken | ||
10 | - fixed [#149](https://github.com/n1k0/casperjs/issues/149) - [`ClientUtils.fill()`](http://casperjs.org/api.html#casper.fill) was searching elements globally | ||
11 | - fixed [#144](https://github.com/n1k0/casperjs/issues/144) - added a [`safeLogs` option](http://casperjs.org/api.html#casper.options) to blur password values in debug logs. **This option is set to `true` by default.** | ||
12 | - added [`Casper.userAgent()`](http://casperjs.org/api.html#casper.userAgent) to ease a more dynamic setting of user-agent string | ||
13 | - added [`Tester.assertTitleMatch()`](http://casperjs.org/api.html#tester.assertTitleMatch) method | ||
14 | - added experimental support of custom headers sending in outgoing request (refs [#137](https://github.com/n1k0/casperjs/issues/137) - PhantomJS 1.6 required) | ||
15 | - switched to more standard `.textContent` property to get a node text; this allows a better compatibility of the clientutils bookmarklet with non-webkit browsers | ||
16 | - casper modules now all use [javascript strict mode](http://www.nczonline.net/blog/2012/03/13/its-time-to-start-using-javascript-strict-mode/) | ||
17 | |||
4 | 2012-06-04, v0.6.10 | 18 | 2012-06-04, v0.6.10 |
5 | ------------------- | 19 | ------------------- |
6 | 20 | ... | ... |
... | @@ -4,15 +4,15 @@ CasperJS is a navigation scripting & testing utility for [PhantomJS](http://www. | ... | @@ -4,15 +4,15 @@ CasperJS is a navigation scripting & testing utility for [PhantomJS](http://www. |
4 | It eases the process of defining a full navigation scenario and provides useful | 4 | It eases the process of defining a full navigation scenario and provides useful |
5 | high-level functions, methods & syntaxic sugar for doing common tasks such as: | 5 | high-level functions, methods & syntaxic sugar for doing common tasks such as: |
6 | 6 | ||
7 | - defining & ordering [navigation steps](http://casperjs.org/#quickstart) | 7 | - defining & ordering [navigation steps](http://casperjs.org/quickstart.html) |
8 | - [filling forms](http://casperjs.org/#phantom_Casper_fill) | 8 | - [filling forms](http://casperjs.org/api.html#casper.fill) |
9 | - [clicking links](http://casperjs.org/#phantom_Casper_click) | 9 | - [clicking links](http://casperjs.org/api.html#casper.click) |
10 | - [capturing screenshots](http://casperjs.org/#phantom_Casper_captureSelector) of a page (or an area) | 10 | - [capturing screenshots](http://casperjs.org/api.html#casper.captureSelector) of a page (or an area) |
11 | - [making assertions on remote DOM](http://casperjs.org/#phantom_Casper_Tester) | 11 | - [making assertions on remote DOM](http://casperjs.org/api.html#tester) |
12 | - [logging](http://casperjs.org/#logging) & [events](http://casperjs.org/#events-filters) | 12 | - [logging](http://casperjs.org/logging.html) & [events](http://casperjs.org/events-filters.html) |
13 | - [downloading base64](http://casperjs.org/#phantom_Casper_download) encoded resources, even binary ones | 13 | - [downloading base64](http://casperjs.org/api.html#casper.download) encoded resources, even binary ones |
14 | - catching errors and react accordingly | 14 | - catching errors and react accordingly |
15 | - writing [functional test suites](http://casperjs.org/#testing), exporting results as JUnit XML (xUnit) | 15 | - writing [functional test suites](http://casperjs.org/testing.html), exporting results as JUnit XML (xUnit) |
16 | 16 | ||
17 | Browse the [sample examples repository](https://github.com/n1k0/casperjs/tree/master/samples). | 17 | Browse the [sample examples repository](https://github.com/n1k0/casperjs/tree/master/samples). |
18 | Don't hesitate to pull request for any cool example of yours as well! | 18 | Don't hesitate to pull request for any cool example of yours as well! | ... | ... |
... | @@ -27,259 +27,266 @@ | ... | @@ -27,259 +27,266 @@ |
27 | * DEALINGS IN THE SOFTWARE. | 27 | * DEALINGS IN THE SOFTWARE. |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | |||
31 | /*global console phantom require*/ | ||
32 | |||
30 | if (phantom.version.major !== 1 || phantom.version.minor < 5) { | 33 | if (phantom.version.major !== 1 || phantom.version.minor < 5) { |
31 | console.error('CasperJS needs at least PhantomJS v1.5.0'); | 34 | console.error('CasperJS needs at least PhantomJS v1.5.0'); |
32 | phantom.exit(1); | 35 | phantom.exit(1); |
33 | } | 36 | } |
34 | 37 | ||
35 | /** | 38 | (function bootstrap(global) { |
36 | * Loads and initialize the CasperJS environment. | 39 | "use strict"; |
37 | */ | 40 | /** |
38 | phantom.loadCasper = function loadCasper() { | 41 | * Loads and initialize the CasperJS environment. |
39 | // Patching fs | 42 | */ |
40 | // TODO: watch for these methods being implemented in official fs module | 43 | phantom.loadCasper = function loadCasper() { |
41 | var fs = (function _fs(fs) { | 44 | // Patching fs |
42 | if (!fs.hasOwnProperty('basename')) { | 45 | // TODO: watch for these methods being implemented in official fs module |
43 | fs.basename = function basename(path) { | 46 | var fs = (function _fs(fs) { |
44 | return path.replace(/.*\//, ''); | 47 | if (!fs.hasOwnProperty('basename')) { |
45 | }; | 48 | fs.basename = function basename(path) { |
46 | } | 49 | return path.replace(/.*\//, ''); |
47 | if (!fs.hasOwnProperty('dirname')) { | 50 | }; |
48 | fs.dirname = function dirname(path) { | 51 | } |
49 | return path.replace(/\\/g, '/').replace(/\/[^\/]*$/, ''); | 52 | if (!fs.hasOwnProperty('dirname')) { |
50 | }; | 53 | fs.dirname = function dirname(path) { |
51 | } | 54 | return path.replace(/\\/g, '/').replace(/\/[^\/]*$/, ''); |
52 | if (!fs.hasOwnProperty('isWindows')) { | 55 | }; |
53 | fs.isWindows = function isWindows() { | 56 | } |
54 | var testPath = arguments[0] || this.workingDirectory; | 57 | if (!fs.hasOwnProperty('isWindows')) { |
55 | return (/^[a-z]{1,2}:/i).test(testPath) || testPath.indexOf("\\\\") === 0; | 58 | fs.isWindows = function isWindows() { |
56 | }; | 59 | var testPath = arguments[0] || this.workingDirectory; |
57 | } | 60 | return (/^[a-z]{1,2}:/i).test(testPath) || testPath.indexOf("\\\\") === 0; |
58 | if (!fs.hasOwnProperty('pathJoin')) { | 61 | }; |
59 | fs.pathJoin = function pathJoin() { | 62 | } |
60 | return Array.prototype.join.call(arguments, this.separator); | 63 | if (!fs.hasOwnProperty('pathJoin')) { |
61 | }; | 64 | fs.pathJoin = function pathJoin() { |
62 | } | 65 | return Array.prototype.join.call(arguments, this.separator); |
63 | return fs; | 66 | }; |
64 | })(require('fs')); | 67 | } |
65 | 68 | return fs; | |
66 | // casper root path | 69 | })(require('fs')); |
67 | if (!phantom.casperPath) { | ||
68 | try { | ||
69 | phantom.casperPath = phantom.args.map(function _map(i) { | ||
70 | var match = i.match(/^--casper-path=(.*)/); | ||
71 | if (match) { | ||
72 | return fs.absolute(match[1]); | ||
73 | } | ||
74 | }).filter(function _filter(path) { | ||
75 | return fs.isDirectory(path); | ||
76 | }).pop(); | ||
77 | } catch (e) {} | ||
78 | } | ||
79 | |||
80 | if (!phantom.casperPath) { | ||
81 | console.error("Couldn't find nor compute phantom.casperPath, exiting."); | ||
82 | phantom.exit(1); | ||
83 | } | ||
84 | 70 | ||
85 | // Embedded, up-to-date, validatable & controlable CoffeeScript | 71 | // casper root path |
86 | phantom.injectJs(fs.pathJoin(phantom.casperPath, 'modules', 'vendors', 'coffee-script.js')); | 72 | if (!phantom.casperPath) { |
73 | try { | ||
74 | phantom.casperPath = phantom.args.map(function _map(i) { | ||
75 | var match = i.match(/^--casper-path=(.*)/); | ||
76 | if (match) { | ||
77 | return fs.absolute(match[1]); | ||
78 | } | ||
79 | }).filter(function _filter(path) { | ||
80 | return fs.isDirectory(path); | ||
81 | }).pop(); | ||
82 | } catch (e) {} | ||
83 | } | ||
87 | 84 | ||
88 | // custom global CasperError | 85 | if (!phantom.casperPath) { |
89 | window.CasperError = function CasperError(msg) { | 86 | console.error("Couldn't find nor compute phantom.casperPath, exiting."); |
90 | Error.call(this); | 87 | phantom.exit(1); |
91 | try { | ||
92 | // let's get where this error has been thrown from, if we can | ||
93 | this._from = arguments.callee.caller.name; | ||
94 | } catch (e) { | ||
95 | this._from = "anonymous"; | ||
96 | } | 88 | } |
97 | this.message = msg; | ||
98 | this.name = 'CasperError'; | ||
99 | }; | ||
100 | 89 | ||
101 | // standard Error prototype inheritance | 90 | // Embedded, up-to-date, validatable & controlable CoffeeScript |
102 | window.CasperError.prototype = Object.getPrototypeOf(new Error()); | 91 | phantom.injectJs(fs.pathJoin(phantom.casperPath, 'modules', 'vendors', 'coffee-script.js')); |
103 | 92 | ||
104 | // CasperJS version, extracted from package.json - see http://semver.org/ | 93 | // custom global CasperError |
105 | phantom.casperVersion = (function getVersion(path) { | 94 | global.CasperError = function CasperError(msg) { |
106 | var parts, patchPart, pkg, pkgFile; | 95 | Error.call(this); |
107 | var fs = require('fs'); | 96 | try { |
108 | pkgFile = fs.absolute(fs.pathJoin(path, 'package.json')); | 97 | // let's get where this error has been thrown from, if we can |
109 | if (!fs.exists(pkgFile)) { | 98 | this._from = arguments.callee.caller.name; |
110 | throw new CasperError('Cannot find package.json at ' + pkgFile); | 99 | } catch (e) { |
111 | } | 100 | this._from = "anonymous"; |
112 | try { | ||
113 | pkg = JSON.parse(require('fs').read(pkgFile)); | ||
114 | } catch (e) { | ||
115 | throw new CasperError('Cannot read package file contents: ' + e); | ||
116 | } | ||
117 | parts = pkg.version.trim().split("."); | ||
118 | if (parts < 3) { | ||
119 | throw new CasperError("Invalid version number"); | ||
120 | } | ||
121 | patchPart = parts[2].split('-'); | ||
122 | return { | ||
123 | major: ~~parts[0] || 0, | ||
124 | minor: ~~parts[1] || 0, | ||
125 | patch: ~~patchPart[0] || 0, | ||
126 | ident: patchPart[1] || "", | ||
127 | toString: function toString() { | ||
128 | var version = [this.major, this.minor, this.patch].join('.'); | ||
129 | if (this.ident) { | ||
130 | version = [version, this.ident].join('-'); | ||
131 | } | ||
132 | return version; | ||
133 | } | 101 | } |
102 | this.message = msg; | ||
103 | this.name = 'CasperError'; | ||
134 | }; | 104 | }; |
135 | })(phantom.casperPath); | ||
136 | 105 | ||
137 | /** | 106 | // standard Error prototype inheritance |
138 | * Retrieves the javascript source code from a given .js or .coffee file. | 107 | global.CasperError.prototype = Object.getPrototypeOf(new Error()); |
139 | * | ||
140 | * @param String file The path to the file | ||
141 | * @param Function|null onError An error callback (optional) | ||
142 | */ | ||
143 | phantom.getScriptCode = function getScriptCode(file, onError) { | ||
144 | var scriptCode = fs.read(file); | ||
145 | if (/\.coffee$/i.test(file)) { | ||
146 | scriptCode = CoffeeScript.compile(scriptCode); | ||
147 | } | ||
148 | return scriptCode; | ||
149 | }; | ||
150 | 108 | ||
151 | /** | 109 | // CasperJS version, extracted from package.json - see http://semver.org/ |
152 | * Patching require() to allow loading of other modules than PhantomJS' | 110 | phantom.casperVersion = (function getVersion(path) { |
153 | * builtin ones. | 111 | var parts, patchPart, pkg, pkgFile; |
154 | * Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/ | 112 | var fs = require('fs'); |
155 | * TODO: remove when PhantomJS has full module support | 113 | pkgFile = fs.absolute(fs.pathJoin(path, 'package.json')); |
156 | */ | 114 | if (!fs.exists(pkgFile)) { |
157 | require = (function _require(require, requireDir) { | 115 | throw new global.CasperError('Cannot find package.json at ' + pkgFile); |
158 | var phantomBuiltins = ['fs', 'webpage', 'webserver', 'system']; | ||
159 | var phantomRequire = phantom.__orig__require = require; | ||
160 | var requireCache = {}; | ||
161 | return function _require(path) { | ||
162 | var i, dir, paths = [], | ||
163 | fileGuesses = [], | ||
164 | file, | ||
165 | module = { | ||
166 | exports: {} | ||
167 | }; | ||
168 | if (phantomBuiltins.indexOf(path) !== -1) { | ||
169 | return phantomRequire(path); | ||
170 | } | ||
171 | if (path[0] === '.') { | ||
172 | paths.push.apply(paths, [ | ||
173 | fs.absolute(path), | ||
174 | fs.absolute(fs.pathJoin(requireDir, path)) | ||
175 | ]); | ||
176 | } else if (path[0] === '/') { | ||
177 | paths.push(path); | ||
178 | } else { | ||
179 | dir = fs.absolute(requireDir); | ||
180 | while (dir !== '' && dir.lastIndexOf(':') !== dir.length - 1) { | ||
181 | // nodejs compatibility | ||
182 | paths.push(fs.pathJoin(dir, 'node_modules', path)); | ||
183 | dir = fs.dirname(dir); | ||
184 | } | ||
185 | paths.push(fs.pathJoin(requireDir, 'lib', path)); | ||
186 | paths.push(fs.pathJoin(requireDir, 'modules', path)); | ||
187 | } | ||
188 | paths.forEach(function _forEach(testPath) { | ||
189 | fileGuesses.push.apply(fileGuesses, [ | ||
190 | testPath, | ||
191 | testPath + '.js', | ||
192 | testPath + '.coffee', | ||
193 | fs.pathJoin(testPath, 'index.js'), | ||
194 | fs.pathJoin(testPath, 'index.coffee'), | ||
195 | fs.pathJoin(testPath, 'lib', fs.basename(testPath) + '.js'), | ||
196 | fs.pathJoin(testPath, 'lib', fs.basename(testPath) + '.coffee') | ||
197 | ]); | ||
198 | }); | ||
199 | file = null; | ||
200 | for (i = 0; i < fileGuesses.length && !file; ++i) { | ||
201 | if (fs.isFile(fileGuesses[i])) { | ||
202 | file = fileGuesses[i]; | ||
203 | } | ||
204 | } | ||
205 | if (!file) { | ||
206 | throw new Error("CasperJS couldn't find module " + path); | ||
207 | } | ||
208 | if (file in requireCache) { | ||
209 | return requireCache[file].exports; | ||
210 | } | 116 | } |
211 | var scriptCode = phantom.getScriptCode(file); | ||
212 | var fn = new Function('__file__', 'require', 'module', 'exports', scriptCode); | ||
213 | try { | 117 | try { |
214 | fn(file, _require, module, module.exports); | 118 | pkg = JSON.parse(require('fs').read(pkgFile)); |
215 | } catch (e) { | 119 | } catch (e) { |
216 | var error = new CasperError('__mod_error(' + path + '):: ' + e); | 120 | throw new global.CasperError('Cannot read package file contents: ' + e); |
217 | error.file = file; | ||
218 | throw error; | ||
219 | } | 121 | } |
220 | requireCache[file] = module; | 122 | parts = pkg.version.trim().split("."); |
221 | return module.exports; | 123 | if (parts < 3) { |
124 | throw new global.CasperError("Invalid version number"); | ||
125 | } | ||
126 | patchPart = parts[2].split('-'); | ||
127 | return { | ||
128 | major: ~~parts[0] || 0, | ||
129 | minor: ~~parts[1] || 0, | ||
130 | patch: ~~patchPart[0] || 0, | ||
131 | ident: patchPart[1] || "", | ||
132 | toString: function toString() { | ||
133 | var version = [this.major, this.minor, this.patch].join('.'); | ||
134 | if (this.ident) { | ||
135 | version = [version, this.ident].join('-'); | ||
136 | } | ||
137 | return version; | ||
138 | } | ||
139 | }; | ||
140 | })(phantom.casperPath); | ||
141 | |||
142 | /** | ||
143 | * Retrieves the javascript source code from a given .js or .coffee file. | ||
144 | * | ||
145 | * @param String file The path to the file | ||
146 | * @param Function|null onError An error callback (optional) | ||
147 | */ | ||
148 | phantom.getScriptCode = function getScriptCode(file, onError) { | ||
149 | var scriptCode = fs.read(file); | ||
150 | if (/\.coffee$/i.test(file)) { | ||
151 | /*global CoffeeScript*/ | ||
152 | scriptCode = CoffeeScript.compile(scriptCode); | ||
153 | } | ||
154 | return scriptCode; | ||
222 | }; | 155 | }; |
223 | })(require, phantom.casperPath); | ||
224 | 156 | ||
225 | // BC < 0.6 | 157 | /** |
226 | phantom.Casper = require('casper').Casper; | 158 | * Patching require() to allow loading of other modules than PhantomJS' |
159 | * builtin ones. | ||
160 | * Inspired by phantomjs-nodify: https://github.com/jgonera/phantomjs-nodify/ | ||
161 | * TODO: remove when PhantomJS has full module support | ||
162 | */ | ||
163 | require = (function _require(require, requireDir) { | ||
164 | var phantomBuiltins = ['fs', 'webpage', 'webserver', 'system']; | ||
165 | var phantomRequire = phantom.__orig__require = require; | ||
166 | var requireCache = {}; | ||
167 | return function _require(path) { | ||
168 | var i, dir, paths = [], | ||
169 | fileGuesses = [], | ||
170 | file, | ||
171 | module = { | ||
172 | exports: {} | ||
173 | }; | ||
174 | if (phantomBuiltins.indexOf(path) !== -1) { | ||
175 | return phantomRequire(path); | ||
176 | } | ||
177 | if (path[0] === '.') { | ||
178 | paths.push.apply(paths, [ | ||
179 | fs.absolute(path), | ||
180 | fs.absolute(fs.pathJoin(requireDir, path)) | ||
181 | ]); | ||
182 | } else if (path[0] === '/') { | ||
183 | paths.push(path); | ||
184 | } else { | ||
185 | dir = fs.absolute(requireDir); | ||
186 | while (dir !== '' && dir.lastIndexOf(':') !== dir.length - 1) { | ||
187 | // nodejs compatibility | ||
188 | paths.push(fs.pathJoin(dir, 'node_modules', path)); | ||
189 | dir = fs.dirname(dir); | ||
190 | } | ||
191 | paths.push(fs.pathJoin(requireDir, 'lib', path)); | ||
192 | paths.push(fs.pathJoin(requireDir, 'modules', path)); | ||
193 | } | ||
194 | paths.forEach(function _forEach(testPath) { | ||
195 | fileGuesses.push.apply(fileGuesses, [ | ||
196 | testPath, | ||
197 | testPath + '.js', | ||
198 | testPath + '.coffee', | ||
199 | fs.pathJoin(testPath, 'index.js'), | ||
200 | fs.pathJoin(testPath, 'index.coffee'), | ||
201 | fs.pathJoin(testPath, 'lib', fs.basename(testPath) + '.js'), | ||
202 | fs.pathJoin(testPath, 'lib', fs.basename(testPath) + '.coffee') | ||
203 | ]); | ||
204 | }); | ||
205 | file = null; | ||
206 | for (i = 0; i < fileGuesses.length && !file; ++i) { | ||
207 | if (fs.isFile(fileGuesses[i])) { | ||
208 | file = fileGuesses[i]; | ||
209 | } | ||
210 | } | ||
211 | if (!file) { | ||
212 | throw new Error("CasperJS couldn't find module " + path); | ||
213 | } | ||
214 | if (file in requireCache) { | ||
215 | return requireCache[file].exports; | ||
216 | } | ||
217 | var scriptCode = phantom.getScriptCode(file); | ||
218 | var fn = new Function('__file__', 'require', 'module', 'exports', scriptCode); | ||
219 | try { | ||
220 | fn(file, _require, module, module.exports); | ||
221 | } catch (e) { | ||
222 | var error = new global.CasperError('__mod_error(' + path + '):: ' + e); | ||
223 | error.file = file; | ||
224 | throw error; | ||
225 | } | ||
226 | requireCache[file] = module; | ||
227 | return module.exports; | ||
228 | }; | ||
229 | })(require, phantom.casperPath); | ||
227 | 230 | ||
228 | // casper cli args | 231 | // BC < 0.6 |
229 | phantom.casperArgs = require('cli').parse(phantom.args); | 232 | phantom.Casper = require('casper').Casper; |
230 | 233 | ||
231 | // loaded status | 234 | // casper cli args |
232 | phantom.casperLoaded = true; | 235 | phantom.casperArgs = require('cli').parse(phantom.args); |
233 | }; | ||
234 | 236 | ||
235 | /** | 237 | // loaded status |
236 | * Initializes the CasperJS Command Line Interface. | 238 | phantom.casperLoaded = true; |
237 | */ | 239 | }; |
238 | phantom.initCasperCli = function initCasperCli() { | ||
239 | var fs = require("fs"); | ||
240 | 240 | ||
241 | if (!!phantom.casperArgs.options.version) { | 241 | /** |
242 | console.log(phantom.casperVersion.toString()); | 242 | * Initializes the CasperJS Command Line Interface. |
243 | phantom.exit(0); | 243 | */ |
244 | } else if (phantom.casperArgs.get(0) === "test") { | 244 | phantom.initCasperCli = function initCasperCli() { |
245 | phantom.casperScript = fs.absolute(fs.pathJoin(phantom.casperPath, 'tests', 'run.js')); | 245 | var fs = require("fs"); |
246 | phantom.casperArgs.drop("test"); | ||
247 | } else if (phantom.casperArgs.args.length === 0 || !!phantom.casperArgs.options.help) { | ||
248 | var phantomVersion = [phantom.version.major, phantom.version.minor, phantom.version.patch].join('.'); | ||
249 | var f = require("utils").format; | ||
250 | console.log(f('CasperJS version %s at %s, using PhantomJS version %s', | ||
251 | phantom.casperVersion.toString(), | ||
252 | phantom.casperPath, phantomVersion)); | ||
253 | console.log(fs.read(fs.pathJoin(phantom.casperPath, 'bin', 'usage.txt'))); | ||
254 | phantom.exit(0); | ||
255 | } | ||
256 | 246 | ||
247 | if (!!phantom.casperArgs.options.version) { | ||
248 | console.log(phantom.casperVersion.toString()); | ||
249 | phantom.exit(0); | ||
250 | } else if (phantom.casperArgs.get(0) === "test") { | ||
251 | phantom.casperScript = fs.absolute(fs.pathJoin(phantom.casperPath, 'tests', 'run.js')); | ||
252 | phantom.casperArgs.drop("test"); | ||
253 | } else if (phantom.casperArgs.args.length === 0 || !!phantom.casperArgs.options.help) { | ||
254 | var phantomVersion = [phantom.version.major, phantom.version.minor, phantom.version.patch].join('.'); | ||
255 | var f = require("utils").format; | ||
256 | console.log(f('CasperJS version %s at %s, using PhantomJS version %s', | ||
257 | phantom.casperVersion.toString(), | ||
258 | phantom.casperPath, phantomVersion)); | ||
259 | console.log(fs.read(fs.pathJoin(phantom.casperPath, 'bin', 'usage.txt'))); | ||
260 | phantom.exit(0); | ||
261 | } | ||
257 | 262 | ||
258 | if (!phantom.casperScript) { | ||
259 | phantom.casperScript = phantom.casperArgs.get(0); | ||
260 | } | ||
261 | 263 | ||
262 | if (!fs.isFile(phantom.casperScript)) { | 264 | if (!phantom.casperScript) { |
263 | console.error('Unable to open file: ' + phantom.casperScript); | 265 | phantom.casperScript = phantom.casperArgs.get(0); |
264 | phantom.exit(1); | 266 | } |
265 | } | ||
266 | 267 | ||
267 | // filter out the called script name from casper args | 268 | if (!fs.isFile(phantom.casperScript)) { |
268 | phantom.casperArgs.drop(phantom.casperScript); | 269 | console.error('Unable to open file: ' + phantom.casperScript); |
270 | phantom.exit(1); | ||
271 | } | ||
269 | 272 | ||
270 | // passed casperjs script execution | 273 | // filter out the called script name from casper args |
271 | phantom.injectJs(phantom.casperScript); | 274 | phantom.casperArgs.drop(phantom.casperScript); |
272 | }; | ||
273 | 275 | ||
274 | if (!phantom.casperLoaded) { | 276 | // passed casperjs script execution |
275 | try { | 277 | phantom.injectJs(phantom.casperScript); |
276 | phantom.loadCasper(); | 278 | }; |
277 | } catch (e) { | 279 | |
278 | console.error("Unable to load casper environment: " + e); | 280 | if (!phantom.casperLoaded) { |
279 | phantom.exit(); | 281 | try { |
282 | phantom.loadCasper(); | ||
283 | } catch (e) { | ||
284 | console.error("Unable to load casper environment: " + e); | ||
285 | phantom.exit(); | ||
286 | } | ||
280 | } | 287 | } |
281 | } | ||
282 | 288 | ||
283 | if (true === phantom.casperArgs.get('cli')) { | 289 | if (true === phantom.casperArgs.get('cli')) { |
284 | phantom.initCasperCli(); | 290 | phantom.initCasperCli(); |
285 | } | 291 | } |
292 | })(window); | ... | ... |
... | @@ -48,6 +48,6 @@ CASPER_COMMAND.extend(CASPER_ARGS) | ... | @@ -48,6 +48,6 @@ CASPER_COMMAND.extend(CASPER_ARGS) |
48 | 48 | ||
49 | try: | 49 | try: |
50 | os.execvp(CASPER_COMMAND[0], CASPER_COMMAND) | 50 | os.execvp(CASPER_COMMAND[0], CASPER_COMMAND) |
51 | except OSError, err: | 51 | except OSError as err: |
52 | print('Fatal: %s; did you install phantomjs?' % err) | 52 | print(('Fatal: %s; did you install phantomjs?' % err)) |
53 | sys.exit(1) | 53 | sys.exit(1) | ... | ... |
... | @@ -28,6 +28,8 @@ | ... | @@ -28,6 +28,8 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /*global CasperError console exports phantom require*/ | ||
32 | |||
31 | var colorizer = require('colorizer'); | 33 | var colorizer = require('colorizer'); |
32 | var events = require('events'); | 34 | var events = require('events'); |
33 | var fs = require('fs'); | 35 | var fs = require('fs'); |
... | @@ -37,11 +39,24 @@ var tester = require('tester'); | ... | @@ -37,11 +39,24 @@ var tester = require('tester'); |
37 | var utils = require('utils'); | 39 | var utils = require('utils'); |
38 | var f = utils.format; | 40 | var f = utils.format; |
39 | 41 | ||
42 | |||
43 | var defaultUserAgent = phantom.defaultPageSettings.userAgent | ||
44 | .replace('PhantomJS', f("CasperJS/%s", phantom.casperVersion) + '+Phantomjs'); | ||
45 | |||
40 | exports.create = function create(options) { | 46 | exports.create = function create(options) { |
47 | "use strict"; | ||
41 | return new Casper(options); | 48 | return new Casper(options); |
42 | }; | 49 | }; |
43 | 50 | ||
44 | exports.selectXPath = function selectXPath(expression) { | 51 | /** |
52 | * Shortcut to build an XPath selector object. | ||
53 | * | ||
54 | * @param String expression The XPath expression | ||
55 | * @return Object | ||
56 | * @see http://casperjs.org/selectors.html | ||
57 | */ | ||
58 | function selectXPath(expression) { | ||
59 | "use strict"; | ||
45 | return { | 60 | return { |
46 | type: 'xpath', | 61 | type: 'xpath', |
47 | path: expression, | 62 | path: expression, |
... | @@ -49,7 +64,8 @@ exports.selectXPath = function selectXPath(expression) { | ... | @@ -49,7 +64,8 @@ exports.selectXPath = function selectXPath(expression) { |
49 | return this.type + ' selector: ' + this.path; | 64 | return this.type + ' selector: ' + this.path; |
50 | } | 65 | } |
51 | }; | 66 | }; |
52 | }; | 67 | } |
68 | exports.selectXPath = selectXPath; | ||
53 | 69 | ||
54 | /** | 70 | /** |
55 | * Main Casper object. | 71 | * Main Casper object. |
... | @@ -57,10 +73,9 @@ exports.selectXPath = function selectXPath(expression) { | ... | @@ -57,10 +73,9 @@ exports.selectXPath = function selectXPath(expression) { |
57 | * @param Object options Casper options | 73 | * @param Object options Casper options |
58 | */ | 74 | */ |
59 | var Casper = function Casper(options) { | 75 | var Casper = function Casper(options) { |
60 | var DEFAULT_DIE_MESSAGE = "Suite explicitely interrupted without any message given."; | 76 | "use strict"; |
61 | var DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1"; | ||
62 | // init & checks | 77 | // init & checks |
63 | if (!(this instanceof arguments.callee)) { | 78 | if (!(this instanceof Casper)) { |
64 | return new Casper(options); | 79 | return new Casper(options); |
65 | } | 80 | } |
66 | // default options | 81 | // default options |
... | @@ -70,6 +85,7 @@ var Casper = function Casper(options) { | ... | @@ -70,6 +85,7 @@ var Casper = function Casper(options) { |
70 | exitOnError: true, | 85 | exitOnError: true, |
71 | logLevel: "error", | 86 | logLevel: "error", |
72 | httpStatusHandlers: {}, | 87 | httpStatusHandlers: {}, |
88 | safeLogs: true, | ||
73 | onAlert: null, | 89 | onAlert: null, |
74 | onDie: null, | 90 | onDie: null, |
75 | onError: null, | 91 | onError: null, |
... | @@ -83,7 +99,7 @@ var Casper = function Casper(options) { | ... | @@ -83,7 +99,7 @@ var Casper = function Casper(options) { |
83 | page: null, | 99 | page: null, |
84 | pageSettings: { | 100 | pageSettings: { |
85 | localToRemoteUrlAccessEnabled: true, | 101 | localToRemoteUrlAccessEnabled: true, |
86 | userAgent: DEFAULT_USER_AGENT | 102 | userAgent: defaultUserAgent |
87 | }, | 103 | }, |
88 | stepTimeout: null, | 104 | stepTimeout: null, |
89 | timeout: null, | 105 | timeout: null, |
... | @@ -150,7 +166,7 @@ var Casper = function Casper(options) { | ... | @@ -150,7 +166,7 @@ var Casper = function Casper(options) { |
150 | 166 | ||
151 | // deprecated feature event handler | 167 | // deprecated feature event handler |
152 | this.on('deprecated', function onDeprecated(message) { | 168 | this.on('deprecated', function onDeprecated(message) { |
153 | this.echo('[deprecated] ' + message, 'COMMENT'); | 169 | this.warn('[deprecated] ' + message); |
154 | }); | 170 | }); |
155 | 171 | ||
156 | // dispatching an event when instance has been constructed | 172 | // dispatching an event when instance has been constructed |
... | @@ -166,6 +182,7 @@ utils.inherits(Casper, events.EventEmitter); | ... | @@ -166,6 +182,7 @@ utils.inherits(Casper, events.EventEmitter); |
166 | * @return Casper | 182 | * @return Casper |
167 | */ | 183 | */ |
168 | Casper.prototype.back = function back() { | 184 | Casper.prototype.back = function back() { |
185 | "use strict"; | ||
169 | return this.then(function _step() { | 186 | return this.then(function _step() { |
170 | this.emit('back'); | 187 | this.emit('back'); |
171 | this.evaluate(function _evaluate() { | 188 | this.evaluate(function _evaluate() { |
... | @@ -186,8 +203,9 @@ Casper.prototype.back = function back() { | ... | @@ -186,8 +203,9 @@ Casper.prototype.back = function back() { |
186 | * @return string Base64 encoded result | 203 | * @return string Base64 encoded result |
187 | */ | 204 | */ |
188 | Casper.prototype.base64encode = function base64encode(url, method, data) { | 205 | Casper.prototype.base64encode = function base64encode(url, method, data) { |
206 | "use strict"; | ||
189 | return this.evaluate(function _evaluate(url, method, data) { | 207 | return this.evaluate(function _evaluate(url, method, data) { |
190 | return __utils__.getBase64(url, method, data); | 208 | return window.__utils__.getBase64(url, method, data); |
191 | }, { url: url, method: method, data: data }); | 209 | }, { url: url, method: method, data: data }); |
192 | }; | 210 | }; |
193 | 211 | ||
... | @@ -202,6 +220,7 @@ Casper.prototype.base64encode = function base64encode(url, method, data) { | ... | @@ -202,6 +220,7 @@ Casper.prototype.base64encode = function base64encode(url, method, data) { |
202 | * @return Casper | 220 | * @return Casper |
203 | */ | 221 | */ |
204 | Casper.prototype.capture = function capture(targetFile, clipRect) { | 222 | Casper.prototype.capture = function capture(targetFile, clipRect) { |
223 | "use strict"; | ||
205 | var previousClipRect; | 224 | var previousClipRect; |
206 | targetFile = fs.absolute(targetFile); | 225 | targetFile = fs.absolute(targetFile); |
207 | if (clipRect) { | 226 | if (clipRect) { |
... | @@ -234,6 +253,7 @@ Casper.prototype.capture = function capture(targetFile, clipRect) { | ... | @@ -234,6 +253,7 @@ Casper.prototype.capture = function capture(targetFile, clipRect) { |
234 | * @return Casper | 253 | * @return Casper |
235 | */ | 254 | */ |
236 | Casper.prototype.captureSelector = function captureSelector(targetFile, selector) { | 255 | Casper.prototype.captureSelector = function captureSelector(targetFile, selector) { |
256 | "use strict"; | ||
237 | return this.capture(targetFile, this.getElementBounds(selector)); | 257 | return this.capture(targetFile, this.getElementBounds(selector)); |
238 | }; | 258 | }; |
239 | 259 | ||
... | @@ -244,6 +264,7 @@ Casper.prototype.captureSelector = function captureSelector(targetFile, selector | ... | @@ -244,6 +264,7 @@ Casper.prototype.captureSelector = function captureSelector(targetFile, selector |
244 | * @param function onComplete An options callback to apply on completion | 264 | * @param function onComplete An options callback to apply on completion |
245 | */ | 265 | */ |
246 | Casper.prototype.checkStep = function checkStep(self, onComplete) { | 266 | Casper.prototype.checkStep = function checkStep(self, onComplete) { |
267 | "use strict"; | ||
247 | if (self.pendingWait || self.loadInProgress) { | 268 | if (self.pendingWait || self.loadInProgress) { |
248 | return; | 269 | return; |
249 | } | 270 | } |
... | @@ -274,6 +295,7 @@ Casper.prototype.checkStep = function checkStep(self, onComplete) { | ... | @@ -274,6 +295,7 @@ Casper.prototype.checkStep = function checkStep(self, onComplete) { |
274 | * @return Casper | 295 | * @return Casper |
275 | */ | 296 | */ |
276 | Casper.prototype.clear = function clear() { | 297 | Casper.prototype.clear = function clear() { |
298 | "use strict"; | ||
277 | this.page.content = ''; | 299 | this.page.content = ''; |
278 | return this; | 300 | return this; |
279 | }; | 301 | }; |
... | @@ -288,6 +310,7 @@ Casper.prototype.clear = function clear() { | ... | @@ -288,6 +310,7 @@ Casper.prototype.clear = function clear() { |
288 | * @return Boolean | 310 | * @return Boolean |
289 | */ | 311 | */ |
290 | Casper.prototype.click = function click(selector) { | 312 | Casper.prototype.click = function click(selector) { |
313 | "use strict"; | ||
291 | return this.mouseEvent('click', selector); | 314 | return this.mouseEvent('click', selector); |
292 | }; | 315 | }; |
293 | 316 | ||
... | @@ -296,10 +319,14 @@ Casper.prototype.click = function click(selector) { | ... | @@ -296,10 +319,14 @@ Casper.prototype.click = function click(selector) { |
296 | * element matching this label will be selected, so use with caution. | 319 | * element matching this label will be selected, so use with caution. |
297 | * | 320 | * |
298 | * @param String label Element innerText value | 321 | * @param String label Element innerText value |
322 | * @param String tag An element tag name (eg. `a` or `button`) (optional) | ||
299 | * @return Boolean | 323 | * @return Boolean |
300 | */ | 324 | */ |
301 | Casper.prototype.clickLabel = function clickLabel(label) { | 325 | Casper.prototype.clickLabel = function clickLabel(label, tag) { |
302 | var selector = exports.selectXPath('//*[text()="' + label.toString() + '"]'); | 326 | "use strict"; |
327 | tag = tag || "*"; | ||
328 | var escapedLabel = label.toString().replace(/"/g, '\\"'); | ||
329 | var selector = selectXPath(f('//%s[text()="%s"]', tag, escapedLabel)); | ||
303 | return this.click(selector); | 330 | return this.click(selector); |
304 | }; | 331 | }; |
305 | 332 | ||
... | @@ -311,6 +338,7 @@ Casper.prototype.clickLabel = function clickLabel(label) { | ... | @@ -311,6 +338,7 @@ Casper.prototype.clickLabel = function clickLabel(label) { |
311 | * @return Function The final step function | 338 | * @return Function The final step function |
312 | */ | 339 | */ |
313 | Casper.prototype.createStep = function createStep(fn, options) { | 340 | Casper.prototype.createStep = function createStep(fn, options) { |
341 | "use strict"; | ||
314 | if (!utils.isFunction(fn)) { | 342 | if (!utils.isFunction(fn)) { |
315 | throw new CasperError("createStep(): a step definition must be a function"); | 343 | throw new CasperError("createStep(): a step definition must be a function"); |
316 | } | 344 | } |
... | @@ -325,6 +353,7 @@ Casper.prototype.createStep = function createStep(fn, options) { | ... | @@ -325,6 +353,7 @@ Casper.prototype.createStep = function createStep(fn, options) { |
325 | * @return Casper | 353 | * @return Casper |
326 | */ | 354 | */ |
327 | Casper.prototype.debugHTML = function debugHTML() { | 355 | Casper.prototype.debugHTML = function debugHTML() { |
356 | "use strict"; | ||
328 | this.echo(this.page.content); | 357 | this.echo(this.page.content); |
329 | return this; | 358 | return this; |
330 | }; | 359 | }; |
... | @@ -335,8 +364,9 @@ Casper.prototype.debugHTML = function debugHTML() { | ... | @@ -335,8 +364,9 @@ Casper.prototype.debugHTML = function debugHTML() { |
335 | * @return Casper | 364 | * @return Casper |
336 | */ | 365 | */ |
337 | Casper.prototype.debugPage = function debugPage() { | 366 | Casper.prototype.debugPage = function debugPage() { |
367 | "use strict"; | ||
338 | this.echo(this.evaluate(function _evaluate() { | 368 | this.echo(this.evaluate(function _evaluate() { |
339 | return document.body.innerText; | 369 | return document.body.textContent || document.body.innerText; |
340 | })); | 370 | })); |
341 | return this; | 371 | return this; |
342 | }; | 372 | }; |
... | @@ -349,9 +379,12 @@ Casper.prototype.debugPage = function debugPage() { | ... | @@ -349,9 +379,12 @@ Casper.prototype.debugPage = function debugPage() { |
349 | * @return Casper | 379 | * @return Casper |
350 | */ | 380 | */ |
351 | Casper.prototype.die = function die(message, status) { | 381 | Casper.prototype.die = function die(message, status) { |
382 | "use strict"; | ||
352 | this.result.status = "error"; | 383 | this.result.status = "error"; |
353 | this.result.time = new Date().getTime() - this.startTime; | 384 | this.result.time = new Date().getTime() - this.startTime; |
354 | message = utils.isString(message) && message.length > 0 ? message : DEFAULT_DIE_MESSAGE; | 385 | if (!utils.isString(message) || !message.length) { |
386 | message = "Suite explicitely interrupted without any message given."; | ||
387 | } | ||
355 | this.log(message, "error"); | 388 | this.log(message, "error"); |
356 | this.emit('die', message, status); | 389 | this.emit('die', message, status); |
357 | if (utils.isFunction(this.options.onDie)) { | 390 | if (utils.isFunction(this.options.onDie)) { |
... | @@ -365,10 +398,13 @@ Casper.prototype.die = function die(message, status) { | ... | @@ -365,10 +398,13 @@ Casper.prototype.die = function die(message, status) { |
365 | * | 398 | * |
366 | * @param String url The url of the resource to download | 399 | * @param String url The url of the resource to download |
367 | * @param String targetPath The destination file path | 400 | * @param String targetPath The destination file path |
401 | * @param String method The HTTP method to use (default: GET) | ||
402 | * @param String data Optional data to pass performing the request | ||
368 | * @return Casper | 403 | * @return Casper |
369 | */ | 404 | */ |
370 | Casper.prototype.download = function download(url, targetPath, method, data) { | 405 | Casper.prototype.download = function download(url, targetPath, method, data) { |
371 | var cu = require('clientutils').create(); | 406 | "use strict"; |
407 | var cu = require('clientutils').create(this.options); | ||
372 | try { | 408 | try { |
373 | fs.write(targetPath, cu.decode(this.base64encode(url, method, data)), 'wb'); | 409 | fs.write(targetPath, cu.decode(this.base64encode(url, method, data)), 'wb'); |
374 | this.emit('downloaded.file', targetPath); | 410 | this.emit('downloaded.file', targetPath); |
... | @@ -388,6 +424,7 @@ Casper.prototype.download = function download(url, targetPath, method, data) { | ... | @@ -388,6 +424,7 @@ Casper.prototype.download = function download(url, targetPath, method, data) { |
388 | * @return Casper | 424 | * @return Casper |
389 | */ | 425 | */ |
390 | Casper.prototype.each = function each(array, fn) { | 426 | Casper.prototype.each = function each(array, fn) { |
427 | "use strict"; | ||
391 | if (!utils.isArray(array)) { | 428 | if (!utils.isArray(array)) { |
392 | this.log("each() only works with arrays", "error"); | 429 | this.log("each() only works with arrays", "error"); |
393 | return this; | 430 | return this; |
... | @@ -409,6 +446,7 @@ Casper.prototype.each = function each(array, fn) { | ... | @@ -409,6 +446,7 @@ Casper.prototype.each = function each(array, fn) { |
409 | * @return Casper | 446 | * @return Casper |
410 | */ | 447 | */ |
411 | Casper.prototype.echo = function echo(text, style, pad) { | 448 | Casper.prototype.echo = function echo(text, style, pad) { |
449 | "use strict"; | ||
412 | var message = style ? this.colorizer.colorize(text, style, pad) : text; | 450 | var message = style ? this.colorizer.colorize(text, style, pad) : text; |
413 | console.log(this.filter('echo.message', message) || message); | 451 | console.log(this.filter('echo.message', message) || message); |
414 | return this; | 452 | return this; |
... | @@ -438,6 +476,7 @@ Casper.prototype.echo = function echo(text, style, pad) { | ... | @@ -438,6 +476,7 @@ Casper.prototype.echo = function echo(text, style, pad) { |
438 | * @see WebPage#evaluate | 476 | * @see WebPage#evaluate |
439 | */ | 477 | */ |
440 | Casper.prototype.evaluate = function evaluate(fn, context) { | 478 | Casper.prototype.evaluate = function evaluate(fn, context) { |
479 | "use strict"; | ||
441 | // ensure client utils are always injected | 480 | // ensure client utils are always injected |
442 | this.injectClientUtils(); | 481 | this.injectClientUtils(); |
443 | // function processing | 482 | // function processing |
... | @@ -455,6 +494,7 @@ Casper.prototype.evaluate = function evaluate(fn, context) { | ... | @@ -455,6 +494,7 @@ Casper.prototype.evaluate = function evaluate(fn, context) { |
455 | * @return Casper | 494 | * @return Casper |
456 | */ | 495 | */ |
457 | Casper.prototype.evaluateOrDie = function evaluateOrDie(fn, message) { | 496 | Casper.prototype.evaluateOrDie = function evaluateOrDie(fn, message) { |
497 | "use strict"; | ||
458 | if (!this.evaluate(fn)) { | 498 | if (!this.evaluate(fn)) { |
459 | return this.die(message); | 499 | return this.die(message); |
460 | } | 500 | } |
... | @@ -469,8 +509,9 @@ Casper.prototype.evaluateOrDie = function evaluateOrDie(fn, message) { | ... | @@ -469,8 +509,9 @@ Casper.prototype.evaluateOrDie = function evaluateOrDie(fn, message) { |
469 | * @return Boolean | 509 | * @return Boolean |
470 | */ | 510 | */ |
471 | Casper.prototype.exists = function exists(selector) { | 511 | Casper.prototype.exists = function exists(selector) { |
512 | "use strict"; | ||
472 | return this.evaluate(function _evaluate(selector) { | 513 | return this.evaluate(function _evaluate(selector) { |
473 | return __utils__.exists(selector); | 514 | return window.__utils__.exists(selector); |
474 | }, { selector: selector }); | 515 | }, { selector: selector }); |
475 | }; | 516 | }; |
476 | 517 | ||
... | @@ -481,6 +522,7 @@ Casper.prototype.exists = function exists(selector) { | ... | @@ -481,6 +522,7 @@ Casper.prototype.exists = function exists(selector) { |
481 | * @return Casper | 522 | * @return Casper |
482 | */ | 523 | */ |
483 | Casper.prototype.exit = function exit(status) { | 524 | Casper.prototype.exit = function exit(status) { |
525 | "use strict"; | ||
484 | this.emit('exit', status); | 526 | this.emit('exit', status); |
485 | phantom.exit(status); | 527 | phantom.exit(status); |
486 | return this; | 528 | return this; |
... | @@ -494,8 +536,9 @@ Casper.prototype.exit = function exit(status) { | ... | @@ -494,8 +536,9 @@ Casper.prototype.exit = function exit(status) { |
494 | * @return String | 536 | * @return String |
495 | */ | 537 | */ |
496 | Casper.prototype.fetchText = function fetchText(selector) { | 538 | Casper.prototype.fetchText = function fetchText(selector) { |
539 | "use strict"; | ||
497 | return this.evaluate(function _evaluate(selector) { | 540 | return this.evaluate(function _evaluate(selector) { |
498 | return __utils__.fetchText(selector); | 541 | return window.__utils__.fetchText(selector); |
499 | }, { selector: selector }); | 542 | }, { selector: selector }); |
500 | }; | 543 | }; |
501 | 544 | ||
... | @@ -507,13 +550,14 @@ Casper.prototype.fetchText = function fetchText(selector) { | ... | @@ -507,13 +550,14 @@ Casper.prototype.fetchText = function fetchText(selector) { |
507 | * @param Boolean submit Submit the form? | 550 | * @param Boolean submit Submit the form? |
508 | */ | 551 | */ |
509 | Casper.prototype.fill = function fill(selector, vals, submit) { | 552 | Casper.prototype.fill = function fill(selector, vals, submit) { |
553 | "use strict"; | ||
510 | submit = submit === true ? submit : false; | 554 | submit = submit === true ? submit : false; |
511 | if (!utils.isObject(vals)) { | 555 | if (!utils.isObject(vals)) { |
512 | throw new CasperError("Form values must be provided as an object"); | 556 | throw new CasperError("Form values must be provided as an object"); |
513 | } | 557 | } |
514 | this.emit('fill', selector, vals, submit); | 558 | this.emit('fill', selector, vals, submit); |
515 | var fillResults = this.evaluate(function _evaluate(selector, values) { | 559 | var fillResults = this.evaluate(function _evaluate(selector, values) { |
516 | return __utils__.fill(selector, values); | 560 | return window.__utils__.fill(selector, values); |
517 | }, { | 561 | }, { |
518 | selector: selector, | 562 | selector: selector, |
519 | values: vals | 563 | values: vals |
... | @@ -548,10 +592,10 @@ Casper.prototype.fill = function fill(selector, vals, submit) { | ... | @@ -548,10 +592,10 @@ Casper.prototype.fill = function fill(selector, vals, submit) { |
548 | // Form submission? | 592 | // Form submission? |
549 | if (submit) { | 593 | if (submit) { |
550 | this.evaluate(function _evaluate(selector) { | 594 | this.evaluate(function _evaluate(selector) { |
551 | var form = __utils__.findOne(selector); | 595 | var form = window.__utils__.findOne(selector); |
552 | var method = (form.getAttribute('method') || "GET").toUpperCase(); | 596 | var method = (form.getAttribute('method') || "GET").toUpperCase(); |
553 | var action = form.getAttribute('action') || "unknown"; | 597 | var action = form.getAttribute('action') || "unknown"; |
554 | __utils__.log('submitting form to ' + action + ', HTTP ' + method, 'info'); | 598 | window.__utils__.log('submitting form to ' + action + ', HTTP ' + method, 'info'); |
555 | if (typeof form.submit === "function") { | 599 | if (typeof form.submit === "function") { |
556 | form.submit(); | 600 | form.submit(); |
557 | } else { | 601 | } else { |
... | @@ -568,6 +612,7 @@ Casper.prototype.fill = function fill(selector, vals, submit) { | ... | @@ -568,6 +612,7 @@ Casper.prototype.fill = function fill(selector, vals, submit) { |
568 | * @return Casper | 612 | * @return Casper |
569 | */ | 613 | */ |
570 | Casper.prototype.forward = function forward(then) { | 614 | Casper.prototype.forward = function forward(then) { |
615 | "use strict"; | ||
571 | return this.then(function _step() { | 616 | return this.then(function _step() { |
572 | this.emit('forward'); | 617 | this.emit('forward'); |
573 | this.evaluate(function _evaluate() { | 618 | this.evaluate(function _evaluate() { |
... | @@ -583,6 +628,7 @@ Casper.prototype.forward = function forward(then) { | ... | @@ -583,6 +628,7 @@ Casper.prototype.forward = function forward(then) { |
583 | * @return Object | 628 | * @return Object |
584 | */ | 629 | */ |
585 | Casper.prototype.getColorizer = function getColorizer() { | 630 | Casper.prototype.getColorizer = function getColorizer() { |
631 | "use strict"; | ||
586 | return colorizer.create(this.options.colorizerType || 'Colorizer'); | 632 | return colorizer.create(this.options.colorizerType || 'Colorizer'); |
587 | }; | 633 | }; |
588 | 634 | ||
... | @@ -592,6 +638,7 @@ Casper.prototype.getColorizer = function getColorizer() { | ... | @@ -592,6 +638,7 @@ Casper.prototype.getColorizer = function getColorizer() { |
592 | * @return String | 638 | * @return String |
593 | */ | 639 | */ |
594 | Casper.prototype.getCurrentUrl = function getCurrentUrl() { | 640 | Casper.prototype.getCurrentUrl = function getCurrentUrl() { |
641 | "use strict"; | ||
595 | return decodeURIComponent(this.evaluate(function _evaluate() { | 642 | return decodeURIComponent(this.evaluate(function _evaluate() { |
596 | return document.location.href; | 643 | return document.location.href; |
597 | })); | 644 | })); |
... | @@ -604,11 +651,12 @@ Casper.prototype.getCurrentUrl = function getCurrentUrl() { | ... | @@ -604,11 +651,12 @@ Casper.prototype.getCurrentUrl = function getCurrentUrl() { |
604 | * @return Object | 651 | * @return Object |
605 | */ | 652 | */ |
606 | Casper.prototype.getElementBounds = function getElementBounds(selector) { | 653 | Casper.prototype.getElementBounds = function getElementBounds(selector) { |
654 | "use strict"; | ||
607 | if (!this.exists(selector)) { | 655 | if (!this.exists(selector)) { |
608 | throw new CasperError("No element matching selector found: " + selector); | 656 | throw new CasperError("No element matching selector found: " + selector); |
609 | } | 657 | } |
610 | var clipRect = this.evaluate(function _evaluate(selector) { | 658 | var clipRect = this.evaluate(function _evaluate(selector) { |
611 | return __utils__.getElementBounds(selector); | 659 | return window.__utils__.getElementBounds(selector); |
612 | }, { selector: selector }); | 660 | }, { selector: selector }); |
613 | if (!utils.isClipRect(clipRect)) { | 661 | if (!utils.isClipRect(clipRect)) { |
614 | throw new CasperError('Could not fetch boundaries for element matching selector: ' + selector); | 662 | throw new CasperError('Could not fetch boundaries for element matching selector: ' + selector); |
... | @@ -623,13 +671,14 @@ Casper.prototype.getElementBounds = function getElementBounds(selector) { | ... | @@ -623,13 +671,14 @@ Casper.prototype.getElementBounds = function getElementBounds(selector) { |
623 | * @return mixed | 671 | * @return mixed |
624 | */ | 672 | */ |
625 | Casper.prototype.getGlobal = function getGlobal(name) { | 673 | Casper.prototype.getGlobal = function getGlobal(name) { |
674 | "use strict"; | ||
626 | var result = this.evaluate(function _evaluate(name) { | 675 | var result = this.evaluate(function _evaluate(name) { |
627 | var result = {}; | 676 | var result = {}; |
628 | try { | 677 | try { |
629 | result.value = JSON.stringify(window[name]); | 678 | result.value = JSON.stringify(window[name]); |
630 | } catch (e) { | 679 | } catch (e) { |
631 | var message = f("Unable to JSON encode window.%s: %s", name, e); | 680 | var message = f("Unable to JSON encode window.%s: %s", name, e); |
632 | __utils__.log(message, "error"); | 681 | window.__utils__.log(message, "error"); |
633 | result.error = message; | 682 | result.error = message; |
634 | } | 683 | } |
635 | return result; | 684 | return result; |
... | @@ -649,6 +698,7 @@ Casper.prototype.getGlobal = function getGlobal(name) { | ... | @@ -649,6 +698,7 @@ Casper.prototype.getGlobal = function getGlobal(name) { |
649 | * @return String | 698 | * @return String |
650 | */ | 699 | */ |
651 | Casper.prototype.getTitle = function getTitle() { | 700 | Casper.prototype.getTitle = function getTitle() { |
701 | "use strict"; | ||
652 | return this.evaluate(function _evaluate() { | 702 | return this.evaluate(function _evaluate() { |
653 | return document.title; | 703 | return document.title; |
654 | }); | 704 | }); |
... | @@ -659,6 +709,7 @@ Casper.prototype.getTitle = function getTitle() { | ... | @@ -659,6 +709,7 @@ Casper.prototype.getTitle = function getTitle() { |
659 | * | 709 | * |
660 | */ | 710 | */ |
661 | Casper.prototype.initErrorHandler = function initErrorHandler() { | 711 | Casper.prototype.initErrorHandler = function initErrorHandler() { |
712 | "use strict"; | ||
662 | var casper = this; | 713 | var casper = this; |
663 | phantom.onError = function phantom_onError(msg, backtrace) { | 714 | phantom.onError = function phantom_onError(msg, backtrace) { |
664 | casper.emit('error', msg, backtrace); | 715 | casper.emit('error', msg, backtrace); |
... | @@ -673,8 +724,9 @@ Casper.prototype.initErrorHandler = function initErrorHandler() { | ... | @@ -673,8 +724,9 @@ Casper.prototype.initErrorHandler = function initErrorHandler() { |
673 | * | 724 | * |
674 | */ | 725 | */ |
675 | Casper.prototype.injectClientUtils = function injectClientUtils() { | 726 | Casper.prototype.injectClientUtils = function injectClientUtils() { |
727 | "use strict"; | ||
676 | var clientUtilsInjected = this.page.evaluate(function() { | 728 | var clientUtilsInjected = this.page.evaluate(function() { |
677 | return typeof __utils__ === "object"; | 729 | return typeof window.__utils__ === "object"; |
678 | }); | 730 | }); |
679 | if (true === clientUtilsInjected) { | 731 | if (true === clientUtilsInjected) { |
680 | return; | 732 | return; |
... | @@ -683,8 +735,13 @@ Casper.prototype.injectClientUtils = function injectClientUtils() { | ... | @@ -683,8 +735,13 @@ Casper.prototype.injectClientUtils = function injectClientUtils() { |
683 | if (true === this.page.injectJs(clientUtilsPath)) { | 735 | if (true === this.page.injectJs(clientUtilsPath)) { |
684 | this.log("Successfully injected Casper client-side utilities", "debug"); | 736 | this.log("Successfully injected Casper client-side utilities", "debug"); |
685 | } else { | 737 | } else { |
686 | this.log("Failed to instantiate Casper client-side utilities!", "warning"); | 738 | this.warn("Failed to inject Casper client-side utilities"); |
687 | } | 739 | } |
740 | // ClientUtils and Casper shares the same options | ||
741 | // These are not the lines I'm the most proud of in my life, but it works. | ||
742 | this.page.evaluate(function() { | ||
743 | window.__utils__ = new ClientUtils(__options); | ||
744 | }.toString().replace('__options', JSON.stringify(this.options))); | ||
688 | }; | 745 | }; |
689 | 746 | ||
690 | /** | 747 | /** |
... | @@ -696,6 +753,7 @@ Casper.prototype.injectClientUtils = function injectClientUtils() { | ... | @@ -696,6 +753,7 @@ Casper.prototype.injectClientUtils = function injectClientUtils() { |
696 | * @return Casper | 753 | * @return Casper |
697 | */ | 754 | */ |
698 | Casper.prototype.log = function log(message, level, space) { | 755 | Casper.prototype.log = function log(message, level, space) { |
756 | "use strict"; | ||
699 | level = level && this.logLevels.indexOf(level) > -1 ? level : "debug"; | 757 | level = level && this.logLevels.indexOf(level) > -1 ? level : "debug"; |
700 | space = space ? space : "phantom"; | 758 | space = space ? space : "phantom"; |
701 | if (level === "error" && utils.isFunction(this.options.onError)) { | 759 | if (level === "error" && utils.isFunction(this.options.onError)) { |
... | @@ -735,12 +793,13 @@ Casper.prototype.log = function log(message, level, space) { | ... | @@ -735,12 +793,13 @@ Casper.prototype.log = function log(message, level, space) { |
735 | * @return Boolean | 793 | * @return Boolean |
736 | */ | 794 | */ |
737 | Casper.prototype.mouseEvent = function mouseEvent(type, selector) { | 795 | Casper.prototype.mouseEvent = function mouseEvent(type, selector) { |
796 | "use strict"; | ||
738 | this.log("Mouse event '" + type + "' on selector: " + selector, "debug"); | 797 | this.log("Mouse event '" + type + "' on selector: " + selector, "debug"); |
739 | if (!this.exists(selector)) { | 798 | if (!this.exists(selector)) { |
740 | throw new CasperError(f("Cannot dispatch %s event on nonexistent selector: %s", type, selector)); | 799 | throw new CasperError(f("Cannot dispatch %s event on nonexistent selector: %s", type, selector)); |
741 | } | 800 | } |
742 | var eventSuccess = this.evaluate(function(type, selector) { | 801 | var eventSuccess = this.evaluate(function(type, selector) { |
743 | return __utils__.mouseEvent(type, selector); | 802 | return window.__utils__.mouseEvent(type, selector); |
744 | }, { | 803 | }, { |
745 | type: type, | 804 | type: type, |
746 | selector: selector | 805 | selector: selector |
... | @@ -758,13 +817,20 @@ Casper.prototype.mouseEvent = function mouseEvent(type, selector) { | ... | @@ -758,13 +817,20 @@ Casper.prototype.mouseEvent = function mouseEvent(type, selector) { |
758 | }; | 817 | }; |
759 | 818 | ||
760 | /** | 819 | /** |
761 | * Performs an HTTP request. | 820 | * Performs an HTTP request, with optional settings. |
821 | * | ||
822 | * Available settings are: | ||
823 | * | ||
824 | * - String method: The HTTP method to use | ||
825 | * - Object data: The data to use to perform the request, eg. {foo: 'bar'} | ||
826 | * - Array headers: An array of request headers, eg. [{'Cache-Control': 'max-age=0'}] | ||
762 | * | 827 | * |
763 | * @param String location The url to open | 828 | * @param String location The url to open |
764 | * @param Object settings The request settings | 829 | * @param Object settings The request settings (optional) |
765 | * @return Casper | 830 | * @return Casper |
766 | */ | 831 | */ |
767 | Casper.prototype.open = function open(location, settings) { | 832 | Casper.prototype.open = function open(location, settings) { |
833 | "use strict"; | ||
768 | // settings validation | 834 | // settings validation |
769 | if (!settings) { | 835 | if (!settings) { |
770 | settings = { | 836 | settings = { |
... | @@ -805,9 +871,13 @@ Casper.prototype.open = function open(location, settings) { | ... | @@ -805,9 +871,13 @@ Casper.prototype.open = function open(location, settings) { |
805 | } | 871 | } |
806 | this.emit('open', this.requestUrl, settings); | 872 | this.emit('open', this.requestUrl, settings); |
807 | this.log(f('opening url: %s, HTTP %s', this.requestUrl, settings.method.toUpperCase()), "debug"); | 873 | this.log(f('opening url: %s, HTTP %s', this.requestUrl, settings.method.toUpperCase()), "debug"); |
874 | if ('headers' in settings && phantom.version.minor < 6) { | ||
875 | this.warn('Custom headers in outgoing requests are supported in PhantomJS >= 1.6'); | ||
876 | } | ||
808 | this.page.openUrl(this.requestUrl, { | 877 | this.page.openUrl(this.requestUrl, { |
809 | operation: settings.method, | 878 | operation: settings.method, |
810 | data: settings.data | 879 | data: settings.data, |
880 | headers: settings.headers | ||
811 | }, this.page.settings); | 881 | }, this.page.settings); |
812 | this.resources = []; | 882 | this.resources = []; |
813 | return this; | 883 | return this; |
... | @@ -822,6 +892,7 @@ Casper.prototype.open = function open(location, settings) { | ... | @@ -822,6 +892,7 @@ Casper.prototype.open = function open(location, settings) { |
822 | * @see Casper#then | 892 | * @see Casper#then |
823 | */ | 893 | */ |
824 | Casper.prototype.repeat = function repeat(times, then) { | 894 | Casper.prototype.repeat = function repeat(times, then) { |
895 | "use strict"; | ||
825 | for (var i = 0; i < times; i++) { | 896 | for (var i = 0; i < times; i++) { |
826 | this.then(then); | 897 | this.then(then); |
827 | } | 898 | } |
... | @@ -836,6 +907,7 @@ Casper.prototype.repeat = function repeat(times, then) { | ... | @@ -836,6 +907,7 @@ Casper.prototype.repeat = function repeat(times, then) { |
836 | * @return Boolean | 907 | * @return Boolean |
837 | */ | 908 | */ |
838 | Casper.prototype.resourceExists = function resourceExists(test) { | 909 | Casper.prototype.resourceExists = function resourceExists(test) { |
910 | "use strict"; | ||
839 | var testFn; | 911 | var testFn; |
840 | switch (utils.betterTypeOf(test)) { | 912 | switch (utils.betterTypeOf(test)) { |
841 | case "string": | 913 | case "string": |
... | @@ -866,6 +938,7 @@ Casper.prototype.resourceExists = function resourceExists(test) { | ... | @@ -866,6 +938,7 @@ Casper.prototype.resourceExists = function resourceExists(test) { |
866 | * @return Casper | 938 | * @return Casper |
867 | */ | 939 | */ |
868 | Casper.prototype.run = function run(onComplete, time) { | 940 | Casper.prototype.run = function run(onComplete, time) { |
941 | "use strict"; | ||
869 | if (!this.steps || this.steps.length < 1) { | 942 | if (!this.steps || this.steps.length < 1) { |
870 | this.log("No steps defined, aborting", "error"); | 943 | this.log("No steps defined, aborting", "error"); |
871 | return this; | 944 | return this; |
... | @@ -882,6 +955,7 @@ Casper.prototype.run = function run(onComplete, time) { | ... | @@ -882,6 +955,7 @@ Casper.prototype.run = function run(onComplete, time) { |
882 | * @param Function step | 955 | * @param Function step |
883 | */ | 956 | */ |
884 | Casper.prototype.runStep = function runStep(step) { | 957 | Casper.prototype.runStep = function runStep(step) { |
958 | "use strict"; | ||
885 | var skipLog = utils.isObject(step.options) && step.options.skipLog === true; | 959 | var skipLog = utils.isObject(step.options) && step.options.skipLog === true; |
886 | var stepInfo = f("Step %d/%d", this.step, this.steps.length); | 960 | var stepInfo = f("Step %d/%d", this.step, this.steps.length); |
887 | var stepResult; | 961 | var stepResult; |
... | @@ -891,7 +965,7 @@ Casper.prototype.runStep = function runStep(step) { | ... | @@ -891,7 +965,7 @@ Casper.prototype.runStep = function runStep(step) { |
891 | if (utils.isNumber(this.options.stepTimeout) && this.options.stepTimeout > 0) { | 965 | if (utils.isNumber(this.options.stepTimeout) && this.options.stepTimeout > 0) { |
892 | var stepTimeoutCheckInterval = setInterval(function _check(self, start, stepNum) { | 966 | var stepTimeoutCheckInterval = setInterval(function _check(self, start, stepNum) { |
893 | if (new Date().getTime() - start > self.options.stepTimeout) { | 967 | if (new Date().getTime() - start > self.options.stepTimeout) { |
894 | if (self.step == stepNum) { | 968 | if (self.step === stepNum) { |
895 | self.emit('step.timeout'); | 969 | self.emit('step.timeout'); |
896 | if (utils.isFunction(self.options.onStepTimeout)) { | 970 | if (utils.isFunction(self.options.onStepTimeout)) { |
897 | self.options.onStepTimeout.call(self, self); | 971 | self.options.onStepTimeout.call(self, self); |
... | @@ -922,6 +996,7 @@ Casper.prototype.runStep = function runStep(step) { | ... | @@ -922,6 +996,7 @@ Casper.prototype.runStep = function runStep(step) { |
922 | * @return Casper | 996 | * @return Casper |
923 | */ | 997 | */ |
924 | Casper.prototype.setHttpAuth = function setHttpAuth(username, password) { | 998 | Casper.prototype.setHttpAuth = function setHttpAuth(username, password) { |
999 | "use strict"; | ||
925 | if (!this.started) { | 1000 | if (!this.started) { |
926 | throw new CasperError("Casper must be started in order to use the setHttpAuth() method"); | 1001 | throw new CasperError("Casper must be started in order to use the setHttpAuth() method"); |
927 | } | 1002 | } |
... | @@ -943,6 +1018,7 @@ Casper.prototype.setHttpAuth = function setHttpAuth(username, password) { | ... | @@ -943,6 +1018,7 @@ Casper.prototype.setHttpAuth = function setHttpAuth(username, password) { |
943 | * @return Casper | 1018 | * @return Casper |
944 | */ | 1019 | */ |
945 | Casper.prototype.start = function start(location, then) { | 1020 | Casper.prototype.start = function start(location, then) { |
1021 | "use strict"; | ||
946 | this.emit('starting'); | 1022 | this.emit('starting'); |
947 | this.log('Starting...', "info"); | 1023 | this.log('Starting...', "info"); |
948 | this.startTime = new Date().getTime(); | 1024 | this.startTime = new Date().getTime(); |
... | @@ -997,6 +1073,7 @@ Casper.prototype.start = function start(location, then) { | ... | @@ -997,6 +1073,7 @@ Casper.prototype.start = function start(location, then) { |
997 | * @return Casper | 1073 | * @return Casper |
998 | */ | 1074 | */ |
999 | Casper.prototype.then = function then(step) { | 1075 | Casper.prototype.then = function then(step) { |
1076 | "use strict"; | ||
1000 | if (!this.started) { | 1077 | if (!this.started) { |
1001 | throw new CasperError("Casper not started; please use Casper#start"); | 1078 | throw new CasperError("Casper not started; please use Casper#start"); |
1002 | } | 1079 | } |
... | @@ -1036,6 +1113,7 @@ Casper.prototype.then = function then(step) { | ... | @@ -1036,6 +1113,7 @@ Casper.prototype.then = function then(step) { |
1036 | * @see Casper#then | 1113 | * @see Casper#then |
1037 | */ | 1114 | */ |
1038 | Casper.prototype.thenClick = function thenClick(selector, then, fallbackToHref) { | 1115 | Casper.prototype.thenClick = function thenClick(selector, then, fallbackToHref) { |
1116 | "use strict"; | ||
1039 | if (arguments.length > 2) { | 1117 | if (arguments.length > 2) { |
1040 | this.emit("deprecated", "The thenClick() method does not process the fallbackToHref argument since 0.6"); | 1118 | this.emit("deprecated", "The thenClick() method does not process the fallbackToHref argument since 0.6"); |
1041 | } | 1119 | } |
... | @@ -1055,6 +1133,7 @@ Casper.prototype.thenClick = function thenClick(selector, then, fallbackToHref) | ... | @@ -1055,6 +1133,7 @@ Casper.prototype.thenClick = function thenClick(selector, then, fallbackToHref) |
1055 | * @see Casper#evaluate | 1133 | * @see Casper#evaluate |
1056 | */ | 1134 | */ |
1057 | Casper.prototype.thenEvaluate = function thenEvaluate(fn, context) { | 1135 | Casper.prototype.thenEvaluate = function thenEvaluate(fn, context) { |
1136 | "use strict"; | ||
1058 | return this.then(function _step() { | 1137 | return this.then(function _step() { |
1059 | this.evaluate(fn, context); | 1138 | this.evaluate(fn, context); |
1060 | }); | 1139 | }); |
... | @@ -1069,6 +1148,7 @@ Casper.prototype.thenEvaluate = function thenEvaluate(fn, context) { | ... | @@ -1069,6 +1148,7 @@ Casper.prototype.thenEvaluate = function thenEvaluate(fn, context) { |
1069 | * @see Casper#open | 1148 | * @see Casper#open |
1070 | */ | 1149 | */ |
1071 | Casper.prototype.thenOpen = function thenOpen(location, then) { | 1150 | Casper.prototype.thenOpen = function thenOpen(location, then) { |
1151 | "use strict"; | ||
1072 | this.then(this.createStep(function _step() { | 1152 | this.then(this.createStep(function _step() { |
1073 | this.open(location); | 1153 | this.open(location); |
1074 | }, { | 1154 | }, { |
... | @@ -1089,10 +1169,26 @@ Casper.prototype.thenOpen = function thenOpen(location, then) { | ... | @@ -1089,10 +1169,26 @@ Casper.prototype.thenOpen = function thenOpen(location, then) { |
1089 | * @see Casper#open | 1169 | * @see Casper#open |
1090 | */ | 1170 | */ |
1091 | Casper.prototype.thenOpenAndEvaluate = function thenOpenAndEvaluate(location, fn, context) { | 1171 | Casper.prototype.thenOpenAndEvaluate = function thenOpenAndEvaluate(location, fn, context) { |
1172 | "use strict"; | ||
1092 | return this.thenOpen(location).thenEvaluate(fn, context); | 1173 | return this.thenOpen(location).thenEvaluate(fn, context); |
1093 | }; | 1174 | }; |
1094 | 1175 | ||
1095 | /** | 1176 | /** |
1177 | * Sets the user-agent string currently used when requesting urls. | ||
1178 | * | ||
1179 | * @param String userAgent User agent string | ||
1180 | * @return String | ||
1181 | */ | ||
1182 | Casper.prototype.userAgent = function userAgent(agent) { | ||
1183 | "use strict"; | ||
1184 | if (!this.started) { | ||
1185 | throw new CasperError("Casper not started, can't set userAgent"); | ||
1186 | } | ||
1187 | this.options.pageSettings.userAgent = this.page.settings.userAgent = agent; | ||
1188 | return this; | ||
1189 | }; | ||
1190 | |||
1191 | /** | ||
1096 | * Changes the current viewport size. | 1192 | * Changes the current viewport size. |
1097 | * | 1193 | * |
1098 | * @param Number width The viewport width, in pixels | 1194 | * @param Number width The viewport width, in pixels |
... | @@ -1100,6 +1196,7 @@ Casper.prototype.thenOpenAndEvaluate = function thenOpenAndEvaluate(location, fn | ... | @@ -1100,6 +1196,7 @@ Casper.prototype.thenOpenAndEvaluate = function thenOpenAndEvaluate(location, fn |
1100 | * @return Casper | 1196 | * @return Casper |
1101 | */ | 1197 | */ |
1102 | Casper.prototype.viewport = function viewport(width, height) { | 1198 | Casper.prototype.viewport = function viewport(width, height) { |
1199 | "use strict"; | ||
1103 | if (!this.started) { | 1200 | if (!this.started) { |
1104 | throw new CasperError("Casper must be started in order to set viewport at runtime"); | 1201 | throw new CasperError("Casper must be started in order to set viewport at runtime"); |
1105 | } | 1202 | } |
... | @@ -1123,12 +1220,26 @@ Casper.prototype.viewport = function viewport(width, height) { | ... | @@ -1123,12 +1220,26 @@ Casper.prototype.viewport = function viewport(width, height) { |
1123 | * @return Boolean | 1220 | * @return Boolean |
1124 | */ | 1221 | */ |
1125 | Casper.prototype.visible = function visible(selector) { | 1222 | Casper.prototype.visible = function visible(selector) { |
1223 | "use strict"; | ||
1126 | return this.evaluate(function _evaluate(selector) { | 1224 | return this.evaluate(function _evaluate(selector) { |
1127 | return __utils__.visible(selector); | 1225 | return window.__utils__.visible(selector); |
1128 | }, { selector: selector }); | 1226 | }, { selector: selector }); |
1129 | }; | 1227 | }; |
1130 | 1228 | ||
1131 | /** | 1229 | /** |
1230 | * Displays a warning message onto the console and logs the event. | ||
1231 | * | ||
1232 | * @param String message | ||
1233 | * @return Casper | ||
1234 | */ | ||
1235 | Casper.prototype.warn = function warn(message) { | ||
1236 | "use strict"; | ||
1237 | this.log(message, "warning", "phantom"); | ||
1238 | var formatted = f.apply(null, ["⚠ " + message].concat([].slice.call(arguments, 1))); | ||
1239 | return this.echo(formatted, 'COMMENT'); | ||
1240 | }; | ||
1241 | |||
1242 | /** | ||
1132 | * Adds a new step that will wait for a given amount of time (expressed | 1243 | * Adds a new step that will wait for a given amount of time (expressed |
1133 | * in milliseconds) before processing an optional next one. | 1244 | * in milliseconds) before processing an optional next one. |
1134 | * | 1245 | * |
... | @@ -1137,6 +1248,7 @@ Casper.prototype.visible = function visible(selector) { | ... | @@ -1137,6 +1248,7 @@ Casper.prototype.visible = function visible(selector) { |
1137 | * @return Casper | 1248 | * @return Casper |
1138 | */ | 1249 | */ |
1139 | Casper.prototype.wait = function wait(timeout, then) { | 1250 | Casper.prototype.wait = function wait(timeout, then) { |
1251 | "use strict"; | ||
1140 | timeout = ~~timeout; | 1252 | timeout = ~~timeout; |
1141 | if (timeout < 1) { | 1253 | if (timeout < 1) { |
1142 | this.die("wait() only accepts a positive integer > 0 as a timeout value"); | 1254 | this.die("wait() only accepts a positive integer > 0 as a timeout value"); |
... | @@ -1157,11 +1269,13 @@ Casper.prototype.wait = function wait(timeout, then) { | ... | @@ -1157,11 +1269,13 @@ Casper.prototype.wait = function wait(timeout, then) { |
1157 | }; | 1269 | }; |
1158 | 1270 | ||
1159 | Casper.prototype.waitStart = function waitStart() { | 1271 | Casper.prototype.waitStart = function waitStart() { |
1272 | "use strict"; | ||
1160 | this.emit('wait.start'); | 1273 | this.emit('wait.start'); |
1161 | this.pendingWait = true; | 1274 | this.pendingWait = true; |
1162 | }; | 1275 | }; |
1163 | 1276 | ||
1164 | Casper.prototype.waitDone = function waitDone() { | 1277 | Casper.prototype.waitDone = function waitDone() { |
1278 | "use strict"; | ||
1165 | this.emit('wait.done'); | 1279 | this.emit('wait.done'); |
1166 | this.pendingWait = false; | 1280 | this.pendingWait = false; |
1167 | }; | 1281 | }; |
... | @@ -1176,6 +1290,7 @@ Casper.prototype.waitDone = function waitDone() { | ... | @@ -1176,6 +1290,7 @@ Casper.prototype.waitDone = function waitDone() { |
1176 | * @return Casper | 1290 | * @return Casper |
1177 | */ | 1291 | */ |
1178 | Casper.prototype.waitFor = function waitFor(testFx, then, onTimeout, timeout) { | 1292 | Casper.prototype.waitFor = function waitFor(testFx, then, onTimeout, timeout) { |
1293 | "use strict"; | ||
1179 | timeout = timeout ? timeout : this.defaultWaitTimeout; | 1294 | timeout = timeout ? timeout : this.defaultWaitTimeout; |
1180 | if (!utils.isFunction(testFx)) { | 1295 | if (!utils.isFunction(testFx)) { |
1181 | this.die("waitFor() needs a test function"); | 1296 | this.die("waitFor() needs a test function"); |
... | @@ -1223,6 +1338,7 @@ Casper.prototype.waitFor = function waitFor(testFx, then, onTimeout, timeout) { | ... | @@ -1223,6 +1338,7 @@ Casper.prototype.waitFor = function waitFor(testFx, then, onTimeout, timeout) { |
1223 | * @return Casper | 1338 | * @return Casper |
1224 | */ | 1339 | */ |
1225 | Casper.prototype.waitForResource = function waitForResource(test, then, onTimeout, timeout) { | 1340 | Casper.prototype.waitForResource = function waitForResource(test, then, onTimeout, timeout) { |
1341 | "use strict"; | ||
1226 | timeout = timeout ? timeout : this.defaultWaitTimeout; | 1342 | timeout = timeout ? timeout : this.defaultWaitTimeout; |
1227 | return this.waitFor(function _check() { | 1343 | return this.waitFor(function _check() { |
1228 | return this.resourceExists(test); | 1344 | return this.resourceExists(test); |
... | @@ -1240,6 +1356,7 @@ Casper.prototype.waitForResource = function waitForResource(test, then, onTimeou | ... | @@ -1240,6 +1356,7 @@ Casper.prototype.waitForResource = function waitForResource(test, then, onTimeou |
1240 | * @return Casper | 1356 | * @return Casper |
1241 | */ | 1357 | */ |
1242 | Casper.prototype.waitForSelector = function waitForSelector(selector, then, onTimeout, timeout) { | 1358 | Casper.prototype.waitForSelector = function waitForSelector(selector, then, onTimeout, timeout) { |
1359 | "use strict"; | ||
1243 | timeout = timeout ? timeout : this.defaultWaitTimeout; | 1360 | timeout = timeout ? timeout : this.defaultWaitTimeout; |
1244 | return this.waitFor(function _check() { | 1361 | return this.waitFor(function _check() { |
1245 | return this.exists(selector); | 1362 | return this.exists(selector); |
... | @@ -1257,6 +1374,7 @@ Casper.prototype.waitForSelector = function waitForSelector(selector, then, onTi | ... | @@ -1257,6 +1374,7 @@ Casper.prototype.waitForSelector = function waitForSelector(selector, then, onTi |
1257 | * @return Casper | 1374 | * @return Casper |
1258 | */ | 1375 | */ |
1259 | Casper.prototype.waitWhileSelector = function waitWhileSelector(selector, then, onTimeout, timeout) { | 1376 | Casper.prototype.waitWhileSelector = function waitWhileSelector(selector, then, onTimeout, timeout) { |
1377 | "use strict"; | ||
1260 | timeout = timeout ? timeout : this.defaultWaitTimeout; | 1378 | timeout = timeout ? timeout : this.defaultWaitTimeout; |
1261 | return this.waitFor(function _check() { | 1379 | return this.waitFor(function _check() { |
1262 | return !this.exists(selector); | 1380 | return !this.exists(selector); |
... | @@ -1274,6 +1392,7 @@ Casper.prototype.waitWhileSelector = function waitWhileSelector(selector, then, | ... | @@ -1274,6 +1392,7 @@ Casper.prototype.waitWhileSelector = function waitWhileSelector(selector, then, |
1274 | * @return Casper | 1392 | * @return Casper |
1275 | */ | 1393 | */ |
1276 | Casper.prototype.waitUntilVisible = function waitUntilVisible(selector, then, onTimeout, timeout) { | 1394 | Casper.prototype.waitUntilVisible = function waitUntilVisible(selector, then, onTimeout, timeout) { |
1395 | "use strict"; | ||
1277 | timeout = timeout ? timeout : this.defaultWaitTimeout; | 1396 | timeout = timeout ? timeout : this.defaultWaitTimeout; |
1278 | return this.waitFor(function _check() { | 1397 | return this.waitFor(function _check() { |
1279 | return this.visible(selector); | 1398 | return this.visible(selector); |
... | @@ -1291,6 +1410,7 @@ Casper.prototype.waitUntilVisible = function waitUntilVisible(selector, then, on | ... | @@ -1291,6 +1410,7 @@ Casper.prototype.waitUntilVisible = function waitUntilVisible(selector, then, on |
1291 | * @return Casper | 1410 | * @return Casper |
1292 | */ | 1411 | */ |
1293 | Casper.prototype.waitWhileVisible = function waitWhileVisible(selector, then, onTimeout, timeout) { | 1412 | Casper.prototype.waitWhileVisible = function waitWhileVisible(selector, then, onTimeout, timeout) { |
1413 | "use strict"; | ||
1294 | timeout = timeout ? timeout : this.defaultWaitTimeout; | 1414 | timeout = timeout ? timeout : this.defaultWaitTimeout; |
1295 | return this.waitFor(function _check() { | 1415 | return this.waitFor(function _check() { |
1296 | return !this.visible(selector); | 1416 | return !this.visible(selector); |
... | @@ -1305,7 +1425,8 @@ Casper.prototype.waitWhileVisible = function waitWhileVisible(selector, then, on | ... | @@ -1305,7 +1425,8 @@ Casper.prototype.waitWhileVisible = function waitWhileVisible(selector, then, on |
1305 | * @since 0.6 | 1425 | * @since 0.6 |
1306 | */ | 1426 | */ |
1307 | Casper.extend = function(proto) { | 1427 | Casper.extend = function(proto) { |
1308 | console.warn('Casper.extend() has been deprecated since 0.6; check the docs'); | 1428 | "use strict"; |
1429 | this.warn('Casper.extend() has been deprecated since 0.6; check the docs'); | ||
1309 | if (!utils.isObject(proto)) { | 1430 | if (!utils.isObject(proto)) { |
1310 | throw new CasperError("extends() only accept objects as prototypes"); | 1431 | throw new CasperError("extends() only accept objects as prototypes"); |
1311 | } | 1432 | } |
... | @@ -1321,12 +1442,8 @@ exports.Casper = Casper; | ... | @@ -1321,12 +1442,8 @@ exports.Casper = Casper; |
1321 | * @return WebPage | 1442 | * @return WebPage |
1322 | */ | 1443 | */ |
1323 | function createPage(casper) { | 1444 | function createPage(casper) { |
1324 | var page; | 1445 | "use strict"; |
1325 | if (phantom.version.major <= 1 && phantom.version.minor < 3 && utils.isFunction(require)) { | 1446 | var page = require('webpage').create(); |
1326 | page = new WebPage(); | ||
1327 | } else { | ||
1328 | page = require('webpage').create(); | ||
1329 | } | ||
1330 | page.onAlert = function onAlert(message) { | 1447 | page.onAlert = function onAlert(message) { |
1331 | casper.log('[alert] ' + message, "info", "remote"); | 1448 | casper.log('[alert] ' + message, "info", "remote"); |
1332 | casper.emit('remote.alert', message); | 1449 | casper.emit('remote.alert', message); |
... | @@ -1375,17 +1492,19 @@ function createPage(casper) { | ... | @@ -1375,17 +1492,19 @@ function createPage(casper) { |
1375 | } | 1492 | } |
1376 | } | 1493 | } |
1377 | if (casper.options.clientScripts) { | 1494 | if (casper.options.clientScripts) { |
1495 | if (utils.isString(casper.options.clientScripts)) { | ||
1496 | casper.options.clientScripts = [casper.options.clientScripts]; | ||
1497 | } | ||
1378 | if (!utils.isArray(casper.options.clientScripts)) { | 1498 | if (!utils.isArray(casper.options.clientScripts)) { |
1379 | throw new CasperError("The clientScripts option must be an array"); | 1499 | throw new CasperError("The clientScripts option must be an array"); |
1380 | } else { | ||
1381 | casper.options.clientScripts.forEach(function _forEach(script) { | ||
1382 | if (casper.page.injectJs(script)) { | ||
1383 | casper.log(f('Automatically injected %s client side', script), "debug"); | ||
1384 | } else { | ||
1385 | casper.log(f('Failed injecting %s client side', script), "warning"); | ||
1386 | } | ||
1387 | }); | ||
1388 | } | 1500 | } |
1501 | casper.options.clientScripts.forEach(function _forEach(script) { | ||
1502 | if (casper.page.injectJs(script)) { | ||
1503 | casper.log(f('Automatically injected %s client side', script), "debug"); | ||
1504 | } else { | ||
1505 | casper.warn('Failed injecting %s client side', script); | ||
1506 | } | ||
1507 | }); | ||
1389 | } | 1508 | } |
1390 | // Client-side utils injection | 1509 | // Client-side utils injection |
1391 | casper.injectClientUtils(); | 1510 | casper.injectClientUtils(); | ... | ... |
... | @@ -28,6 +28,8 @@ | ... | @@ -28,6 +28,8 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /*global CasperError console exports phantom require*/ | ||
32 | |||
31 | var utils = require('utils'); | 33 | var utils = require('utils'); |
32 | 34 | ||
33 | /** | 35 | /** |
... | @@ -38,6 +40,7 @@ var utils = require('utils'); | ... | @@ -38,6 +40,7 @@ var utils = require('utils'); |
38 | * @return Object | 40 | * @return Object |
39 | */ | 41 | */ |
40 | exports.parse = function parse(phantomArgs) { | 42 | exports.parse = function parse(phantomArgs) { |
43 | "use strict"; | ||
41 | var extract = { | 44 | var extract = { |
42 | args: [], | 45 | args: [], |
43 | options: {}, | 46 | options: {}, |
... | @@ -110,6 +113,7 @@ exports.parse = function parse(phantomArgs) { | ... | @@ -110,6 +113,7 @@ exports.parse = function parse(phantomArgs) { |
110 | * @return Mixed | 113 | * @return Mixed |
111 | */ | 114 | */ |
112 | function castArgument(arg) { | 115 | function castArgument(arg) { |
116 | "use strict"; | ||
113 | if (arg.match(/^-?\d+$/)) { | 117 | if (arg.match(/^-?\d+$/)) { |
114 | return parseInt(arg, 10); | 118 | return parseInt(arg, 10); |
115 | } else if (arg.match(/^-?\d+\.\d+$/)) { | 119 | } else if (arg.match(/^-?\d+\.\d+$/)) { | ... | ... |
... | @@ -27,15 +27,21 @@ | ... | @@ -27,15 +27,21 @@ |
27 | * DEALINGS IN THE SOFTWARE. | 27 | * DEALINGS IN THE SOFTWARE. |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | |||
31 | /*global console escape exports NodeList window*/ | ||
32 | |||
30 | (function(exports) { | 33 | (function(exports) { |
31 | exports.create = function create() { | 34 | "use strict"; |
32 | return new this.ClientUtils(); | 35 | |
36 | exports.create = function create(options) { | ||
37 | return new this.ClientUtils(options); | ||
33 | }; | 38 | }; |
34 | 39 | ||
35 | /** | 40 | /** |
36 | * Casper client-side helpers. | 41 | * Casper client-side helpers. |
37 | */ | 42 | */ |
38 | exports.ClientUtils = function ClientUtils() { | 43 | exports.ClientUtils = function ClientUtils(options) { |
44 | // private members | ||
39 | var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 45 | var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
40 | var BASE64_DECODE_CHARS = new Array( | 46 | var BASE64_DECODE_CHARS = new Array( |
41 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 47 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
... | @@ -49,6 +55,9 @@ | ... | @@ -49,6 +55,9 @@ |
49 | ); | 55 | ); |
50 | var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath']; | 56 | var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath']; |
51 | 57 | ||
58 | // public members | ||
59 | this.options = options || {}; | ||
60 | |||
52 | /** | 61 | /** |
53 | * Clicks on the DOM element behind the provided selector. | 62 | * Clicks on the DOM element behind the provided selector. |
54 | * | 63 | * |
... | @@ -70,35 +79,35 @@ | ... | @@ -70,35 +79,35 @@ |
70 | while (i < len) { | 79 | while (i < len) { |
71 | do { | 80 | do { |
72 | c1 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff]; | 81 | c1 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff]; |
73 | } while (i < len && c1 == -1); | 82 | } while (i < len && c1 === -1); |
74 | if (c1 == -1) { | 83 | if (c1 === -1) { |
75 | break; | 84 | break; |
76 | } | 85 | } |
77 | do { | 86 | do { |
78 | c2 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff]; | 87 | c2 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff]; |
79 | } while (i < len && c2 == -1); | 88 | } while (i < len && c2 === -1); |
80 | if (c2 == -1) { | 89 | if (c2 === -1) { |
81 | break; | 90 | break; |
82 | } | 91 | } |
83 | out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); | 92 | out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); |
84 | do { | 93 | do { |
85 | c3 = str.charCodeAt(i++) & 0xff; | 94 | c3 = str.charCodeAt(i++) & 0xff; |
86 | if (c3 == 61) | 95 | if (c3 === 61) |
87 | return out; | 96 | return out; |
88 | c3 = BASE64_DECODE_CHARS[c3]; | 97 | c3 = BASE64_DECODE_CHARS[c3]; |
89 | } while (i < len && c3 == -1); | 98 | } while (i < len && c3 === -1); |
90 | if (c3 == -1) { | 99 | if (c3 === -1) { |
91 | break; | 100 | break; |
92 | } | 101 | } |
93 | out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); | 102 | out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); |
94 | do { | 103 | do { |
95 | c4 = str.charCodeAt(i++) & 0xff; | 104 | c4 = str.charCodeAt(i++) & 0xff; |
96 | if (c4 == 61) { | 105 | if (c4 === 61) { |
97 | return out; | 106 | return out; |
98 | } | 107 | } |
99 | c4 = BASE64_DECODE_CHARS[c4]; | 108 | c4 = BASE64_DECODE_CHARS[c4]; |
100 | } while (i < len && c4 == -1); | 109 | } while (i < len && c4 === -1); |
101 | if (c4 == -1) { | 110 | if (c4 === -1) { |
102 | break; | 111 | break; |
103 | } | 112 | } |
104 | out += String.fromCharCode(((c3 & 0x03) << 6) | c4); | 113 | out += String.fromCharCode(((c3 & 0x03) << 6) | c4); |
... | @@ -117,14 +126,14 @@ | ... | @@ -117,14 +126,14 @@ |
117 | var out = "", i = 0, len = str.length, c1, c2, c3; | 126 | var out = "", i = 0, len = str.length, c1, c2, c3; |
118 | while (i < len) { | 127 | while (i < len) { |
119 | c1 = str.charCodeAt(i++) & 0xff; | 128 | c1 = str.charCodeAt(i++) & 0xff; |
120 | if (i == len) { | 129 | if (i === len) { |
121 | out += BASE64_ENCODE_CHARS.charAt(c1 >> 2); | 130 | out += BASE64_ENCODE_CHARS.charAt(c1 >> 2); |
122 | out += BASE64_ENCODE_CHARS.charAt((c1 & 0x3) << 4); | 131 | out += BASE64_ENCODE_CHARS.charAt((c1 & 0x3) << 4); |
123 | out += "=="; | 132 | out += "=="; |
124 | break; | 133 | break; |
125 | } | 134 | } |
126 | c2 = str.charCodeAt(i++); | 135 | c2 = str.charCodeAt(i++); |
127 | if (i == len) { | 136 | if (i === len) { |
128 | out += BASE64_ENCODE_CHARS.charAt(c1 >> 2); | 137 | out += BASE64_ENCODE_CHARS.charAt(c1 >> 2); |
129 | out += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); | 138 | out += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); |
130 | out += BASE64_ENCODE_CHARS.charAt((c2 & 0xF) << 2); | 139 | out += BASE64_ENCODE_CHARS.charAt((c2 & 0xF) << 2); |
... | @@ -165,7 +174,7 @@ | ... | @@ -165,7 +174,7 @@ |
165 | var text = '', elements = this.findAll(selector); | 174 | var text = '', elements = this.findAll(selector); |
166 | if (elements && elements.length) { | 175 | if (elements && elements.length) { |
167 | Array.prototype.forEach.call(elements, function _forEach(element) { | 176 | Array.prototype.forEach.call(elements, function _forEach(element) { |
168 | text += element.innerText; | 177 | text += element.textContent || element.innerText; |
169 | }); | 178 | }); |
170 | } | 179 | } |
171 | return text; | 180 | return text; |
... | @@ -185,7 +194,7 @@ | ... | @@ -185,7 +194,7 @@ |
185 | files: [] | 194 | files: [] |
186 | }; | 195 | }; |
187 | if (!(form instanceof HTMLElement) || typeof form === "string") { | 196 | if (!(form instanceof HTMLElement) || typeof form === "string") { |
188 | __utils__.log("attempting to fetch form element from selector: '" + form + "'", "info"); | 197 | this.log("attempting to fetch form element from selector: '" + form + "'", "info"); |
189 | try { | 198 | try { |
190 | form = this.findOne(form); | 199 | form = this.findOne(form); |
191 | } catch (e) { | 200 | } catch (e) { |
... | @@ -203,7 +212,7 @@ | ... | @@ -203,7 +212,7 @@ |
203 | if (!vals.hasOwnProperty(name)) { | 212 | if (!vals.hasOwnProperty(name)) { |
204 | continue; | 213 | continue; |
205 | } | 214 | } |
206 | var field = this.findAll('[name="' + name + '"]'); | 215 | var field = this.findAll('[name="' + name + '"]', form); |
207 | var value = vals[name]; | 216 | var value = vals[name]; |
208 | if (!field) { | 217 | if (!field) { |
209 | out.errors.push('no field named "' + name + '" in form'); | 218 | out.errors.push('no field named "' + name + '" in form'); |
... | @@ -229,16 +238,18 @@ | ... | @@ -229,16 +238,18 @@ |
229 | /** | 238 | /** |
230 | * Finds all DOM elements matching by the provided selector. | 239 | * Finds all DOM elements matching by the provided selector. |
231 | * | 240 | * |
232 | * @param String selector CSS3 selector | 241 | * @param String selector CSS3 selector |
242 | * @param HTMLElement|null scope Element to search child elements within | ||
233 | * @return NodeList|undefined | 243 | * @return NodeList|undefined |
234 | */ | 244 | */ |
235 | this.findAll = function findAll(selector) { | 245 | this.findAll = function findAll(selector, scope) { |
246 | scope = scope || document; | ||
236 | try { | 247 | try { |
237 | var pSelector = this.processSelector(selector); | 248 | var pSelector = this.processSelector(selector); |
238 | if (pSelector.type === 'xpath') { | 249 | if (pSelector.type === 'xpath') { |
239 | return this.getElementsByXPath(pSelector.path); | 250 | return this.getElementsByXPath(pSelector.path); |
240 | } else { | 251 | } else { |
241 | return document.querySelectorAll(pSelector.path); | 252 | return scope.querySelectorAll(pSelector.path); |
242 | } | 253 | } |
243 | } catch (e) { | 254 | } catch (e) { |
244 | this.log('findAll(): invalid selector provided "' + selector + '":' + e, "error"); | 255 | this.log('findAll(): invalid selector provided "' + selector + '":' + e, "error"); |
... | @@ -248,16 +259,18 @@ | ... | @@ -248,16 +259,18 @@ |
248 | /** | 259 | /** |
249 | * Finds a DOM element by the provided selector. | 260 | * Finds a DOM element by the provided selector. |
250 | * | 261 | * |
251 | * @param String selector CSS3 selector | 262 | * @param String selector CSS3 selector |
263 | * @param HTMLElement|null scope Element to search child elements within | ||
252 | * @return HTMLElement|undefined | 264 | * @return HTMLElement|undefined |
253 | */ | 265 | */ |
254 | this.findOne = function findOne(selector) { | 266 | this.findOne = function findOne(selector, scope) { |
267 | scope = scope || document; | ||
255 | try { | 268 | try { |
256 | var pSelector = this.processSelector(selector); | 269 | var pSelector = this.processSelector(selector); |
257 | if (pSelector.type === 'xpath') { | 270 | if (pSelector.type === 'xpath') { |
258 | return this.getElementByXPath(pSelector.path); | 271 | return this.getElementByXPath(pSelector.path); |
259 | } else { | 272 | } else { |
260 | return document.querySelector(pSelector.path); | 273 | return scope.querySelector(pSelector.path); |
261 | } | 274 | } |
262 | } catch (e) { | 275 | } catch (e) { |
263 | this.log('findOne(): invalid selector provided "' + selector + '":' + e, "error"); | 276 | this.log('findOne(): invalid selector provided "' + selector + '":' + e, "error"); |
... | @@ -462,8 +475,8 @@ | ... | @@ -462,8 +475,8 @@ |
462 | * @param mixed value The field value to set | 475 | * @param mixed value The field value to set |
463 | */ | 476 | */ |
464 | this.setField = function setField(field, value) { | 477 | this.setField = function setField(field, value) { |
465 | var fields, out; | 478 | var logValue, fields, out; |
466 | value = value || ""; | 479 | value = logValue = (value || ""); |
467 | if (field instanceof NodeList) { | 480 | if (field instanceof NodeList) { |
468 | fields = field; | 481 | fields = field; |
469 | field = fields[0]; | 482 | field = fields[0]; |
... | @@ -471,11 +484,15 @@ | ... | @@ -471,11 +484,15 @@ |
471 | if (!field instanceof HTMLElement) { | 484 | if (!field instanceof HTMLElement) { |
472 | this.log("Invalid field type; only HTMLElement and NodeList are supported", "error"); | 485 | this.log("Invalid field type; only HTMLElement and NodeList are supported", "error"); |
473 | } | 486 | } |
474 | this.log('Set "' + field.getAttribute('name') + '" field value to ' + value, "debug"); | 487 | if (this.options && this.options.safeLogs && field.getAttribute('type') === "password") { |
488 | // obfuscate password value | ||
489 | logValue = new Array(value.length + 1).join("*"); | ||
490 | } | ||
491 | this.log('Set "' + field.getAttribute('name') + '" field value to ' + logValue, "debug"); | ||
475 | try { | 492 | try { |
476 | field.focus(); | 493 | field.focus(); |
477 | } catch (e) { | 494 | } catch (e) { |
478 | __utils__.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning"); | 495 | this.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning"); |
479 | } | 496 | } |
480 | var nodeName = field.nodeName.toLowerCase(); | 497 | var nodeName = field.nodeName.toLowerCase(); |
481 | switch (nodeName) { | 498 | switch (nodeName) { |
... | @@ -544,7 +561,7 @@ | ... | @@ -544,7 +561,7 @@ |
544 | try { | 561 | try { |
545 | field.blur(); | 562 | field.blur(); |
546 | } catch (err) { | 563 | } catch (err) { |
547 | __utils__.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning"); | 564 | this.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning"); |
548 | } | 565 | } |
549 | return out; | 566 | return out; |
550 | }; | 567 | }; |
... | @@ -570,7 +587,4 @@ | ... | @@ -570,7 +587,4 @@ |
570 | } | 587 | } |
571 | }; | 588 | }; |
572 | }; | 589 | }; |
573 | |||
574 | // silly "hack" to force having an instance available | ||
575 | exports.__utils__ = new exports.ClientUtils(); | ||
576 | })(typeof exports === "object" ? exports : window); | 590 | })(typeof exports === "object" ? exports : window); | ... | ... |
... | @@ -28,10 +28,13 @@ | ... | @@ -28,10 +28,13 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /*global exports console require*/ | ||
32 | |||
31 | var fs = require('fs'); | 33 | var fs = require('fs'); |
32 | var utils = require('utils'); | 34 | var utils = require('utils'); |
33 | 35 | ||
34 | exports.create = function create(type) { | 36 | exports.create = function create(type) { |
37 | "use strict"; | ||
35 | if (!type) { | 38 | if (!type) { |
36 | return; | 39 | return; |
37 | } | 40 | } |
... | @@ -48,6 +51,7 @@ exports.create = function create(type) { | ... | @@ -48,6 +51,7 @@ exports.create = function create(type) { |
48 | * (c) Fabien Potencier, Symfony project, MIT license | 51 | * (c) Fabien Potencier, Symfony project, MIT license |
49 | */ | 52 | */ |
50 | var Colorizer = function Colorizer() { | 53 | var Colorizer = function Colorizer() { |
54 | "use strict"; | ||
51 | var options = { bold: 1, underscore: 4, blink: 5, reverse: 7, conceal: 8 }; | 55 | var options = { bold: 1, underscore: 4, blink: 5, reverse: 7, conceal: 8 }; |
52 | var foreground = { black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37 }; | 56 | var foreground = { black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37 }; |
53 | var background = { black: 40, red: 41, green: 42, yellow: 43, blue: 44, magenta: 45, cyan: 46, white: 47 }; | 57 | var background = { black: 40, red: 41, green: 42, yellow: 43, blue: 44, magenta: 45, cyan: 46, white: 47 }; |
... | @@ -104,7 +108,7 @@ var Colorizer = function Colorizer() { | ... | @@ -104,7 +108,7 @@ var Colorizer = function Colorizer() { |
104 | if (typeof pad === "number" && text.length < pad) { | 108 | if (typeof pad === "number" && text.length < pad) { |
105 | text += new Array(pad - text.length + 1).join(' '); | 109 | text += new Array(pad - text.length + 1).join(' '); |
106 | } | 110 | } |
107 | return "\033[" + codes.join(';') + 'm' + text + "\033[0m"; | 111 | return "\u001b[" + codes.join(';') + 'm' + text + "\u001b[0m"; |
108 | }; | 112 | }; |
109 | }; | 113 | }; |
110 | exports.Colorizer = Colorizer; | 114 | exports.Colorizer = Colorizer; |
... | @@ -114,6 +118,7 @@ exports.Colorizer = Colorizer; | ... | @@ -114,6 +118,7 @@ exports.Colorizer = Colorizer; |
114 | * | 118 | * |
115 | */ | 119 | */ |
116 | var Dummy = function Dummy() { | 120 | var Dummy = function Dummy() { |
121 | "use strict"; | ||
117 | this.colorize = function colorize(text, styleName, pad) { | 122 | this.colorize = function colorize(text, styleName, pad) { |
118 | return text; | 123 | return text; |
119 | }; | 124 | }; | ... | ... |
... | @@ -28,9 +28,12 @@ | ... | @@ -28,9 +28,12 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /*global CasperError console encodeURIComponent escape exports require*/ | ||
32 | |||
31 | var utils = require('utils'); | 33 | var utils = require('utils'); |
32 | 34 | ||
33 | exports.create = function create(fn) { | 35 | exports.create = function create(fn) { |
36 | "use strict"; | ||
34 | return new FunctionArgsInjector(fn); | 37 | return new FunctionArgsInjector(fn); |
35 | }; | 38 | }; |
36 | 39 | ||
... | @@ -40,6 +43,7 @@ exports.create = function create(fn) { | ... | @@ -40,6 +43,7 @@ exports.create = function create(fn) { |
40 | * FIXME: use new Function() instead of eval() | 43 | * FIXME: use new Function() instead of eval() |
41 | */ | 44 | */ |
42 | var FunctionArgsInjector = function FunctionArgsInjector(fn) { | 45 | var FunctionArgsInjector = function FunctionArgsInjector(fn) { |
46 | "use strict"; | ||
43 | if (!utils.isFunction(fn)) { | 47 | if (!utils.isFunction(fn)) { |
44 | throw new CasperError("FunctionArgsInjector() can only process functions"); | 48 | throw new CasperError("FunctionArgsInjector() can only process functions"); |
45 | } | 49 | } | ... | ... |
... | @@ -28,13 +28,17 @@ | ... | @@ -28,13 +28,17 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /*global CasperError exports require*/ | ||
32 | |||
31 | var utils = require('utils'); | 33 | var utils = require('utils'); |
32 | 34 | ||
33 | exports.create = function create(casper) { | 35 | exports.create = function create(casper) { |
36 | "use strict"; | ||
34 | return new Mouse(casper); | 37 | return new Mouse(casper); |
35 | }; | 38 | }; |
36 | 39 | ||
37 | var Mouse = function Mouse(casper) { | 40 | var Mouse = function Mouse(casper) { |
41 | "use strict"; | ||
38 | if (!utils.isCasperObject(casper)) { | 42 | if (!utils.isCasperObject(casper)) { |
39 | throw new CasperError('Mouse() needs a Casper instance'); | 43 | throw new CasperError('Mouse() needs a Casper instance'); |
40 | } | 44 | } | ... | ... |
... | @@ -28,7 +28,7 @@ | ... | @@ -28,7 +28,7 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /*global exports:false, phantom:false, require:false, CasperError:false*/ | 31 | /*global CasperError exports phantom require*/ |
32 | 32 | ||
33 | var fs = require('fs'); | 33 | var fs = require('fs'); |
34 | var events = require('events'); | 34 | var events = require('events'); |
... | @@ -55,6 +55,7 @@ var Tester = function Tester(casper, options) { | ... | @@ -55,6 +55,7 @@ var Tester = function Tester(casper, options) { |
55 | 55 | ||
56 | this.currentTestFile = null; | 56 | this.currentTestFile = null; |
57 | this.exporter = require('xunit').create(); | 57 | this.exporter = require('xunit').create(); |
58 | this.includes = []; | ||
58 | this.running = false; | 59 | this.running = false; |
59 | this.suites = []; | 60 | this.suites = []; |
60 | this.options = utils.mergeObjects({ | 61 | this.options = utils.mergeObjects({ |
... | @@ -287,7 +288,7 @@ var Tester = function Tester(casper, options) { | ... | @@ -287,7 +288,7 @@ var Tester = function Tester(casper, options) { |
287 | standard: "Subject matches the provided pattern", | 288 | standard: "Subject matches the provided pattern", |
288 | values: { | 289 | values: { |
289 | subject: subject, | 290 | subject: subject, |
290 | pattern: pattern | 291 | pattern: pattern.toString() |
291 | } | 292 | } |
292 | }); | 293 | }); |
293 | }; | 294 | }; |
... | @@ -361,7 +362,7 @@ var Tester = function Tester(casper, options) { | ... | @@ -361,7 +362,7 @@ var Tester = function Tester(casper, options) { |
361 | */ | 362 | */ |
362 | this.assertTextExists = this.assertTextExist = function assertTextExists(text, message) { | 363 | this.assertTextExists = this.assertTextExist = function assertTextExists(text, message) { |
363 | var textFound = (casper.evaluate(function _evaluate() { | 364 | var textFound = (casper.evaluate(function _evaluate() { |
364 | return document.body.innerText; | 365 | return document.body.textContent || document.body.innerText; |
365 | }).indexOf(text) !== -1); | 366 | }).indexOf(text) !== -1); |
366 | return this.assert(textFound, message, { | 367 | return this.assert(textFound, message, { |
367 | type: "assertTextExists", | 368 | type: "assertTextExists", |
... | @@ -392,6 +393,25 @@ var Tester = function Tester(casper, options) { | ... | @@ -392,6 +393,25 @@ var Tester = function Tester(casper, options) { |
392 | }; | 393 | }; |
393 | 394 | ||
394 | /** | 395 | /** |
396 | * Asserts that title of the remote page matched the provided pattern. | ||
397 | * | ||
398 | * @param RegExp pattern The pattern to test the title against | ||
399 | * @param String message Test description | ||
400 | * @return Object An assertion result object | ||
401 | */ | ||
402 | this.assertTitleMatch = this.assertTitleMatches = function assertTitleMatch(pattern, message) { | ||
403 | var currentTitle = casper.getTitle(); | ||
404 | return this.assert(pattern.test(currentTitle), message, { | ||
405 | type: "assertTitle", | ||
406 | details: "Page title does not match the provided pattern", | ||
407 | values: { | ||
408 | subject: currentTitle, | ||
409 | pattern: pattern.toString() | ||
410 | } | ||
411 | }); | ||
412 | }; | ||
413 | |||
414 | /** | ||
395 | * Asserts that the provided subject is of the given type. | 415 | * Asserts that the provided subject is of the given type. |
396 | * | 416 | * |
397 | * @param mixed subject The value to test | 417 | * @param mixed subject The value to test |
... | @@ -427,7 +447,7 @@ var Tester = function Tester(casper, options) { | ... | @@ -427,7 +447,7 @@ var Tester = function Tester(casper, options) { |
427 | standard: "Current url matches the provided pattern", | 447 | standard: "Current url matches the provided pattern", |
428 | values: { | 448 | values: { |
429 | currentUrl: currentUrl, | 449 | currentUrl: currentUrl, |
430 | pattern: pattern | 450 | pattern: pattern.toString() |
431 | } | 451 | } |
432 | }); | 452 | }); |
433 | }; | 453 | }; |
... | @@ -695,6 +715,9 @@ var Tester = function Tester(casper, options) { | ... | @@ -695,6 +715,9 @@ var Tester = function Tester(casper, options) { |
695 | this.runTest = function runTest(testFile) { | 715 | this.runTest = function runTest(testFile) { |
696 | this.bar(f('Test file: %s', testFile), 'INFO_BAR'); | 716 | this.bar(f('Test file: %s', testFile), 'INFO_BAR'); |
697 | this.running = true; // this.running is set back to false with done() | 717 | this.running = true; // this.running is set back to false with done() |
718 | this.includes.forEach(function(include) { | ||
719 | phantom.injectJs(include); | ||
720 | }); | ||
698 | this.exec(testFile); | 721 | this.exec(testFile); |
699 | }; | 722 | }; |
700 | 723 | ... | ... |
... | @@ -28,329 +28,343 @@ | ... | @@ -28,329 +28,343 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | /** | 31 | /*global CasperError console exports phantom require*/ |
32 | * Provides a better typeof operator equivalent, able to retrieve the array | ||
33 | * type. | ||
34 | * | ||
35 | * @param mixed input | ||
36 | * @return String | ||
37 | * @see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ | ||
38 | */ | ||
39 | function betterTypeOf(input) { | ||
40 | try { | ||
41 | return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1].toLowerCase(); | ||
42 | } catch (e) { | ||
43 | return typeof input; | ||
44 | } | ||
45 | } | ||
46 | exports.betterTypeOf = betterTypeOf; | ||
47 | 32 | ||
48 | /** | 33 | (function(exports) { |
49 | * Dumps a JSON representation of passed value to the console. Used for | 34 | "use strict"; |
50 | * debugging purpose only. | ||
51 | * | ||
52 | * @param Mixed value | ||
53 | */ | ||
54 | function dump(value) { | ||
55 | console.log(serialize(value)); | ||
56 | } | ||
57 | exports.dump = dump; | ||
58 | 35 | ||
59 | /** | 36 | /** |
60 | * Returns the file extension in lower case. | 37 | * Provides a better typeof operator equivalent, able to retrieve the array |
61 | * | 38 | * type. |
62 | * @param String file File path | 39 | * |
63 | * @return string | 40 | * @param mixed input |
64 | */ | 41 | * @return String |
65 | function fileExt(file) { | 42 | * @see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ |
66 | try { | 43 | */ |
67 | return file.split('.').pop().toLowerCase().trim(); | 44 | function betterTypeOf(input) { |
68 | } catch(e) { | 45 | try { |
69 | return ''; | 46 | return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1].toLowerCase(); |
47 | } catch (e) { | ||
48 | return typeof input; | ||
49 | } | ||
70 | } | 50 | } |
71 | } | 51 | exports.betterTypeOf = betterTypeOf; |
72 | exports.fileExt = fileExt; | ||
73 | 52 | ||
74 | /** | 53 | /** |
75 | * Takes a string and append blanks until the pad value is reached. | 54 | * Dumps a JSON representation of passed value to the console. Used for |
76 | * | 55 | * debugging purpose only. |
77 | * @param String text | 56 | * |
78 | * @param Number pad Pad value (optional; default: 80) | 57 | * @param Mixed value |
79 | * @return String | 58 | */ |
80 | */ | 59 | function dump(value) { |
81 | function fillBlanks(text, pad) { | 60 | console.log(serialize(value)); |
82 | pad = pad || 80; | ||
83 | if (text.length < pad) { | ||
84 | text += new Array(pad - text.length + 1).join(' '); | ||
85 | } | 61 | } |
86 | return text; | 62 | exports.dump = dump; |
87 | } | ||
88 | exports.fillBlanks = fillBlanks; | ||
89 | 63 | ||
90 | /** | 64 | /** |
91 | * Formats a string with passed parameters. Ported from nodejs `util.format()`. | 65 | * Returns the file extension in lower case. |
92 | * | 66 | * |
93 | * @return String | 67 | * @param String file File path |
94 | */ | 68 | * @return string |
95 | function format(f) { | 69 | */ |
96 | var i; | 70 | function fileExt(file) { |
97 | if (typeof f !== 'string') { | 71 | try { |
98 | var objects = []; | 72 | return file.split('.').pop().toLowerCase().trim(); |
99 | for (i = 0; i < arguments.length; i++) { | 73 | } catch(e) { |
100 | objects.push(inspect(arguments[i])); | 74 | return ''; |
101 | } | 75 | } |
102 | return objects.join(' '); | ||
103 | } | 76 | } |
104 | i = 1; | 77 | exports.fileExt = fileExt; |
105 | var args = arguments; | 78 | |
106 | var len = args.length; | 79 | /** |
107 | var str = String(f).replace(/%[sdj%]/g, function _replace(x) { | 80 | * Takes a string and append blanks until the pad value is reached. |
108 | if (i >= len) return x; | 81 | * |
109 | switch (x) { | 82 | * @param String text |
110 | case '%s': | 83 | * @param Number pad Pad value (optional; default: 80) |
111 | return String(args[i++]); | 84 | * @return String |
112 | case '%d': | 85 | */ |
113 | return Number(args[i++]); | 86 | function fillBlanks(text, pad) { |
114 | case '%j': | 87 | pad = pad || 80; |
115 | return JSON.stringify(args[i++]); | 88 | if (text.length < pad) { |
116 | case '%%': | 89 | text += new Array(pad - text.length + 1).join(' '); |
117 | return '%'; | ||
118 | default: | ||
119 | return x; | ||
120 | } | ||
121 | }); | ||
122 | for (var x = args[i]; i < len; x = args[++i]) { | ||
123 | if (x === null || typeof x !== 'object') { | ||
124 | str += ' ' + x; | ||
125 | } else { | ||
126 | str += ' ' + inspect(x); | ||
127 | } | 90 | } |
91 | return text; | ||
128 | } | 92 | } |
129 | return str; | 93 | exports.fillBlanks = fillBlanks; |
130 | } | ||
131 | exports.format = format; | ||
132 | 94 | ||
133 | /** | 95 | /** |
134 | * Inherit the prototype methods from one constructor into another. | 96 | * Formats a string with passed parameters. Ported from nodejs `util.format()`. |
135 | * | 97 | * |
136 | * @param {function} ctor Constructor function which needs to inherit the | 98 | * @return String |
137 | * prototype. | 99 | */ |
138 | * @param {function} superCtor Constructor function to inherit prototype from. | 100 | function format(f) { |
139 | */ | 101 | var i = 1; |
140 | function inherits(ctor, superCtor) { | 102 | var args = arguments; |
141 | ctor.super_ = ctor.__super__ = superCtor; | 103 | var len = args.length; |
142 | ctor.prototype = Object.create(superCtor.prototype, { | 104 | var str = String(f).replace(/%[sdj%]/g, function _replace(x) { |
143 | constructor: { | 105 | if (i >= len) return x; |
144 | value: ctor, | 106 | switch (x) { |
145 | enumerable: false, | 107 | case '%s': |
146 | writable: true, | 108 | return String(args[i++]); |
147 | configurable: true | 109 | case '%d': |
110 | return Number(args[i++]); | ||
111 | case '%j': | ||
112 | return JSON.stringify(args[i++]); | ||
113 | case '%%': | ||
114 | return '%'; | ||
115 | default: | ||
116 | return x; | ||
117 | } | ||
118 | }); | ||
119 | for (var x = args[i]; i < len; x = args[++i]) { | ||
120 | if (x === null || typeof x !== 'object') { | ||
121 | str += ' ' + x; | ||
122 | } else { | ||
123 | str += '[obj]'; | ||
124 | } | ||
148 | } | 125 | } |
149 | }); | 126 | return str; |
150 | } | 127 | } |
151 | exports.inherits = inherits; | 128 | exports.format = format; |
152 | 129 | ||
153 | /** | 130 | /** |
154 | * Checks if value is a javascript Array | 131 | * Inherit the prototype methods from one constructor into another. |
155 | * | 132 | * |
156 | * @param mixed value | 133 | * @param {function} ctor Constructor function which needs to inherit the |
157 | * @return Boolean | 134 | * prototype. |
158 | */ | 135 | * @param {function} superCtor Constructor function to inherit prototype from. |
159 | function isArray(value) { | 136 | */ |
160 | return Array.isArray(value) || isType(value, "array"); | 137 | function inherits(ctor, superCtor) { |
161 | } | 138 | ctor.super_ = ctor.__super__ = superCtor; |
162 | exports.isArray = isArray; | 139 | ctor.prototype = Object.create(superCtor.prototype, { |
140 | constructor: { | ||
141 | value: ctor, | ||
142 | enumerable: false, | ||
143 | writable: true, | ||
144 | configurable: true | ||
145 | } | ||
146 | }); | ||
147 | } | ||
148 | exports.inherits = inherits; | ||
163 | 149 | ||
164 | /** | 150 | /** |
165 | * Checks if passed argument is an instance of Capser object. | 151 | * Checks if value is a javascript Array |
166 | * | 152 | * |
167 | * @param mixed value | 153 | * @param mixed value |
168 | * @return Boolean | 154 | * @return Boolean |
169 | */ | 155 | */ |
170 | function isCasperObject(value) { | 156 | function isArray(value) { |
171 | return value instanceof require('casper').Casper; | 157 | return Array.isArray(value) || isType(value, "array"); |
172 | } | 158 | } |
173 | exports.isCasperObject = isCasperObject; | 159 | exports.isArray = isArray; |
174 | 160 | ||
175 | /** | 161 | /** |
176 | * Checks if value is a phantomjs clipRect-compatible object | 162 | * Checks if passed argument is an instance of Capser object. |
177 | * | 163 | * |
178 | * @param mixed value | 164 | * @param mixed value |
179 | * @return Boolean | 165 | * @return Boolean |
180 | */ | 166 | */ |
181 | function isClipRect(value) { | 167 | function isCasperObject(value) { |
182 | return isType(value, "cliprect") || ( | 168 | return value instanceof require('casper').Casper; |
183 | isObject(value) && | 169 | } |
184 | isNumber(value.top) && isNumber(value.left) && | 170 | exports.isCasperObject = isCasperObject; |
185 | isNumber(value.width) && isNumber(value.height) | ||
186 | ); | ||
187 | } | ||
188 | exports.isClipRect = isClipRect; | ||
189 | 171 | ||
190 | /** | 172 | /** |
191 | * Checks if value is a javascript Function | 173 | * Checks if value is a phantomjs clipRect-compatible object |
192 | * | 174 | * |
193 | * @param mixed value | 175 | * @param mixed value |
194 | * @return Boolean | 176 | * @return Boolean |
195 | */ | 177 | */ |
196 | function isFunction(value) { | 178 | function isClipRect(value) { |
197 | return isType(value, "function"); | 179 | return isType(value, "cliprect") || ( |
198 | } | 180 | isObject(value) && |
199 | exports.isFunction = isFunction; | 181 | isNumber(value.top) && isNumber(value.left) && |
182 | isNumber(value.width) && isNumber(value.height) | ||
183 | ); | ||
184 | } | ||
185 | exports.isClipRect = isClipRect; | ||
200 | 186 | ||
201 | /** | 187 | /** |
202 | * Checks if a file is apparently javascript compatible (.js or .coffee). | 188 | * Checks if value is a javascript Function |
203 | * | 189 | * |
204 | * @param String file Path to the file to test | 190 | * @param mixed value |
205 | * @return Boolean | 191 | * @return Boolean |
206 | */ | 192 | */ |
207 | function isJsFile(file) { | 193 | function isFunction(value) { |
208 | var ext = fileExt(file); | 194 | return isType(value, "function"); |
209 | return isString(ext, "string") && ['js', 'coffee'].indexOf(ext) !== -1; | 195 | } |
210 | } | 196 | exports.isFunction = isFunction; |
211 | exports.isJsFile = isJsFile; | ||
212 | 197 | ||
213 | /** | 198 | /** |
214 | * Checks if the provided value is null | 199 | * Checks if a file is apparently javascript compatible (.js or .coffee). |
215 | * | 200 | * |
216 | * @return Boolean | 201 | * @param String file Path to the file to test |
217 | */ | 202 | * @return Boolean |
218 | function isNull(value) { | 203 | */ |
219 | return isType(value, "null"); | 204 | function isJsFile(file) { |
220 | } | 205 | var ext = fileExt(file); |
221 | exports.isNull = isNull; | 206 | return isString(ext, "string") && ['js', 'coffee'].indexOf(ext) !== -1; |
207 | } | ||
208 | exports.isJsFile = isJsFile; | ||
222 | 209 | ||
223 | /** | 210 | /** |
224 | * Checks if value is a javascript Number | 211 | * Checks if the provided value is null |
225 | * | 212 | * |
226 | * @param mixed value | 213 | * @return Boolean |
227 | * @return Boolean | 214 | */ |
228 | */ | 215 | function isNull(value) { |
229 | function isNumber(value) { | 216 | return isType(value, "null"); |
230 | return isType(value, "number"); | 217 | } |
231 | } | 218 | exports.isNull = isNull; |
232 | exports.isNumber = isNumber; | ||
233 | 219 | ||
234 | /** | 220 | /** |
235 | * Checks if value is a javascript Object | 221 | * Checks if value is a javascript Number |
236 | * | 222 | * |
237 | * @param mixed value | 223 | * @param mixed value |
238 | * @return Boolean | 224 | * @return Boolean |
239 | */ | 225 | */ |
240 | function isObject(value) { | 226 | function isNumber(value) { |
241 | return isType(value, "object"); | 227 | return isType(value, "number"); |
242 | } | 228 | } |
243 | exports.isObject = isObject; | 229 | exports.isNumber = isNumber; |
244 | 230 | ||
245 | /** | 231 | /** |
246 | * Checks if value is a javascript String | 232 | * Checks if value is a javascript Object |
247 | * | 233 | * |
248 | * @param mixed value | 234 | * @param mixed value |
249 | * @return Boolean | 235 | * @return Boolean |
250 | */ | 236 | */ |
251 | function isString(value) { | 237 | function isObject(value) { |
252 | return isType(value, "string"); | 238 | var objectTypes = ["array", "object", "qtruntimeobject"]; |
253 | } | 239 | return objectTypes.indexOf(betterTypeOf(value)) >= 0; |
254 | exports.isString = isString; | 240 | } |
241 | exports.isObject = isObject; | ||
255 | 242 | ||
256 | /** | 243 | /** |
257 | * Shorthands for checking if a value is of the given type. Can check for | 244 | * Checks if value is a javascript String |
258 | * arrays. | 245 | * |
259 | * | 246 | * @param mixed value |
260 | * @param mixed what The value to check | 247 | * @return Boolean |
261 | * @param String typeName The type name ("string", "number", "function", etc.) | 248 | */ |
262 | * @return Boolean | 249 | function isString(value) { |
263 | */ | 250 | return isType(value, "string"); |
264 | function isType(what, typeName) { | ||
265 | if (typeof typeName !== "string" || !typeName) { | ||
266 | throw new CasperError("You must pass isType() a typeName string"); | ||
267 | } | 251 | } |
268 | return betterTypeOf(what).toLowerCase() === typeName.toLowerCase(); | 252 | exports.isString = isString; |
269 | } | ||
270 | exports.isType = isType; | ||
271 | 253 | ||
272 | /** | 254 | /** |
273 | * Checks if the provided value is undefined | 255 | * Shorthands for checking if a value is of the given type. Can check for |
274 | * | 256 | * arrays. |
275 | * @return Boolean | 257 | * |
276 | */ | 258 | * @param mixed what The value to check |
277 | function isUndefined(value) { | 259 | * @param String typeName The type name ("string", "number", "function", etc.) |
278 | return isType(value, "undefined"); | 260 | * @return Boolean |
279 | } | 261 | */ |
280 | exports.isUndefined = isUndefined; | 262 | function isType(what, typeName) { |
263 | if (typeof typeName !== "string" || !typeName) { | ||
264 | throw new CasperError("You must pass isType() a typeName string"); | ||
265 | } | ||
266 | return betterTypeOf(what).toLowerCase() === typeName.toLowerCase(); | ||
267 | } | ||
268 | exports.isType = isType; | ||
281 | 269 | ||
282 | /** | 270 | /** |
283 | * Checks if the provided var is a WebPage instance | 271 | * Checks if the provided value is undefined |
284 | * | 272 | * |
285 | * @param mixed what | 273 | * @return Boolean |
286 | * @return Boolean | 274 | */ |
287 | */ | 275 | function isUndefined(value) { |
288 | function isWebPage(what) { | 276 | return isType(value, "undefined"); |
289 | if (!what || !isObject(what)) { | ||
290 | return false; | ||
291 | } | 277 | } |
292 | if (phantom.version.major <= 1 && phantom.version.minor < 3 && isFunction(require)) { | 278 | exports.isUndefined = isUndefined; |
293 | return what instanceof WebPage; | 279 | |
294 | } else { | 280 | /** |
295 | return what.toString().indexOf('WebPage(') === 0; | 281 | * Checks if the provided var is a WebPage instance |
282 | * | ||
283 | * @param mixed what | ||
284 | * @return Boolean | ||
285 | */ | ||
286 | function isWebPage(what) { | ||
287 | return betterTypeOf(what) === "qtruntimeobject" && what.objectName === 'WebPage'; | ||
296 | } | 288 | } |
297 | } | 289 | exports.isWebPage = isWebPage; |
298 | exports.isWebPage = isWebPage; | ||
299 | 290 | ||
300 | /** | 291 | /** |
301 | * Object recursive merging utility. | 292 | * Object recursive merging utility. |
302 | * | 293 | * |
303 | * @param Object origin the origin object | 294 | * @param Object origin the origin object |
304 | * @param Object add the object to merge data into origin | 295 | * @param Object add the object to merge data into origin |
305 | * @return Object | 296 | * @return Object |
306 | */ | 297 | */ |
307 | function mergeObjects(origin, add) { | 298 | function mergeObjects(origin, add) { |
308 | for (var p in add) { | 299 | for (var p in add) { |
309 | try { | 300 | try { |
310 | if (add[p].constructor === Object) { | 301 | if (add[p].constructor === Object) { |
311 | origin[p] = mergeObjects(origin[p], add[p]); | 302 | origin[p] = mergeObjects(origin[p], add[p]); |
312 | } else { | 303 | } else { |
313 | origin[p] = add[p]; | 304 | origin[p] = add[p]; |
305 | } | ||
306 | } catch(e) { | ||
307 | origin[p] = add[p]; | ||
314 | } | 308 | } |
315 | } catch(e) { | ||
316 | origin[p] = add[p]; | ||
317 | } | 309 | } |
310 | return origin; | ||
318 | } | 311 | } |
319 | return origin; | 312 | exports.mergeObjects = mergeObjects; |
320 | } | ||
321 | exports.mergeObjects = mergeObjects; | ||
322 | 313 | ||
323 | /** | 314 | /** |
324 | * Creates an (SG|X)ML node element. | 315 | * Creates an (SG|X)ML node element. |
325 | * | 316 | * |
326 | * @param String name The node name | 317 | * @param String name The node name |
327 | * @param Object attributes Optional attributes | 318 | * @param Object attributes Optional attributes |
328 | * @return HTMLElement | 319 | * @return HTMLElement |
329 | */ | 320 | */ |
330 | function node(name, attributes) { | 321 | function node(name, attributes) { |
331 | var _node = document.createElement(name); | 322 | var _node = document.createElement(name); |
332 | for (var attrName in attributes) { | 323 | for (var attrName in attributes) { |
333 | var value = attributes[attrName]; | 324 | var value = attributes[attrName]; |
334 | if (attributes.hasOwnProperty(attrName) && isString(attrName)) { | 325 | if (attributes.hasOwnProperty(attrName) && isString(attrName)) { |
335 | _node.setAttribute(attrName, value); | 326 | _node.setAttribute(attrName, value); |
327 | } | ||
336 | } | 328 | } |
329 | return _node; | ||
337 | } | 330 | } |
338 | return _node; | 331 | exports.node = node; |
339 | } | ||
340 | exports.node = node; | ||
341 | 332 | ||
342 | /** | 333 | /** |
343 | * Serializes a value using JSON. | 334 | * Serializes a value using JSON. |
344 | * | 335 | * |
345 | * @param Mixed value | 336 | * @param Mixed value |
346 | * @return String | 337 | * @return String |
347 | */ | 338 | */ |
348 | function serialize(value) { | 339 | function serialize(value) { |
349 | if (isArray(value)) { | 340 | if (isArray(value)) { |
350 | value = value.map(function _map(prop) { | 341 | value = value.map(function _map(prop) { |
351 | return isFunction(prop) ? prop.toString().replace(/\s{2,}/, '') : prop; | 342 | return isFunction(prop) ? prop.toString().replace(/\s{2,}/, '') : prop; |
352 | }); | 343 | }); |
344 | } | ||
345 | return JSON.stringify(value, null, 4); | ||
346 | } | ||
347 | exports.serialize = serialize; | ||
348 | |||
349 | /** | ||
350 | * Returns unique values from an array. | ||
351 | * | ||
352 | * Note: ugly code is ugly, but efficient: http://jsperf.com/array-unique2/8 | ||
353 | * | ||
354 | * @param Array array | ||
355 | * @return Array | ||
356 | */ | ||
357 | function unique(array) { | ||
358 | var o = {}, | ||
359 | r = []; | ||
360 | for (var i = 0, len = array.length; i !== len; i++) { | ||
361 | var d = array[i]; | ||
362 | if (o[d] !== 1) { | ||
363 | o[d] = 1; | ||
364 | r[r.length] = d; | ||
365 | } | ||
366 | } | ||
367 | return r; | ||
353 | } | 368 | } |
354 | return JSON.stringify(value, null, 4); | 369 | exports.unique = unique; |
355 | } | 370 | })(exports); |
356 | exports.serialize = serialize; | ... | ... |
This diff could not be displayed because it is too large.
... | @@ -27,13 +27,15 @@ | ... | @@ -27,13 +27,15 @@ |
27 | * DEALINGS IN THE SOFTWARE. | 27 | * DEALINGS IN THE SOFTWARE. |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | /*global exports, phantom, require, CasperError*/ | 30 | |
31 | /*global CasperError console exports phantom require*/ | ||
32 | |||
31 | var utils = require('utils'); | 33 | var utils = require('utils'); |
32 | var fs = require('fs'); | 34 | var fs = require('fs'); |
33 | 35 | ||
34 | exports.create = function create() { | 36 | exports.create = function create() { |
35 | "use strict"; | 37 | "use strict"; |
36 | return new this.XUnitExporter(); | 38 | return new XUnitExporter(); |
37 | }; | 39 | }; |
38 | 40 | ||
39 | /** | 41 | /** | ... | ... |
1 | casper = require("casper").create | 1 | casper = require("casper").create |
2 | verbose: true | 2 | verbose: true |
3 | 3 | ||
4 | # If we don't set a limit, it could go on forever | ||
5 | upTo = ~~casper.cli.get(0) || 10 | ||
6 | |||
7 | ### | ||
8 | Fetch all <a> elements from the page and return | ||
9 | the ones which contains a href starting with 'http://' | ||
10 | ### | ||
11 | searchLinks = -> | ||
12 | filter = Array::filter | ||
13 | map = Array::map | ||
14 | map.call filter.call(document.querySelectorAll("a"), (a) -> | ||
15 | (/^http:\/\/.*/i).test a.getAttribute("href") | ||
16 | ), (a) -> | ||
17 | a.getAttribute "href" | ||
18 | |||
19 | # The base links array | 4 | # The base links array |
20 | links = [ | 5 | links = [ |
21 | "http://google.com/" | 6 | "http://google.com/" |
... | @@ -23,10 +8,10 @@ links = [ | ... | @@ -23,10 +8,10 @@ links = [ |
23 | "http://bing.com/" | 8 | "http://bing.com/" |
24 | ] | 9 | ] |
25 | 10 | ||
26 | # Just opens the page and prints the title | 11 | currentLink = 0; |
27 | start = (link) -> | 12 | |
28 | @start link, -> | 13 | # If we don't set a limit, it could go on forever |
29 | @echo "Page title: #{ @getTitle() }" | 14 | upTo = ~~casper.cli.get(0) || 10 |
30 | 15 | ||
31 | ### | 16 | ### |
32 | Get the links, and add them to the links array | 17 | Get the links, and add them to the links array |
... | @@ -38,12 +23,22 @@ addLinks = (link) -> | ... | @@ -38,12 +23,22 @@ addLinks = (link) -> |
38 | @echo "#{found.length} links found on #{link}" | 23 | @echo "#{found.length} links found on #{link}" |
39 | links = links.concat found | 24 | links = links.concat found |
40 | 25 | ||
41 | casper.start() | 26 | ### |
42 | 27 | Fetch all <a> elements from the page and return | |
43 | casper.then -> | 28 | the ones which contains a href starting with 'http://' |
44 | @echo "Starting" | 29 | ### |
30 | searchLinks = -> | ||
31 | filter = Array::filter | ||
32 | map = Array::map | ||
33 | map.call filter.call(document.querySelectorAll("a"), (a) -> | ||
34 | (/^http:\/\/.*/i).test a.getAttribute("href") | ||
35 | ), (a) -> | ||
36 | a.getAttribute "href" | ||
45 | 37 | ||
46 | currentLink = 0; | 38 | # Just opens the page and prints the title |
39 | start = (link) -> | ||
40 | @start link, -> | ||
41 | @echo "Page title: #{ @getTitle() }" | ||
47 | 42 | ||
48 | # As long as it has a next link, and is under the maximum limit, will keep running | 43 | # As long as it has a next link, and is under the maximum limit, will keep running |
49 | check = -> | 44 | check = -> |
... | @@ -57,4 +52,9 @@ check = -> | ... | @@ -57,4 +52,9 @@ check = -> |
57 | @echo "All done." | 52 | @echo "All done." |
58 | @exit() | 53 | @exit() |
59 | 54 | ||
55 | casper.start() | ||
56 | |||
57 | casper.then -> | ||
58 | @echo "Starting" | ||
59 | |||
60 | casper.run check | 60 | casper.run check | ... | ... |
... | @@ -2,24 +2,6 @@ var casper = require("casper").create({ | ... | @@ -2,24 +2,6 @@ var casper = require("casper").create({ |
2 | verbose: true | 2 | verbose: true |
3 | }); | 3 | }); |
4 | 4 | ||
5 | // If we don't set a limit, it could go on forever | ||
6 | var upTo = ~~casper.cli.get(0) || 10; | ||
7 | |||
8 | /* | ||
9 | Fetch all <a> elements from the page and return | ||
10 | the ones which contains a href starting with 'http://' | ||
11 | */ | ||
12 | var searchLinks = function() { | ||
13 | var filter, map; | ||
14 | filter = Array.prototype.filter; | ||
15 | map = Array.prototype.map; | ||
16 | return map.call(filter.call(document.querySelectorAll("a"), function(a) { | ||
17 | return /^http:\/\/.*/i.test(a.getAttribute("href")); | ||
18 | }), function(a) { | ||
19 | return a.getAttribute("href"); | ||
20 | }); | ||
21 | }; | ||
22 | |||
23 | // The base links array | 5 | // The base links array |
24 | var links = [ | 6 | var links = [ |
25 | "http://google.com/", | 7 | "http://google.com/", |
... | @@ -27,30 +9,40 @@ var links = [ | ... | @@ -27,30 +9,40 @@ var links = [ |
27 | "http://bing.com/" | 9 | "http://bing.com/" |
28 | ]; | 10 | ]; |
29 | 11 | ||
30 | // Just opens the page and prints the title | 12 | // If we don't set a limit, it could go on forever |
31 | var start = function(link) { | 13 | var upTo = ~~casper.cli.get(0) || 10; |
32 | this.start(link, function() { | 14 | |
33 | this.echo('Page title: ' + this.getTitle()); | 15 | var currentLink = 0; |
34 | }); | ||
35 | }; | ||
36 | 16 | ||
37 | // Get the links, and add them to the links array | 17 | // Get the links, and add them to the links array |
38 | // (It could be done all in one step, but it is intentionally splitted) | 18 | // (It could be done all in one step, but it is intentionally splitted) |
39 | var addLinks = function(link) { | 19 | function addLinks(link) { |
40 | this.then(function() { | 20 | this.then(function() { |
41 | var found = this.evaluate(searchLinks); | 21 | var found = this.evaluate(searchLinks); |
42 | this.echo(found.length + " links found on " + link); | 22 | this.echo(found.length + " links found on " + link); |
43 | links = links.concat(found); | 23 | links = links.concat(found); |
44 | }); | 24 | }); |
45 | }; | 25 | } |
46 | 26 | ||
47 | casper.start(); | 27 | // Fetch all <a> elements from the page and return |
48 | 28 | // the ones which contains a href starting with 'http://' | |
49 | casper.then(function() { | 29 | function searchLinks() { |
50 | this.echo("Starting"); | 30 | var filter, map; |
51 | }); | 31 | filter = Array.prototype.filter; |
32 | map = Array.prototype.map; | ||
33 | return map.call(filter.call(document.querySelectorAll("a"), function(a) { | ||
34 | return (/^http:\/\/.*/i).test(a.getAttribute("href")); | ||
35 | }), function(a) { | ||
36 | return a.getAttribute("href"); | ||
37 | }); | ||
38 | } | ||
52 | 39 | ||
53 | var currentLink = 0; | 40 | // Just opens the page and prints the title |
41 | function start(link) { | ||
42 | this.start(link, function() { | ||
43 | this.echo('Page title: ' + this.getTitle()); | ||
44 | }); | ||
45 | } | ||
54 | 46 | ||
55 | // As long as it has a next link, and is under the maximum limit, will keep running | 47 | // As long as it has a next link, and is under the maximum limit, will keep running |
56 | function check() { | 48 | function check() { |
... | @@ -64,6 +56,10 @@ function check() { | ... | @@ -64,6 +56,10 @@ function check() { |
64 | this.echo("All done."); | 56 | this.echo("All done."); |
65 | this.exit(); | 57 | this.exit(); |
66 | } | 58 | } |
67 | }; | 59 | } |
60 | |||
61 | casper.start().then(function() { | ||
62 | this.echo("Starting"); | ||
63 | }); | ||
68 | 64 | ||
69 | casper.run(check); | 65 | casper.run(check); | ... | ... |
... | @@ -6,24 +6,47 @@ if (!phantom.casperLoaded) { | ... | @@ -6,24 +6,47 @@ if (!phantom.casperLoaded) { |
6 | var fs = require('fs'); | 6 | var fs = require('fs'); |
7 | var utils = require('utils'); | 7 | var utils = require('utils'); |
8 | var f = utils.format; | 8 | var f = utils.format; |
9 | var includes = []; | ||
10 | var tests = []; | ||
9 | var casper = require('casper').create({ | 11 | var casper = require('casper').create({ |
10 | exitOnError: false | 12 | exitOnError: false |
11 | }); | 13 | }); |
12 | 14 | ||
13 | // Options from cli | 15 | // local utils |
16 | function checkIncludeFile(include) { | ||
17 | var absInclude = fs.absolute(include.trim()); | ||
18 | if (!fs.exists(absInclude)) { | ||
19 | casper.warn("%s file not found, can't be included", absInclude); | ||
20 | return; | ||
21 | } | ||
22 | if (!utils.isJsFile(absInclude)) { | ||
23 | casper.warn("%s is not a supported file type, can't be included", absInclude); | ||
24 | return; | ||
25 | } | ||
26 | if (fs.isDirectory(absInclude)) { | ||
27 | casper.warn("%s is a directory, can't be included", absInclude); | ||
28 | return; | ||
29 | } | ||
30 | if (tests.indexOf(include) > -1 || tests.indexOf(absInclude) > -1) { | ||
31 | casper.warn("%s is a test file, can't be included", absInclude); | ||
32 | return; | ||
33 | } | ||
34 | return absInclude; | ||
35 | } | ||
36 | |||
37 | // parse some options from cli | ||
14 | casper.options.verbose = casper.cli.get('direct') || false; | 38 | casper.options.verbose = casper.cli.get('direct') || false; |
15 | casper.options.logLevel = casper.cli.get('log-level') || "error"; | 39 | casper.options.logLevel = casper.cli.get('log-level') || "error"; |
16 | 40 | ||
17 | // Overriding Casper.open to prefix all test urls | 41 | // overriding Casper.open to prefix all test urls |
18 | casper.setFilter('open.location', function(location) { | 42 | casper.setFilter('open.location', function(location) { |
19 | if (!/^http/.test(location)) { | 43 | if (!/^http/.test(location)) { |
20 | return f('file://%s/%s', phantom.casperPath, location); | 44 | return f('file://%s/%s', fs.workingDirectory, location); |
21 | } | 45 | } |
22 | return location; | 46 | return location; |
23 | }); | 47 | }); |
24 | 48 | ||
25 | var tests = []; | 49 | // test paths are passed as args |
26 | |||
27 | if (casper.cli.args.length) { | 50 | if (casper.cli.args.length) { |
28 | tests = casper.cli.args.filter(function(path) { | 51 | tests = casper.cli.args.filter(function(path) { |
29 | return fs.isFile(path) || fs.isDirectory(path); | 52 | return fs.isFile(path) || fs.isDirectory(path); |
... | @@ -33,8 +56,21 @@ if (casper.cli.args.length) { | ... | @@ -33,8 +56,21 @@ if (casper.cli.args.length) { |
33 | casper.exit(1); | 56 | casper.exit(1); |
34 | } | 57 | } |
35 | 58 | ||
59 | // includes handling | ||
60 | if (casper.cli.has('includes')) { | ||
61 | includes = casper.cli.get('includes').split(',').map(function(include) { | ||
62 | // we can't use filter() directly because of abspath transformation | ||
63 | return checkIncludeFile(include); | ||
64 | }).filter(function(include) { | ||
65 | return utils.isString(include); | ||
66 | }); | ||
67 | casper.test.includes = utils.unique(includes); | ||
68 | } | ||
69 | |||
70 | // test suites completion listener | ||
36 | casper.test.on('tests.complete', function() { | 71 | casper.test.on('tests.complete', function() { |
37 | this.renderResults(true, undefined, casper.cli.get('xunit') || undefined); | 72 | this.renderResults(true, undefined, casper.cli.get('xunit') || undefined); |
38 | }); | 73 | }); |
39 | 74 | ||
75 | // run all the suites | ||
40 | casper.test.runSuites.apply(casper.test, tests); | 76 | casper.test.runSuites.apply(casper.test, tests); | ... | ... |
1 | <!DOCTYPE html> | 1 | <!DOCTYPE html> |
2 | <html> | 2 | <html> |
3 | <head> | 3 | <head> |
4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | 4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
5 | <title>CasperJS test form</title> | 5 | <title>CasperJS test form</title> |
6 | </head> | 6 | </head> |
7 | <body> | 7 | <body> |
8 | <form action="result.html" enctype="multipart/form-data"> | 8 | <form action="result.html" enctype="multipart/form-data"> |
9 | <input type="text" name="email" placeholder="email" /> | 9 | <input type="text" name="email" placeholder="email"> |
10 | <input type="password" name="password" placeholder="password"> | ||
10 | <textarea name="content"></textarea> | 11 | <textarea name="content"></textarea> |
11 | <select name="topic"> | 12 | <select name="topic"> |
12 | <option>foo</option> | 13 | <option>foo</option> |
13 | <option value="bar">baz</option> | 14 | <option value="bar">baz</option> |
14 | </select> | 15 | </select> |
15 | <input type="checkbox" name="check" /> | 16 | <input type="checkbox" name="check"> |
16 | <input type="radio" name="choice" value="yes"/> | 17 | <input type="radio" name="choice" value="yes"> |
17 | <input type="radio" name="choice" value="no"/> | 18 | <input type="radio" name="choice" value="no"> |
18 | <input type="file" name="file"/> | 19 | <input type="file" name="file"> |
19 | <input type="checkbox" name="checklist[]" value="1" /> | 20 | <input type="checkbox" name="checklist[]" value="1"> |
20 | <input type="checkbox" name="checklist[]" value="2" /> | 21 | <input type="checkbox" name="checklist[]" value="2"> |
21 | <input type="checkbox" name="checklist[]" value="3" /> | 22 | <input type="checkbox" name="checklist[]" value="3"> |
22 | <input type="submit" name="submit" value="submit" /> | 23 | <input type="submit" name="submit" value="submit"> |
23 | </form> | 24 | </form> |
24 | </body> | 25 | </body> |
25 | </html> | 26 | </html> | ... | ... |
tests/site/multiple-forms.html
0 → 100644
1 | <!DOCTYPE html> | ||
2 | <html> | ||
3 | <head> | ||
4 | <title>Multiple forms test</title> | ||
5 | </head> | ||
6 | <body> | ||
7 | <form name="f1"> | ||
8 | <input type="hidden" name="f" value="f1"> | ||
9 | <input type="text" name="yo"> | ||
10 | </form> | ||
11 | <form name="f2"> | ||
12 | <input type="hidden" name="f" value="f2"> | ||
13 | <input type="text" name="yo"> | ||
14 | </form> | ||
15 | </body> | ||
16 | </html> |
tests/suites/casper/agent.js
0 → 100644
1 | function testUA(ua, match) { | ||
2 | casper.test.assertMatch( | ||
3 | ua, match, 'Default user agent matches ' + match | ||
4 | ); | ||
5 | } | ||
6 | |||
7 | function fetchUA(request) { | ||
8 | testUA(request.headers.filter(function(header) { | ||
9 | return header.name === "User-Agent"; | ||
10 | }).pop().value, /plop/); | ||
11 | } | ||
12 | |||
13 | testUA(casper.options.pageSettings.userAgent, /CasperJS/); | ||
14 | |||
15 | casper.start(); | ||
16 | |||
17 | casper.userAgent('plop').on('resource.requested', fetchUA); | ||
18 | |||
19 | casper.thenOpen('tests/site/index.html'); | ||
20 | |||
21 | casper.run(function() { | ||
22 | this.removeListener('resource.requested', fetchUA); | ||
23 | this.test.done(); | ||
24 | }); |
tests/suites/casper/clientutils.js
deleted
100644 → 0
1 | var fs = require('fs'); | ||
2 | var clientutils = require('clientutils').create(); | ||
3 | |||
4 | var testCases = { | ||
5 | 'an empty string': '', | ||
6 | 'a word': 'plop', | ||
7 | 'a null char': 'a\u0000', | ||
8 | 'an utf8 string': 'ÀÁÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ', | ||
9 | 'song lyrics': ("Voilà l'été, j'aperçois le soleil\n" + | ||
10 | "Les nuages filent et le ciel s'éclaircit\n" + | ||
11 | "Et dans ma tête qui bourdonnent?\n" + | ||
12 | "Les abeilles!"), | ||
13 | 'a file contents': fs.read(phantom.casperPath + '/tests/site/alert.html') | ||
14 | }; | ||
15 | |||
16 | casper.test.comment('ClientUtils.encode()'); | ||
17 | |||
18 | for (var what in testCases) { | ||
19 | var source = testCases[what]; | ||
20 | var encoded = clientutils.encode(source); | ||
21 | casper.test.assertEquals(clientutils.decode(encoded), source, 'ClientUtils can encode and decode ' + what); | ||
22 | } | ||
23 | |||
24 | casper.test.done(); |
... | @@ -2,6 +2,7 @@ casper.start('tests/site/form.html', function() { | ... | @@ -2,6 +2,7 @@ casper.start('tests/site/form.html', function() { |
2 | this.test.comment('Casper.fill()'); | 2 | this.test.comment('Casper.fill()'); |
3 | this.fill('form[action="result.html"]', { | 3 | this.fill('form[action="result.html"]', { |
4 | email: 'chuck@norris.com', | 4 | email: 'chuck@norris.com', |
5 | password: 'chuck', | ||
5 | content: 'Am watching thou', | 6 | content: 'Am watching thou', |
6 | check: true, | 7 | check: true, |
7 | choice: 'no', | 8 | choice: 'no', |
... | @@ -13,6 +14,9 @@ casper.start('tests/site/form.html', function() { | ... | @@ -13,6 +14,9 @@ casper.start('tests/site/form.html', function() { |
13 | return document.querySelector('input[name="email"]').value; | 14 | return document.querySelector('input[name="email"]').value; |
14 | }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field'); | 15 | }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field'); |
15 | this.test.assertEvalEquals(function() { | 16 | this.test.assertEvalEquals(function() { |
17 | return document.querySelector('input[name="password"]').value; | ||
18 | }, 'chuck', 'Casper.fill() can fill an input[type=password] form field'); | ||
19 | this.test.assertEvalEquals(function() { | ||
16 | return document.querySelector('textarea[name="content"]').value; | 20 | return document.querySelector('textarea[name="content"]').value; |
17 | }, 'Am watching thou', 'Casper.fill() can fill a textarea form field'); | 21 | }, 'Am watching thou', 'Casper.fill() can fill a textarea form field'); |
18 | this.test.assertEvalEquals(function() { | 22 | this.test.assertEvalEquals(function() { |
... | @@ -41,12 +45,25 @@ casper.start('tests/site/form.html', function() { | ... | @@ -41,12 +45,25 @@ casper.start('tests/site/form.html', function() { |
41 | casper.then(function() { | 45 | casper.then(function() { |
42 | this.test.comment('Form submitted'); | 46 | this.test.comment('Form submitted'); |
43 | this.test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); | 47 | this.test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); |
48 | this.test.assertUrlMatch(/password=chuck/, 'Casper.fill() input[type=password] field was submitted'); | ||
44 | this.test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted'); | 49 | this.test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted'); |
45 | this.test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted'); | 50 | this.test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted'); |
46 | this.test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted'); | 51 | this.test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted'); |
47 | this.test.assertUrlMatch(/topic=bar/, 'Casper.fill() select field was submitted'); | 52 | this.test.assertUrlMatch(/topic=bar/, 'Casper.fill() select field was submitted'); |
48 | }); | 53 | }); |
49 | 54 | ||
55 | // multiple forms | ||
56 | casper.thenOpen('tests/site/multiple-forms.html', function() { | ||
57 | this.test.comment('Multiple forms'); | ||
58 | this.fill('form[name="f2"]', { | ||
59 | yo: "ok" | ||
60 | }, true); | ||
61 | }); | ||
62 | |||
63 | casper.then(function() { | ||
64 | this.test.assertUrlMatch(/\?f=f2&yo=ok$/, 'Casper.fill() handles multiple forms'); | ||
65 | }), | ||
66 | |||
50 | casper.run(function() { | 67 | casper.run(function() { |
51 | this.test.done(); | 68 | this.test.done(); |
52 | }); | 69 | }); | ... | ... |
tests/suites/clientutils.js
0 → 100644
1 | var fs = require('fs'); | ||
2 | var x = require('casper').selectXPath; | ||
3 | |||
4 | function fakeDocument(html) { | ||
5 | window.document.body.innerHTML = html; | ||
6 | } | ||
7 | |||
8 | (function(casper) { | ||
9 | casper.test.comment('ClientUtils.encode()'); | ||
10 | var clientutils = require('clientutils').create(); | ||
11 | var testCases = { | ||
12 | 'an empty string': '', | ||
13 | 'a word': 'plop', | ||
14 | 'a null char': 'a\u0000', | ||
15 | 'an utf8 string': 'ÀÁÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ', | ||
16 | 'song lyrics': ("Voilà l'été, j'aperçois le soleil\n" + | ||
17 | "Les nuages filent et le ciel s'éclaircit\n" + | ||
18 | "Et dans ma tête qui bourdonnent?\n" + | ||
19 | "Les abeilles!"), | ||
20 | 'a file contents': fs.read(phantom.casperPath + '/tests/site/alert.html') | ||
21 | }; | ||
22 | for (var what in testCases) { | ||
23 | var source = testCases[what]; | ||
24 | var encoded = clientutils.encode(source); | ||
25 | casper.test.assertEquals(clientutils.decode(encoded), source, 'ClientUtils.encode() encodes and decodes ' + what); | ||
26 | } | ||
27 | })(casper); | ||
28 | |||
29 | (function(casper) { | ||
30 | casper.test.comment('ClientUtils.exists()'); | ||
31 | var clientutils = require('clientutils').create(); | ||
32 | fakeDocument('<ul class="foo"><li>bar</li><li>baz</li></ul>'); | ||
33 | casper.test.assert(clientutils.exists('ul'), 'ClientUtils.exists() checks that an element exist'); | ||
34 | casper.test.assertNot(clientutils.exists('ol'), 'ClientUtils.exists() checks that an element exist'); | ||
35 | casper.test.assert(clientutils.exists('ul.foo li'), 'ClientUtils.exists() checks that an element exist'); | ||
36 | // xpath | ||
37 | casper.test.assert(clientutils.exists(x('//ul')), 'ClientUtils.exists() checks that an element exist using XPath'); | ||
38 | casper.test.assertNot(clientutils.exists(x('//ol')), 'ClientUtils.exists() checks that an element exist using XPath'); | ||
39 | fakeDocument(null); | ||
40 | })(casper); | ||
41 | |||
42 | (function(casper) { | ||
43 | casper.test.comment('ClientUtils.findAll()'); | ||
44 | var clientutils = require('clientutils').create(); | ||
45 | fakeDocument('<ul class="foo"><li>bar</li><li>baz</li></ul>'); | ||
46 | casper.test.assertType(clientutils.findAll('li'), 'nodelist', 'ClientUtils.findAll() can find matching DOM elements'); | ||
47 | casper.test.assertEquals(clientutils.findAll('li').length, 2, 'ClientUtils.findAll() can find matching DOM elements'); | ||
48 | casper.test.assertType(clientutils.findAll('ol'), 'nodelist', 'ClientUtils.findAll() can find matching DOM elements'); | ||
49 | casper.test.assertEquals(clientutils.findAll('ol').length, 0, 'ClientUtils.findAll() can find matching DOM elements'); | ||
50 | // scoped | ||
51 | var scope = clientutils.findOne('ul'); | ||
52 | casper.test.assertType(clientutils.findAll('li', scope), 'nodelist', 'ClientUtils.findAll() can find matching DOM elements within a given scope'); | ||
53 | fakeDocument(null); | ||
54 | })(casper); | ||
55 | |||
56 | (function(casper) { | ||
57 | casper.test.comment('ClientUtils.findOne()'); | ||
58 | var clientutils = require('clientutils').create(); | ||
59 | fakeDocument('<ul class="foo"><li>bar</li><li>baz</li></ul>'); | ||
60 | casper.test.assertType(clientutils.findOne('ul'), 'htmlulistelement', 'ClientUtils.findOne() can find a matching DOM element'); | ||
61 | casper.test.assertNot(clientutils.findOne('ol'), 'ClientUtils.findOne() can find a matching DOM element'); | ||
62 | // scoped | ||
63 | var scope = clientutils.findOne('ul'); | ||
64 | casper.test.assertType(clientutils.findAll('li', scope), 'nodelist', 'ClientUtils.findAll() can find matching DOM elements within a given scope'); | ||
65 | casper.test.assertEquals(clientutils.findAll('li', scope).length, 2, 'ClientUtils.findAll() can find matching DOM elements within a given scope'); | ||
66 | fakeDocument(null); | ||
67 | })(casper); | ||
68 | |||
69 | (function(casper) { | ||
70 | casper.test.comment('ClientUtils.processSelector()'); | ||
71 | var clientutils = require('clientutils').create(); | ||
72 | // CSS3 selector | ||
73 | var cssSelector = clientutils.processSelector('html body > ul.foo li'); | ||
74 | casper.test.assertType(cssSelector, 'object', 'ClientUtils.processSelector() can process a CSS3 selector'); | ||
75 | casper.test.assertEquals(cssSelector.type, 'css', 'ClientUtils.processSelector() can process a CSS3 selector'); | ||
76 | casper.test.assertEquals(cssSelector.path, 'html body > ul.foo li', 'ClientUtils.processSelector() can process a CSS3 selector'); | ||
77 | // XPath selector | ||
78 | var xpathSelector = clientutils.processSelector(x('//li[text()="blah"]')); | ||
79 | casper.test.assertType(xpathSelector, 'object', 'ClientUtils.processSelector() can process a XPath selector'); | ||
80 | casper.test.assertEquals(xpathSelector.type, 'xpath', 'ClientUtils.processSelector() can process a XPath selector'); | ||
81 | casper.test.assertEquals(xpathSelector.path, '//li[text()="blah"]', 'ClientUtils.processSelector() can process a XPath selector'); | ||
82 | })(casper); | ||
83 | |||
84 | casper.test.done(); |
... | @@ -96,6 +96,9 @@ casper.then(function() { | ... | @@ -96,6 +96,9 @@ casper.then(function() { |
96 | t.comment('Tester.assertTitle()'); | 96 | t.comment('Tester.assertTitle()'); |
97 | t.assertTitle('CasperJS test index', 'Tester.assertTitle() works as expected'); | 97 | t.assertTitle('CasperJS test index', 'Tester.assertTitle() works as expected'); |
98 | 98 | ||
99 | t.comment('Tester.assertTitleMatch()'); | ||
100 | t.assertTitleMatch(/test index/, 'Tester.assertTitleMatch() works as expected'); | ||
101 | |||
99 | t.comment('Tester.assertType()'); | 102 | t.comment('Tester.assertType()'); |
100 | t.assertType("plop", "string", "Tester.assertType() works as expected"); | 103 | t.assertType("plop", "string", "Tester.assertType() works as expected"); |
101 | 104 | ... | ... |
... | @@ -29,6 +29,13 @@ t.comment('fillBlanks()'); | ... | @@ -29,6 +29,13 @@ t.comment('fillBlanks()'); |
29 | } | 29 | } |
30 | })(); | 30 | })(); |
31 | 31 | ||
32 | t.comment('isArray()'); | ||
33 | (function() { | ||
34 | t.assertEquals(utils.isArray([]), true, 'isArray() checks for an Array'); | ||
35 | t.assertEquals(utils.isArray({}), false, 'isArray() checks for an Array'); | ||
36 | t.assertEquals(utils.isArray("foo"), false, 'isArray() checks for an Array'); | ||
37 | })(); | ||
38 | |||
32 | t.comment('isClipRect()'); | 39 | t.comment('isClipRect()'); |
33 | (function() { | 40 | (function() { |
34 | testCases = [ | 41 | testCases = [ |
... | @@ -44,6 +51,26 @@ t.comment('isClipRect()'); | ... | @@ -44,6 +51,26 @@ t.comment('isClipRect()'); |
44 | }); | 51 | }); |
45 | })(); | 52 | })(); |
46 | 53 | ||
54 | t.comment('isObject()'); | ||
55 | (function() { | ||
56 | t.assertEquals(utils.isObject({}), true, 'isObject() checks for an Object'); | ||
57 | t.assertEquals(utils.isObject([]), true, 'isObject() checks for an Object'); | ||
58 | t.assertEquals(utils.isObject(1), false, 'isObject() checks for an Object'); | ||
59 | t.assertEquals(utils.isObject("1"), false, 'isObject() checks for an Object'); | ||
60 | t.assertEquals(utils.isObject(function(){}), false, 'isObject() checks for an Object'); | ||
61 | t.assertEquals(utils.isObject(new Function('return {};')()), true, 'isObject() checks for an Object'); | ||
62 | t.assertEquals(utils.isObject(require('webpage').create()), true, 'isObject() checks for an Object'); | ||
63 | t.assertEquals(utils.isObject(null), false, 'isObject() checks for an Object'); | ||
64 | })(); | ||
65 | |||
66 | t.comment('isWebPage()'); | ||
67 | (function() { | ||
68 | var pageModule = require('webpage'); | ||
69 | t.assertEquals(utils.isWebPage(pageModule), false, 'isWebPage() checks for a WebPage instance'); | ||
70 | t.assertEquals(utils.isWebPage(pageModule.create()), true, 'isWebPage() checks for a WebPage instance'); | ||
71 | t.assertEquals(utils.isWebPage(null), false, 'isWebPage() checks for a WebPage instance'); | ||
72 | })(); | ||
73 | |||
47 | t.comment('isJsFile()'); | 74 | t.comment('isJsFile()'); |
48 | (function() { | 75 | (function() { |
49 | testCases = { | 76 | testCases = { |
... | @@ -90,4 +117,29 @@ t.comment('mergeObjects()'); | ... | @@ -90,4 +117,29 @@ t.comment('mergeObjects()'); |
90 | }); | 117 | }); |
91 | })(); | 118 | })(); |
92 | 119 | ||
120 | t.comment('unique()'); | ||
121 | (function() { | ||
122 | testCases = [ | ||
123 | { | ||
124 | input: [1,2,3], | ||
125 | output: [1,2,3] | ||
126 | }, | ||
127 | { | ||
128 | input: [1,2,3,2,1], | ||
129 | output: [1,2,3] | ||
130 | }, | ||
131 | { | ||
132 | input: ["foo", "bar", "foo"], | ||
133 | output: ["foo", "bar"] | ||
134 | }, | ||
135 | { | ||
136 | input: [], | ||
137 | output: [] | ||
138 | } | ||
139 | ]; | ||
140 | testCases.forEach(function(testCase) { | ||
141 | t.assertEquals(utils.unique(testCase.input), testCase.output, 'unique() computes unique values of an array'); | ||
142 | }); | ||
143 | })(); | ||
144 | |||
93 | t.done(); | 145 | t.done(); | ... | ... |
-
Please register or sign in to post a comment