mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Added CasperJS Functional Test to Build
Fixes #363 - Added new grunt task to run casperjs tests. - Added prerequisites (sass/bourbon/casperjs) to travis config. - Updated failing functional tests to use more robust `waitFor` statements. - Updated capserjs `base.js` file to use a password which conforms to our 8 character minimum. - Added necessary logout to first test and also registration step to ensure a user is present in the system.
This commit is contained in:
parent
1efd16dbcc
commit
badd6d10d4
8 changed files with 210 additions and 66 deletions
13
.travis.yml
13
.travis.yml
|
@ -4,5 +4,16 @@ node_js:
|
|||
- "0.10"
|
||||
git:
|
||||
submodules: false
|
||||
before_install:
|
||||
- gem update --system
|
||||
- gem install sass bourbon
|
||||
- npm install -g grunt-cli
|
||||
- git clone git://github.com/n1k0/casperjs.git ~/casperjs
|
||||
- cd ~/casperjs
|
||||
- git checkout tags/1.1-beta1
|
||||
- export PATH=$PATH:`pwd`/bin
|
||||
- cd -
|
||||
before_script:
|
||||
- npm install -g grunt-cli
|
||||
- phantomjs --version
|
||||
- casperjs --version
|
||||
- grunt init
|
35
Gruntfile.js
35
Gruntfile.js
|
@ -6,6 +6,8 @@ var path = require('path'),
|
|||
spawn = require("child_process").spawn,
|
||||
buildDirectory = path.resolve(process.cwd(), '.build'),
|
||||
distDirectory = path.resolve(process.cwd(), '.dist'),
|
||||
config = require('./config'),
|
||||
_ = require('underscore'),
|
||||
configureGrunt = function (grunt) {
|
||||
|
||||
// load all grunt tasks
|
||||
|
@ -343,6 +345,34 @@ var path = require('path'),
|
|||
cfg.buildType = type;
|
||||
});
|
||||
|
||||
grunt.registerTask('spawn-casperjs', function () {
|
||||
var done = this.async(),
|
||||
options = ['host', 'noPort', 'port', 'email', 'password'],
|
||||
args = ['test', 'admin/', '--includes=base.js', '--direct', '--log-level=debug'];
|
||||
|
||||
// Forward parameters from grunt to casperjs
|
||||
_.each(options, function processOption(option) {
|
||||
if (grunt.option(option)) {
|
||||
args.push('--' + option + '=' + grunt.option(option));
|
||||
}
|
||||
});
|
||||
|
||||
grunt.util.spawn({
|
||||
cmd: 'casperjs',
|
||||
args: args,
|
||||
opts: {
|
||||
cwd: path.resolve('core/test/functional'),
|
||||
stdio: 'inherit'
|
||||
}
|
||||
}, function (error, result, code) {
|
||||
if (error) {
|
||||
grunt.fail.fatal(result.stdout);
|
||||
}
|
||||
grunt.log.writeln(result.stdout);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Prepare the project for development
|
||||
// TODO: Git submodule init/update (https://github.com/jaubourg/grunt-update-submodules)?
|
||||
grunt.registerTask("init", ["shell:bourbon", "sass:admin", 'handlebars']);
|
||||
|
@ -356,8 +386,11 @@ var path = require('path'),
|
|||
// Run migrations tests only
|
||||
grunt.registerTask("test-m", ["mochacli:migrate"]);
|
||||
|
||||
// Run casperjs tests only
|
||||
grunt.registerTask('test-functional', ['express', 'spawn-casperjs']);
|
||||
|
||||
// Run tests and lint code
|
||||
grunt.registerTask("validate", ["jslint", "mochacli:all"]);
|
||||
grunt.registerTask("validate", ["jslint", "mochacli:all", "test-functional"]);
|
||||
|
||||
// Generate Docs
|
||||
grunt.registerTask("docs", ["groc"]);
|
||||
|
|
|
@ -1,4 +1,59 @@
|
|||
/*globals casper, __utils__, url, user, falseUser */
|
||||
|
||||
casper.test.begin('Ensure Session is Killed', 1, function suite(test) {
|
||||
casper.test.filename = 'login_logout_test.png';
|
||||
|
||||
casper.start(url + 'logout/', function (response) {
|
||||
test.assert(/\/ghost\//.test(response.url), response.url);
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
casper.test.begin('Ensure a User is Registered', 2, function suite(test) {
|
||||
casper.test.filename = 'login_user_registered_test.png';
|
||||
|
||||
casper.start(url + 'ghost/signup/');
|
||||
|
||||
casper.waitFor(function checkOpaque() {
|
||||
return this.evaluate(function () {
|
||||
var loginBox = document.querySelector('.login-box');
|
||||
return window.getComputedStyle(loginBox).getPropertyValue('display') === "block"
|
||||
&& window.getComputedStyle(loginBox).getPropertyValue('opacity') === "1";
|
||||
});
|
||||
}, function then() {
|
||||
checkUrl = true;
|
||||
this.fill("#register", user, true);
|
||||
});
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function (text) {
|
||||
test.assertSelectorHasText('.notification-error', 'already registered');
|
||||
// If the previous assert succeeds, then we should skip the next check and just pass.
|
||||
test.pass('Already registered!');
|
||||
}, function () {
|
||||
test.assertUrlMatch(/\/ghost\/$/, 'If we\'re not already registered, we should be logged in.');
|
||||
test.pass('Successfully registered.')
|
||||
}, 2000);
|
||||
|
||||
casper.run(function () {
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
casper.test.begin('Ensure Session is Killed after Registration', 1, function suite(test) {
|
||||
casper.test.filename = 'login_logout2_test.png';
|
||||
|
||||
casper.start(url + 'logout/', function (response) {
|
||||
test.assert(/\/ghost\//.test(response.url), response.url);
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
casper.test.begin("Ghost admin will load login page", 2, function suite(test) {
|
||||
|
||||
casper.test.filename = "admin_test.png";
|
||||
|
@ -26,9 +81,9 @@ casper.test.begin('Redirects to signin', 2, function suite(test) {
|
|||
});
|
||||
});
|
||||
|
||||
casper.test.begin("Can login to Ghost", 3, function suite(test) {
|
||||
casper.test.begin("Can't spam it", 2, function suite(test) {
|
||||
|
||||
casper.test.filename = "login_test.png";
|
||||
casper.test.filename = "login_spam_test.png";
|
||||
|
||||
casper.start(url + "ghost/signin/", function testTitle() {
|
||||
test.assertTitle("", "Ghost admin has no title");
|
||||
|
@ -42,6 +97,39 @@ casper.test.begin("Can login to Ghost", 3, function suite(test) {
|
|||
&& window.getComputedStyle(loginBox).getPropertyValue('opacity') === "1";
|
||||
});
|
||||
}, function then() {
|
||||
this.fill("#login", falseUser, true);
|
||||
casper.wait(200, function doneWait() {
|
||||
this.fill("#login", falseUser, true);
|
||||
});
|
||||
});
|
||||
casper.wait(1000, function doneWait() {
|
||||
this.echo("I've waited for 1 seconds.");
|
||||
});
|
||||
|
||||
casper.then(function testForErrorMessage() {
|
||||
test.assertSelectorHasText('.notification-error', 'Slow down, there are way too many login attempts!');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
casper.test.begin("Can login to Ghost", 3, function suite(test) {
|
||||
|
||||
casper.test.filename = "login_test.png";
|
||||
|
||||
casper.start(url + "ghost/login/", function testTitle() {
|
||||
test.assertTitle("", "Ghost admin has no title");
|
||||
}).viewport(1280, 1024);
|
||||
|
||||
casper.waitFor(function checkOpaque() {
|
||||
return this.evaluate(function () {
|
||||
var loginBox = document.querySelector('.login-box');
|
||||
return window.getComputedStyle(loginBox).getPropertyValue('display') === "block"
|
||||
&& window.getComputedStyle(loginBox).getPropertyValue('opacity') === "1";
|
||||
});
|
||||
}, function then() {
|
||||
this.fill("#login", user, true);
|
||||
});
|
||||
|
||||
|
@ -58,38 +146,3 @@ casper.test.begin("Can login to Ghost", 3, function suite(test) {
|
|||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
casper.test.begin("Can't spam it", 2, function suite(test) {
|
||||
|
||||
casper.test.filename = "login_test.png";
|
||||
|
||||
casper.start(url + "ghost/login/", function testTitle() {
|
||||
test.assertTitle("", "Ghost admin has no title");
|
||||
}).viewport(1280, 1024);
|
||||
|
||||
casper.waitFor(function checkOpaque() {
|
||||
return this.evaluate(function () {
|
||||
var loginBox = document.querySelector('.login-box');
|
||||
return window.getComputedStyle(loginBox).getPropertyValue('display') === "block"
|
||||
&& window.getComputedStyle(loginBox).getPropertyValue('opacity') === "1";
|
||||
});
|
||||
}, function then() {
|
||||
this.fill("#login", falseUser, true);
|
||||
casper.wait(200, function doneWait() {
|
||||
this.fill("#login", falseUser, true);
|
||||
});
|
||||
|
||||
});
|
||||
casper.wait(200, function doneWait() {
|
||||
this.echo("I've waited for 1 seconds.");
|
||||
});
|
||||
|
||||
casper.then(function testForErrorMessage() {
|
||||
test.assertSelectorHasText('.notification-error', 'Slow down, there are way too many login attempts!');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ casper.test.begin("Haunted markdown in editor works", 3, function suite(test) {
|
|||
}).viewport(1280, 1024);
|
||||
|
||||
casper.then(function testImage() {
|
||||
casper.writeContentToCodeMirror("![some text]()");
|
||||
casper.writeContentToCodeMirror("![sometext]()");
|
||||
});
|
||||
|
||||
// We must wait after sending keys to CodeMirror
|
||||
|
@ -77,9 +77,9 @@ casper.test.begin("Haunted markdown in editor works", 3, function suite(test) {
|
|||
|
||||
test.assertEvalEquals(function () {
|
||||
return document.querySelector('.CodeMirror-wrap textarea').value;
|
||||
}, "![some text]()", 'Editor value is correct');
|
||||
}, "![sometext]()", 'Editor value is correct');
|
||||
|
||||
test.assertSelectorHasText('.entry-preview .rendered-markdown', 'Add image of some text', 'Editor value is correct');
|
||||
test.assertSelectorHasText('.entry-preview .rendered-markdown', 'Add image of sometext', 'Editor value is correct');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
|
|
|
@ -82,7 +82,12 @@ casper.test.begin("Settings screen is correct", 19, function suite(test) {
|
|||
|
||||
casper.then(function checkUserWasSaved() {
|
||||
casper.removeListener('resource.requested', handleUserRequest);
|
||||
test.assertExists('.notification-success', 'got success notification');
|
||||
});
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No success notification :(');
|
||||
});
|
||||
|
||||
casper.thenClick('#main-menu .settings a').then(function testOpeningSettingsTwice() {
|
||||
|
@ -105,7 +110,12 @@ casper.test.begin("Settings screen is correct", 19, function suite(test) {
|
|||
|
||||
casper.then(function checkSettingsWereSaved() {
|
||||
casper.removeListener('resource.requested', handleSettingsRequest);
|
||||
test.assertExists('.notification-success', 'got success notification');
|
||||
});
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No success notification :(');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
|
@ -130,24 +140,36 @@ casper.test.begin("User settings screen validates email", 6, function suite(test
|
|||
brokenEmail = email.replace('.', '-');
|
||||
|
||||
casper.fillSelectors('.user-details-container', {
|
||||
'#user-email': brokenEmail
|
||||
'#user-email': brokenEmail
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('#user .button-save').waitForResource('/users/', function () {
|
||||
test.assertExists('.notification-error', 'got error notification');
|
||||
casper.thenClick('#user .button-save');
|
||||
|
||||
casper.waitForResource('/users/');
|
||||
|
||||
casper.waitForSelector('.notification-error', function onSuccess() {
|
||||
test.assert(true, 'Got error notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No error notification :(');
|
||||
});
|
||||
|
||||
casper.then(function resetEmailToValid() {
|
||||
casper.fillSelectors('.user-details-container', {
|
||||
'#user-email': email
|
||||
'#user-email': email
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('#user .button-save').waitForResource('/users/', function () {
|
||||
test.assertExists('.notification-success', 'got success notification');
|
||||
casper.thenClick('#user .button-save');
|
||||
|
||||
casper.waitForResource('/users/');
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-success', '[object Object]');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No success notification :(');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
|
|
|
@ -22,8 +22,14 @@ casper.test.begin("Ghost edit draft flow works correctly", 7, function suite(tes
|
|||
this.echo("I've waited for 1 seconds.");
|
||||
});
|
||||
|
||||
casper.thenClick('.button-save').waitForResource(/posts/, function then() {
|
||||
test.assertExists('.notification-success', 'got success notification');
|
||||
casper.thenClick('.button-save');
|
||||
|
||||
casper.waitForResource(/posts/);
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No success notification :(');
|
||||
});
|
||||
|
||||
casper.thenOpen(url + 'ghost/content/', function then() {
|
||||
|
@ -42,8 +48,14 @@ casper.test.begin("Ghost edit draft flow works correctly", 7, function suite(tes
|
|||
test.assertUrlMatch(/editor/, "Ghost doesn't require login this time");
|
||||
});
|
||||
|
||||
casper.thenClick('.button-save').waitForResource(/posts/, function then() {
|
||||
test.assertExists('.notification-success', 'got success notification');
|
||||
casper.thenClick('.button-save');
|
||||
|
||||
casper.waitForResource(/posts/);
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No success notification :(');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
|
|
|
@ -19,8 +19,14 @@ casper.test.begin("Ghost logout works correctly", 2, function suite(test) {
|
|||
});
|
||||
});
|
||||
|
||||
casper.thenClick('.usermenu-signout a').waitForResource(/login/, function then() {
|
||||
test.assertExists('.notification-success', 'got success notification');
|
||||
casper.thenClick('.usermenu-signout a');
|
||||
|
||||
casper.waitForResource(/signin/);
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No success notification :(');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
|
@ -50,13 +56,12 @@ casper.test.begin("Can't spam signin", 3, function suite(test) {
|
|||
});
|
||||
|
||||
});
|
||||
casper.wait(200, function doneWait() {
|
||||
this.echo("I've waited for 1 seconds.");
|
||||
});
|
||||
|
||||
casper.then(function testForErrorMessage() {
|
||||
test.assertExists('.notification-error', 'got error notification');
|
||||
casper.waitForSelector('.notification-error', function onSuccess() {
|
||||
test.assert(true, 'Got error notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No error notification :(');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
|
@ -77,9 +82,13 @@ casper.test.begin("Ghost signup fails properly", 5, function suite(test) {
|
|||
});
|
||||
|
||||
// should now throw a short password error
|
||||
casper.waitForResource(/signup/, function () {
|
||||
test.assertExists('.notification-error', 'got error notification');
|
||||
casper.waitForResource(/signup/);
|
||||
|
||||
casper.waitForSelector('.notification-error', function onSuccess() {
|
||||
test.assert(true, 'Got error notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No error notification :(');
|
||||
});
|
||||
|
||||
casper.then(function signupWithLongPassword() {
|
||||
|
@ -87,9 +96,13 @@ casper.test.begin("Ghost signup fails properly", 5, function suite(test) {
|
|||
});
|
||||
|
||||
// should now throw a 1 user only error
|
||||
casper.waitForResource(/signup/, function () {
|
||||
test.assertExists('.notification-error', 'got error notification');
|
||||
casper.waitForResource(/signup/);
|
||||
|
||||
casper.waitForSelector('.notification-error', function onSuccess() {
|
||||
test.assert(true, 'Got error notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'No error notification :(');
|
||||
});
|
||||
|
||||
casper.run(function () {
|
||||
|
|
|
@ -25,7 +25,7 @@ var host = casper.cli.options.host || 'localhost',
|
|||
noPort = casper.cli.options.noPort || false,
|
||||
port = casper.cli.options.port || '2368',
|
||||
email = casper.cli.options.email || 'ghost@tryghost.org',
|
||||
password = casper.cli.options.password || 'Sl1m3r',
|
||||
password = casper.cli.options.password || 'Sl1m3rson',
|
||||
url = "http://" + host + (noPort ? '/' : ":" + port + "/"),
|
||||
user = {
|
||||
email: email,
|
||||
|
|
Loading…
Add table
Reference in a new issue