casperjs 1.0.0.RC1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +289 -1
- data/CONTRIBUTING.md +93 -0
- data/CONTRIBUTORS.md +53 -0
- data/README.md +29 -1
- data/batchbin/casperjs.bat +5 -0
- data/bin/bootstrap.js +164 -114
- data/bin/casperjs +84 -0
- data/bin/usage.txt +2 -1
- data/casperjs.gemspec +7 -4
- data/modules/casper.js +661 -239
- data/modules/clientutils.js +240 -54
- data/modules/colorizer.js +2 -1
- data/modules/events.js +13 -1
- data/modules/http.js +70 -0
- data/modules/mouse.js +1 -2
- data/modules/pagestack.js +166 -0
- data/modules/tester.js +1013 -659
- data/modules/utils.js +519 -367
- data/modules/vendors/coffee-script.js +2 -2
- data/modules/xunit.js +56 -24
- data/package.json +2 -2
- data/rpm/casperjs.spec +203 -0
- data/rpm/mkrpm.sh +25 -0
- data/rubybin/casperjs +9 -4
- data/samples/bbcshots.coffee +11 -10
- data/samples/bbcshots.js +16 -15
- data/samples/cliplay.js +3 -0
- data/samples/customevents.js +3 -0
- data/samples/customlogging.coffee +17 -19
- data/samples/customlogging.js +26 -27
- data/samples/download.js +4 -1
- data/samples/dynamic.js +3 -0
- data/samples/each.js +3 -0
- data/samples/events.js +4 -2
- data/samples/extends.js +4 -1
- data/samples/googlelinks.coffee +4 -1
- data/samples/googlelinks.js +10 -3
- data/samples/googlematch.coffee +1 -1
- data/samples/googlematch.js +5 -2
- data/samples/googlepagination.js +4 -1
- data/samples/googletesting.js +3 -0
- data/samples/logcolor.js +3 -0
- data/samples/metaextract.js +3 -0
- data/samples/multirun.js +3 -0
- data/samples/screenshot.js +4 -1
- data/samples/statushandlers.js +4 -1
- data/samples/steptimeout.js +3 -0
- data/samples/timeout.js +4 -1
- data/samples/translate.coffee +23 -0
- data/samples/translate.js +30 -0
- data/tests/commands/mytest.js +14 -0
- data/tests/commands/script.js +3 -0
- data/tests/run.js +82 -37
- data/tests/sample_modules/config.json +1 -0
- data/tests/sample_modules/csmodule.coffee +1 -0
- data/tests/sample_modules/jsmodule.js +1 -0
- data/tests/selftest.js +57 -0
- data/tests/site/dummy.js +1 -0
- data/tests/site/field-array.html +14 -0
- data/tests/site/frame1.html +10 -0
- data/tests/site/frame2.html +11 -0
- data/tests/site/frame3.html +11 -0
- data/tests/site/frames.html +12 -0
- data/tests/site/global.html +6 -1
- data/tests/site/includes/include1.js +6 -0
- data/tests/site/includes/include2.js +6 -0
- data/tests/site/index.html +3 -0
- data/tests/site/popup.html +19 -0
- data/tests/site/resources.html +7 -8
- data/tests/site/urls.html +14 -0
- data/tests/suites/casper/agent.js +3 -1
- data/tests/suites/casper/alert.js +14 -0
- data/tests/suites/casper/auth.js +24 -0
- data/tests/suites/casper/capture.js +12 -12
- data/tests/suites/casper/click.js +11 -1
- data/tests/suites/casper/confirm.js +24 -16
- data/tests/suites/casper/debug.js +10 -0
- data/tests/suites/casper/elementattribute.js +3 -1
- data/tests/suites/casper/encode.js +6 -2
- data/tests/suites/casper/evaluate.js +78 -18
- data/tests/suites/casper/events.js +3 -1
- data/tests/suites/casper/exists.js +3 -1
- data/tests/suites/casper/fetchtext.js +3 -1
- data/tests/suites/casper/flow.coffee +1 -1
- data/tests/suites/casper/formfill.js +39 -4
- data/tests/suites/casper/frames.js +43 -0
- data/tests/suites/casper/global.js +9 -3
- data/tests/suites/casper/headers.js +41 -0
- data/tests/suites/casper/history.js +3 -1
- data/tests/suites/casper/hooks.js +3 -1
- data/tests/suites/casper/keys.js +15 -0
- data/tests/suites/casper/location.js +21 -0
- data/tests/suites/casper/logging.js +3 -1
- data/tests/suites/casper/mouseevents.js +3 -1
- data/tests/suites/casper/onerror.js +3 -1
- data/tests/suites/casper/open.js +63 -1
- data/tests/suites/casper/popup.js +86 -0
- data/tests/suites/casper/prompt.js +11 -15
- data/tests/suites/casper/request.js +36 -0
- data/tests/suites/casper/resources.coffee +5 -5
- data/tests/suites/casper/scripts.js +32 -0
- data/tests/suites/casper/start.js +3 -1
- data/tests/suites/casper/steps.js +4 -2
- data/tests/suites/casper/urls.js +21 -0
- data/tests/suites/casper/viewport.js +3 -1
- data/tests/suites/casper/visible.js +3 -1
- data/tests/suites/casper/wait.js +22 -12
- data/tests/suites/casper/xpath.js +3 -1
- data/tests/suites/cli.js +3 -1
- data/tests/suites/clientutils.js +57 -3
- data/tests/suites/coffee.coffee +1 -1
- data/tests/suites/fs.js +3 -1
- data/tests/suites/http_status.js +19 -3
- data/tests/suites/popup.js +33 -0
- data/tests/suites/require.js +31 -0
- data/tests/suites/tester.js +134 -29
- data/tests/suites/utils.js +108 -8
- data/tests/suites/xunit.js +37 -6
- metadata +49 -15
- data/modules/injector.js +0 -93
- data/tests/suites/injector.js +0 -64
data/samples/cliplay.js
CHANGED
data/samples/customevents.js
CHANGED
@@ -2,29 +2,27 @@
|
|
2
2
|
A basic custom logging implementation. The idea is to (extremely) verbosely
|
3
3
|
log every received resource.
|
4
4
|
###
|
5
|
-
|
6
5
|
casper = require("casper").create
|
7
|
-
###
|
8
|
-
Every time a resource is received, a new log entry is added to the stack
|
9
|
-
at the 'verbose' level.
|
10
|
-
|
11
|
-
@param Object resource A phantomjs resource object
|
12
|
-
###
|
13
|
-
onResourceReceived: (self, resource) ->
|
14
|
-
infos = []
|
15
|
-
props = [
|
16
|
-
"url"
|
17
|
-
"status"
|
18
|
-
"statusText"
|
19
|
-
"redirectURL"
|
20
|
-
"bodySize"
|
21
|
-
]
|
22
|
-
infos.push resource[prop] for prop in props
|
23
|
-
infos.push "[#{header.name}: #{header.value}]" for header in resource.headers
|
24
|
-
@log infos.join(", "), "verbose"
|
25
6
|
verbose: true # we want to see the log printed out to the console
|
26
7
|
logLevel: "verbose" # of course we want to see logs to our new level :)
|
27
8
|
|
9
|
+
###
|
10
|
+
Every time a resource is received, a new log entry is added to the stack
|
11
|
+
at the 'verbose' level.
|
12
|
+
###
|
13
|
+
casper.on 'resource.received', (resource) ->
|
14
|
+
infos = []
|
15
|
+
props = [
|
16
|
+
"url"
|
17
|
+
"status"
|
18
|
+
"statusText"
|
19
|
+
"redirectURL"
|
20
|
+
"bodySize"
|
21
|
+
]
|
22
|
+
infos.push resource[prop] for prop in props
|
23
|
+
infos.push "[#{header.name}: #{header.value}]" for header in resource.headers
|
24
|
+
@log infos.join(", "), "verbose"
|
25
|
+
|
28
26
|
# add a new 'verbose' logging level at the lowest priority
|
29
27
|
casper.logLevels = ["verbose"].concat casper.logLevels
|
30
28
|
|
data/samples/customlogging.js
CHANGED
@@ -1,38 +1,37 @@
|
|
1
|
-
/*
|
1
|
+
/*jshint strict:false*/
|
2
|
+
/*global CasperError console phantom require*/
|
3
|
+
|
4
|
+
/**
|
2
5
|
* A basic custom logging implementation. The idea is to (extremely) verbosely
|
3
6
|
* log every received resource.
|
4
7
|
*/
|
5
|
-
|
6
8
|
var casper = require("casper").create({
|
7
|
-
/*
|
8
|
-
Every time a resource is received, a new log entry is added to the stack at
|
9
|
-
the 'verbose' level.
|
10
|
-
*/
|
11
|
-
onResourceReceived: function(self, resource) {
|
12
|
-
var header, infos, prop, props, _i, _j, _len, _len1, _ref;
|
13
|
-
infos = [];
|
14
|
-
props = [
|
15
|
-
"url",
|
16
|
-
"status",
|
17
|
-
"statusText",
|
18
|
-
"redirectURL",
|
19
|
-
"bodySize"
|
20
|
-
];
|
21
|
-
for (_i = 0, _len = props.length; _i < _len; _i++) {
|
22
|
-
prop = props[_i];
|
23
|
-
infos.push(resource[prop]);
|
24
|
-
}
|
25
|
-
_ref = resource.headers;
|
26
|
-
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
27
|
-
header = _ref[_j];
|
28
|
-
infos.push("[" + header.name + ": " + header.value + "]");
|
29
|
-
}
|
30
|
-
this.log(infos.join(", "), "verbose");
|
31
|
-
},
|
32
9
|
verbose: true,
|
33
10
|
logLevel: "verbose"
|
34
11
|
});
|
35
12
|
|
13
|
+
/**
|
14
|
+
* Every time a resource is received, a new log entry is added to the stack at
|
15
|
+
* the 'verbose' level.
|
16
|
+
*/
|
17
|
+
casper.on('resource.received', function(resource) {
|
18
|
+
var infos = [];
|
19
|
+
var props = [
|
20
|
+
"url",
|
21
|
+
"status",
|
22
|
+
"statusText",
|
23
|
+
"redirectURL",
|
24
|
+
"bodySize"
|
25
|
+
];
|
26
|
+
props.forEach(function(prop) {
|
27
|
+
infos.push(resource[prop]);
|
28
|
+
});
|
29
|
+
resource.headers.forEach(function(header) {
|
30
|
+
infos.push("[" + header.name + ": " + header.value + "]");
|
31
|
+
});
|
32
|
+
this.log(infos.join(", "), "verbose");
|
33
|
+
});
|
34
|
+
|
36
35
|
// add a new 'verbose' logging level at the lowest priority
|
37
36
|
casper.logLevels = ["verbose"].concat(casper.logLevels);
|
38
37
|
|
data/samples/download.js
CHANGED
data/samples/dynamic.js
CHANGED
data/samples/each.js
CHANGED
data/samples/events.js
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
/*
|
1
|
+
/*jshint strict:false*/
|
2
|
+
/*global CasperError console phantom require*/
|
3
|
+
|
4
|
+
/**
|
2
5
|
* This script will add a custom HTTP status code handler, here for 404 pages.
|
3
6
|
*/
|
4
|
-
|
5
7
|
var casper = require("casper").create();
|
6
8
|
|
7
9
|
casper.on("http.status.200", function(resource) {
|
data/samples/extends.js
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
/*jshint strict:false*/
|
2
|
+
/*global CasperError console phantom require*/
|
3
|
+
|
1
4
|
var casper = require("casper").create({
|
2
5
|
loadImages: false,
|
3
6
|
logLevel: "debug",
|
@@ -34,4 +37,4 @@ Object.keys(links).forEach(function(url) {
|
|
34
37
|
fantomas.run(function() {
|
35
38
|
this.renderJSON(links);
|
36
39
|
this.exit();
|
37
|
-
});
|
40
|
+
});
|
data/samples/googlelinks.coffee
CHANGED
@@ -4,7 +4,10 @@ casper = require("casper").create()
|
|
4
4
|
getLinks = ->
|
5
5
|
links = document.querySelectorAll("h3.r a")
|
6
6
|
Array::map.call links, (e) ->
|
7
|
-
|
7
|
+
try
|
8
|
+
(/url\?q=(.*)&sa=U/).exec(e.getAttribute("href"))[1]
|
9
|
+
catch e
|
10
|
+
e.getAttribute "href"
|
8
11
|
|
9
12
|
casper.start "http://google.fr/", ->
|
10
13
|
# search for 'casperjs' from google form
|
data/samples/googlelinks.js
CHANGED
@@ -1,12 +1,19 @@
|
|
1
|
+
/*jshint strict:false*/
|
2
|
+
/*global CasperError console phantom require*/
|
1
3
|
var links = [];
|
2
4
|
var casper = require("casper").create();
|
3
5
|
|
4
6
|
function getLinks() {
|
5
7
|
var links = document.querySelectorAll("h3.r a");
|
6
8
|
return Array.prototype.map.call(links, function(e) {
|
7
|
-
|
9
|
+
try {
|
10
|
+
// google handles redirects hrefs to some script of theirs
|
11
|
+
return (/url\?q=(.*)&sa=U/).exec(e.getAttribute("href"))[1];
|
12
|
+
} catch (err) {
|
13
|
+
return e.getAttribute("href");
|
14
|
+
}
|
8
15
|
});
|
9
|
-
}
|
16
|
+
}
|
10
17
|
|
11
18
|
casper.start("http://google.fr/", function() {
|
12
19
|
// search for 'casperjs' from google form
|
@@ -28,6 +35,6 @@ casper.then(function() {
|
|
28
35
|
casper.run(function() {
|
29
36
|
// echo results in some pretty fashion
|
30
37
|
this.echo(links.length + " links found:");
|
31
|
-
this.echo(" - " + links.join("\n - "))
|
38
|
+
this.echo(" - " + links.join("\n - "));
|
32
39
|
this.exit();
|
33
40
|
});
|
data/samples/googlematch.coffee
CHANGED
@@ -14,7 +14,7 @@ casper = require("casper").create verbose: true
|
|
14
14
|
|
15
15
|
casper.fetchScore = ->
|
16
16
|
@evaluate ->
|
17
|
-
result =
|
17
|
+
result = __utils__.findOne('#resultStats').innerText
|
18
18
|
parseInt /Environ ([0-9\s]{1,}).*/.exec(result)[1].replace(/\s/g, '')
|
19
19
|
|
20
20
|
terms = casper.cli.args # terms are passed through command-line arguments
|
data/samples/googlematch.js
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
/*
|
1
|
+
/*jshint strict:false*/
|
2
|
+
/*global CasperError console phantom require*/
|
3
|
+
|
4
|
+
/**
|
2
5
|
* Takes provided terms passed as arguments and query google for the number of
|
3
6
|
* estimated results each have.
|
4
7
|
*
|
@@ -16,7 +19,7 @@ var casper = require("casper").create({
|
|
16
19
|
|
17
20
|
casper.fetchScore = function() {
|
18
21
|
return this.evaluate(function() {
|
19
|
-
var result =
|
22
|
+
var result = __utils__.findOne('#resultStats').innerText;
|
20
23
|
return parseInt(/Environ ([0-9\s]{1,}).*/.exec(result)[1].replace(/\s/g, ''), 10);
|
21
24
|
});
|
22
25
|
};
|
data/samples/googlepagination.js
CHANGED
data/samples/googletesting.js
CHANGED
data/samples/logcolor.js
CHANGED
data/samples/metaextract.js
CHANGED
data/samples/multirun.js
CHANGED
data/samples/screenshot.js
CHANGED
data/samples/statushandlers.js
CHANGED
data/samples/steptimeout.js
CHANGED
data/samples/timeout.js
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
###
|
2
|
+
Translation using the Google Translate Service.
|
3
|
+
|
4
|
+
Usage:
|
5
|
+
|
6
|
+
$ casperjs translate.coffee --target=fr "hello world"
|
7
|
+
bonjour tout le monde
|
8
|
+
###
|
9
|
+
system = require("system")
|
10
|
+
casper = require("casper").create()
|
11
|
+
format = require("utils").format
|
12
|
+
source = casper.cli.get("source") or "auto"
|
13
|
+
target = casper.cli.get("target")
|
14
|
+
text = casper.cli.get(0)
|
15
|
+
result = undefined
|
16
|
+
|
17
|
+
casper.warn("The --target option is mandatory.").exit 1 unless target
|
18
|
+
|
19
|
+
casper.start(format("http://translate.google.com/#%s/%s/%s", source, target, text), ->
|
20
|
+
@fill "form#gt-form", text: text
|
21
|
+
).waitForSelector "span.hps", -> @echo @fetchText("#result_box")
|
22
|
+
|
23
|
+
casper.run()
|
@@ -0,0 +1,30 @@
|
|
1
|
+
/*jshint strict:false*/
|
2
|
+
/*global CasperError console phantom require*/
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Translation using the Google Translate Service.
|
6
|
+
*
|
7
|
+
* Usage:
|
8
|
+
*
|
9
|
+
* $ casperjs translate.js --target=fr "hello world"
|
10
|
+
* bonjour tout le monde
|
11
|
+
*/
|
12
|
+
var system = require('system'),
|
13
|
+
casper = require('casper').create(),
|
14
|
+
format = require('utils').format,
|
15
|
+
source = casper.cli.get('source') || 'auto',
|
16
|
+
target = casper.cli.get('target'),
|
17
|
+
text = casper.cli.get(0),
|
18
|
+
result;
|
19
|
+
|
20
|
+
if (!target) {
|
21
|
+
casper.warn('The --target option is mandatory.').exit(1);
|
22
|
+
}
|
23
|
+
|
24
|
+
casper.start(format('http://translate.google.com/#%s/%s/%s', source, target, text), function() {
|
25
|
+
this.fill('form#gt-form', {text: text});
|
26
|
+
}).waitForSelector('span.hps', function() {
|
27
|
+
this.echo(this.fetchText("#result_box"));
|
28
|
+
});
|
29
|
+
|
30
|
+
casper.run();
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/*jshint strict:false*/
|
2
|
+
/*global CasperError casper console phantom require*/
|
3
|
+
casper.start('about:blank', function() {
|
4
|
+
this.test.pass('ok1');
|
5
|
+
});
|
6
|
+
|
7
|
+
casper.then(function() {
|
8
|
+
this.test.pass('ok2');
|
9
|
+
});
|
10
|
+
|
11
|
+
casper.run(function() {
|
12
|
+
this.test.pass('ok3');
|
13
|
+
this.test.done();
|
14
|
+
});
|
data/tests/run.js
CHANGED
@@ -1,19 +1,35 @@
|
|
1
|
+
/*global phantom CasperError*/
|
2
|
+
|
1
3
|
if (!phantom.casperLoaded) {
|
2
4
|
console.log('This script must be invoked using the casperjs executable');
|
3
5
|
phantom.exit(1);
|
4
6
|
}
|
5
7
|
|
6
|
-
var fs
|
7
|
-
var
|
8
|
-
var
|
9
|
-
var
|
10
|
-
var
|
11
|
-
var
|
8
|
+
var fs = require('fs');
|
9
|
+
var colorizer = require('colorizer');
|
10
|
+
var utils = require('utils');
|
11
|
+
var f = utils.format;
|
12
|
+
var loadIncludes = ['includes', 'pre', 'post'];
|
13
|
+
var tests = [];
|
14
|
+
var casper = require('casper').create({
|
12
15
|
exitOnError: false
|
13
16
|
});
|
14
17
|
|
15
18
|
// local utils
|
19
|
+
function checkSelfTest(tests) {
|
20
|
+
"use strict";
|
21
|
+
var isCasperTest = false;
|
22
|
+
tests.forEach(function(test) {
|
23
|
+
var testDir = fs.absolute(fs.dirname(test));
|
24
|
+
if (fs.isDirectory(testDir) && fs.exists(fs.pathJoin(testDir, '.casper'))) {
|
25
|
+
isCasperTest = true;
|
26
|
+
}
|
27
|
+
});
|
28
|
+
return isCasperTest;
|
29
|
+
}
|
30
|
+
|
16
31
|
function checkIncludeFile(include) {
|
32
|
+
"use strict";
|
17
33
|
var absInclude = fs.absolute(include.trim());
|
18
34
|
if (!fs.exists(absInclude)) {
|
19
35
|
casper.warn("%s file not found, can't be included", absInclude);
|
@@ -34,43 +50,72 @@ function checkIncludeFile(include) {
|
|
34
50
|
return absInclude;
|
35
51
|
}
|
36
52
|
|
37
|
-
|
38
|
-
|
39
|
-
|
53
|
+
function checkArgs() {
|
54
|
+
"use strict";
|
55
|
+
// parse some options from cli
|
56
|
+
casper.options.verbose = casper.cli.get('direct') || false;
|
57
|
+
casper.options.logLevel = casper.cli.get('log-level') || "error";
|
58
|
+
if (casper.cli.get('no-colors') === true) {
|
59
|
+
var cls = 'Dummy';
|
60
|
+
casper.options.colorizerType = cls;
|
61
|
+
casper.colorizer = colorizer.create(cls);
|
62
|
+
}
|
63
|
+
casper.test.options.failFast = casper.cli.get('fail-fast') || false;
|
40
64
|
|
41
|
-
//
|
42
|
-
casper.
|
43
|
-
|
44
|
-
|
65
|
+
// test paths are passed as args
|
66
|
+
if (casper.cli.args.length) {
|
67
|
+
tests = casper.cli.args.filter(function(path) {
|
68
|
+
if (fs.isFile(path) || fs.isDirectory(path)) {
|
69
|
+
return true;
|
70
|
+
}
|
71
|
+
throw new CasperError(f("Invalid test path: %s", path));
|
72
|
+
});
|
73
|
+
} else {
|
74
|
+
casper.echo('No test path passed, exiting.', 'RED_BAR', 80);
|
75
|
+
casper.exit(1);
|
45
76
|
}
|
46
|
-
return location;
|
47
|
-
});
|
48
77
|
|
49
|
-
//
|
50
|
-
if (
|
51
|
-
|
52
|
-
|
53
|
-
}
|
54
|
-
} else {
|
55
|
-
casper.echo('No test path passed, exiting.', 'RED_BAR', 80);
|
56
|
-
casper.exit(1);
|
78
|
+
// check for casper selftests
|
79
|
+
if (!phantom.casperSelfTest && checkSelfTest(tests)) {
|
80
|
+
casper.warn('To run casper self tests, use the `selftest` command.');
|
81
|
+
casper.exit(1);
|
82
|
+
}
|
57
83
|
}
|
58
84
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
85
|
+
function initRunner() {
|
86
|
+
"use strict";
|
87
|
+
// includes handling
|
88
|
+
loadIncludes.forEach(function(include){
|
89
|
+
var container;
|
90
|
+
if (casper.cli.has(include)) {
|
91
|
+
container = casper.cli.get(include).split(',').map(function(file) {
|
92
|
+
return checkIncludeFile(file);
|
93
|
+
}).filter(function(file) {
|
94
|
+
return utils.isString(file);
|
95
|
+
});
|
96
|
+
casper.test.loadIncludes[include] = utils.unique(container);
|
97
|
+
}
|
98
|
+
});
|
99
|
+
|
100
|
+
// test suites completion listener
|
101
|
+
casper.test.on('tests.complete', function() {
|
102
|
+
this.renderResults(true, undefined, casper.cli.get('xunit') || undefined);
|
103
|
+
if (this.options.failFast && this.testResults.failures.length > 0) {
|
104
|
+
casper.warn('Test suite failed fast, all tests may not have been executed.');
|
105
|
+
}
|
66
106
|
});
|
67
|
-
casper.test.includes = utils.unique(includes);
|
68
107
|
}
|
69
108
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
})
|
109
|
+
var error;
|
110
|
+
try {
|
111
|
+
checkArgs();
|
112
|
+
} catch (e) {
|
113
|
+
error = true;
|
114
|
+
casper.warn(e);
|
115
|
+
casper.exit(1);
|
116
|
+
}
|
74
117
|
|
75
|
-
|
76
|
-
|
118
|
+
if (!error) {
|
119
|
+
initRunner();
|
120
|
+
casper.test.runSuites.apply(casper.test, tests);
|
121
|
+
}
|