Commit 484639be 484639be1e1e8f45c136d82a53b80e9adf2b97b9 by Nicolas Perriault

Initial attempt at bringing support for test cases - refs #56

1 parent a2ebe03a
......@@ -4,6 +4,7 @@ CasperJS Changelog
XXXX-XX-XX, v1.0.0
------------------
- merged PR [#322](https://github.com/n1k0/casperjs/pull/322) - Support number in withFrame()
- fixed [#323](https://github.com/n1k0/casperjs/issues/323) - `thenEvaluate()` should be updated to take the same parameters as `evaluate()`, while maintaining backwards compatibility.
- merged PR [#319](https://github.com/n1k0/casperjs/pull/319), fixed [#209](https://github.com/n1k0/casperjs/issues/209) - test duration has been added to XUnit XML result file.
- `Casper.userAgent()` does not require the instance to be started anymore
......
......@@ -5,17 +5,18 @@ You can check out the [contribution graphs on github](https://github.com/n1k0/ca
```
$ git shortlog -s -n | cut -c8-
Nicolas Perriault
oncletom
Brikou CARRE
oncletom
hannyu
Chris Lorenzo
Victor Yap
nrabinowitz
pborreli
Dave Lee
Rob Barreca
Andrew Childs
Solomon White
reina.sweet
Andrew Childs
Dave Lee
Reina Sweet
Elmar Langholz
Jason Funk
......@@ -24,7 +25,6 @@ Julien Moulin
Michael Geers
Jan Schaumann
Clochix
Rafael Garcia
Raphaël Benitte
Tim Bunce
alfetopito
......@@ -49,4 +49,5 @@ Mehdi Kabab
Mikko Peltonen
Pascal Borreli
Rafael
Rafael Garcia
```
......
Subproject commit b0f51d643a839fb66c174086c426b9c7b49e2a80
Subproject commit 0f6c923dbfe9bb605adfa5c9d6c8cd3ac1d56586
......
......@@ -1372,6 +1372,19 @@ Casper.prototype.sendKeys = function(selector, keys, options) {
};
/**
* Sets current page content.
*
* @param String content Desired page content
* @return Casper
*/
Casper.prototype.setContent = function setContent(content) {
"use strict";
this.checkStarted();
this.page.content = content;
return this;
};
/**
* Sets current WebPage instance the credentials for HTTP authentication.
*
* @param String username
......@@ -1873,18 +1886,22 @@ Casper.prototype.waitWhileVisible = function waitWhileVisible(selector, then, on
* Makes the provided frame page as the currently active one. Note that the
* active page will be reverted when finished.
*
* @param String frameName Target frame name
* @param String|Number frameInfo Target frame name or number
* @param Function then Next step function
* @return Casper
*/
Casper.prototype.withFrame = function withFrame(frameName, then) {
Casper.prototype.withFrame = function withFrame(frameInfo, then) {
"use strict";
this.then(function _step() {
if (this.page.childFramesName().indexOf(frameName) === -1) {
throw new CasperError(f('No frame named "%s" was found.', frameName));
if (utils.isNumber(frameInfo)) {
if (frameInfo > this.page.childFramesCount() - 1) {
throw new CasperError(f('Frame number "%d" is out of bounds.', frameInfo));
}
} else if (this.page.childFramesName().indexOf(frameInfo) === -1) {
throw new CasperError(f('No frame named "%s" was found.', frameInfo));
}
// make the frame page the currently active one
this.page.switchToChildFrame(frameName);
this.page.switchToChildFrame(frameInfo);
});
try {
this.then(then);
......
......@@ -35,6 +35,13 @@ var events = require('events');
var utils = require('utils');
var f = utils.format;
/**
* Creates a tester instance.
*
* @param Casper casper A Casper instance
* @param Object options Tester options
* @return Tester
*/
exports.create = function create(casper, options) {
"use strict";
return new Tester(casper, options);
......@@ -48,7 +55,7 @@ exports.create = function create(casper, options) {
*/
var Tester = function Tester(casper, options) {
"use strict";
/*jshint maxstatements:20*/
/*jshint maxstatements:30*/
if (!utils.isCasperObject(casper)) {
throw new CasperError("Tester needs a Casper instance");
......@@ -60,32 +67,22 @@ var Tester = function Tester(casper, options) {
this.executed = 0;
this.currentTestFile = null;
this.currentSuite = undefined;
this.currentSuiteNum = 0;
this.exporter = require('xunit').create();
this.loadIncludes = {
includes: [],
pre: [],
post: []
};
this.running = false;
this.suites = [];
this.suites = new TestSuite();
this.options = utils.mergeObjects({
failFast: false, // terminates a suite as soon as a test fails?
failText: "FAIL", // text to use for a successful test
failText: "FAIL", // text to use for a succesful test
passText: "PASS", // text to use for a failed test
pad: 80 // maximum number of chars for a result line
}, options);
// properties
this.testResults = {
passed: 0,
failed: 0,
passes: [],
failures: [],
passesTime: [],
failuresTime: []
};
// measuring test duration
this.currentTestStartTime = null;
this.lastAssertTime = 0;
......@@ -93,47 +90,27 @@ var Tester = function Tester(casper, options) {
this.configure();
this.on('success', function onSuccess(success) {
this.testResults.passes.push(success);
var timeElapsed = new Date() - this.currentTestStartTime;
this.testResults.passesTime.push(timeElapsed - this.lastAssertTime);
this.exporter.addSuccess(fs.absolute(success.file), success.message || success.standard, timeElapsed - this.lastAssertTime);
this.currentSuite.addSuccess(success, timeElapsed - this.lastAssertTime);
this.lastAssertTime = timeElapsed;
});
this.on('fail', function onFail(failure) {
// export
var timeElapsed = new Date() - this.currentTestStartTime;
this.testResults.failuresTime.push(timeElapsed - this.lastAssertTime);
this.exporter.addFailure(
fs.absolute(failure.file),
failure.message || failure.standard,
failure.standard || "test failed",
failure.type || "unknown",
(timeElapsed - this.lastAssertTime)
);
var valueKeys = Object.keys(failure.values),
timeElapsed = new Date() - this.currentTestStartTime;
this.currentSuite.addFailure(failure, timeElapsed - this.lastAssertTime);
this.lastAssertTime = timeElapsed;
this.testResults.failures.push(failure);
// special printing
if (failure.type) {
this.comment(' type: ' + failure.type);
}
if (failure.values && Object.keys(failure.values).length > 0) {
for (var name in failure.values) {
var comment = ' ' + name + ': ';
var value = failure.values[name];
try {
comment += utils.serialize(failure.values[name]);
} catch (e) {
try {
comment += utils.serialize(failure.values[name].toString());
} catch (e2) {
comment += '(unserializable value)';
}
}
this.comment(comment);
}
if (!failure.values || valueKeys.length === 0) {
return;
}
valueKeys.forEach(function(name) {
this.comment(f(' %s: %s', name, utils.formatTestValue(failure.values[name], name)));
}.bind(this));
});
// casper events
......@@ -147,7 +124,7 @@ var Tester = function Tester(casper, options) {
line = backtrace[0].line;
} catch (e) {}
}
this.test.uncaughtError(msg, this.test.currentTestFile, line);
this.test.uncaughtError(msg, this.test.currentTestFile, line, backtrace);
this.test.done();
});
......@@ -175,7 +152,8 @@ exports.Tester = Tester;
* @param Object|null context Assertion context object (Optional)
* @return Object An assertion result object
*/
Tester.prototype.assert = Tester.prototype.assertTrue = function assert(subject, message, context) {
Tester.prototype.assert =
Tester.prototype.assertTrue = function assert(subject, message, context) {
"use strict";
this.executed++;
return this.processAssertionResult(utils.mergeObjects({
......@@ -198,9 +176,10 @@ Tester.prototype.assert = Tester.prototype.assertTrue = function assert(subject,
* @param String message Test description (Optional)
* @return Object An assertion result object
*/
Tester.prototype.assertEquals = Tester.prototype.assertEqual = function assertEquals(subject, expected, message) {
Tester.prototype.assertEquals =
Tester.prototype.assertEqual = function assertEquals(subject, expected, message) {
"use strict";
return this.assert(this.testEquals(subject, expected), message, {
return this.assert(utils.equals(subject, expected), message, {
type: "assertEquals",
standard: "Subject equals the expected value",
values: {
......@@ -235,10 +214,12 @@ Tester.prototype.assertNotEquals = function assertNotEquals(subject, shouldnt, m
*
* @param Function fn A function to be evaluated in remote DOM
* @param String message Test description
* @param Object params Object/Array containing the parameters to inject into the function (optional)
* @param Object params Object/Array containing the parameters to inject into
* the function (optional)
* @return Object An assertion result object
*/
Tester.prototype.assertEval = Tester.prototype.assertEvaluate = function assertEval(fn, message, params) {
Tester.prototype.assertEval =
Tester.prototype.assertEvaluate = function assertEval(fn, message, params) {
"use strict";
return this.assert(this.casper.evaluate(fn, params), message, {
type: "assertEval",
......@@ -257,13 +238,15 @@ Tester.prototype.assertEval = Tester.prototype.assertEvaluate = function assertE
* @param Function fn The function to be evaluated in remote DOM
* @param Boolean expected The expected value
* @param String|null message Test description
* @param Object|null params Object containing the parameters to inject into the function (optional)
* @param Object|null params Object containing the parameters to inject into the
* function (optional)
* @return Object An assertion result object
*/
Tester.prototype.assertEvalEquals = Tester.prototype.assertEvalEqual = function assertEvalEquals(fn, expected, message, params) {
Tester.prototype.assertEvalEquals =
Tester.prototype.assertEvalEqual = function assertEvalEquals(fn, expected, message, params) {
"use strict";
var subject = this.casper.evaluate(fn, params);
return this.assert(this.testEquals(subject, expected), message, {
return this.assert(utils.equals(subject, expected), message, {
type: "assertEvalEquals",
standard: "Evaluated function returns the expected value",
values: {
......@@ -288,7 +271,7 @@ Tester.prototype.assertField = function assertField(inputName, expected, messag
var actual = this.casper.evaluate(function(inputName) {
return __utils__.getFieldValue(inputName);
}, inputName);
return this.assert(this.testEquals(actual, expected), message, {
return this.assert(utils.equals(actual, expected), message, {
type: 'assertField',
standard: f('"%s" input field has the value "%s"', inputName, expected),
values: {
......@@ -307,7 +290,10 @@ Tester.prototype.assertField = function assertField(inputName, expected, messag
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertExists = Tester.prototype.assertExist = Tester.prototype.assertSelectorExists = Tester.prototype.assertSelectorExist = function assertExists(selector, message) {
Tester.prototype.assertExists =
Tester.prototype.assertExist =
Tester.prototype.assertSelectorExists =
Tester.prototype.assertSelectorExist = function assertExists(selector, message) {
"use strict";
return this.assert(this.casper.exists(selector), message, {
type: "assertExists",
......@@ -326,7 +312,8 @@ Tester.prototype.assertExists = Tester.prototype.assertExist = Tester.prototype.
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertDoesntExist = Tester.prototype.assertNotExists = function assertDoesntExist(selector, message) {
Tester.prototype.assertDoesntExist =
Tester.prototype.assertNotExists = function assertDoesntExist(selector, message) {
"use strict";
return this.assert(!this.casper.exists(selector), message, {
type: "assertDoesntExist",
......@@ -347,7 +334,7 @@ Tester.prototype.assertDoesntExist = Tester.prototype.assertNotExists = function
Tester.prototype.assertHttpStatus = function assertHttpStatus(status, message) {
"use strict";
var currentHTTPStatus = this.casper.currentHTTPStatus;
return this.assert(this.testEquals(this.casper.currentHTTPStatus, status), message, {
return this.assert(utils.equals(this.casper.currentHTTPStatus, status), message, {
type: "assertHttpStatus",
standard: f("HTTP status code is: %s", status),
values: {
......@@ -365,7 +352,8 @@ Tester.prototype.assertHttpStatus = function assertHttpStatus(status, message) {
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertMatch = Tester.prototype.assertMatches = function assertMatch(subject, pattern, message) {
Tester.prototype.assertMatch =
Tester.prototype.assertMatches = function assertMatch(subject, pattern, message) {
"use strict";
return this.assert(pattern.test(subject), message, {
type: "assertMatch",
......@@ -384,7 +372,8 @@ Tester.prototype.assertMatch = Tester.prototype.assertMatches = function assertM
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertNot = Tester.prototype.assertFalse = function assertNot(condition, message) {
Tester.prototype.assertNot =
Tester.prototype.assertFalse = function assertNot(condition, message) {
"use strict";
return this.assert(!condition, message, {
type: "assertNot",
......@@ -402,7 +391,8 @@ Tester.prototype.assertNot = Tester.prototype.assertFalse = function assertNot(c
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertNotVisible = Tester.prototype.assertInvisible = function assertNotVisible(selector, message) {
Tester.prototype.assertNotVisible =
Tester.prototype.assertInvisible = function assertNotVisible(selector, message) {
"use strict";
return this.assert(!this.casper.visible(selector), message, {
type: "assertVisible",
......@@ -422,7 +412,9 @@ Tester.prototype.assertNotVisible = Tester.prototype.assertInvisible = function
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertRaises = Tester.prototype.assertRaise = Tester.prototype.assertThrows = function assertRaises(fn, args, message) {
Tester.prototype.assertRaises =
Tester.prototype.assertRaise =
Tester.prototype.assertThrows = function assertRaises(fn, args, message) {
"use strict";
var context = {
type: "assertRaises",
......@@ -447,7 +439,8 @@ Tester.prototype.assertRaises = Tester.prototype.assertRaise = Tester.prototype.
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertResourceExists = Tester.prototype.assertResourceExist = function assertResourceExists(test, message) {
Tester.prototype.assertResourceExists =
Tester.prototype.assertResourceExist = function assertResourceExists(test, message) {
"use strict";
return this.assert(this.casper.resourceExists(test), message, {
type: "assertResourceExists",
......@@ -465,7 +458,8 @@ Tester.prototype.assertResourceExists = Tester.prototype.assertResourceExist = f
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertTextDoesntExist = Tester.prototype.assertTextDoesntExist = function assertTextDoesntExist(text, message) {
Tester.prototype.assertTextDoesntExist =
Tester.prototype.assertTextDoesntExist = function assertTextDoesntExist(text, message) {
"use strict";
var textFound = (this.casper.evaluate(function _evaluate() {
return document.body.textContent || document.body.innerText;
......@@ -486,7 +480,8 @@ Tester.prototype.assertTextDoesntExist = Tester.prototype.assertTextDoesntExist
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertTextExists = Tester.prototype.assertTextExist = function assertTextExists(text, message) {
Tester.prototype.assertTextExists =
Tester.prototype.assertTextExist = function assertTextExists(text, message) {
"use strict";
var textFound = (this.casper.evaluate(function _evaluate() {
return document.body.textContent || document.body.innerText;
......@@ -546,7 +541,8 @@ Tester.prototype.assertFalsy = function assertFalsy(subject, message) {
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertSelectorHasText = Tester.prototype.assertSelectorContains = function assertSelectorHasText(selector, text, message) {
Tester.prototype.assertSelectorHasText =
Tester.prototype.assertSelectorContains = function assertSelectorHasText(selector, text, message) {
"use strict";
var textFound = this.casper.fetchText(selector).indexOf(text) !== -1;
return this.assert(textFound, message, {
......@@ -567,7 +563,8 @@ Tester.prototype.assertSelectorHasText = Tester.prototype.assertSelectorContains
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertSelectorDoesntHaveText = Tester.prototype.assertSelectorDoesntContain = function assertSelectorDoesntHaveText(selector, text, message) {
Tester.prototype.assertSelectorDoesntHaveText =
Tester.prototype.assertSelectorDoesntContain = function assertSelectorDoesntHaveText(selector, text, message) {
"use strict";
var textFound = this.casper.fetchText(selector).indexOf(text) === -1;
return this.assert(textFound, message, {
......@@ -590,7 +587,7 @@ Tester.prototype.assertSelectorDoesntHaveText = Tester.prototype.assertSelectorD
Tester.prototype.assertTitle = function assertTitle(expected, message) {
"use strict";
var currentTitle = this.casper.getTitle();
return this.assert(this.testEquals(currentTitle, expected), message, {
return this.assert(utils.equals(currentTitle, expected), message, {
type: "assertTitle",
standard: f('Page title is: "%s"', expected),
values: {
......@@ -607,7 +604,8 @@ Tester.prototype.assertTitle = function assertTitle(expected, message) {
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertTitleMatch = Tester.prototype.assertTitleMatches = function assertTitleMatch(pattern, message) {
Tester.prototype.assertTitleMatch =
Tester.prototype.assertTitleMatches = function assertTitleMatch(pattern, message) {
"use strict";
var currentTitle = this.casper.getTitle();
return this.assert(pattern.test(currentTitle), message, {
......@@ -631,7 +629,7 @@ Tester.prototype.assertTitleMatch = Tester.prototype.assertTitleMatches = functi
Tester.prototype.assertType = function assertType(subject, type, message) {
"use strict";
var actual = utils.betterTypeOf(subject);
return this.assert(this.testEquals(actual, type), message, {
return this.assert(utils.equals(actual, type), message, {
type: "assertType",
standard: f('Subject type is: "%s"', type),
values: {
......@@ -651,7 +649,8 @@ Tester.prototype.assertType = function assertType(subject, type, message) {
* @param String message Test description
* @return Object An assertion result object
*/
Tester.prototype.assertUrlMatch = Tester.prototype.assertUrlMatches = function assertUrlMatch(pattern, message) {
Tester.prototype.assertUrlMatch =
Tester.prototype.assertUrlMatches = function assertUrlMatch(pattern, message) {
"use strict";
var currentUrl = this.casper.getCurrentUrl(),
patternType = utils.betterTypeOf(pattern),
......@@ -701,16 +700,26 @@ Tester.prototype.bar = function bar(text, style) {
};
/**
* Retrieves the sum of all durations of the tests which were
* executed in the current suite
* Starts a suite.
*
* @return Number duration of all tests executed until now (in the current suite)
* @param String description Test suite description
* @param Function suiteFn Suite function
*/
Tester.prototype.calculateSuiteDuration = function calculateSuiteDuration() {
Tester.prototype.begin = function begin(description, suiteFn) {
"use strict";
return this.testResults.passesTime.concat(this.testResults.failuresTime).reduce(function add(a, b) {
return a + b;
}, 0);
description = description || "Untitled suite in " + this.currentTestFile;
this.comment(description);
this.executed = 0;
this.currentSuite = new TestSuiteResult({
name: description,
file: this.currentTestFile
});
try {
suiteFn.call(this, this.casper);
} catch (e) {
this.uncaughtError(e, this.currentTestFile, e.line);
this.done();
}
};
/**
......@@ -767,14 +776,38 @@ Tester.prototype.configure = function configure() {
Tester.prototype.done = function done(planned) {
"use strict";
if (planned > 0 && planned !== this.executed) {
this.fail(f('%s: %d tests planned, %d tests executed',
this.currentTestFile, planned, this.executed));
this.dubious(planned, this.executed);
}
if (this.currentSuite) {
this.suites.push(this.currentSuite);
this.currentSuite = undefined;
this.executed = 0;
}
this.emit('test.done');
this.running = false;
};
/**
* Marks a test as dubious, when the number of planned tests doesn't match the
* number of actually executed one.
*
* @param String message
*/
Tester.prototype.dubious = function dubious(planned, executed) {
"use strict";
var message = f('%d tests planned, %d tests executed', planned, executed);
return this.assert(false, message, {
type: "dubious",
standard: message,
message: message,
values: {
planned: planned,
executed: executed
}
});
};
/**
* Writes an error-style formatted message to stdout.
*
* @param String message
......@@ -857,57 +890,6 @@ Tester.prototype.formatMessage = function formatMessage(message, style) {
};
/**
* Retrieves current failure data and all failed cases.
*
* @return Object casedata An object containg information about cases
* @return Number casedata.length The number of failed cases
* @return Array casedata.cases An array of all the failed case objects
*/
Tester.prototype.getFailures = function getFailures() {
"use strict";
return {
length: this.testResults.failed,
cases: this.testResults.failures
};
};
/**
* Retrieves current passed data and all passed cases.
*
* @return Object casedata An object containg information about cases
* @return Number casedata.length The number of passed cases
* @return Array casedata.cases An array of all the passed case objects
*/
Tester.prototype.getPasses = function getPasses() {
"use strict";
return {
length: this.testResults.passed,
cases: this.testResults.passes
};
};
/**
* Retrieves the array where all the durations of failed tests are stored
*
* @return Array durations of failed tests
*/
Tester.prototype.getFailuresTime = function getFailuresTime() {
"use strict";
return this.testResults.failuresTime;
}
/**
* Retrieves the array where all the durations of passed tests are stored
*
* @return Array durations of passed tests
*/
Tester.prototype.getPassesTime = function getPassesTime() {
"use strict";
return this.testResults.passesTime;
}
/**
* Writes an info-style formatted message to stdout.
*
* @param String message
......@@ -918,7 +900,7 @@ Tester.prototype.info = function info(message) {
};
/**
* Adds a successful test entry to the stack.
* Adds a succesful test entry to the stack.
*
* @param String message
*/
......@@ -939,6 +921,12 @@ Tester.prototype.pass = function pass(message) {
*/
Tester.prototype.processAssertionResult = function processAssertionResult(result) {
"use strict";
if (!this.currentSuite) {
this.currentSuite = new TestSuiteResult({
name: "Untitled suite in " + this.currentTestFile,
file: this.currentTestFile
});
}
var eventName= 'success',
message = result.message || result.standard,
style = 'INFO',
......@@ -947,9 +935,6 @@ Tester.prototype.processAssertionResult = function processAssertionResult(result
eventName = 'fail';
style = 'RED_BAR';
status = this.options.failText;
this.testResults.failed++;
} else {
this.testResults.passed++;
}
this.casper.echo([this.colorize(status, style), this.formatMessage(message)].join(' '));
this.emit(eventName, result);
......@@ -962,21 +947,22 @@ Tester.prototype.processAssertionResult = function processAssertionResult(result
/**
* Renders a detailed report for each failed test.
*
* @param Array failures
*/
Tester.prototype.renderFailureDetails = function renderFailureDetails(failures) {
Tester.prototype.renderFailureDetails = function renderFailureDetails() {
"use strict";
var failures = this.suites.getAllFailures();
if (failures.length === 0) {
return;
}
this.casper.echo(f("\nDetails for the %d failed test%s:\n", failures.length, failures.length > 1 ? "s" : ""), "PARAMETER");
this.casper.echo(f("\nDetails for the %d failed test%s:\n",
failures.length, failures.length > 1 ? "s" : ""), "PARAMETER");
failures.forEach(function _forEach(failure) {
var type, message, line;
type = failure.type || "unknown";
line = ~~failure.line;
message = failure.message;
this.casper.echo(f('In %s:%s', failure.file, line));
this.casper.echo(f(' %s: %s', type, message || failure.standard || "(no message was entered)"), "COMMENT");
this.casper.echo(f('In %s%s', failure.file, ~~failure.line ? ':' + ~~failure.line : ''));
if (failure.suite) {
this.casper.echo(f(' %s', failure.suite), "PARAMETER");
}
this.casper.echo(f(' %s: %s', failure.type || "unknown",
failure.message || failure.standard || "(no message was entered)"), "COMMENT");
});
};
......@@ -989,14 +975,19 @@ Tester.prototype.renderResults = function renderResults(exit, status, save) {
"use strict";
/*jshint maxstatements:20*/
save = save || this.options.save;
var total = this.testResults.passed + this.testResults.failed, statusText, style, result;
var exitStatus = ~~(status || (this.testResults.failed > 0 ? 1 : 0));
var failed = this.suites.countFailed(),
passed = this.suites.countPassed(),
total = this.suites.countTotal(),
statusText,
style,
result,
exitStatus = ~~(status || (failed > 0 ? 1 : 0));
if (total === 0) {
statusText = this.options.failText;
style = 'RED_BAR';
result = f("%s Looks like you didn't run any test.", statusText);
} else {
if (this.testResults.failed > 0) {
if (failed > 0) {
statusText = this.options.failText;
style = 'RED_BAR';
} else {
......@@ -1004,12 +995,12 @@ Tester.prototype.renderResults = function renderResults(exit, status, save) {
style = 'GREEN_BAR';
}
result = f('%s %s tests executed in %ss, %d passed, %d failed.',
statusText, total, utils.ms2seconds(this.calculateSuiteDuration()),
this.testResults.passed, this.testResults.failed);
statusText, total, utils.ms2seconds(this.suites.calculateDuration()),
passed, failed);
}
this.casper.echo(result, style, this.options.pad);
if (this.testResults.failed > 0) {
this.renderFailureDetails(this.testResults.failures);
if (failed > 0) {
this.renderFailureDetails();
}
if (save) {
this.saveResults(save);
......@@ -1053,12 +1044,15 @@ Tester.prototype.runSuites = function runSuites() {
});
if (testFiles.length === 0) {
this.bar(f("No test file found in %s, aborting.", Array.prototype.slice.call(arguments)), "RED_BAR");
this.bar(f("No test file found in %s, aborting.",
Array.prototype.slice.call(arguments)), "RED_BAR");
this.casper.exit(1);
}
self.currentSuiteNum = 0;
self.currentTestStartTime = new Date();
self.lastAssertTime = 0;
var interval = setInterval(function _check(self) {
if (self.running) {
return;
......@@ -1066,13 +1060,9 @@ Tester.prototype.runSuites = function runSuites() {
if (self.currentSuiteNum === testFiles.length) {
self.emit('tests.complete');
clearInterval(interval);
self.exporter.setSuiteDuration(self.calculateSuiteDuration());
} else {
self.runTest(testFiles[self.currentSuiteNum]);
self.exporter.setSuiteDuration(self.calculateSuiteDuration());
self.currentSuiteNum++;
self.passesTime = [];
self.failuresTime = [];
}
}, 100, this);
};
......@@ -1096,12 +1086,10 @@ Tester.prototype.runTest = function runTest(testFile) {
*/
Tester.prototype.saveResults = function saveResults(filepath) {
"use strict";
// FIXME: looks like phantomjs has a pb with fs.isWritable https://groups.google.com/forum/#!topic/casperjs/hcUdwgGZOrU
// if (!fs.isWritable(filepath)) {
// throw new CasperError(f('Path %s is not writable.', filepath));
// }
var exporter = require('xunit').create();
exporter.setResults(this.suites);
try {
fs.write(filepath, this.exporter.getXML(), 'w');
fs.write(filepath, exporter.getXML(), 'w');
this.casper.echo(f('Result log stored in %s', filepath), 'INFO', 80);
} catch (e) {
this.casper.echo(f('Unable to write results to %s: %s', filepath, e), 'ERROR', 80);
......@@ -1127,17 +1115,184 @@ Tester.prototype.testEquals = Tester.prototype.testEqual = function testEquals(v
* @param Error|String error The error
* @param String file Test file where the error occurred
* @param Number line Line number (optional)
* @param Array backtrace Error stack trace (optional)
*/
Tester.prototype.uncaughtError = function uncaughtError(error, file, line) {
Tester.prototype.uncaughtError = function uncaughtError(error, file, line, backtrace) {
"use strict";
return this.processAssertionResult({
success: false,
type: "uncaughtError",
file: file,
line: ~~line || "unknown",
line: ~~line,
message: utils.isObject(error) ? error.message : error,
values: {
error: error
error: error,
stack: backtrace
}
});
};
/**
* Test suites array.
*
*/
function TestSuite() {}
TestSuite.prototype = [];
exports.TestSuite = TestSuite;
/**
* Returns the number of tests.
*
* @return Number
*/
TestSuite.prototype.countTotal = function countTotal() {
"use strict";
return this.countPassed() + this.countFailed();
};
/**
* Returns the number of failed tests.
*
* @return Number
*/
TestSuite.prototype.countFailed = function countFailed() {
"use strict";
return this.map(function(result) {
return result.failed;
}).reduce(function(a, b) {
return a + b;
});
};
/**
* Returns the number of succesful tests.
*
* @return Number
*/
TestSuite.prototype.countPassed = function countPassed() {
"use strict";
return this.map(function(result) {
return result.passed;
}).reduce(function(a, b) {
return a + b;
});
};
/**
* Returns all failures from this suite.
*
* @return Array
*/
TestSuite.prototype.getAllFailures = function getAllFailures() {
"use strict";
var failures = [];
this.forEach(function(result) {
failures = failures.concat(result.failures);
});
return failures;
};
/**
* Returns all succesful tests from this suite.
*
* @return Array
*/
TestSuite.prototype.getAllPasses = function getAllPasses() {
"use strict";
var passes = [];
this.forEach(function(result) {
passes = passes.concat(result.passes);
});
return passes;
};
/**
* Returns all results from this suite.
*
* @return Array
*/
TestSuite.prototype.getAllResults = function getAllResults() {
"use strict";
return this.getAllPasses().concat(this.getAllFailures());
};
/**
* Computes the sum of all durations of the tests which were executed in the
* current suite.
*
* @return Number
*/
TestSuite.prototype.calculateDuration = function calculateDuration() {
"use strict";
return this.getAllResults().map(function(result) {
return result.time;
}).reduce(function add(a, b) {
return a + b;
}, 0);
};
/**
* Test suite results object.
*
* @param Object options
*/
function TestSuiteResult(options) {
"use strict";
this.name = options && options.name;
this.file = options && options.file;
this.assertions = 0;
this.passed = 0;
this.failed = 0;
this.passes = [];
this.failures = [];
}
exports.TestSuiteResult = TestSuiteResult;
/**
* Adds a success record and its execution time to their associated stacks.
*
* @param Object success
* @param Number time
*/
TestSuiteResult.prototype.addSuccess = function addSuccess(success, time) {
"use strict";
success.suite = this.name;
success.time = time;
this.passes.push(success);
this.assertions++;
this.passed++;
};
/**
* Adds a failure record and its execution time to their associated stacks.
*
* @param Object failure
* @param Number time
*/
TestSuiteResult.prototype.addFailure = function addFailure(failure, time) {
"use strict";
failure.suite = this.name;
failure.time = time;
this.failures.push(failure);
this.assertions++;
this.failed++;
};
/**
* Computes total duration for this suite.
*
* @return Number
*/
TestSuiteResult.prototype.calculateDuration = function calculateDuration() {
"use strict";
function add(a, b) {
return a + b;
}
var passedTimes = this.passes.map(function(success) {
return ~~success.time;
}).reduce(add, 0);
var failedTimes = this.failures.map(function(failure) {
return ~~failure.time;
}).reduce(add, 0);
return passedTimes + failedTimes;
};
......
......@@ -200,6 +200,43 @@ function format(f) {
exports.format = format;
/**
* Formats a test value.
*
* @param Mixed value
* @return String
*/
function formatTestValue(value, name) {
"use strict";
var formatted = '';
if (value instanceof Error) {
formatted += value.message + '\n';
if (value.stack) {
formatted += indent(value.stack, 12, '#');
}
} else if (name === 'stack') {
if (isArray(value)) {
formatted += value.map(function(entry) {
return format('in %s() in %s:%d', (entry.function || "anonymous"), entry.file, entry.line);
}).join('\n');
} else {
formatted += 'not provided';
}
} else {
try {
formatted += serialize(value);
} catch (e) {
try {
formatted += serialize(value.toString());
} catch (e2) {
formatted += '(unserializable value)';
}
}
}
return formatted;
}
exports.formatTestValue = formatTestValue;
/**
* Retrieves the value of an Object foreign property using a dot-separated
* path string.
*
......@@ -226,6 +263,22 @@ function getPropertyPath(obj, path) {
exports.getPropertyPath = getPropertyPath;
/**
* Indents a string.
*
* @param String string
* @param Number nchars
* @param String prefix
* @return String
*/
function indent(string, nchars, prefix) {
"use strict";
return string.split('\n').map(function(line) {
return (prefix || '') + new Array(nchars).join(' ') + line;
}).join('\n');
}
exports.indent = indent;
/**
* Inherit the prototype methods from one constructor into another.
*
* @param {function} ctor Constructor function which needs to inherit the
......@@ -295,7 +348,7 @@ exports.isClipRect = isClipRect;
function isFalsy(subject) {
"use strict";
/*jshint eqeqeq:false*/
return subject == new Function('return false;')();
return !subject;
}
exports.isFalsy = isFalsy;
/**
......@@ -392,7 +445,7 @@ exports.isString = isString;
function isTruthy(subject) {
"use strict";
/*jshint eqeqeq:false*/
return subject == new Function('return true;')();
return !!subject;
}
exports.isTruthy = isTruthy;
......
......@@ -80,76 +80,75 @@ exports.create = function create() {
*/
function XUnitExporter() {
"use strict";
this._xml = utils.node('testsuite');
this.results = undefined;
this._xml = utils.node('testsuites');
this._xml.toString = function toString() {
return this.outerHTML; // ouch
return '<?xml version="1.0" encoding="UTF-8"?>' + this.outerHTML; // ouch
};
}
exports.XUnitExporter = XUnitExporter;
/**
* Adds a successful test result.
* Retrieves generated XML object - actually an HTMLElement.
*
* @param String classname
* @param String name
* @param Number duration Test duration in milliseconds
* @return HTMLElement
*/
XUnitExporter.prototype.addSuccess = function addSuccess(classname, name, duration) {
XUnitExporter.prototype.getXML = function getXML() {
"use strict";
var snode = utils.node('testcase', {
classname: generateClassName(classname),
name: name
});
if (duration !== undefined) {
snode.setAttribute('time', utils.ms2seconds(duration));
if (!(this.results instanceof require('tester').TestSuite)) {
throw new CasperError('Results not set, cannot get XML.');
}
this._xml.appendChild(snode);
};
/**
* Adds a failed test result.
*
* @param String classname
* @param String name
* @param String message
* @param String type
* @param Number duration Test duration in milliseconds
*/
XUnitExporter.prototype.addFailure = function addFailure(classname, name, message, type, duration) {
"use strict";
var fnode = utils.node('testcase', {
classname: generateClassName(classname),
name: name
this.results.forEach(function(result) {
var suiteNode = utils.node('testsuite', {
name: result.name,
tests: result.assertions,
failures: result.failed,
time: utils.ms2seconds(result.calculateDuration()),
'package': generateClassName(result.file),
});
result.passes.forEach(function(success) {
var testCase = utils.node('testcase', {
name: success.message || success.standard,
classname: generateClassName(success.file),
time: utils.ms2seconds(~~success.time)
});
suiteNode.appendChild(testCase);
});
if (duration !== undefined) {
fnode.setAttribute('time', utils.ms2seconds(duration));
result.failures.forEach(function(failure) {
var testCase = utils.node('testcase', {
name: failure.message || failure.standard,
classname: generateClassName(failure.file),
time: utils.ms2seconds(~~failure.time)
});
var failureNode = utils.node('failure', {
type: failure.type || "failure"
});
failureNode.appendChild(document.createTextNode(failure.message || "no message left"));
if (failure.values && failure.values.error instanceof Error) {
var errorNode = utils.node('error', {
type: utils.betterTypeOf(failure.values.error)
});
errorNode.appendChild(document.createTextNode(failure.values.error.stack));
testCase.appendChild(errorNode);
}
var failure = utils.node('failure', {
type: type || "unknown"
testCase.appendChild(failureNode);
suiteNode.appendChild(testCase);
});
failure.appendChild(document.createTextNode(message || "no message left"));
fnode.appendChild(failure);
this._xml.appendChild(fnode);
this._xml.appendChild(suiteNode);
}.bind(this));
this._xml.setAttribute('duration', utils.ms2seconds(this.results.calculateDuration()));
return this._xml;
};
/**
* Adds test suite duration
* Sets test results.
*
* @param Number duration Test duration in milliseconds
* @param TestSuite results
*/
XUnitExporter.prototype.setSuiteDuration = function setSuiteDuration(duration) {
XUnitExporter.prototype.setResults = function setResults(results) {
"use strict";
if (!isNaN(duration)) {
this._xml.setAttribute("time", utils.ms2seconds(duration));
if (!(results instanceof require('tester').TestSuite)) {
throw new CasperError('Invalid results type.');
}
};
/**
* Retrieves generated XML object - actually an HTMLElement.
*
* @return HTMLElement
*/
XUnitExporter.prototype.getXML = function getXML() {
"use strict";
return this._xml;
return this.results = results;
};
......
......@@ -25,7 +25,17 @@ casper.withFrame('frame2', function() {
this.test.assertTitle('CasperJS frame 3');
});
casper.withFrame(0, function() {
this.test.assertTitle('CasperJS frame 1');
this.test.assertExists("#f1");
this.test.assertDoesntExist("#f2");
});
casper.withFrame(1, function() {
this.test.assertTitle('CasperJS frame 3');
});
casper.run(function() {
this.test.assertTitle('CasperJS test frames');
this.test.done(10);
this.test.done(14);
});
......
......@@ -47,7 +47,7 @@ casper.thenOpen('tests/site/index.html', function() {
t.assertTruthy('1', 'Tester.assertTruthy() works as expected');
t.comment('Tester.assertFalsy()');
t.assertFalsy('0', 'Tester.assertFalsy() works as expected');
t.assertFalsy('', 'Tester.assertFalsy() works as expected');
t.comment('Tester.assertNot()');
t.assertNot(false, 'Tester.assertNot() works as expected');
......@@ -200,27 +200,6 @@ casper.reload(function() {
t.assertField('checklist[]', [], 'Tester.assertField() works as expected with check lists');
});
casper.then(function() {
t.comment('Tester.getFailures()');
t.assertEquals(typeof t.getFailures().length, "number", "Tester.getFailures() works as expected");
var passCount = t.getPasses().length;
t.comment('Tester.getPasses()');
t.assertEquals(1, 1, "Rogue assertEquals pass case");
t.assertEquals(t.getPasses().length, passCount + 1, "Tester.getPasses() works as expected");
});
casper.then(function() {
t.comment('Tester.calculateSuiteDuration()');
function add(a, b) {
return a + b;
}
var passedTime = t.getPassesTime().reduce(add, 0),
failedTime = t.getFailuresTime().reduce(add, 0),
calculatedSum = t.calculateSuiteDuration();
t.assertEquals(calculatedSum, passedTime + failedTime, "Tester.calculateSuiteDuration() works as expected")
});
casper.run(function() {
t.done(59);
t.done(55);
});
......
......@@ -4,8 +4,7 @@ var utils = require('utils'),
t = casper.test,
x = require('casper').selectXPath;
t.comment('betterTypeOf()');
(function() {
casper.test.begin('utils.betterTypeOf() tests', function(casper) {
var testCases = [
{subject: 1, expected: 'number'},
{subject: '1', expected: 'string'},
......@@ -19,13 +18,13 @@ t.comment('betterTypeOf()');
{subject: new RegExp(), expected: 'regexp'}
];
testCases.forEach(function(testCase) {
t.assertEquals(utils.betterTypeOf(testCase.subject), testCase.expected,
require('utils').format('betterTypeOf() detects expected type "%s"', testCase.subject));
});
})();
this.assertEquals(utils.betterTypeOf(testCase.subject), testCase.expected,
utils.format('betterTypeOf() detects expected type "%s"', testCase.expected));
}.bind(this));
this.done(testCases.length);
});
t.comment('cleanUrl()');
(function() {
casper.test.begin('utils.cleanUrl() tests', function(casper) {
var testCases = {
'http://google.com/': 'http://google.com/',
'http://google.com': 'http://google.com/',
......@@ -39,47 +38,47 @@ t.comment('cleanUrl()');
'/100': '/100'
};
for (var testCase in testCases) {
t.assertEquals(utils.cleanUrl(testCase), testCases[testCase], 'cleanUrl() cleans an URL');
this.assertEquals(utils.cleanUrl(testCase), testCases[testCase], 'cleanUrl() cleans an URL');
}
})();
this.done(Object.keys(testCases).length);
});
t.comment('clone()');
(function() {
casper.test.begin('utils.clone() tests', function(casper) {
var a = {a: 1, b: 2, c: [1, 2]};
t.assertEquals(utils.clone(a), a);
this.assertEquals(utils.clone(a), a);
var b = [1, 2, 3, a];
t.assertEquals(utils.clone(b), b);
})();
this.assertEquals(utils.clone(b), b);
this.done(2);
});
t.comment('equals()');
(function() {
t.assert(utils.equals(null, null), 'equals() null equality');
t.assertNot(utils.equals(null, undefined), 'equals() null vs. undefined inequality');
t.assert(utils.equals("hi", "hi"), 'equals() string equality');
t.assertNot(utils.equals("hi", "ih"), 'equals() string inequality');
t.assert(utils.equals(5, 5), 'equals() number equality');
t.assertNot(utils.equals("5", 5), 'equals() number equality without implicit cast');
t.assert(utils.equals(5, 5.0), 'equals() number equality with cast');
t.assertNot(utils.equals(5, 10), 'equals() number inequality');
t.assert(utils.equals([], []), 'equals() empty array equality');
t.assert(utils.equals([1,2], [1,2]), 'equals() array equality');
t.assert(utils.equals([1,2,[1,2,function(){}]], [1,2,[1,2,function(){}]]), 'equals() complex array equality');
t.assertNot(utils.equals([1,2,[1,2,function(a){}]], [1,2,[1,2,function(b){}]]), 'equals() complex array inequality');
t.assertNot(utils.equals([1,2], [2,1]), 'equals() shuffled array inequality');
t.assertNot(utils.equals([1,2], [1,2,3]), 'equals() array length inequality');
t.assert(utils.equals({}, {}), 'equals() empty object equality');
t.assert(utils.equals({a:1,b:2}, {a:1,b:2}), 'equals() object length equality');
t.assert(utils.equals({a:1,b:2}, {b:2,a:1}), 'equals() shuffled object keys equality');
t.assertNot(utils.equals({a:1,b:2}, {a:1,b:3}), 'equals() object inequality');
t.assert(utils.equals({1:{name:"bob",age:28}, 2:{name:"john",age:26}}, {1:{name:"bob",age:28}, 2:{name:"john",age:26}}), 'equals() complex object equality');
t.assertNot(utils.equals({1:{name:"bob",age:28}, 2:{name:"john",age:26}}, {1:{name:"bob",age:28}, 2:{name:"john",age:27}}), 'equals() complex object inequality');
t.assert(utils.equals(function(x){return x;}, function(x){return x;}), 'equals() function equality');
t.assertNot(utils.equals(function(x){return x;}, function(y){return y+2;}), 'equals() function inequality');
t.assert(utils.equals([{a:1, b:2}, {c:3, d:4}], [{a:1, b:2}, {c:3, d:4}]), 'equals() arrays of objects');
})();
casper.test.begin('equals() tests', function(casper) {
this.assert(utils.equals(null, null), 'equals() null equality');
this.assertNot(utils.equals(null, undefined), 'equals() null vs. undefined inequality');
this.assert(utils.equals("hi", "hi"), 'equals() string equality');
this.assertNot(utils.equals("hi", "ih"), 'equals() string inequality');
this.assert(utils.equals(5, 5), 'equals() number equality');
this.assertNot(utils.equals("5", 5), 'equals() number equality without implicit cast');
this.assert(utils.equals(5, 5.0), 'equals() number equality with cast');
this.assertNot(utils.equals(5, 10), 'equals() number inequality');
this.assert(utils.equals([], []), 'equals() empty array equality');
this.assert(utils.equals([1,2], [1,2]), 'equals() array equality');
this.assert(utils.equals([1,2,[1,2,function(){}]], [1,2,[1,2,function(){}]]), 'equals() complex array equality');
this.assertNot(utils.equals([1,2,[1,2,function(a){}]], [1,2,[1,2,function(b){}]]), 'equals() complex array inequality');
this.assertNot(utils.equals([1,2], [2,1]), 'equals() shuffled array inequality');
this.assertNot(utils.equals([1,2], [1,2,3]), 'equals() array length inequality');
this.assert(utils.equals({}, {}), 'equals() empty object equality');
this.assert(utils.equals({a:1,b:2}, {a:1,b:2}), 'equals() object length equality');
this.assert(utils.equals({a:1,b:2}, {b:2,a:1}), 'equals() shuffled object keys equality');
this.assertNot(utils.equals({a:1,b:2}, {a:1,b:3}), 'equals() object inequality');
this.assert(utils.equals({1:{name:"bob",age:28}, 2:{name:"john",age:26}}, {1:{name:"bob",age:28}, 2:{name:"john",age:26}}), 'equals() complex object equality');
this.assertNot(utils.equals({1:{name:"bob",age:28}, 2:{name:"john",age:26}}, {1:{name:"bob",age:28}, 2:{name:"john",age:27}}), 'equals() complex object inequality');
this.assert(utils.equals(function(x){return x;}, function(x){return x;}), 'equals() function equality');
this.assertNot(utils.equals(function(x){return x;}, function(y){return y+2;}), 'equals() function inequality');
this.assert(utils.equals([{a:1, b:2}, {c:3, d:4}], [{a:1, b:2}, {c:3, d:4}]), 'equals() arrays of objects');
this.done(23);
});
t.comment('fileExt()');
(function() {
casper.test.begin('fileExt() tests', function() {
var testCases = {
'foo.ext': 'ext',
'FOO.EXT': 'ext',
......@@ -88,27 +87,25 @@ t.comment('fileExt()');
'toto.': '',
' plop.ext ': 'ext'
};
for (var testCase in testCases) {
t.assertEquals(utils.fileExt(testCase), testCases[testCase], 'fileExt() extract file extension');
this.assertEquals(utils.fileExt(testCase), testCases[testCase], 'fileExt() extract file extension');
}
})();
this.done(Object.keys(testCases).length);
});
t.comment('fillBlanks()');
(function() {
casper.test.begin('fillBlanks() tests', function() {
var testCases = {
'foo': 'foo ',
' foo bar ': ' foo bar ',
' foo bar ': ' foo bar '
};
for (var testCase in testCases) {
t.assertEquals(utils.fillBlanks(testCase, 10), testCases[testCase], 'fillBlanks() fills blanks');
this.assertEquals(utils.fillBlanks(testCase, 10), testCases[testCase], 'fillBlanks() fills blanks');
}
})();
this.done(Object.keys(testCases).length);
});
t.comment('getPropertyPath()');
(function() {
casper.test.begin('getPropertyPath() tests', function() {
var testCases = [
{
input: utils.getPropertyPath({}, 'a.b.c'),
......@@ -140,19 +137,19 @@ t.comment('getPropertyPath()');
}
];
testCases.forEach(function(testCase) {
t.assertEquals(testCase.input, testCase.output, 'getPropertyPath() gets a property using a path');
});
})();
this.assertEquals(testCase.input, testCase.output, 'getPropertyPath() gets a property using a path');
}.bind(this));
this.done(testCases.length);
});
t.comment('isArray()');
(function() {
t.assertEquals(utils.isArray([]), true, 'isArray() checks for an Array');
t.assertEquals(utils.isArray({}), false, 'isArray() checks for an Array');
t.assertEquals(utils.isArray("foo"), false, 'isArray() checks for an Array');
})();
casper.test.begin('isArray() tests', function() {
this.assertEquals(utils.isArray([]), true, 'isArray() checks for an Array');
this.assertEquals(utils.isArray({}), false, 'isArray() checks for an Array');
this.assertEquals(utils.isArray("foo"), false, 'isArray() checks for an Array');
this.done(3);
});
t.comment('isClipRect()');
(function() {
casper.test.begin('isClipRect() tests', function() {
var testCases = [
[{}, false],
[{top: 2}, false],
......@@ -160,14 +157,13 @@ t.comment('isClipRect()');
[{top: 2, left: 2, height: 2, width: 2}, true],
[{top: 2, left: 2, width: 2, height: new Date()}, false]
];
testCases.forEach(function(testCase) {
t.assertEquals(utils.isClipRect(testCase[0]), testCase[1], 'isClipRect() checks for a ClipRect');
});
})();
this.assertEquals(utils.isClipRect(testCase[0]), testCase[1], 'isClipRect() checks for a ClipRect');
}.bind(this));
this.done(testCases.length);
});
t.comment('isHTTPResource()');
(function() {
casper.test.begin('isHTTPResource() tests', function() {
var testCases = [
[{}, false],
[{url: 'file:///var/www/i.html'}, false],
......@@ -176,26 +172,25 @@ t.comment('isHTTPResource()');
[{url: 'HTTP://plop.com/'}, true],
[{url: 'https://plop.com/'}, true]
];
testCases.forEach(function(testCase) {
t.assertEquals(utils.isHTTPResource(testCase[0]), testCase[1], 'isHTTPResource() checks for an HTTP resource');
});
})();
this.assertEquals(utils.isHTTPResource(testCase[0]), testCase[1], 'isHTTPResource() checks for an HTTP resource');
}.bind(this));
this.done(Object.keys(testCases).length);
});
t.comment('isObject()');
(function() {
t.assertEquals(utils.isObject({}), true, 'isObject() checks for an Object');
t.assertEquals(utils.isObject([]), true, 'isObject() checks for an Object');
t.assertEquals(utils.isObject(1), false, 'isObject() checks for an Object');
t.assertEquals(utils.isObject("1"), false, 'isObject() checks for an Object');
t.assertEquals(utils.isObject(function(){}), false, 'isObject() checks for an Object');
t.assertEquals(utils.isObject(new Function('return {};')()), true, 'isObject() checks for an Object');
t.assertEquals(utils.isObject(require('webpage').create()), true, 'isObject() checks for an Object');
t.assertEquals(utils.isObject(null), false, 'isObject() checks for an Object');
})();
casper.test.begin('isObject() tests', function() {
this.assertEquals(utils.isObject({}), true, 'isObject() checks for an Object');
this.assertEquals(utils.isObject([]), true, 'isObject() checks for an Object');
this.assertEquals(utils.isObject(1), false, 'isObject() checks for an Object');
this.assertEquals(utils.isObject("1"), false, 'isObject() checks for an Object');
this.assertEquals(utils.isObject(function(){}), false, 'isObject() checks for an Object');
this.assertEquals(utils.isObject(new Function('return {};')()), true, 'isObject() checks for an Object');
this.assertEquals(utils.isObject(require('webpage').create()), true, 'isObject() checks for an Object');
this.assertEquals(utils.isObject(null), false, 'isObject() checks for an Object');
this.done(8);
});
t.comment('isValidSelector()');
(function() {
casper.test.begin('isValidSelector() tests', function() {
t.assertEquals(utils.isValidSelector({}), false, 'isValidSelector() checks for a valid selector');
t.assertEquals(utils.isValidSelector(""), false, 'isValidSelector() checks for a valid selector');
t.assertEquals(utils.isValidSelector("a"), true, 'isValidSelector() checks for a valid selector');
......@@ -219,18 +214,18 @@ t.comment('isValidSelector()');
type: "css3",
path: "a"
}), false, 'isValidSelector() checks for a valid selector');
})();
this.done(10);
});
t.comment('isWebPage()');
(function() {
casper.test.begin('isWebPage() tests', function() {
var pageModule = require('webpage');
t.assertEquals(utils.isWebPage(pageModule), false, 'isWebPage() checks for a WebPage instance');
t.assertEquals(utils.isWebPage(pageModule.create()), true, 'isWebPage() checks for a WebPage instance');
t.assertEquals(utils.isWebPage(null), false, 'isWebPage() checks for a WebPage instance');
})();
this.assertEquals(utils.isWebPage(pageModule), false, 'isWebPage() checks for a WebPage instance');
this.assertEquals(utils.isWebPage(pageModule.create()), true, 'isWebPage() checks for a WebPage instance');
this.assertEquals(utils.isWebPage(null), false, 'isWebPage() checks for a WebPage instance');
this.done(3);
});
t.comment('isJsFile()');
(function() {
casper.test.begin('isJsFile() tests', function() {
var testCases = {
'': false,
'toto.png': false,
......@@ -238,14 +233,13 @@ t.comment('isJsFile()');
'gniii.coffee': true,
'script.js': true
};
for (var testCase in testCases) {
t.assertEquals(utils.isJsFile(testCase), testCases[testCase], 'isJsFile() checks for js file');
this.assertEquals(utils.isJsFile(testCase), testCases[testCase], 'isJsFile() checks for js file');
}
})();
this.done(Object.keys(testCases).length);
});
t.comment('mergeObjects()');
(function() {
casper.test.begin('mergeObjects() tests', function() {
var testCases = [
{
obj1: {a: 1}, obj2: {b: 2}, merged: {a: 1, b: 2}
......@@ -269,20 +263,18 @@ t.comment('mergeObjects()');
}
}
];
testCases.forEach(function(testCase) {
t.assertEquals(utils.mergeObjects(testCase.obj1, testCase.obj2), testCase.merged, 'mergeObjects() can merge objects');
});
})();
this.assertEquals(utils.mergeObjects(testCase.obj1, testCase.obj2), testCase.merged, 'mergeObjects() can merge objects');
}.bind(this));
this.done(testCases.length);
});
t.comment('objectValues()');
(function() {
t.assertEquals(utils.objectValues({}), [], 'objectValues() can extract object values');
t.assertEquals(utils.objectValues({a: 1, b: 2}), [1, 2], 'objectValues() can extract object values');
})();
casper.test.begin('objectValues() tests', function() {
this.assertEquals(utils.objectValues({}), [], 'objectValues() can extract object values');
this.assertEquals(utils.objectValues({a: 1, b: 2}), [1, 2], 'objectValues() can extract object values');
});
t.comment('unique()');
(function() {
casper.test.begin('unique() tests', function() {
var testCases = [
{
input: [1,2,3],
......@@ -302,8 +294,7 @@ t.comment('unique()');
}
];
testCases.forEach(function(testCase) {
t.assertEquals(utils.unique(testCase.input), testCase.output, 'unique() computes unique values of an array');
});
})();
t.done(112);
this.assertEquals(utils.unique(testCase.input), testCase.output, 'unique() computes unique values of an array');
}.bind(this));
this.done(testCases.length);
});
......
/*global casper*/
/*jshint strict:false*/
casper.test.comment('phantom.Casper.XUnitExporter');
var tester = require('tester');
var testpage = require('webpage').create();
var xunit = require('xunit').create();
xunit.addSuccess('foo', 'bar');
casper.test.assertMatch(xunit.getXML(),
/<testcase classname="foo" name="bar"/,
'XUnitExporter.addSuccess() adds a successful testcase');
xunit.addFailure('bar', 'baz', 'wrong', 'chucknorriz');
casper.test.assertMatch(xunit.getXML(),
/<testcase classname="bar" name="baz"><failure type="chucknorriz">wrong/,
'XUnitExporter.addFailure() adds a failed testcase');
casper.test.begin('XUnitReporter() initialization', function suite() {
var xunit = require('xunit').create();
var results = new tester.TestSuite();
xunit.setResults(results);
this.assertTruthy(xunit.getXML());
this.done(1);
});
// named classname
xunit = require('xunit').create();
xunit.addSuccess(require('fs').workingDirectory + '/plop.js', 'It worked');
casper.test.assertMatch(xunit.getXML(),
/<testcase classname="(.*)plop" name="It worked"/,
'XUnitExporter.addSuccess() handles class name');
xunit.addSuccess(require('fs').workingDirectory + '/plip.js', 'Failure');
casper.test.assertMatch(xunit.getXML(),
/<testcase classname="(.*)plip" name="Failure"/,
'XUnitExporter.addFailure() handles class name');
casper.test.begin('XUnitReporter() can hold test suites', function suite() {
var xunit = require('xunit').create();
var results = new tester.TestSuite();
var suite1 = new tester.TestSuiteResult({
name: 'foo',
file: '/foo'
});
results.push(suite1);
var suite2 = new tester.TestSuiteResult({
name: 'bar',
file: '/bar'
});
results.push(suite2);
xunit.setResults(results);
casper.start().setContent(xunit.getXML());
this.assertEvalEquals(function() {
return __utils__.findAll('testsuite').length;
}, 2);
this.assertExists('testsuites[duration]');
this.assertExists('testsuite[name="foo"][package="foo"]');
this.assertExists('testsuite[name="bar"][package="bar"]');
this.done(4);
});
// named with time
xunit = require('xunit').create();
xunit.addSuccess('foo', 'It worked', 1024);
casper.test.assertMatch(xunit.getXML(),
/<testcase classname="foo" name="It worked" time="(.*)"/,
'XUnitExporter.addSuccess() writes duration of test');
xunit.addFailure('bar', 'baz', 'wrong', 'chucknorriz', 1024);
casper.test.assertMatch(xunit.getXML(),
/<testcase classname="bar" name="baz" time="(.*)"><failure type="chucknorriz">wrong/,
'XUnitExporter.addFailure() adds a failed testcase with duration');
casper.test.begin('XUnitReporter() can hold a suite with a succesful test', function suite() {
var xunit = require('xunit').create();
var results = new tester.TestSuite();
var suite1 = new tester.TestSuiteResult({
name: 'foo',
file: '/foo'
});
suite1.addSuccess({
success: true,
type: "footype",
message: "footext",
file: "/foo"
});
results.push(suite1);
xunit.setResults(results);
casper.start().setContent(xunit.getXML());
this.assertExists('testsuite[name="foo"][package="foo"][tests="1"][failures="0"] testcase[name="footext"]');
casper.test.done(1);
});
// named with time
xunit = require('xunit').create();
casper.test.assertMatch(xunit.getXML(),
/<testsuite>/,
'XUnitExporter.create() created <testsuite> without time');
xunit.setSuiteDuration(1024);
casper.test.assertMatch(xunit.getXML(),
/<testsuite time="1.024">/,
'XUnitExporter.setSuiteDuration() sets time in seconds');
casper.test.begin('XUnitReporter() can handle a failed test', function suite() {
var xunit = require('xunit').create();
var results = new tester.TestSuite();
var suite1 = new tester.TestSuiteResult({
name: 'foo',
file: '/foo'
});
suite1.addFailure({
success: false,
type: "footype",
message: "footext",
file: "/foo"
});
results.push(suite1);
xunit.setResults(results);
casper.start().setContent(xunit.getXML());
this.assertExists('testsuite[name="foo"][package="foo"][tests="1"][failures="1"] testcase[name="footext"] failure[type="footype"]');
casper.test.done(1);
});
casper.test.done(8);
......