Commit 4dc8e4ca 4dc8e4ca8e91b44112af8f57c61554f6ef5ab80f by Nicolas Perriault

integrated PR #22 into modularization branch

1 parent 8c102519
......@@ -68,7 +68,6 @@
this.currentUrl = 'about:blank';
this.currentHTTPStatus = 200;
this.defaultWaitTimeout = 5000;
this.delayedExecution = false;
this.history = [];
this.loadInProgress = false;
this.logFormats = {};
......@@ -81,14 +80,16 @@
};
this.options = mergeObjects(this.defaults, options);
this.page = null;
this.pendingWait = false;
this.requestUrl = 'about:blank';
this.resources = [];
this.result = {
log: [],
status: "success",
time: 0
};
this.started = false;
this.step = 0;
this.step = -1;
this.steps = [];
this.test = new phantom.Casper.Tester(this);
};
......@@ -188,11 +189,13 @@
* @param function onComplete An options callback to apply on completion
*/
checkStep: function(self, onComplete) {
var step = self.steps[self.step];
if (!self.loadInProgress && isType(step, "function")) {
self.runStep(step);
if (self.pendingWait || self.loadInProgress) {
return;
}
if (!isType(step, "function") && !self.delayedExecution) {
var step = self.steps[self.step++];
if (isType(step, "function")) {
self.runStep(step);
} else {
self.result.time = new Date().getTime() - self.startTime;
self.log("Done " + self.steps.length + " steps in " + self.result.time + 'ms.', "info");
clearInterval(self.checker);
......@@ -592,6 +595,24 @@
},
/**
* Checks if a given resource was loaded by the remote page.
*
* @param Function/String test A test function or string. In case a string is passed,
* @return Boolean
*/
resourceExists: function(test) {
var testFn;
if (isType(test, "string")) {
testFn = function (res) {
return res.url.match(test);
};
} else {
testFn = test;
}
return this.resources.some(testFn);
},
/**
* Runs the whole suite of steps.
*
* @param function onComplete an optional callback
......@@ -615,7 +636,7 @@
*/
runStep: function(step) {
var skipLog = isType(step.options, "object") && step.options.skipLog === true;
var stepInfo = "Step " + (this.step + 1) + "/" + this.steps.length;
var stepInfo = "Step " + (this.step) + "/" + this.steps.length;
var stepResult;
if (!skipLog) {
this.log(stepInfo + ' ' + this.getCurrentUrl() + ' (HTTP ' + this.currentHTTPStatus + ')', "info");
......@@ -721,7 +742,20 @@
if (!isType(step, "function")) {
throw "You can only define a step as a function";
}
this.steps.push(step);
// check if casper is running
if (this.checker === null) {
// append step to the end of the queue
step.level = 0;
this.steps.push(step);
} else {
// insert substep a level deeper
step.level = this.steps[this.step - 1].level + 1;
var insertIndex = this.step;
while (this.steps[insertIndex] && step.level === this.steps[insertIndex].level) {
insertIndex++;
}
this.steps.splice(insertIndex, 0, step);
}
return this;
},
......@@ -825,21 +859,25 @@
this.die("wait() a step definition must be a function");
}
return this.then(function(self) {
self.delayedExecution = true;
var start = new Date().getTime();
var interval = setInterval(function(self, then) {
if (new Date().getTime() - start > timeout) {
self.delayedExecution = false;
self.log("wait() finished wating for " + timeout + "ms.", "info");
if (then) {
self.then(then);
}
clearInterval(interval);
}
}, 100, self, then);
self.waitStart();
setTimeout(function() {
self.log("wait() finished wating for " + timeout + "ms.", "info");
if (then) {
then.call(self, self);
}
self.waitDone();
}, timeout);
});
},
waitStart: function() {
this.pendingWait = true;
},
waitDone: function() {
this.pendingWait = false;
},
/**
* Waits until a function returns true to process a next step.
*
......@@ -857,32 +895,49 @@
if (then && !isType(then, "function")) {
this.die("waitFor() next step definition must be a function");
}
this.delayedExecution = true;
var start = new Date().getTime();
var condition = false;
var interval = setInterval(function(self, testFx, onTimeout) {
if ((new Date().getTime() - start < timeout) && !condition) {
condition = testFx(self);
} else {
self.delayedExecution = false;
if (!condition) {
self.log("Casper.waitFor() timeout", "warning");
if (isType(onTimeout, "function")) {
onTimeout.call(self, self);
} else {
self.die("Expired timeout, exiting.", "error");
}
clearInterval(interval);
return this.then(function(self) {
self.waitStart();
var start = new Date().getTime();
var condition = false;
var interval = setInterval(function(self, testFx, onTimeout) {
if ((new Date().getTime() - start < timeout) && !condition) {
condition = testFx(self);
} else {
self.log("waitFor() finished in " + (new Date().getTime() - start) + "ms.", "info");
if (then) {
self.then(then);
self.waitDone();
if (!condition) {
self.log("Casper.waitFor() timeout", "warning");
if (isType(onTimeout, "function")) {
onTimeout.call(self, self);
} else {
self.die("Expired timeout, exiting.", "error");
}
clearInterval(interval);
} else {
self.log("waitFor() finished in " + (new Date().getTime() - start) + "ms.", "info");
if (then) {
self.then(then);
}
clearInterval(interval);
}
clearInterval(interval);
}
}
}, 100, this, testFx, onTimeout);
return this;
}, 100, self, testFx, onTimeout);
});
},
/**
* Waits until a given resource is loaded
*
* @param String/Function test A function to test if the resource exists. A string will be matched against the resources url.
* @param Function then The next step to perform (optional)
* @param Function onTimeout A callback function to call on timeout (optional)
* @param Number timeout The max amount of time to wait, in milliseconds (optional)
* @return Casper
*/
waitForResource: function(test, then, onTimeout, timeout) {
timeout = timeout ? timeout : this.defaultWaitTimeout;
return this.waitFor(function(self) {
return self.resourceExists(test);
}, then, onTimeout, timeout);
},
/**
......
......@@ -177,6 +177,16 @@
};
/**
* Asserts that the current page has a resource that matches the provided test
*
* @param Function/String test A test function that is called with every response
* @param String message Test description
*/
this.assertResourceExists = function(test, message) {
return this.assert(casper.resourceExists(test), message);
};
/**
* Asserts that at least an element matching the provided CSS3 selector
* exists in remote DOM.
*
......
......@@ -70,6 +70,7 @@ function createPage(casper) {
casper.log(msg, level, "remote");
};
page.onLoadStarted = function() {
casper.resources = [];
casper.loadInProgress = true;
};
page.onLoadFinished = function(status) {
......@@ -119,6 +120,9 @@ function createPage(casper) {
if (isType(casper.options.onResourceReceived, "function")) {
casper.options.onResourceReceived.call(casper, casper, resource);
}
if (resource.stage === "end") {
casper.resources.push(resource);
}
if (resource.url === casper.requestUrl && resource.stage === "start") {
casper.currentHTTPStatus = resource.status;
if (isType(casper.options.httpStatusHandlers, "object") && resource.status in casper.options.httpStatusHandlers) {
......
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CasperJS test resource</title>
<script>
setTimeout(function () {
document.querySelector("img").setAttribute("src","images/phantom.png");
}, 1000);
</script>
</head>
<body>
<img width="55" height="55" border="1">
</body>
</html>
\ No newline at end of file
do(casper) ->
step = 0
# testing resources
casper.start "tests/site/resources.html", ->
@test.assertEquals ++step, 1, "step 1"
@wait 400, ->
@test.assertEquals ++step, 2, "step 1.1"
@wait 200, ->
@test.assertEquals ++step, 3, "step 1.1.1"
@wait 200, ->
@test.assertEquals ++step, 4, "step 1.1.1.1"
@then ->
@test.assertEquals ++step, 5, "step 1.1.2.1"
@wait 400, ->
@test.assertEquals ++step, 6, "step 1.2"
casper.wait 200, ->
@test.assertEquals ++step, 7, "step 2"
casper.waitForSelector(
'#noneExistingSelector'
-> @test.fail "should run into timeout"
-> @test.assertEquals ++step, 8, "step 3 sucessfully timed out"
1000
)
casper.then ->
@test.assertEquals ++step, 9, "step 4"
@wait 300, ->
@test.assertEquals ++step, 10, "step 4.1"
@wait 300, ->
@test.assertEquals ++step, 11, "step 4.1.1"
@wait 100, ->
@test.assertEquals ++step, 12, "step 5.2"
casper.then ->
@test.assertEquals ++step, 13, "last step"
casper.run(-> @test.done())
\ No newline at end of file
do(casper) ->
casper.onError = ->
console.log 'err'
casper.start "tests/site/resources.html", ->
console.log 'loaded'
@test.assertEquals @resources.length, 1, "only one resource found"
@waitForResource "phantom.png", ->
@test.assertEquals(
@resources.length
2
"two resources found"
)
@test.assertResourceExists(
(res) -> res.url.match "phantom.png"
"phantom image found via test function"
)
@test.assertResourceExists(
"phantom.png"
"phantom image found via test string"
)
casper.run(-> @test.done())