added Casper#waitFor() and Casper#waitForSelector()
Showing
5 changed files
with
131 additions
and
1 deletions
... | @@ -58,6 +58,8 @@ | ... | @@ -58,6 +58,8 @@ |
58 | this.colorizer = new phantom.Casper.Colorizer(); | 58 | this.colorizer = new phantom.Casper.Colorizer(); |
59 | this.currentUrl = 'about:blank'; | 59 | this.currentUrl = 'about:blank'; |
60 | this.currentHTTPStatus = 200; | 60 | this.currentHTTPStatus = 200; |
61 | this.defaultWaitTimeout = 5000; | ||
62 | this.delayedExecution = false; | ||
61 | this.loadInProgress = false; | 63 | this.loadInProgress = false; |
62 | this.logLevels = ["debug", "info", "warning", "error"]; | 64 | this.logLevels = ["debug", "info", "warning", "error"]; |
63 | this.logStyles = { | 65 | this.logStyles = { |
... | @@ -174,7 +176,7 @@ | ... | @@ -174,7 +176,7 @@ |
174 | self.log(stepInfo + "done in " + time + "ms.", "info"); | 176 | self.log(stepInfo + "done in " + time + "ms.", "info"); |
175 | self.step++; | 177 | self.step++; |
176 | } | 178 | } |
177 | if (typeof step !== "function") { | 179 | if (typeof step !== "function" && !self.delayedExecution) { |
178 | self.result.time = new Date().getTime() - self.startTime; | 180 | self.result.time = new Date().getTime() - self.startTime; |
179 | self.log("Done " + self.steps.length + " steps in " + self.result.time + 'ms.', "info"); | 181 | self.log("Done " + self.steps.length + " steps in " + self.result.time + 'ms.', "info"); |
180 | clearInterval(self.checker); | 182 | clearInterval(self.checker); |
... | @@ -629,6 +631,64 @@ | ... | @@ -629,6 +631,64 @@ |
629 | */ | 631 | */ |
630 | thenOpenAndEvaluate: function(location, fn, replacements) { | 632 | thenOpenAndEvaluate: function(location, fn, replacements) { |
631 | return this.thenOpen(location).thenEvaluate(fn, replacements); | 633 | return this.thenOpen(location).thenEvaluate(fn, replacements); |
634 | }, | ||
635 | |||
636 | /** | ||
637 | * Waits until a function returns true to process a next step. | ||
638 | * | ||
639 | * @param Function testFx A function to be evaluated for returning condition satisfecit | ||
640 | * @param Function then The next step to perform | ||
641 | * @param Number timeout The max amount of time to wait, in milliseconds | ||
642 | * @return Casper | ||
643 | */ | ||
644 | waitFor: function(testFx, then, onTimeout, timeout) { | ||
645 | timeout = timeout ? timeout : this.defaultWaitTimeout; | ||
646 | if (typeof testFx !== "function") { | ||
647 | this.die("waitUntil() needs a test function"); | ||
648 | } | ||
649 | if (typeof then !== "function") { | ||
650 | this.die("waitUntil() needs a next step definition"); | ||
651 | } | ||
652 | this.delayedExecution = true; | ||
653 | var start = new Date().getTime(); | ||
654 | var condition = false; | ||
655 | var interval = setInterval(function(self, testFx, onTimeout) { | ||
656 | if ((new Date().getTime() - start < timeout) && !condition) { | ||
657 | condition = testFx(self); | ||
658 | } else { | ||
659 | self.delayedExecution = false; | ||
660 | if (!condition) { | ||
661 | self.log("Casper.waitFor() timeout", "warning"); | ||
662 | if (typeof onTimeout === "function") { | ||
663 | onTimeout(self); | ||
664 | } else { | ||
665 | self.die("Expired timeout, exiting.", "error"); | ||
666 | } | ||
667 | clearInterval(interval); | ||
668 | } else { | ||
669 | self.log("waitFor() finished in " + (new Date().getTime() - start) + "ms.", "info"); | ||
670 | self.then(then); | ||
671 | clearInterval(interval); | ||
672 | } | ||
673 | } | ||
674 | }, 100, this, testFx, onTimeout); | ||
675 | return this; | ||
676 | }, | ||
677 | |||
678 | /** | ||
679 | * Waits until an element matching the provided CSS3 selector exists in | ||
680 | * remote DOM to process a next step. | ||
681 | * | ||
682 | * @param String selector A CSS3 selector | ||
683 | * @param Function then The next step to perform | ||
684 | * @param Number timeout The max amount of time to wait, in milliseconds | ||
685 | * @return Casper | ||
686 | */ | ||
687 | waitForSelector: function(selector, then, onTimeout, timeout) { | ||
688 | timeout = timeout ? timeout : this.defaultWaitTimeout; | ||
689 | return this.waitFor(function(self) { | ||
690 | return self.exists(selector); | ||
691 | }, then, onTimeout, timeout); | ||
632 | } | 692 | } |
633 | }; | 693 | }; |
634 | 694 | ||
... | @@ -1169,6 +1229,15 @@ | ... | @@ -1169,6 +1229,15 @@ |
1169 | }; | 1229 | }; |
1170 | 1230 | ||
1171 | /** | 1231 | /** |
1232 | * Adds a failed test entry to the stack. | ||
1233 | * | ||
1234 | * @param String message | ||
1235 | */ | ||
1236 | this.fail = function(message) { | ||
1237 | this.assert(false, message); | ||
1238 | }; | ||
1239 | |||
1240 | /** | ||
1172 | * Formats a message to highlight some parts of it. | 1241 | * Formats a message to highlight some parts of it. |
1173 | * | 1242 | * |
1174 | * @param String message | 1243 | * @param String message |
... | @@ -1192,6 +1261,15 @@ | ... | @@ -1192,6 +1261,15 @@ |
1192 | }; | 1261 | }; |
1193 | 1262 | ||
1194 | /** | 1263 | /** |
1264 | * Adds a successful test entry to the stack. | ||
1265 | * | ||
1266 | * @param String message | ||
1267 | */ | ||
1268 | this.pass = function(message) { | ||
1269 | this.assert(true, message); | ||
1270 | }; | ||
1271 | |||
1272 | /** | ||
1195 | * Render tests results, an optionnaly exit phantomjs. | 1273 | * Render tests results, an optionnaly exit phantomjs. |
1196 | * | 1274 | * |
1197 | * @param Boolean exit | 1275 | * @param Boolean exit | ... | ... |
samples/screenshot.js
0 → 100644
1 | phantom.injectJs('casper.js'); | ||
2 | |||
3 | var casper = new phantom.Casper({ | ||
4 | logLevel: "debug", | ||
5 | verbose: true | ||
6 | }); | ||
7 | |||
8 | casper.start('https://twitter.com/#!/twilio', function(self) { | ||
9 | self.waitForSelector('.tweet-row', function(self) { | ||
10 | self.captureSelector('twitter.png', 'html'); | ||
11 | }, null, 12000); | ||
12 | }); | ||
13 | |||
14 | casper.run(function(self) { | ||
15 | self.exit(); | ||
16 | }); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -136,6 +136,19 @@ casper.then(function(self) { | ... | @@ -136,6 +136,19 @@ casper.then(function(self) { |
136 | casper.options.verbose = true; | 136 | casper.options.verbose = true; |
137 | }); | 137 | }); |
138 | 138 | ||
139 | // Casper.waitFor | ||
140 | casper.thenOpen('tests/site/waitFor.html', function(self) { | ||
141 | self.waitFor(function(self) { | ||
142 | return self.evaluate(function() { | ||
143 | return document.querySelectorAll('li').length === 4; | ||
144 | }); | ||
145 | }, function(self) { | ||
146 | self.test.pass('Casper.waitFor() can wait for something to happen'); | ||
147 | }, function(self) { | ||
148 | self.test.fail('Casper.waitFor() can wait for something to happen'); | ||
149 | }); | ||
150 | }); | ||
151 | |||
139 | // run suite | 152 | // run suite |
140 | casper.run(function(self) { | 153 | casper.run(function(self) { |
141 | self.test.assertEquals(self.result.log.length, 3, 'log() logged messages'); | 154 | self.test.assertEquals(self.result.log.length, 3, 'log() logged messages'); | ... | ... |
tests/site/waitFor.html
0 → 100644
1 | <!DOCTYPE html> | ||
2 | <html> | ||
3 | <head> | ||
4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
5 | <title>waitFor test</title> | ||
6 | </head> | ||
7 | <body> | ||
8 | <img src="images/phantom.png"/> | ||
9 | <ul> | ||
10 | <li>one</li> | ||
11 | <li>two</li> | ||
12 | <li>three</li> | ||
13 | </ul> | ||
14 | <script> | ||
15 | setTimeout(function() { | ||
16 | var li = document.createElement('li') | ||
17 | li.appendChild(document.createTextNode('four')); | ||
18 | document.querySelector('ul').appendChild(li); | ||
19 | }, 2000); | ||
20 | </script> | ||
21 | </body> | ||
22 | </html> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or sign in to post a comment