apostrophe
Version:
Apostrophe is a user-friendly content management system. You'll need more than this core module. See apostrophenow.org to get started.
554 lines (528 loc) • 21.6 kB
JavaScript
/* global it, describe */
var assert = require('assert');
var mongo = require('mongodb');
var _ = require('lodash');
var async = require('async');
var apos = require('../lib/apostrophe.js')();
var db;
function find(a, b) {
for (var i in a) {
if (b(a[i])) {
return a[i];
}
}
}
function req(d) {
var o = {
traceIn: function() {},
traceOut: function() {}
};
_.extend(o, d);
return o;
}
describe('apostrophe', function() {
describe('initialize resources', function() {
it('initialize mongodb', function(done) {
mongo.connect('mongodb://127.0.0.1:27017/apostest', function(err, _db) {
assert(!err);
assert(_db);
db = _db;
// Reset the database for another go
db.dropDatabase(function(err) {
assert(!err);
return done();
});
});
});
it('initialize apostrophe', function(done) {
return apos.init({
db: db,
app: {
request: {},
locals: {},
get: function() {},
post: function() {},
all: function() {}
}
}, function(err) {
assert(!err);
return done();
});
});
});
var start;
describe('test apos.build', function() {
it('returns a URL unmodified', function(done) {
start = (new Date()).getTime();
assert(apos.build('/events') === '/events');
return done();
});
it('returns the URL "#" unmodified', function(done) {
try {
assert(apos.build('#') === '#');
} catch (e) {
console.error(e.stack);
}
return done();
});
it('adds a single parameter to a queryless URL', function(done) {
assert(apos.build('/events', { tag: 'blue' }) === '/events?tag=blue');
return done();
});
it('appends a parameter to a URL with a query', function(done) {
// TODO this test is currently rather "this week's v8" specific, probably, in that the
// order of the parameters is not guaranteed; other orderings would be acceptable too
assert(apos.build('/events?page=5', { tag: 'blue' }) === '/events?tag=blue&page=5');
return done();
});
it('replaces parameters in the URL', function(done) {
assert(apos.build('/events?tag=blue', { tag: 'red' }) === '/events?tag=red');
return done();
});
it('removes parameters', function(done) {
assert(apos.build('/events?tag=blue', { tag: null }) === '/events');
return done();
});
it('correctly allows the last data object to win', function(done) {
assert(apos.build('/events', { tag: 'red' }, { tag: 'blue' }) === '/events?tag=blue');
return done();
});
it('places path properties in the path', function(done) {
assert(apos.build('/events', [ 'year', 'month' ], { year: '2013', month: '05', tag: 'red' }) === '/events/2013/05?tag=red');
return done();
});
it('switches to placing path properties in the query if it encounters a non-slugify-compliant property', function(done) {
assert(apos.build('/events', [ 'year', 'month' ], { year: '2013!@#@', month: '05', tag: 'red' }) === '/events?year=2013!%40%23%40&month=05&tag=red');
return done();
});
it('does the right thing for a case that crashed once', function(done) {
assert(apos.build("/events", ["year","month"], {}, {}) === '/events');
return done();
});
it('correctly allows the last data object to win for a path property', function(done) {
assert(apos.build("/events", ["year", "month"], { year: '2013', month: '01', tag: 'dance' }, { year: 2012, month: '12' }) === '/events/2012/12?tag=dance');
return done();
});
it('DR use case #1', function(done) {
assert(apos.build('/events',
[ 'year', 'month' ],
{ year: '2013', month: '05', tag: 'dance' },
{ tag: 'tour' }) === '/events/2013/05?tag=tour');
return done();
});
it('DR use case #2', function(done) {
var result = apos.build('/events',
[ 'year', 'month' ],
{ year: '2013', month: '05', tag: 'dance' },
{ page: '2' });
assert(result === '/events/2013/05?page=2&tag=dance');
return done();
});
it('DR use case #3', function(done) {
var result = apos.build('/events',
[ 'year', 'month' ],
{ year: '2013', month: '05', tag: 'dance' },
{});
assert(result === '/events/2013/05?tag=dance');
return done();
});
it('IH use case #1: later objects can prevent path properties from being added', function(done) {
var result = apos.build('/calendar',
[ 'year', 'month' ],
{ year: '2014', month: '01', tag: undefined },
{ year: null, month: null });
assert(result === '/calendar');
return done();
});
it('Preserves hashes', function(done) {
var result = apos.build('/calendar#skipdown',
[ 'year', 'month' ],
{ year: '2014', month: '01', tag: 'blue' }
);
assert(result === '/calendar/2014/01?tag=blue#skipdown');
return done();
});
it('Takes less than 250 msec to run these tests', function(done) {
var end = (new Date()).getTime();
// console.log(end - start);
assert((end - start) < 250);
return done();
});
});
describe('test escapeHtml', function() {
it('is defined', function() {
assert(apos.escapeHtml);
});
it('does not alter a string requiring no escaping', function() {
assert(apos.escapeHtml('this is fun') === 'this is fun');
});
it('escapes a string requiring escaping', function() {
assert(apos.escapeHtml('<p>hmm</p>', '<p>hmm</p>'));
});
it('escapes & properly too', function() {
assert(apos.escapeHtml('&', '&'));
});
var pretty = 'This is fun.\nhttp://google.com/\nHow about now?';
it('leaves newlines and URLs alone when pretty is off', function() {
assert(apos.escapeHtml(pretty) === pretty);
});
it('turns newlines into br and URLs into links when pretty is on', function() {
assert(apos.escapeHtml(pretty, true) === 'This is fun.<br /><a href="http://google.com/">http://google.com/</a><br />How about now?');
});
});
describe('test pruneTemporaryProperties', function() {
it('is defined', function() {
assert(apos.pruneTemporaryProperties);
});
it('prunes correctly', function() {
var o = {
a: 1,
b: 1,
c: {
d: 1,
e: 2,
f: 3
},
d: [
{
a: 5,
b: 7,
c: 'whee',
d: {
a: 'boo'
}
},
57
]
};
var correct = JSON.stringify(o);
o._e = 'should get pruned';
o.d[0].d._f = 'should get pruned too';
apos.pruneTemporaryProperties(o);
assert(JSON.stringify(o) === correct);
});
});
describe('test slugify', function() {
it('is defined', function() {
assert(apos.slugify);
});
it('behaves reasonably for ascii', function() {
assert.equal(apos.slugify('I love manicotti, cheese!!! and sushi '), 'i-love-manicotti-cheese-and-sushi');
});
it('behaves reasonably for non-ascii', function() {
assert.equal(apos.slugify('I love manicottiณณณ, cheese!!! and sushi '), 'i-love-manicottiณณณ-cheese-and-sushi');
});
});
describe('test permissions.can', function() {
it('apos.permissions is defined', function() {
assert(apos.permissions);
});
it('allows view-page in the generic case', function() {
assert(apos.permissions.can(req(), 'view-page'));
});
it('rejects edit-page in the generic case', function() {
assert(!apos.permissions.can(req(), 'edit-page'));
});
it('forbids view-page for public with loginRequired', function() {
assert(!apos.permissions.can(req(), 'view-page', { published: true, loginRequired: 'loginRequired' }));
});
it('permits view-page for public without loginRequired', function() {
assert(apos.permissions.can(req(), 'view-page', { published: true }));
});
it('prohibits view-page for public without published', function() {
assert(!apos.permissions.can(req(), 'view-page', {}));
});
it('prohibits view-page for public with loginRequired', function() {
assert(!apos.permissions.can(req(), 'view-page', { published: true, loginRequired: 'loginRequired' }));
});
it('permits view-page for guest user with loginRequired', function() {
assert(apos.permissions.can(req({ user: { permissions: { guest: 1 } } }), 'view-page', { published: true, loginRequired: 'loginRequired' }));
});
it('permits view-page for individual with proper id', function() {
assert(apos.permissions.can(req({ user: { _id: 1 } }), 'view-page', { published: true, loginRequired: 'certainPeople', pagePermissions: [ 'view-1' ] }));
});
it('forbids view-page for individual with wrong id', function() {
assert(!apos.permissions.can(req({ user: { _id: 2 } }), 'view-page', { published: true, loginRequired: 'certainPeople', pagePermissions: [ 'view-1' ] }));
});
it('permits view-page for individual with group id', function() {
assert(apos.permissions.can(req({ user: { _id: 1, groupIds: [ 1001, 1002 ] } }), 'view-page', { published: true, loginRequired: 'certainPeople', pagePermissions: [ 'view-1002' ] }));
});
it('forbids view-page for individual with wrong group id', function() {
assert(!apos.permissions.can(req({ user: { _id: 2, groupIds: [ 1001, 1002 ] } }), 'view-page', { published: true, loginRequired: 'certainPeople', pagePermissions: [ 'view-1003' ] }));
});
it('certainPeople will not let you slide past to an unpublished page', function() {
assert(!apos.permissions.can(req({ user: { _id: 1 } }), 'view-page', { loginRequired: 'certainPeople', pagePermissions: [ 'view-1' ] }));
});
it('permits view-page for unpublished page for individual with group id for editing', function() {
assert(apos.permissions.can(req({ user: { _id: 1, groupIds: [ 1001, 1002 ] } }), 'view-page', { pagePermissions: [ 'edit-1002' ] }));
});
it('permits edit-page for individual with group id for editing and the edit permission', function() {
assert(apos.permissions.can(req({ user: { _id: 1, groupIds: [ 1001, 1002 ], permissions: { edit: true } } }), 'edit-page', { pagePermissions: [ 'edit-1002' ] }));
});
it('forbids edit-page for individual with group id for editing but no edit permission', function() {
assert(!apos.permissions.can(req({ user: { _id: 1, groupIds: [ 1001, 1002 ] } }), 'edit-page', { pagePermissions: [ 'edit-1002' ] }));
});
it('permits edit-page for individual with group id for managing and edit permission', function() {
assert(apos.permissions.can(req({ user: { _id: 1, groupIds: [ 1001, 1002 ], permissions: { edit: true } } }), 'edit-page', { pagePermissions: [ 'publish-1002' ] }));
});
it('forbids edit-page for other person', function() {
assert(!apos.permissions.can(req({ user: { _id: 7 } }), 'edit-page', { pagePermissions: [ 'publish-1002' ] }));
});
});
describe('test permissions.criteria', function() {
it('successfully inserted test data', function(done) {
return apos.pages.insert([
{
_id: 'page-1',
slug: 'page-1',
published: true
},
{
_id: 'page-2',
slug: 'page-2',
},
{
_id: 'page-3',
slug: 'page-3',
published: true,
loginRequired: 'loginRequired'
},
{
_id: 'page-4',
slug: 'page-4',
published: true,
loginRequired: 'certainPeople',
pagePermissions: [ 'view-1' ]
},
{
_id: 'page-5',
slug: 'page-5',
loginRequired: 'certainPeople',
pagePermissions: [ 'view-1' ]
},
{
_id: 'page-6',
slug: 'page-6',
published: true,
loginRequired: 'certainPeople',
pagePermissions: [ 'view-1002' ]
},
{
_id: 'page-7',
slug: 'page-7',
pagePermissions: [ 'edit-1002' ]
},
{
_id: 'page-8',
slug: 'page-8',
pagePermissions: [ 'publish-1002' ]
}
], function(err, count) {
assert(!err);
done();
});
});
var err;
var results;
it('public user queries without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({}), 'view-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('forbids view-page for public with loginRequired', function() {
assert(!find(results, function(result) {
return !!result.loginRequired;
}));
});
it('allows public view-page without loginRequired', function() {
assert(find(results, function(result) {
return !result.loginRequired;
}));
});
it('prohibits view-page for public without published', function() {
assert(!find(results, function(result) {
return !result.published;
}));
});
it('guest user queries without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({ user: { permissions: { guest: 1 } } }), 'view-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('permits view-page for guest user with loginRequired', function() {
assert(find(results, function(result) {
return result.loginRequired === 'loginRequired';
}));
});
it('id 1 user queries without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({ user: { _id: 1 } }), 'view-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('permits view-page for individual with proper id', function() {
assert(find(results, function(result) {
return (result.loginRequired === 'certainPeople') && result.pagePermissions && (result.pagePermissions.length === 1) && (result.pagePermissions[0] === 'view-1');
}));
});
it('certainPeople will not let you slide past to an unpublished page', function() {
assert(!find(results, function(result) {
return (result.loginRequired === 'certainPeople') && (result.pagePermissions.length === 1) && (result.pagePermissions[0] === 'view-1') && (!result.published);
}));
});
it('id 2 user queries without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({ user: { _id: 2 } }), 'view-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('forbids view-page for individual with wrong id', function() {
assert(!find(results, function(result) {
return (result.loginRequired === 'certainPeople') && result.pagePermissions && (result.pagePermissions.length === 1) && (result.pagePermissions[0] === 'view-1');
}));
});
it('group 1002 user queries without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({ user: { _id: 3, groupIds: [ 1002 ] } }), 'view-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('permits view-page for individual with proper group id', function() {
assert(find(results, function(result) {
return (result.loginRequired === 'certainPeople') && result.pagePermissions && (find(result.pagePermissions, function(p) { return p === 'view-1002'; }));
}));
});
it('permits view-page for unpublished page for individual with group id for editing', function() {
assert(find(results, function(result) {
return (result.loginRequired !== 'certainPeople') && result.pagePermissions && (find(result.pagePermissions, function(p) { return p === 'edit-1002'; }));
}));
});
it('group 1003 user queries without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({ user: { _id: 3, groupIds: [ 1003 ] } }), 'view-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('forbids view-page for individual with wrong group id', function() {
assert(!find(results, function(result) {
return (result.loginRequired === 'certainPeople') && result.pagePermissions && (find(result.pagePermissions, function(p) { return p === 'view-1002'; }));
}));
});
it('group 1002 user queries for editing without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({ user: { _id: 3, groupIds: [ 1002 ], permissions: { edit: true } } }), 'edit-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('permits edit-page for individual with group id for editing', function() {
assert(find(results, function(result) {
return (result.pagePermissions && find(result.pagePermissions, function(p) { return p === 'edit-1002'; }));
}));
});
it('permits edit-page for individual with group id for editing', function() {
assert(find(results, function(result) {
return (result.pagePermissions && find(result.pagePermissions, function(p) { return p === 'edit-1002'; }));
}));
});
it('permits edit-page for individual with group id for managing', function() {
assert(find(results, function(result) {
return (result.pagePermissions && find(result.pagePermissions, function(p) { return p === 'publish-1002'; }));
}));
});
it('other user queries for editing without error', function(done) {
return apos.pages.find(apos.permissions.criteria(req({ user: { _id: 7 } }), 'edit-page')).toArray(function(_err, _results) {
err = _err;
assert(!err);
results = _results;
assert(Array.isArray(results));
done();
});
});
it('forbids edit-page for other person', function() {
assert(!results.length);
});
it('appropriate user can add area to page-1 with putArea without error', function(done) {
return apos.putArea(req({ user: { permissions: { admin: 1 } } }), 'page-1:test', { type: 'area', items: [ { type: 'richText', content: '<h4>Whee</h4>' } ] }, function(err) {
assert(!err);
done();
});
});
it('the area actually gets there', function(done) {
return apos.getPage(req({ user: { permissions: { admin: 1 } } }), 'page-1', function(err, page) {
assert(!err);
assert(page);
assert(page.test);
assert(page.test.items[0]);
assert(page.test.items[0].content === '<h4>Whee</h4>');
done();
});
});
it('inappropriate user cannot add area to page-1 with putArea', function(done) {
return apos.putArea(req({ user: { permissions: { guest: 1 } } }), 'page-1:test', { type: 'area', items: [ { type: 'richText', content: '<h4>Whee</h4>' } ] }, function(err) {
assert(err);
done();
});
});
it('appropriate user can make new page with putArea without error', function(done) {
return apos.putArea(req({ user: { permissions: { admin: 1 } } }), 'global:test', { type: 'area', items: [ { type: 'richText', content: '<h4>Whee</h4>' } ] }, function(err) {
assert(!err);
done();
});
});
it('an area on a new page actually gets there', function(done) {
return apos.getPage(req({ user: { permissions: { admin: 1 } } }), 'global', function(err, page) {
assert(!err);
assert(page);
assert(page.test);
assert(page.test.items[0]);
assert(page.test.items[0].content === '<h4>Whee</h4>');
done();
});
});
it('can add a second area to that new page', function(done) {
return apos.putArea(req({ user: { permissions: { admin: 1 } } }), 'global:test2', { type: 'area', items: [ { type: 'richText', content: '<h4>Whee</h4>' } ] }, function(err) {
assert(!err);
done();
});
});
it('second area does not blow out the first', function(done) {
return apos.getPage(req({ user: { permissions: { admin: 1 } } }), 'global', function(err, page) {
assert(!err);
assert(page);
assert(page.test);
assert(page.test.items[0]);
assert(page.test.items[0].content === '<h4>Whee</h4>');
done();
});
});
it('even an admin cannot make a new page with putArea if the slug starts with /', function(done) {
return apos.putArea(req({ user: { permissions: { admin: 1 } } }), '/:test', { type: 'area', items: [ { type: 'richText', content: '<h4>Whee</h4>' } ] }, function(err) {
assert(err);
done();
});
});
});
});