apostrophe-pages
Version:
Adds trees of pages to the Apostrophe content management system
653 lines (631 loc) • 18.9 kB
JavaScript
var assert = require('assert');
var mongo = require('mongodb');
var _ = require('underscore');
var apos = require('apostrophe')();
var db;
var pages;
var home;
var page;
var children;
var about;
var contact;
var req = apos.getTaskReq();
// TODO: test 'before' position for move(), test conflicting paths and slugs
describe('apostrophe-pages', function() {
describe('initialize resources', function() {
it('initialize mongodb', function(done) {
db = new mongo.Db(
'apostest',
new mongo.Server('127.0.0.1', 27017, {}),
// Sensible default of safe: true
// (soon to be the driver's default)
{ safe: true }
);
assert(!!db);
db.open(function(err) {
assert(!err);
return done();
});
});
it('initialize apostrophe', function(done) {
return apos.init({
db: db,
app: {
request: {},
locals: {},
get: function() {},
post: function() {}
}
}, function(err) {
assert(!err);
return done();
});
});
it('initialize apostrophe-pages', function(done) {
pages = require('../index.js')({
apos: apos,
ui: false
}, function(err) {
assert(!err);
assert(!!pages);
return done();
});
});
});
describe('remove test data', function() {
it('removed', function(done) {
apos.pages.remove({}, function(err) {
assert(!err);
done();
});
});
});
describe('insert test data', function() {
apos.pages = apos.pages;
it('inserted', function(done) {
apos.pages.insert(
[
{
_id: 'home',
path: 'home',
title: 'Home',
sortTitle: 'home',
level: 0,
rank: 0,
slug: '/',
areas: {
body: {
items: [
{
type: 'richText',
content: '<p>Body content</p>'
}
]
},
sidebar: {
items: [
{
type: 'richText',
content: '<p>Sidebar content</p>'
}
]
}
},
published: true
},
// Kids in scrambled order so sort() has work to do
{
_id: 'contact',
path: 'home/contact',
title: 'Contact',
sortTitle: 'contact',
level: 1,
rank: 2,
slug: '/contact',
areas: {
body: {
items: [
{
type: 'richText',
content: '<p>Body content</p>'
}
]
},
sidebar: {
items: [
{
type: 'richText',
content: '<p>Sidebar content</p>'
}
]
}
},
tags: [ 'red', 'green' ],
published: true
},
{
_id: 'about',
path: 'home/about',
title: 'About',
sortTitle: 'about',
level: 1,
rank: 0,
slug: '/about',
areas: {
body: {
items: [
{
type: 'richText',
content: '<p>Body content</p>'
}
]
},
sidebar: {
items: [
{
type: 'richText',
content: '<p>Sidebar content</p>'
}
]
}
},
tags: [ 'green', 'blue' ],
published: true
},
{
_id: 'location',
path: 'home/about/location',
title: 'Location',
sortTitle: 'location',
level: 2,
rank: 1,
slug: '/about/location',
areas: {
body: {
items: [
{
type: 'richText',
content: '<p>Body content</p>'
}
]
},
sidebar: {
items: [
{
type: 'richText',
content: '<p>Sidebar content</p>'
}
]
}
},
published: true
},
{
_id: 'people',
path: 'home/about/people',
title: 'People',
sortTitle: 'people',
level: 2,
rank: 0,
slug: '/about/people',
areas: {
body: {
items: [
{
type: 'richText',
content: '<p>Body content</p>'
}
]
},
sidebar: {
items: [
{
type: 'richText',
content: '<p>Sidebar content</p>'
}
]
}
},
tags: [ 'green' ],
published: true
},
{
_id: 'products',
path: 'home/products',
title: 'Products',
sortTitle: 'products',
level: 1,
rank: 1,
slug: '/products',
areas: {
body: {
items: [
{
type: 'richText',
content: '<p>Body content</p>'
}
]
},
sidebar: {
items: [
{
type: 'richText',
content: '<p>Sidebar content</p>'
}
]
}
},
published: true
}
], function(err) {
assert(!err);
done();
}
);
});
});
describe('fetch home page', function() {
it('fetched', function(done) {
apos.pages.findOne({ _id: 'home' }, function(err, doc) {
assert(!!doc);
home = doc;
page = doc;
done();
});
});
});
describe('fetch ancestors of home page (should be empty)', function() {
it('fetched', function(done) {
pages.getAncestors(req, page, function(err, ancestors) {
assert(ancestors.length === 0);
done();
});
});
});
describe('fetch descendants of home page', function() {
it('fetched', function(done) {
pages.getDescendants(req, page, { depth: 2 }, function(err, childrenArg) {
children = childrenArg;
assert(!err);
assert(children.length === 3);
done();
});
});
it('in order', function() {
assert(children[0]._id === 'about');
assert(children[1]._id === 'products');
assert(children[2]._id === 'contact');
});
it('did not return areas', function() {
assert(!children[0].areas);
assert(!children[1].areas);
assert(!children[2].areas);
});
it('have grandkids', function() {
assert(children[0].children.length === 2);
});
it('grandkids in order', function() {
assert(children[0].children[0]._id === 'people');
assert(children[0].children[1]._id === 'location');
});
it('fetch again with areas turned on', function(done) {
pages.getDescendants(req, page, { depth: 2, areas: true }, function(err, childrenArg) {
children = childrenArg;
assert(!err);
assert(children.length === 3);
done();
});
});
it('did return all areas', function() {
assert(_.keys(children[0].areas).length > 1);
assert(_.keys(children[1].areas).length > 1);
assert(_.keys(children[2].areas).length > 1);
});
it('fetch again with specific area', function(done) {
pages.getDescendants(req, page, { depth: 2, areas: [ 'body' ] }, function(err, childrenArg) {
children = childrenArg;
assert(!err);
assert(children.length === 3);
done();
});
});
it('returned only one area', function() {
assert(_.keys(children[0].areas).length === 1);
assert(_.keys(children[1].areas).length === 1);
assert(_.keys(children[2].areas).length === 1);
});
it('returned only one area', function() {
assert(_.keys(children[0].areas)[0] === 'body');
assert(_.keys(children[1].areas)[0] === 'body');
assert(_.keys(children[2].areas)[0] === 'body');
});
});
var ancestors;
describe('fetch ancestors of home/about/people', function() {
it('fetched', function(done) {
var people = children[0].children[0];
pages.getAncestors(req, people, function(err, ancestorsArg) {
assert(!err);
assert(ancestorsArg);
ancestors = ancestorsArg;
done();
});
});
it('correct count', function() {
assert(ancestors.length === 2);
});
it('correct paths in order', function() {
assert(ancestors[0]._id === 'home');
assert(ancestors[1]._id === 'about');
});
it('did not return areas', function() {
assert(!ancestors[0].areas);
assert(!ancestors[1].areas);
});
it('fetch again with areas turned on', function(done) {
var people = children[0].children[0];
pages.getAncestors(req, people, { areas: true }, function(err, ancestorsArg) {
assert(!err);
assert(ancestorsArg);
ancestors = ancestorsArg;
done();
});
});
it('did return all areas', function() {
assert(_.keys(ancestors[0].areas).length > 1);
assert(_.keys(ancestors[1].areas).length > 1);
});
it('fetch again with specific area', function(done) {
var people = children[0].children[0];
pages.getAncestors(req, people, { areas: [ 'body' ] }, function(err, ancestorsArg) {
assert(!err);
assert(ancestorsArg);
ancestors = ancestorsArg;
done();
});
});
it('returned only one area', function() {
assert(_.keys(ancestors[0].areas).length === 1);
assert(_.keys(ancestors[1].areas).length === 1);
});
it('returned only one area', function() {
assert(_.keys(ancestors[0].areas)[0] === 'body');
assert(_.keys(ancestors[1].areas)[0] === 'body');
});
});
describe('getParent returns home/about for home/about/people', function() {
it('returned', function(done) {
var people = children[0].children[0];
pages.getParent(req, people, function(err, parent) {
assert(!err);
assert(parent);
assert(parent._id === 'about');
about = parent;
return done();
});
});
});
describe('move home/about/people after home/contact', function() {
var people;
it('people exists', function(done) {
people = children[0].children[0];
assert(people._id === 'people');
done();
});
it('moved without error', function(done) {
pages.move(req, people, '/contact', 'after', function(err) {
if (err) {
console.log(err);
}
assert(!err);
return done();
});
});
it('home has 4 descendants', function(done) {
pages.getDescendants(req, home, { depth: 1 }, function(err, childrenArg) {
children = childrenArg;
assert(children.length === 4);
done();
});
});
it('people is now the final child of home', function(done) {
assert(children[3]._id === 'people');
return done();
});
it('slug of people is now /people', function(done) {
assert(children[3].slug === '/people');
return done();
});
});
describe('move home/people back under home/about as first child', function() {
var people;
it('people exists', function(done) {
people = children[3];
assert(people._id === 'people');
done();
});
it('moved without error', function(done) {
pages.move(req, people, '/about', 'inside', function(err) {
if (err) {
console.log(err);
}
assert(!err);
return done();
});
});
it('home/about has 2 descendants', function(done) {
pages.getDescendants(req, about, { depth: 1 }, function(err, childrenArg) {
children = childrenArg;
assert(children.length === 2);
done();
});
});
it('first child of home/about is now people', function(done) {
assert(children[0]._id === 'people');
return done();
});
it('people is at /about/people', function(done) {
assert(children[0].slug === '/about/people');
return done();
});
});
describe('move home/about under home/contact, by slug', function() {
var location;
it('moved without error', function(done) {
pages.move(req, '/about', '/contact', 'inside', function(err) {
if (err) {
console.log(err);
}
assert(!err);
return done();
});
});
it('got contact', function(done) {
apos.pages.findOne({ slug: '/contact' }, function(err, page) {
contact = page;
assert(page);
return done();
});
});
it('home/contact has 1 child', function(done) {
pages.getDescendants(req, contact, { depth: 2 }, function(err, childrenArg) {
children = childrenArg;
assert(children.length === 1);
done();
});
});
it('home/contact/about/location exists at the right path', function(done) {
apos.pages.findOne({ _id: 'location', path: 'home/contact/about/location' }, function(err, page) {
location = page;
assert(location);
return done();
});
});
it('home/contact/about/location has level 3', function(done) {
assert(location.level === 3);
return done();
});
it('home/contact/about/location has slug /contact/about/location', function(done) {
assert(location.slug === '/contact/about/location');
return done();
});
});
describe('fetch pages by tag', function() {
var fetched;
it('fetched without error', function(done) {
pages.getByTag(req, 'green', function(err, fetchedArg) {
if (err) {
console.log(err);
}
assert(!err);
fetched = fetchedArg.pages;
return done();
});
});
it('fetched three pages', function(done) {
assert(fetched.length === 3);
return done();
});
it('first one must be about due to title order', function(done) {
assert(fetched[0]._id === 'about');
return done();
});
it('filterByTag returns only contact for "red"', function(done) {
var filtered = pages.filterByTag(fetched, 'red');
assert(filtered.length === 1);
assert(filtered[0]._id === 'contact');
return done();
});
});
describe('add page', function() {
it('adds a new page beneath /contact called /contact/new-kid', function(done) {
var req = {
user: {
permissions: {
admin: true
}
},
body: {
parent: '/contact',
title: 'New Kid',
published: true,
tags: [ 'one', 'two' ],
type: 'default'
}
};
var res = {
send: function(data) {
assert((!res.statusCode) || (res.statusCode === 200));
var page = JSON.parse(data);
assert(typeof(page) === 'object');
assert(page.slug === '/contact/new-kid');
return apos.getPage(req, '/contact', function(err, page) {
assert(!err);
assert(page);
assert(page.slug === '/contact');
return pages.getDescendants(apos.getTaskReq(), page, { depth: 2 }, function(err, children) {
assert(children.length === 2);
assert(children[0].slug === '/contact/about');
assert(children[1].slug === '/contact/new-kid');
assert(children[1].path === 'home/contact/new-kid');
return done();
});
});
}
};
return pages._newRoute(req, res);
});
});
describe('edit page settings', function() {
it('propagates slug changes to children properly', function(done) {
var req = {
user: {
permissions: {
admin: true
}
},
body: {
originalSlug: '/contact/about',
slug: '/contact/about2',
title: 'About2',
published: true,
tags: [ 'one', 'two' ],
type: 'default'
}
};
var res = {
send: function(data) {
assert((!res.statusCode) || (res.statusCode === 200));
var page = JSON.parse(data);
assert(typeof(page) === 'object');
assert(page.slug === '/contact/about2');
return pages.getDescendants(apos.getTaskReq(), page, { depth: 2 }, function(err, childrenArg) {
children = childrenArg;
assert(!err);
assert(children.length === 2);
assert(children[0]._id === 'people');
assert(children[0].slug === '/contact/about2/people');
assert(children[1].slug === '/contact/about2/location');
return done();
});
}
};
return pages._editRoute(req, res);
});
it('retains children when avoiding a duplicate slug error', function(done) {
var req = {
user: {
permissions: {
admin: true
}
},
body: {
originalSlug: '/contact/about2',
slug: '/contact/new-kid',
title: 'About2',
published: true,
tags: [ 'one', 'two' ],
type: 'default'
}
};
var res = {
send: function(data) {
assert((!res.statusCode) || (res.statusCode === 200));
var page = JSON.parse(data);
assert(typeof(page) === 'object');
assert(page.slug.match(/^\/contact\/new\-kid\d$/));
var baseSlug = page.slug;
return pages.getDescendants(apos.getTaskReq(), page, { depth: 2 }, function(err, childrenArg) {
children = childrenArg;
assert(!err);
assert(children.length === 2);
assert(children[0]._id === 'people');
assert(children[0].slug === baseSlug + '/people');
assert(children[1].slug === baseSlug + '/location');
return done();
});
}
};
return pages._editRoute(req, res);
}); });
});