Merge pull request #983 from gotdibbs/Issue362

Refactored tests
This commit is contained in:
Hannah Wolfe 2013-10-08 03:04:15 -07:00
commit 53dc1b4466
23 changed files with 1161 additions and 804 deletions

View File

@ -817,7 +817,7 @@ var path = require('path'),
grunt.registerTask('init', ['shell:bourbon', 'default']);
// Run unit tests
grunt.registerTask('test-unit', ['setTestEnv', 'loadConfig', 'mochacli:all']);
grunt.registerTask('test-unit', ['setTestEnv', 'loadConfig', 'express:test', 'mochacli:all']);
// Run casperjs tests only
grunt.registerTask('test-functional', ['setTestEnv', 'express:test', 'spawn-casperjs']);

View File

@ -1,12 +1,31 @@
/*globals casper, __utils__, url, testPost */
casper.test.begin("Content screen is correct", 17, function suite(test) {
test.filename = "content_test.png";
CasperTest.begin("Content screen is correct", 20, function suite(test) {
// Create a sample post
casper.thenOpen(url + 'ghost/editor/', function testTitleAndUrl() {
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
});
casper.start(url + "ghost/content/", function testTitleAndUrl() {
casper.then(function createTestPost() {
casper.sendKeys('#entry-title', testPost.title);
casper.writeContentToCodeMirror(testPost.html);
});
casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
test.assertSelectorHasText('.entry-preview .rendered-markdown', 'test', 'Editor value is correct');
});
casper.thenClick('.js-publish-button');
casper.waitForResource(/posts/, function checkPostWasCreated() {
test.assertExists('.notification-success', 'got success notification');
});
// Begin test
casper.thenOpen(url + "ghost/content/", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
test.assertUrlMatch(/ghost\/content\/$/, "Ghost doesn't require login this time");
}).viewport(1280, 1024);
});
casper.then(function testMenus() {
test.assertExists("#main-menu", "Main menu is present");
@ -25,40 +44,25 @@ casper.test.begin("Content screen is correct", 17, function suite(test) {
test.assertExists(".content-list-content", "Content list view is present");
test.assertExists(".content-list-content li .entry-title", "Content list view has at least one item");
test.assertExists(".content-preview", "Content preview is present");
test.assertSelectorHasText(".content-list-content li:first-child h3", testPost.title, "first item is the post we created");
test.assertSelectorHasText(".content-list-content li:first-child h3", testPost.title, "item is present and has content");
});
casper.then(function testActiveItem() {
casper.test.assertEvalEquals(function () {
test.assertEvalEquals(function () {
return document.querySelector('.content-list-content li').className;
}, "active", "first item is active");
}).thenClick(".content-list-content li:nth-child(2) a", function then() {
casper.test.assertEvalEquals(function () {
test.assertEvalEquals(function () {
return document.querySelectorAll('.content-list-content li')[1].className;
}, "active", "second item is active");
});
// TODO: finish testing delete
// casper.then(function testDeletePost() {
// casper.clickLabel(testPost.title, "h3");
// });
casper.run(function () {
test.done();
});
});
casper.test.begin('Infinite scrolling', 1, function suite(test) {
test.filename = 'content_infinite_scrolling_test.png';
CasperTest.begin('Infinite scrolling', 1, function suite(test) {
// Placeholder for infinite scrolling/pagination tests (will need to setup 16+ posts).
casper.start(url + "ghost/content/", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
}).viewport(1280, 1024);
casper.run(function () {
test.done();
casper.thenOpen(url + 'ghost/content/', function testTitleAndUrl() {
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
});
});

View File

@ -1,15 +1,12 @@
/*globals casper, __utils__, url, testPost */
casper.test.begin("Ghost editor is correct", 9, function suite(test) {
test.filename = "editor_test.png";
casper.start(url + "ghost/editor/", function testTitleAndUrl() {
CasperTest.begin("Ghost editor is correct", 10, function suite(test) {
casper.thenOpen(url + "ghost/editor/", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
test.assertUrlMatch(/ghost\/editor\/$/, "Ghost doesn't require login this time");
test.assertExists(".entry-markdown", "Ghost editor is present");
test.assertExists(".entry-preview", "Ghost preview is present");
}).viewport(1280, 1024);
});
// test saving with no data
casper.thenClick('.js-publish-button');
@ -26,9 +23,8 @@ casper.test.begin("Ghost editor is correct", 9, function suite(test) {
casper.writeContentToCodeMirror(testPost.html);
});
// We must wait after sending keys to CodeMirror
casper.wait(1000, function doneWait() {
this.echo("I've waited for 1 seconds.");
casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
test.assertSelectorHasText('.entry-preview .rendered-markdown', 'test', 'Editor value is correct.');
});
casper.thenClick('.js-publish-button');
@ -40,54 +36,31 @@ casper.test.begin("Ghost editor is correct", 9, function suite(test) {
test.assertEvalEquals(function () {
return document.querySelector('#entry-title').value;
}, testPost.title, 'Title is correct');
// TODO: make this work - spaces & newlines are problematic
// test.assertTextExists(testPost.html, 'Post html exists');
});
casper.run(function () {
test.done();
});
});
casper.test.begin("Haunted markdown in editor works", 3, function suite(test) {
test.filename = "markdown_test.png";
casper.start(url + "ghost/editor/", function testTitleAndUrl() {
CasperTest.begin("Haunted markdown in editor works", 3, function suite(test) {
casper.thenOpen(url + "ghost/editor/", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
}).viewport(1280, 1024);
});
casper.then(function testImage() {
casper.writeContentToCodeMirror("![sometext]()");
});
// We must wait after sending keys to CodeMirror
casper.wait(1000, function doneWait() {
this.echo("I've waited for 1 seconds.");
// bind to resource events so we can get the API response
});
casper.then(function checkPostWasCreated() {
casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
test.assertEvalEquals(function () {
return document.querySelector('.CodeMirror-wrap textarea').value;
}, "![sometext]()", 'Editor value is correct');
}, '![sometext]()', 'Editor value is correct');
test.assertSelectorHasText('.entry-preview .rendered-markdown', 'Add image of sometext', 'Editor value is correct');
});
casper.run(function () {
test.done();
});
});
casper.test.begin("Word count and plurality", 4, function suite(test) {
test.filename = "editor_plurality_test.png";
casper.start(url + "ghost/editor/", function testTitleAndUrl() {
CasperTest.begin("Word count and plurality", 4, function suite(test) {
casper.thenOpen(url + "ghost/editor/", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
}).viewport(1280, 1024);
});
casper.then(function checkZeroPlural() {
test.assertSelectorHasText('.entry-word-count', '0 words', 'count of 0 produces plural "words".');
@ -97,42 +70,26 @@ casper.test.begin("Word count and plurality", 4, function suite(test) {
casper.writeContentToCodeMirror('test');
});
// We must wait after sending keys to CodeMirror
casper.wait(1000, function doneWait() {
this.echo('I\'ve waited for 1 seconds.');
});
casper.then(function checkSinglular() {
casper.waitForSelectorTextChange('.entry-word-count', function onSuccess() {
test.assertSelectorHasText('.entry-word-count', '1 word', 'count of 1 produces singular "word".');
});
})
casper.then(function () {
casper.writeContentToCodeMirror('test'); // append another word, assumes newline
});
// We must wait after sending keys to CodeMirror
casper.wait(1000, function doneWait() {
this.echo('I\'ve waited for 1 seconds.');
});
casper.then(function checkPlural() {
casper.waitForSelectorTextChange('.entry-word-count', function onSuccess() {
test.assertSelectorHasText('.entry-word-count', '2 words', 'count of 2 produces plural "words".');
});
casper.run(function () {
test.done();
});
});
casper.test.begin('Title Trimming', function suite(test) {
CasperTest.begin('Title Trimming', 2, function suite(test) {
var untrimmedTitle = ' test title ',
trimmedTitle = 'test title';
test.filename = 'editor_title_trimming_test.png';
casper.start(url + 'ghost/editor/', function testTitleAndUrl() {
casper.thenOpen(url + 'ghost/editor/', function testTitleAndUrl() {
test.assertTitle("Ghost Admin", 'Ghost admin has no title');
}).viewport(1280, 1024);
});
casper.then(function populateTitle() {
casper.sendKeys('#entry-title', untrimmedTitle);
@ -143,18 +100,12 @@ casper.test.begin('Title Trimming', function suite(test) {
}, trimmedTitle, 'Entry title should match expected value.');
});
casper.run(function () {
test.done();
});
});
casper.test.begin('Publish menu - new post', function suite(test) {
test.filename = 'publish_menu_new_post.png';
casper.start(url + 'ghost/editor/', function testTitleAndUrl() {
CasperTest.begin('Publish menu - new post', 11, function suite(test) {
casper.thenOpen(url + 'ghost/editor/', function testTitleAndUrl() {
test.assertTitle("Ghost Admin", 'Ghost admin has no title');
}).viewport(1280, 1024);
});
// ... check default option status, label, class
casper.then(function () {
@ -184,28 +135,21 @@ casper.test.begin('Publish menu - new post', function suite(test) {
return (__utils__.findOne('.js-publish-button').getAttribute('data-status') === 'published');
}, 'Publish button\'s updated status should be "published"');
});
casper.run(function () {
test.done();
});
});
casper.test.begin('Publish menu - existing post', function suite(test) {
test.filename = 'publish_menu_existing_post.png';
CasperTest.begin('Publish menu - existing post', 24, function suite(test) {
// Create a post, save it and test refreshed editor
casper.start(url + 'ghost/editor/', function testTitleAndUrl() {
casper.thenOpen(url + 'ghost/editor/', function testTitleAndUrl() {
test.assertTitle("Ghost Admin", 'Ghost admin has no title');
}).viewport(1280, 1024);
});
casper.then(function createTestPost() {
casper.sendKeys('#entry-title', testPost.title);
casper.writeContentToCodeMirror(testPost.html);
});
// We must wait after sending keys to CodeMirror
casper.wait(1000, function doneWait() {
this.echo("I've waited for 1 seconds.");
casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
test.assertSelectorHasText('.entry-preview .rendered-markdown', 'test', 'Editor value is correct');
});
// Create a post in draft status
@ -279,8 +223,4 @@ casper.test.begin('Publish menu - existing post', function suite(test) {
return (__utils__.findOne('.js-publish-button').getAttribute('data-status') === 'draft');
}, 'Publish button\'s updated status should be "draft"');
});
casper.run(function () {
test.done();
});
});

View File

@ -3,22 +3,18 @@
*/
/*globals casper, __utils__, url, testPost */
casper.test.begin("Ghost edit draft flow works correctly", 7, function suite(test) {
test.filename = "flow_test.png";
casper.start(url + "ghost/editor/", function then() {
CasperTest.begin("Ghost edit draft flow works correctly", 8, function suite(test) {
casper.thenOpen(url + "ghost/editor/", function then() {
test.assertUrlMatch(/ghost\/editor\/$/, "Ghost doesn't require login this time");
}).viewport(1280, 1024);
// First, create a new draft post
casper.then(function createTestPost() {
casper.sendKeys('#entry-title', 'Test Draft Post');
casper.writeContentToCodeMirror('I am a draft');
});
// We must wait after sending keys to CodeMirror
casper.wait(1000, function doneWait() {
this.echo("I've waited for 1 seconds.");
casper.then(function createTestPost() {
casper.sendKeys('#entry-title', testPost.title);
casper.writeContentToCodeMirror(testPost.html);
});
casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
test.assertSelectorHasText('.entry-preview .rendered-markdown', 'test', 'Editor value is correct');
});
casper.thenClick('.js-publish-button');
@ -39,7 +35,7 @@ casper.test.begin("Ghost edit draft flow works correctly", 7, function suite(tes
return document.querySelector('.content-list-content li').className;
}, "active", "first item is active");
test.assertSelectorHasText(".content-list-content li:first-child h3", 'Test Draft Post', "first item is the post we created");
test.assertSelectorHasText(".content-list-content li:first-child h3", testPost.title, "first item is the post we created");
});
casper.thenClick('.post-edit').waitForResource(/editor/, function then() {
@ -54,16 +50,11 @@ casper.test.begin("Ghost edit draft flow works correctly", 7, function suite(tes
}, function onTimeout() {
test.assert(false, 'No success notification :(');
});
casper.run(function () {
test.done();
});
});
// TODO: test publishing, editing, republishing, unpublishing etc
//casper.test.begin("Ghost edit published flow works correctly", 6, function suite(test) {
//CasperTest.begin("Ghost edit published flow works correctly", 6, function suite(test) {
//
// test.filename = "flow_test.png";
//
//
//});

View File

@ -1,21 +1,13 @@
/*globals casper, __utils__, url, user, falseUser */
casper.test.begin('Ensure Session is Killed', 1, function suite(test) {
test.filename = 'login_logout_test.png';
casper.start(url + 'logout/', function (response) {
CasperTest.begin('Ensure Session is Killed', 1, function suite(test) {
casper.thenOpen(url + 'logout/', function (response) {
test.assertUrlMatch(/ghost\/sign/, 'We got redirected to signin or signup page');
});
}, true);
casper.run(function () {
test.done();
});
});
casper.test.begin('Ensure a User is Registered', 2, function suite(test) {
test.filename = 'login_user_registered_test.png';
casper.start(url + 'ghost/signup/').viewport(1280, 1024);
CasperTest.begin('Ensure a User is Registered', 2, function suite(test) {
casper.thenOpen(url + 'ghost/signup/');
casper.waitForOpaque(".signup-box",
function then() {
@ -28,61 +20,35 @@ casper.test.begin('Ensure a User is Registered', 2, function suite(test) {
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
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!');
casper.echo('Already registered!');
}, function onTimeout() {
test.assertUrlMatch(/\/ghost\/$/, 'If we\'re not already registered, we should be logged in.');
test.pass('Successfully registered.');
casper.echo('Successfully registered.');
}, 2000);
casper.run(function () {
test.done();
casper.thenOpen(url + 'logout/', function then() {
test.assertUrlMatch(/ghost\/signin/, 'We got redirected to signin page.');
});
});
}, true);
casper.test.begin('Ensure Session is Killed after Registration', 1, function suite(test) {
test.filename = 'login_logout2_test.png';
casper.start(url + 'logout/', function then() {
test.assertUrlMatch(/ghost\/signin/, 'We got redirected to signin page');
});
casper.run(function () {
test.done();
});
});
casper.test.begin("Ghost admin will load login page", 2, function suite(test) {
test.filename = "admin_test.png";
casper.start(url + "ghost", function testTitleAndUrl() {
CasperTest.begin("Ghost admin will load login page", 2, function suite(test) {
casper.thenOpen(url + "ghost", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
test.assertUrlMatch(/ghost\/signin\/$/, 'If we\'re not already registered, we should be logged in.');
}).viewport(1280, 1024);
casper.run(function () {
test.done();
test.assertUrlMatch(/ghost\/signin\/$/, 'We should be presented with the signin page.');
});
});
casper.test.begin('Redirects to signin', 2, function suite(test) {
test.filename = 'login_redirect_test.png';
}, true);
CasperTest.begin('Redirects login to signin', 2, function suite(test) {
casper.start(url + 'ghost/login/', function testRedirect(response) {
test.assertEqual(response.status, 200, 'Response status should be 200.');
test.assertUrlMatch(/ghost\/signin\/$/, 'Should be redirected to /signin/.');
});
}, true);
casper.run(function () {
test.done();
});
});
casper.test.begin("Can't spam it", 4, function suite(test) {
test.filename = "login_spam_test.png";
casper.start(url + "ghost/signin/", function testTitle() {
CasperTest.begin("Can't spam it", 4, function suite(test) {
casper.thenOpen(url + "ghost/signin/", function testTitle() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
}).viewport(1280, 1024);
});
casper.waitForOpaque(".login-box",
function then() {
@ -107,18 +73,12 @@ casper.test.begin("Can't spam it", 4, function suite(test) {
// This test causes the spam notification
// add a wait to ensure future tests don't get tripped up by this.
casper.wait(1000);
}, true);
casper.run(function () {
test.done();
});
});
casper.test.begin("Can login to Ghost", 4, function suite(test) {
test.filename = "login_test.png";
casper.start(url + "ghost/login/", function testTitle() {
CasperTest.begin("Can login to Ghost", 4, function suite(test) {
casper.thenOpen(url + "ghost/login/", function testTitle() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
}).viewport(1280, 1024);
});
casper.waitForOpaque(".login-box",
function then() {
@ -132,8 +92,4 @@ casper.test.begin("Can login to Ghost", 4, function suite(test) {
}, function onTimeOut() {
test.fail('Failed to load ghost/ resource');
});
casper.run(function () {
test.done();
});
});
}, true);

View File

@ -3,12 +3,12 @@
*/
/*globals casper, __utils__, url, testPost, falseUser, email */
casper.test.begin("Ghost logout works correctly", 2, function suite(test) {
test.filename = "logout_test.png";
CasperTest.begin("Ghost logout works correctly", 2, function suite(test) {
CasperTest.Routines.login.run(test);
casper.start(url + "ghost/", function then() {
casper.thenOpen(url + "ghost/", function then() {
test.assertEquals(casper.getCurrentUrl(), url + "ghost/", "Ghost doesn't require login this time");
}).viewport(1280, 1024);
});
casper.thenClick('#usermenu a').waitFor(function checkOpaque() {
return this.evaluate(function () {
@ -26,19 +26,13 @@ casper.test.begin("Ghost logout works correctly", 2, function suite(test) {
}, function onTimeout() {
test.assert(false, 'No success notification :(');
});
casper.run(function () {
test.done();
});
});
}, true);
// has to be done after signing out
casper.test.begin("Can't spam signin", 3, function suite(test) {
test.filename = "spam_test.png";
casper.start(url + "ghost/signin/", function testTitle() {
CasperTest.begin("Can't spam signin", 3, function suite(test) {
casper.thenOpen(url + "ghost/signin/", function testTitle() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
}).viewport(1280, 1024);
});
casper.waitFor(function checkOpaque() {
return this.evaluate(function () {
@ -60,18 +54,12 @@ casper.test.begin("Can't spam signin", 3, function suite(test) {
}, function onTimeout() {
test.assert(false, 'No error notification :(');
});
}, true);
casper.run(function () {
test.done();
});
});
casper.test.begin("Ghost signup fails properly", 5, function suite(test) {
test.filename = "signup_test.png";
casper.start(url + "ghost/signup/", function then() {
CasperTest.begin("Ghost signup fails properly", 5, function suite(test) {
casper.thenOpen(url + "ghost/signup/", function then() {
test.assertEquals(casper.getCurrentUrl(), url + "ghost/signup/", "Reached signup page");
}).viewport(1280, 1024);
});
casper.then(function signupWithShortPassword() {
this.fill("#signup", {email: email, password: 'test'}, true);
@ -98,8 +86,4 @@ casper.test.begin("Ghost signup fails properly", 5, function suite(test) {
}, function onTimeout() {
test.assert(false, 'No error notification :(');
});
casper.run(function () {
test.done();
});
});
}, true);

View File

@ -1,12 +1,10 @@
/*globals casper, __utils__, url */
casper.test.begin("Settings screen is correct", 15, function suite(test) {
test.filename = "settings_test.png";
casper.start(url + "ghost/settings/", function testTitleAndUrl() {
CasperTest.begin("Settings screen is correct", 15, function suite(test) {
casper.thenOpen(url + "ghost/settings/", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
test.assertUrlMatch(/ghost\/settings\/general\/$/, "Ghost doesn't require login this time");
}).viewport(1280, 1024);
});
casper.then(function testViews() {
test.assertExists(".wrapper", "Settings main view is present");
@ -41,14 +39,14 @@ casper.test.begin("Settings screen is correct", 15, function suite(test) {
function handleUserRequest(requestData, request) {
// make sure we only get requests from the user pane
if (requestData.url.indexOf('settings/') !== -1) {
casper.test.fail("Saving the user pane triggered another settings pane to save");
test.fail("Saving the user pane triggered another settings pane to save");
}
}
function handleSettingsRequest(requestData, request) {
// make sure we only get requests from the user pane
if (requestData.url.indexOf('users/') !== -1) {
casper.test.fail("Saving a settings pane triggered the user pane to save");
test.fail("Saving a settings pane triggered the user pane to save");
}
}
@ -64,7 +62,7 @@ casper.test.begin("Settings screen is correct", 15, function suite(test) {
}, function doneWaiting() {
}, function waitTimeout() {
casper.test.fail("Saving the user pane did not result in a notification");
test.fail("Saving the user pane did not result in a notification");
});
casper.then(function checkUserWasSaved() {
@ -92,7 +90,7 @@ casper.test.begin("Settings screen is correct", 15, function suite(test) {
}, function doneWaiting() {
}, function waitTimeout() {
casper.test.fail("Saving the general pane did not result in a notification");
test.fail("Saving the general pane did not result in a notification");
});
casper.then(function checkSettingsWereSaved() {
@ -105,22 +103,19 @@ casper.test.begin("Settings screen is correct", 15, function suite(test) {
test.assert(false, 'No success notification :(');
});
casper.run(function () {
CasperTest.beforeDone(function () {
casper.removeListener('resource.requested', handleUserRequest);
casper.removeListener('resource.requested', handleSettingsRequest);
test.done();
});
});
casper.test.begin("User settings screen validates email", 6, function suite(test) {
CasperTest.begin("User settings screen validates email", 6, function suite(test) {
var email, brokenEmail;
test.filename = "user_settings_test.png";
casper.start(url + "ghost/settings/user/", function testTitleAndUrl() {
casper.thenOpen(url + "ghost/settings/user/", function testTitleAndUrl() {
test.assertTitle("Ghost Admin", "Ghost admin has no title");
test.assertUrlMatch(/ghost\/settings\/user\/$/, "Ghost doesn't require login this time");
}).viewport(1280, 1024);
});
casper.then(function setEmailToInvalid() {
email = casper.getElementInfo('#user-email').attributes.value;
@ -158,8 +153,4 @@ casper.test.begin("User settings screen validates email", 6, function suite(test
}, function onTimeout() {
test.assert(false, 'No success notification :(');
});
casper.run(function () {
test.done();
});
});

View File

@ -83,4 +83,141 @@ casper.on("page.error", function (msg, trace) {
casper.test.on("fail", function captureFailure() {
var filename = casper.test.filename || "casper_test_fail.png";
casper.capture(new Date().getTime() + '_' + filename);
});
});
var CasperTest = (function() {
var _beforeDoneHandler,
_noop = function noop() { },
_isUserRegistered = false;
// Always log out at end of test.
casper.test.tearDown(function (done) {
casper.then(_beforeDoneHandler);
casper.thenOpen(url + 'signout/');
casper.waitForResource(/ghost\/sign/);
casper.run(done);
});
// Wrapper around `casper.test.begin`
function begin(testName, expect, suite, doNotAutoLogin) {
_beforeDoneHandler = _noop;
var runTest = function (test) {
test.filename = testName.toLowerCase().replace(/ /g, '-').concat('.png');
casper.start().viewport(1280, 1024);
if (!doNotAutoLogin) {
// Only call register once for the lifetime of Mindless
if (!_isUserRegistered) {
CasperTest.Routines.logout.run(test);
CasperTest.Routines.register.run(test);
_isUserRegistered = true;
}
/* Ensure we're logged out at the start of every test or we may get
unexpected failures. */
CasperTest.Routines.logout.run(test);
CasperTest.Routines.login.run(test);
}
suite.call(casper, test);
casper.run(function () {
test.done();
});
};
if (typeof expect === 'function') {
doNotAutoLogin = suite;
suite = expect;
casper.test.begin(testName, runTest);
}
else {
casper.test.begin(testName, expect, runTest);
}
}
// Sets a handler to be invoked right before `test.done` is invoked
function beforeDone(fn) {
if (fn) {
_beforeDoneHandler = fn;
}
else {
_beforeDoneHandler = _noop;
}
}
return {
begin: begin,
beforeDone: beforeDone
};
}());
CasperTest.Routines = (function () {
function register(test) {
casper.thenOpen(url + 'ghost/signup/').viewport(1280, 1024);
casper.waitForOpaque('.signup-box', function then() {
this.fill('#signup', newUser, true);
});
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
this.echo('It appears as though a user is already registered.');
}, function onTimeout() {
this.echo('It appears as though a user was not already registered.');
}, 2000);
}
function login(test) {
casper.thenOpen(url + 'ghost/signin/');
casper.waitForOpaque('.login-box', function then() {
this.fill("#login", user, true);
});
casper.waitForResource(/ghost\/$/);
}
function logout(test) {
casper.thenOpen(url + 'signout/');
// Wait for signin or signup
casper.waitForResource(/ghost\/sign/);
}
function deletePost(id) {
casper.thenOpen(url + 'ghost/');
casper.thenEvaluate(function (id) {
return __utils__.sendAJAX(Ghost.settings.apiRoot + '/posts/' + id, 'DELETE');
}, id);
}
function _createRunner(fn) {
fn.run = function run(test) {
var routine = this;
casper.then(function () {
routine.call(casper, test);
});
};
return fn;
}
return {
register: _createRunner(register),
login: _createRunner(login),
logout: _createRunner(logout),
deletePost: _createRunner(deletePost)
};
}());

View File

@ -1,16 +0,0 @@
/**
* Tests logging out and attempting to sign up
*/
/*globals casper, __utils__, url, testPost, falseUser, email */
casper.test.begin('Redirects page 1 request', 1, function suite(test) {
test.filename = '01_route_test_redirects_page_1.png';
casper.start(url + 'page/1/', function then(response) {
test.assertEqual(casper.getCurrentUrl().indexOf('page/'), -1, 'Should be redirected to "/".');
}).viewport(1280, 1024);
casper.run(function () {
test.done();
});
});

View File

@ -0,0 +1,10 @@
/**
* Tests logging out and attempting to sign up
*/
/*globals casper, __utils__, url, testPost, falseUser, email */
CasperTest.begin('Redirects page 1 request', 1, function suite(test) {
casper.thenOpen(url + 'page/1/', function then(response) {
test.assertEqual(casper.getCurrentUrl().indexOf('page/'), -1, 'Should be redirected to "/".');
});
}, true);

View File

@ -1,16 +1,10 @@
/**
* Tests if RSS exists and is working
*/
casper.test.begin('Ensure that RSS is available', 3, function suite(test) {
test.filename = 'rss_test.png';
casper.start(url + 'rss/', function (response) {
CasperTest.begin('Ensure that RSS is available', 3, function suite(test) {
casper.thenOpen(url + 'rss/', function (response) {
test.assertEqual(response.status, 200, 'Response status should be 200.');
test.assert(this.getPageContent().indexOf('<rss') >= 0, 'Feed should contain <rss');
test.assert(this.getPageContent().indexOf('</rss>') >= 0, 'Feed should contain </rss>');
});
casper.run(function () {
test.done();
});
});
}, true);

View File

@ -1,36 +1,32 @@
/*globals describe, before, beforeEach, afterEach, it */
var testUtils = require('./testUtils'),
should = require('should'),
_ = require('underscore'),
when = require('when'),
sequence = require('when/sequence'),
_ = require('underscore');
// Stuff we are testing
Models = require('../../server/models');
describe('Post API', function () {
describe('Post Model', function () {
var PostModel = Models.Post,
UserModel = Models.User,
userData = {
password: 'testpass1',
email: 'test@test1.com',
name: 'Mr Biscuits'
};
var user = testUtils.DataGenerator.forModel.users[0],
authCookie;
before(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
testUtils.clearData()
.then(function () {
done();
}, done);
});
beforeEach(function (done) {
this.timeout(5000);
testUtils.initData()
.then(function () {
return UserModel.add(userData);
return testUtils.insertDefaultFixtures();
})
.then(function () {
return testUtils.API.login(user.email, user.password);
})
.then(function (authResponse) {
authCookie = authResponse;
done();
}, done);
});
@ -41,330 +37,13 @@ describe('Post Model', function () {
}, done);
});
it('can browse', function (done) {
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.equal(1);
// should be in published_at, DESC order
// model and API differ here - need to fix
//results.models[0].attributes.published_at.should.be.above(results.models[1].attributes.published_at);
done();
}).then(null, done);
});
it('can read', function (done) {
var firstPost;
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPost = results.models[0];
return PostModel.read({slug: firstPost.attributes.slug});
}).then(function (found) {
should.exist(found);
found.attributes.title.should.equal(firstPost.attributes.title);
done();
}).then(null, done);
});
it('can findAll, returning author and user data', function (done) {
var firstPost;
PostModel.findAll({}).then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPost = results.models[0].toJSON();
firstPost.author.should.be.a('object');
firstPost.user.should.be.a('object');
firstPost.author.name.should.equal('Mr Biscuits');
firstPost.user.name.should.equal('Mr Biscuits');
done();
}, done);
});
it('can findOne, returning author and user data', function (done) {
var firstPost;
PostModel.findOne({}).then(function (result) {
it('can retrieve a post', function (done) {
testUtils.API.get(testUtils.API.ApiRouteBase + 'posts/?status=all', authCookie).then(function (result) {
should.exist(result);
firstPost = result.toJSON();
firstPost.author.should.be.a('object');
firstPost.user.should.be.a('object');
firstPost.author.name.should.equal('Mr Biscuits');
firstPost.user.name.should.equal('Mr Biscuits');
done();
}, done);
});
it('can edit', function (done) {
var firstPost;
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPost = results.models[0];
return PostModel.edit({id: firstPost.id, title: 'new title'});
}).then(function (edited) {
should.exist(edited);
edited.attributes.title.should.equal('new title');
done();
}).then(null, done);
});
it('can add, defaulting as a draft', function (done) {
var createdPostUpdatedDate,
newPost = {
title: 'Test Title 1',
markdown: 'Test Content 1'
};
PostModel.add(newPost).then(function (createdPost) {
return new PostModel({id: createdPost.id}).fetch();
}).then(function (createdPost) {
should.exist(createdPost);
createdPost.has('uuid').should.equal(true);
createdPost.get('status').should.equal('draft');
createdPost.get('title').should.equal(newPost.title, 'title is correct');
createdPost.get('markdown').should.equal(newPost.markdown, 'markdown is correct');
createdPost.has('html').should.equal(true);
createdPost.get('html').should.equal('<p>' + newPost.markdown + '</p>');
createdPost.get('slug').should.equal('test-title-1');
createdPost.get('created_at').should.be.above(new Date(0).getTime());
createdPost.get('created_by').should.equal(1);
createdPost.get('author_id').should.equal(1);
createdPost.get('created_by').should.equal(createdPost.get('author_id'));
createdPost.get('updated_at').should.be.above(new Date(0).getTime());
createdPost.get('updated_by').should.equal(1);
should.equal(createdPost.get('published_at'), null);
should.equal(createdPost.get('published_by'), null);
createdPostUpdatedDate = createdPost.get('updated_at');
// Set the status to published to check that `published_at` is set.
return createdPost.save({status: 'published'});
}).then(function (publishedPost) {
publishedPost.get('published_at').should.be.instanceOf(Date);
publishedPost.get('published_by').should.equal(1);
publishedPost.get('updated_at').should.be.instanceOf(Date);
publishedPost.get('updated_by').should.equal(1);
publishedPost.get('updated_at').should.not.equal(createdPostUpdatedDate);
done();
}).then(null, done);
});
it('can trim title', function (done) {
var untrimmedCreateTitle = ' test trimmed create title ',
untrimmedUpdateTitle = ' test trimmed update title ',
newPost = {
title: untrimmedCreateTitle,
markdown: 'Test Content'
};
PostModel.add(newPost).then(function (createdPost) {
return new PostModel({ id: createdPost.id }).fetch();
}).then(function (createdPost) {
should.exist(createdPost);
createdPost.get('title').should.equal(untrimmedCreateTitle.trim());
return createdPost.save({ title: untrimmedUpdateTitle });
}).then(function (updatedPost) {
updatedPost.get('title').should.equal(untrimmedUpdateTitle.trim());
should.exist(result.response);
result.response.posts.length.should.be.above(1);
done();
}).otherwise(done);
});
it('can generate a non conflicting slug', function (done) {
var newPost = {
title: 'Test Title',
markdown: 'Test Content 1'
};
this.timeout(5000); // this is a patch to ensure it doesn't timeout.
// Create 12 posts with the same title
sequence(_.times(12, function (i) {
return function () {
return PostModel.add({
title: 'Test Title',
markdown: 'Test Content ' + (i+1)
});
};
})).then(function (createdPosts) {
// Should have created 12 posts
createdPosts.length.should.equal(12);
// Should have unique slugs and contents
_(createdPosts).each(function (post, i) {
var num = i + 1;
// First one has normal title
if (num === 1) {
post.get('slug').should.equal('test-title');
return;
}
post.get('slug').should.equal('test-title-' + num);
post.get('markdown').should.equal('Test Content ' + num);
});
done();
}).otherwise(done);
});
it('can generate slugs without duplicate hyphens', function (done) {
var newPost = {
title: 'apprehensive titles have too many spaces ',
markdown: 'Test Content 1'
};
PostModel.add(newPost).then(function (createdPost) {
createdPost.get('slug').should.equal('apprehensive-titles-have-too-many-spaces');
done();
}).then(null, done);
});
it('detects duplicate slugs before saving', function (done) {
var firstPost = {
title: 'First post',
markdown: 'First content 1'
},
secondPost = {
title: 'Second post',
markdown: 'Second content 1'
};
// Create the first post
PostModel.add(firstPost)
.then(function (createdFirstPost) {
// Store the slug for later
firstPost.slug = createdFirstPost.get('slug');
// Create the second post
return PostModel.add(secondPost);
}).then(function (createdSecondPost) {
// Store the slug for comparison later
secondPost.slug = createdSecondPost.get('slug');
// Update with a conflicting slug from the first post
return createdSecondPost.save({
slug: firstPost.slug
});
}).then(function (updatedSecondPost) {
// Should have updated from original
updatedSecondPost.get('slug').should.not.equal(secondPost.slug);
// Should not have a conflicted slug from the first
updatedSecondPost.get('slug').should.not.equal(firstPost.slug);
return PostModel.read({
id: updatedSecondPost.id
});
}).then(function (foundPost) {
// Should have updated from original
foundPost.get('slug').should.not.equal(secondPost.slug);
// Should not have a conflicted slug from the first
foundPost.get('slug').should.not.equal(firstPost.slug);
done();
}).otherwise(done);
});
it('can delete', function (done) {
var firstPostId;
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPostId = results.models[0].id;
return PostModel.destroy(firstPostId);
}).then(function () {
return PostModel.browse();
}).then(function (newResults) {
var ids, hasDeletedId;
ids = _.pluck(newResults.models, 'id');
hasDeletedId = _.any(ids, function (id) {
return id === firstPostId;
});
hasDeletedId.should.equal(false);
done();
}).then(null, done);
});
it('can create a new Post with a previous published_at date', function (done) {
var previousPublishedAtDate = new Date(2013, 8, 21, 12);
PostModel.add({
status: 'published',
published_at: previousPublishedAtDate,
title: 'published_at test',
markdown: 'This is some content'
}).then(function (newPost) {
should.exist(newPost);
newPost.get('published_at').should.equal(previousPublishedAtDate);
done();
}).otherwise(done);
});
it('can fetch a paginated set, with various options', function (done) {
this.timeout(10000); // this is a patch to ensure it doesn't timeout.
testUtils.insertMorePosts().then(function () {
return PostModel.findPage({page: 2});
}).then(function (paginationResult) {
paginationResult.page.should.equal(2);
paginationResult.limit.should.equal(15);
paginationResult.posts.length.should.equal(15);
paginationResult.pages.should.equal(4);
return PostModel.findPage({page: 5});
}).then(function (paginationResult) {
paginationResult.page.should.equal(5);
paginationResult.limit.should.equal(15);
paginationResult.posts.length.should.equal(0);
paginationResult.pages.should.equal(4);
return PostModel.findPage({limit: 30});
}).then(function (paginationResult) {
paginationResult.page.should.equal(1);
paginationResult.limit.should.equal(30);
paginationResult.posts.length.should.equal(30);
paginationResult.pages.should.equal(2);
return PostModel.findPage({limit: 10, page: 2, where: {language: 'fr'}});
}).then(function (paginationResult) {
paginationResult.page.should.equal(2);
paginationResult.limit.should.equal(10);
paginationResult.posts.length.should.equal(10);
paginationResult.pages.should.equal(3);
return PostModel.findPage({limit: 10, page: 2, status: 'all'});
}).then(function (paginationResult) {
paginationResult.pages.should.equal(11);
done();
}).then(null, done);
});
});

File diff suppressed because one or more lines are too long

View File

@ -22,6 +22,7 @@ describe("Ghost API", function () {
});
beforeEach(function (done) {
this.timeout(5000);
sandbox = sinon.sandbox.create();
testUtils.initData().then(function () {

View File

@ -6,100 +6,6 @@ var testUtils = require('./testUtils'),
// Stuff we are testing
Models = require('../../server/models');
describe("Role Model", function () {
var RoleModel = Models.Role;
should.exist(RoleModel);
before(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
beforeEach(function (done) {
this.timeout(5000);
testUtils.initData().then(function () {
done();
}, done);
});
afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
it("can browse roles", function (done) {
RoleModel.browse().then(function (foundRoles) {
should.exist(foundRoles);
foundRoles.models.length.should.be.above(0);
done();
}).then(null, done);
});
it("can read roles", function (done) {
RoleModel.read({id: 1}).then(function (foundRole) {
should.exist(foundRole);
done();
}).then(null, done);
});
it("can edit roles", function (done) {
RoleModel.read({id: 1}).then(function (foundRole) {
should.exist(foundRole);
return foundRole.set({name: "updated"}).save();
}).then(function () {
return RoleModel.read({id: 1});
}).then(function (updatedRole) {
should.exist(updatedRole);
updatedRole.get("name").should.equal("updated");
done();
}).then(null, done);
});
it("can add roles", function (done) {
var newRole = {
name: "test1",
description: "test1 description"
};
RoleModel.add(newRole).then(function (createdRole) {
should.exist(createdRole);
createdRole.attributes.name.should.equal(newRole.name);
createdRole.attributes.description.should.equal(newRole.description);
done();
}).then(null, done);
});
it("can delete roles", function (done) {
RoleModel.read({id: 1}).then(function (foundRole) {
should.exist(foundRole);
return RoleModel['delete'](1);
}).then(function () {
return RoleModel.browse();
}).then(function (foundRoles) {
var hasRemovedId = foundRoles.any(function (role) {
return role.id === 1;
});
hasRemovedId.should.equal(false);
done();
}).then(null, done);
});
});
describe("Permission Model", function () {
var PermissionModel = Models.Permission;

View File

@ -0,0 +1,364 @@
/*globals describe, before, beforeEach, afterEach, it */
var testUtils = require('./testUtils'),
should = require('should'),
_ = require('underscore'),
when = require('when'),
sequence = require('when/sequence'),
// Stuff we are testing
Models = require('../../server/models');
describe('Post Model', function () {
var PostModel = Models.Post,
UserModel = Models.User;
before(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
beforeEach(function (done) {
this.timeout(5000);
testUtils.initData()
.then(function () {
return testUtils.insertDefaultFixtures();
})
.then(function () {
done();
}, done);
});
afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
it('can browse', function (done) {
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.be.above(1);
// should be in published_at, DESC order
// model and API differ here - need to fix
//results.models[0].attributes.published_at.should.be.above(results.models[1].attributes.published_at);
done();
}).then(null, done);
});
it('can read', function (done) {
var firstPost;
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPost = results.models[0];
return PostModel.read({slug: firstPost.attributes.slug});
}).then(function (found) {
should.exist(found);
found.attributes.title.should.equal(firstPost.attributes.title);
done();
}).then(null, done);
});
it('can findAll, returning author and user data', function (done) {
var firstPost;
PostModel.findAll({}).then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPost = results.models[0].toJSON();
firstPost.author.should.be.a('object');
firstPost.user.should.be.a('object');
firstPost.author.name.should.equal(DataGenerator.Content.users[0].name);
firstPost.user.name.should.equal(DataGenerator.Content.users[0].name);
done();
}, done);
});
it('can findOne, returning author and user data', function (done) {
this.timeout(5000);
var firstPost;
PostModel.findOne({}).then(function (result) {
should.exist(result);
firstPost = result.toJSON();
firstPost.author.should.be.a('object');
firstPost.user.should.be.a('object');
firstPost.author.name.should.equal(testUtils.DataGenerator.Content.users[0].name);
firstPost.user.name.should.equal(testUtils.DataGenerator.Content.users[0].name);
done();
}, done);
});
it('can edit', function (done) {
var firstPost;
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPost = results.models[0];
return PostModel.edit({id: firstPost.id, title: 'new title'});
}).then(function (edited) {
should.exist(edited);
edited.attributes.title.should.equal('new title');
done();
}).then(null, done);
});
it('can add, defaulting as a draft', function (done) {
var createdPostUpdatedDate,
newPost = testUtils.DataGenerator.forModel.posts[2],
newPostDB = testUtils.DataGenerator.Content.posts[2];
PostModel.add(newPost).then(function (createdPost) {
return new PostModel({id: createdPost.id}).fetch();
}).then(function (createdPost) {
should.exist(createdPost);
createdPost.has('uuid').should.equal(true);
createdPost.get('status').should.equal('draft');
createdPost.get('title').should.equal(newPost.title, 'title is correct');
createdPost.get('markdown').should.equal(newPost.markdown, 'markdown is correct');
createdPost.has('html').should.equal(true);
createdPost.get('html').should.equal(newPostDB.html);
createdPost.get('slug').should.equal(newPostDB.slug + '-2');
createdPost.get('created_at').should.be.above(new Date(0).getTime());
createdPost.get('created_by').should.equal(1);
createdPost.get('author_id').should.equal(1);
createdPost.get('created_by').should.equal(createdPost.get('author_id'));
createdPost.get('updated_at').should.be.above(new Date(0).getTime());
createdPost.get('updated_by').should.equal(1);
should.equal(createdPost.get('published_at'), null);
should.equal(createdPost.get('published_by'), null);
createdPostUpdatedDate = createdPost.get('updated_at');
// Set the status to published to check that `published_at` is set.
return createdPost.save({status: 'published'});
}).then(function (publishedPost) {
publishedPost.get('published_at').should.be.instanceOf(Date);
publishedPost.get('published_by').should.equal(1);
publishedPost.get('updated_at').should.be.instanceOf(Date);
publishedPost.get('updated_by').should.equal(1);
publishedPost.get('updated_at').should.not.equal(createdPostUpdatedDate);
done();
}).then(null, done);
});
it('can trim title', function (done) {
var untrimmedCreateTitle = ' test trimmed create title ',
untrimmedUpdateTitle = ' test trimmed update title ',
newPost = {
title: untrimmedCreateTitle,
markdown: 'Test Content'
};
PostModel.add(newPost).then(function (createdPost) {
return new PostModel({ id: createdPost.id }).fetch();
}).then(function (createdPost) {
should.exist(createdPost);
createdPost.get('title').should.equal(untrimmedCreateTitle.trim());
return createdPost.save({ title: untrimmedUpdateTitle });
}).then(function (updatedPost) {
updatedPost.get('title').should.equal(untrimmedUpdateTitle.trim());
done();
}).otherwise(done);
});
it('can generate a non conflicting slug', function (done) {
var newPost = {
title: 'Test Title',
markdown: 'Test Content 1'
};
this.timeout(5000); // this is a patch to ensure it doesn't timeout.
// Create 12 posts with the same title
sequence(_.times(12, function (i) {
return function () {
return PostModel.add({
title: 'Test Title',
markdown: 'Test Content ' + (i+1)
});
};
})).then(function (createdPosts) {
// Should have created 12 posts
createdPosts.length.should.equal(12);
// Should have unique slugs and contents
_(createdPosts).each(function (post, i) {
var num = i + 1;
// First one has normal title
if (num === 1) {
post.get('slug').should.equal('test-title');
return;
}
post.get('slug').should.equal('test-title-' + num);
post.get('markdown').should.equal('Test Content ' + num);
});
done();
}).otherwise(done);
});
it('can generate slugs without duplicate hyphens', function (done) {
var newPost = {
title: 'apprehensive titles have too many spaces ',
markdown: 'Test Content 1'
};
PostModel.add(newPost).then(function (createdPost) {
createdPost.get('slug').should.equal('apprehensive-titles-have-too-many-spaces');
done();
}).then(null, done);
});
it('detects duplicate slugs before saving', function (done) {
var firstPost = {
title: 'First post',
markdown: 'First content 1'
},
secondPost = {
title: 'Second post',
markdown: 'Second content 1'
};
// Create the first post
PostModel.add(firstPost)
.then(function (createdFirstPost) {
// Store the slug for later
firstPost.slug = createdFirstPost.get('slug');
// Create the second post
return PostModel.add(secondPost);
}).then(function (createdSecondPost) {
// Store the slug for comparison later
secondPost.slug = createdSecondPost.get('slug');
// Update with a conflicting slug from the first post
return createdSecondPost.save({
slug: firstPost.slug
});
}).then(function (updatedSecondPost) {
// Should have updated from original
updatedSecondPost.get('slug').should.not.equal(secondPost.slug);
// Should not have a conflicted slug from the first
updatedSecondPost.get('slug').should.not.equal(firstPost.slug);
return PostModel.read({
id: updatedSecondPost.id
});
}).then(function (foundPost) {
// Should have updated from original
foundPost.get('slug').should.not.equal(secondPost.slug);
// Should not have a conflicted slug from the first
foundPost.get('slug').should.not.equal(firstPost.slug);
done();
}).otherwise(done);
});
it('can delete', function (done) {
var firstPostId;
PostModel.browse().then(function (results) {
should.exist(results);
results.length.should.be.above(0);
firstPostId = results.models[0].id;
return PostModel.destroy(firstPostId);
}).then(function () {
return PostModel.browse();
}).then(function (newResults) {
var ids, hasDeletedId;
ids = _.pluck(newResults.models, 'id');
hasDeletedId = _.any(ids, function (id) {
return id === firstPostId;
});
hasDeletedId.should.equal(false);
done();
}).then(null, done);
});
it('can create a new Post with a previous published_at date', function (done) {
var previousPublishedAtDate = new Date(2013, 8, 21, 12);
PostModel.add({
status: 'published',
published_at: previousPublishedAtDate,
title: 'published_at test',
markdown: 'This is some content'
}).then(function (newPost) {
should.exist(newPost);
newPost.get('published_at').should.equal(previousPublishedAtDate);
done();
}).otherwise(done);
});
it('can fetch a paginated set, with various options', function (done) {
this.timeout(10000); // this is a patch to ensure it doesn't timeout.
testUtils.insertMorePosts().then(function () {
return PostModel.findPage({page: 2});
}).then(function (paginationResult) {
paginationResult.page.should.equal(2);
paginationResult.limit.should.equal(15);
paginationResult.posts.length.should.equal(15);
paginationResult.pages.should.equal(4);
return PostModel.findPage({page: 5});
}).then(function (paginationResult) {
paginationResult.page.should.equal(5);
paginationResult.limit.should.equal(15);
paginationResult.posts.length.should.equal(0);
paginationResult.pages.should.equal(4);
return PostModel.findPage({limit: 30});
}).then(function (paginationResult) {
paginationResult.page.should.equal(1);
paginationResult.limit.should.equal(30);
paginationResult.posts.length.should.equal(30);
paginationResult.pages.should.equal(2);
return PostModel.findPage({limit: 10, page: 2, where: {language: 'fr'}});
}).then(function (paginationResult) {
paginationResult.page.should.equal(2);
paginationResult.limit.should.equal(10);
paginationResult.posts.length.should.equal(10);
paginationResult.pages.should.equal(3);
return PostModel.findPage({limit: 10, page: 2, status: 'all'});
}).then(function (paginationResult) {
paginationResult.pages.should.equal(11);
done();
}).then(null, done);
});
});

View File

@ -0,0 +1,101 @@
/*globals describe, it, before, beforeEach, afterEach */
var testUtils = require('./testUtils'),
should = require('should'),
errors = require('../../server/errorHandling'),
// Stuff we are testing
Models = require('../../server/models');
describe("Role Model", function () {
var RoleModel = Models.Role;
should.exist(RoleModel);
before(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
beforeEach(function (done) {
this.timeout(5000);
testUtils.initData().then(function () {
done();
}, done);
});
afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
it("can browse roles", function (done) {
RoleModel.browse().then(function (foundRoles) {
should.exist(foundRoles);
foundRoles.models.length.should.be.above(0);
done();
}).then(null, done);
});
it("can read roles", function (done) {
RoleModel.read({id: 1}).then(function (foundRole) {
should.exist(foundRole);
done();
}).then(null, done);
});
it("can edit roles", function (done) {
RoleModel.read({id: 1}).then(function (foundRole) {
should.exist(foundRole);
return foundRole.set({name: "updated"}).save();
}).then(function () {
return RoleModel.read({id: 1});
}).then(function (updatedRole) {
should.exist(updatedRole);
updatedRole.get("name").should.equal("updated");
done();
}).then(null, done);
});
it("can add roles", function (done) {
var newRole = {
name: "test1",
description: "test1 description"
};
RoleModel.add(newRole).then(function (createdRole) {
should.exist(createdRole);
createdRole.attributes.name.should.equal(newRole.name);
createdRole.attributes.description.should.equal(newRole.description);
done();
}).then(null, done);
});
it("can delete roles", function (done) {
RoleModel.read({id: 1}).then(function (foundRole) {
should.exist(foundRole);
return RoleModel['delete'](1);
}).then(function () {
return RoleModel.browse();
}).then(function (foundRoles) {
var hasRemovedId = foundRoles.any(function (role) {
return role.id === 1;
});
hasRemovedId.should.equal(false);
done();
}).then(null, done);
});
});

View File

@ -36,8 +36,8 @@ describe('Tag Model', function () {
var PostModel = Models.Post;
it('can add a tag', function (done) {
var newPost = {title: 'Test Title 1', markdown: 'Test Content 1'},
newTag = {name: 'tag1'},
var newPost = testUtils.DataGenerator.forModel.posts[0],
newTag = testUtils.DataGenerator.forModel.tags[0],
createdPostID;
when.all([
@ -62,8 +62,8 @@ describe('Tag Model', function () {
// The majority of this test is ripped from above, which is obviously a Bad Thing.
// Would be nice to find a way to seed data with relations for cases like this,
// because there are more DB hits than needed
var newPost = {title: 'Test Title 1', markdown: 'Test Content 1'},
newTag = {name: 'tag1'},
var newPost = testUtils.DataGenerator.forModel.posts[0],
newTag = testUtils.DataGenerator.forModel.tags[0],
createdTagID,
createdPostID;
@ -96,13 +96,12 @@ describe('Tag Model', function () {
function seedTags(tagNames) {
var createOperations = [
PostModel.add({title: 'title', markdown: 'content'})
PostModel.add(testUtils.DataGenerator.forModel.posts[0])
];
var tagModels = tagNames.map(function (tagName) { return TagModel.add({name: tagName}); });
createOperations = createOperations.concat(tagModels);
return when.all(createOperations).then(function (models) {
var postModel = models[0],
attachOperations;
@ -209,7 +208,7 @@ describe('Tag Model', function () {
it('can add a tag to a post on creation', function (done) {
var newPost = {title: 'Test Title 1', markdown: 'Test Content 1', tags: [{name: 'test_tag_1'}]};
var newPost = _.extend(testUtils.DataGenerator.forModel.posts[0], {tags: [{name: 'test_tag_1'}]})
PostModel.add(newPost).then(function (createdPost) {
return PostModel.read({id: createdPost.id}, { withRelated: ['tags']});

View File

@ -33,11 +33,7 @@ describe('User Model', function run() {
});
it('can add first', function (done) {
var userData = {
name: 'test',
password: 'testpass1',
email: "test@test1.com"
};
var userData = testUtils.DataGenerator.forModel.users[0];
UserModel.add(userData).then(function (createdUser) {
should.exist(createdUser);
@ -64,11 +60,7 @@ describe('User Model', function run() {
});
it('can\'t add second', function (done) {
var userData = {
name: 'test',
password: 'testpass3',
email: "test3@test1.com"
};
var userData = testUtils.DataGenerator.forModel.users[1];
return UserModel.add(userData).then(done, function (failure) {
failure.message.should.eql('A user is already registered. Only one user for now!');

View File

@ -13,7 +13,7 @@ var testUtils = require('./testUtils'),
PermissionsProvider = Models.Permission,
PostProvider = Models.Post;
describe('permissions', function () {
describe('Permissions', function () {
before(function (done) {
testUtils.clearData()

File diff suppressed because one or more lines are too long

118
core/test/unit/utils/api.js Normal file
View File

@ -0,0 +1,118 @@
var _ = require('underscore'),
when = require('when'),
http = require('http'),
HttpMethods,
ApiRouteBase = '/api/v0.1/';
HttpMethods = {
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
DELETE: 'DELETE'
};
function createRequest(httpMethod, overrides) {
return _.defaults(overrides, {
'host': 'localhost',
'port': '2369',
'method': httpMethod
});
}
function post(route, data, authCookie) {
var jsonData = JSON.stringify(data),
options = createRequest(HttpMethods.POST, {
path: route,
headers: {
'Content-Type': 'application/json',
'Content-Length': jsonData.length
}
}),
req,
response = '',
deferred = when.defer();
if (authCookie) {
options.headers['Cookie'] = authCookie;
}
req = http.request(options, function (res) {
res.setEncoding('utf-8');
if (res.statusCode === 401) {
return deferred.resolver.reject(new Error('401 Unauthorized.'));
}
res.on('data', function (chunk) {
response += chunk;
});
res.on('end', function () {
deferred.resolver.resolve({
headers: res.headers,
response: JSON.parse(response)
});
});
}).on('error', deferred.resolver.reject);
req.write(jsonData);
req.end();
return deferred.promise;
}
function get(route, authCookie) {
var options = createRequest(HttpMethods.GET, {
path: route,
headers: {}
}),
response = '',
deferred = when.defer();
if (authCookie) {
options.headers['Cookie'] = authCookie;
}
http.get(options, function (res) {
res.setEncoding('utf-8');
if (res.statusCode === 401) {
return deferred.resolver.reject(new Error('401 Unauthorized.'));
}
res.on('data', function (chunk) {
response += chunk;
});
res.on('end', function () {
deferred.resolve({
headers: res.headers,
response: JSON.parse(response)
});
});
}).on('error', deferred.resolver.reject);
return deferred.promise;
}
function login(email, password) {
var data = {
email: email,
password: password
};
return post('/ghost/signin/', data).then(function (response) {
return response.headers['set-cookie'];
});
}
module.exports = {
HttpMethods: HttpMethods,
ApiRouteBase: ApiRouteBase,
createRequest: createRequest,
post: post,
get: get,
login: login
};