0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-13 06:32:39 +00:00

Getting both renderers to play nice

This commit is contained in:
Scott Tolksdorf
2017-02-12 23:35:19 -05:00
parent b40e5bc4c4
commit 304cd0ffcd
22 changed files with 136 additions and 82 deletions

90
tests/admin.test.js Normal file
View File

@@ -0,0 +1,90 @@
const testing = require('./test.init.js');
const request = require('supertest-as-promised');
const config = require('nconf');
const app = require('app.js');
const DB = require('db.js');
const BrewData = require('brew.data.js');
const Error = require('error.js');
let brewA = {
title : 'good title',
text : 'original text',
authors : ['your_dm']
};
describe('Admin API', ()=>{
before('Connect DB', DB.connect);
describe('Brew Lookup', ()=>{
before('Clear DB', BrewData.removeAll);
before('Create brew', ()=>{
return BrewData.create(brewA)
.then((brew)=>{ brewA = brew; });
});
it('throws an error if not admin', ()=>{
return request(app)
.get(`/admin/lookup/${brewA.editId}`)
.expect(401);
});
it('looks up a brew based on the share id', () => {
return request(app)
.get(`/admin/lookup/${brewA.shareId}`)
.set('x-homebrew-admin', config.get('admin:key'))
.expect(200)
.then((res) => {
const brew = res.body;
brew.should.have.property('editId').equal(brewA.editId);
brew.should.have.property('shareId').equal(brewA.shareId);
brew.should.have.property('text').equal(brewA.text);
});
});
it('looks up a brew based on the edit id', () => {
return request(app)
.get(`/admin/lookup/${brewA.editId}`)
.set('x-homebrew-admin', config.get('admin:key'))
.expect(200)
.then((res) => {
const brew = res.body;
brew.should.have.property('editId').equal(brewA.editId);
brew.should.have.property('shareId').equal(brewA.shareId);
brew.should.have.property('text').equal(brewA.text);
});
});
it('looks up a brew based on a partial id', () => {
const query = brewA.editId.substring(0, brewA.editId.length -2);
return request(app)
.get(`/admin/lookup/${query}`)
.set('x-homebrew-admin', config.get('admin:key'))
.expect(200)
.then((res) => {
const brew = res.body;
brew.should.have.property('editId').equal(brewA.editId);
brew.should.have.property('shareId').equal(brewA.shareId);
brew.should.have.property('text').equal(brewA.text);
});
});
it('throws an error if it can not find a brew', ()=>{
return request(app)
.get(`/admin/lookup/BADID`)
.set('x-homebrew-admin', config.get('admin:key'))
.expect(404);
});
});
describe('Invalid Brew', ()=>{
before('Clear DB', BrewData.removeAll);
before('Create brew', ()=>{
return BrewData.create(brewA)
.then((brew)=>{ brewA = brew; });
});
});
});

248
tests/api.test.js Normal file
View File

@@ -0,0 +1,248 @@
const Test = require('./test.init.js');
const _ = require('lodash');
const request = require('supertest-as-promised');
const config = require('nconf');
const app = require('app.js');
const DB = require('db.js');
const BrewData = require('brew.data.js');
const BrewGen = require('./brew.gen.js');
const Error = require('error.js');
const UserX = { username : 'userX' };
const UserA = { username : 'userA' };
let UserXToken, UserAToken;
describe('Brew API', () => {
before('Create session token', () => {
UserXToken = Test.getSessionToken(UserX);
UserAToken = Test.getSessionToken(UserA);
});
describe('CRUD', ()=>{
before('Connect DB', DB.connect);
before('Clear DB', BrewData.removeAll);
before('Populate brews', ()=>{
return BrewGen.populateDB(BrewGen.static());
});
describe('Create', () => {
it('creates a new brew', () => {
return request(app)
.post(`/api/brew`)
.send({ text : 'Brew Text' })
.expect(200)
.then((res) => {
const brew = res.body;
brew.should.have.property('editId').that.is.a('string');
brew.should.have.property('shareId').that.is.a('string');
brew.should.have.property('text').equal('Brew Text');
brew.should.not.have.property('_id');
});
});
it('creates a new brew with a session author', () => {
return request(app)
.post(`/api/brew`)
.set('Cookie', `nc_session=${UserXToken}`)
.send({ text : 'Brew Text' })
.expect(200)
.then((res) => {
const brew = res.body;
brew.should.have.property('authors').include(UserX.username);
});
});
});
describe('Update', () => {
it('updates an existing brew', () => {
const storedBrew = BrewGen.get('BrewA');
return request(app)
.put(`/api/brew/${storedBrew.editId}`)
.send({ text : 'New Text' })
.expect(200)
.then((res) => {
const brew = res.body;
brew.should.have.property('editId').equal(storedBrew.editId);
brew.should.have.property('text').equal('New Text');
brew.should.have.property('authors').include(storedBrew.authors[0]);
brew.should.not.have.property('_id');
});
});
it('adds the user as author', () => {
const storedBrew = BrewGen.get('BrewA');
return request(app)
.put(`/api/brew/${storedBrew.editId}`)
.set('Cookie', `nc_session=${UserXToken}`)
.send({ text : 'New Text' })
.expect(200)
.then((res) => {
const brew = res.body;
brew.should.have.property('authors').include(UserX.username);
brew.should.have.property('authors').include(storedBrew.authors[0]);
});
});
it('should throw error on bad edit id', ()=>{
const storedBrew = BrewGen.get('BrewA');
return request(app)
.put(`/api/brew/BADEDITID`)
.send({ text : 'New Text' })
.expect(404)
});
});
describe('Remove', () => {
it('should removes a brew', ()=>{
const storedBrew = BrewGen.get('BrewA');
return request(app)
.del(`/api/brew/${storedBrew.editId}`)
.send()
.expect(200)
.then(() => {
BrewData.getByEdit(storedBrew.editId)
.then(() => { throw 'Brew found when one should not have been'; })
.catch((err) => {
err.should.be.instanceof(Error.noBrew);
})
});
});
});
})
describe('Search', () => {
before('Connect DB', DB.connect);
before('Clear DB', BrewData.removeAll);
before('Populate brews', ()=>{
return BrewGen.populateDB(BrewGen.static());
});
it('should be able to search for all published brews', ()=>{
return request(app)
.get(`/api/brew`)
.query({})
.send()
.expect(200)
.then((res) => {
const result = res.body;
result.total.should.be.equal(2);
result.brews.should.have.brews('BrewB','BrewD');
result.brews[0].should.not.have.property('editId');
});
});
it('should be able to search for brews with given terms', ()=>{
return request(app)
.get(`/api/brew`)
.query({
terms : '5e ranger'
})
.send()
.expect(200)
.then((res) => {
const result = res.body;
result.total.should.be.equal(1);
result.brews.should.have.brews('BrewD');
});
});
it('should be able to sort the search', ()=>{
return request(app)
.get(`/api/brew`)
.query({
sort : { views : 1}
})
.send()
.expect(200)
.then((res) => {
const result = res.body;
result.total.should.be.equal(2);
result.brews[0].should.be.brew('BrewD');
result.brews[1].should.be.brew('BrewB');
});
});
it('should use pagniation on the search', ()=>{
return request(app)
.get(`/api/brew`)
.query({
limit : 1,
page : 1,
sort : { views : -1}
})
.send()
.expect(200)
.then((res) => {
const result = res.body;
result.total.should.be.equal(2);
result.brews[0].should.be.brew('BrewD');
})
});
it('should return all brews and editIds if admin', ()=>{
return request(app)
.get(`/api/brew`)
.query({})
.set('x-homebrew-admin', config.get('admin:key'))
.send()
.expect(200)
.then((res) => {
const result = res.body;
const brewCount = _.size(BrewGen.static());
result.total.should.be.equal(brewCount);
result.brews.length.should.be.equal(brewCount);
result.brews[0].should.have.property('editId');
});
});
});
describe('User', () => {
before('Connect DB', DB.connect);
before('Clear DB', BrewData.removeAll);
before('Populate brews', ()=>{
return BrewGen.populateDB(BrewGen.static());
});
it('should be able to query brews for a specific user', ()=>{
return request(app)
.get(`/api/user/userA`)
.send()
.expect(200)
.then((res) => {
const result = res.body;
result.total.should.be.equal(1);
result.brews.length.should.be.equal(1);
result.brews.should.have.brews('BrewB');
result.brews[0].should.not.have.property('editId');
});
});
it('should have full access if loggedin user is queried user', ()=>{
return request(app)
.get(`/api/user/userA`)
.set('Cookie', `nc_session=${UserAToken}`)
.send()
.expect(200)
.then((res) => {
const result = res.body;
result.total.should.be.equal(3);
result.brews.length.should.be.equal(3);
result.brews.should.have.brews('BrewA', 'BrewB', 'BrewC');
result.brews[0].should.have.property('editId');
});
});
it('should have full access if admin', ()=>{
return request(app)
.get(`/api/user/userA`)
.set('x-homebrew-admin', config.get('admin:key'))
.send()
.expect(200)
.then((res) => {
const result = res.body;
result.total.should.be.equal(3);
result.brews.length.should.be.equal(3);
result.brews.should.have.brews('BrewA', 'BrewB', 'BrewC');
result.brews[0].should.have.property('editId');
});
});
});
});

125
tests/brew.gen.js Normal file
View File

@@ -0,0 +1,125 @@
const _ = require('lodash');
const BrewData = require('../server/brew.data.js');
let PopulatedBrews = {};
module.exports = {
//TODO: Add in a generator for old brews to test the old rendering code
random : (num = 20)=>{
return _.times(num, ()=>{
//TODO: Build better generator, use new snippets?
return {
title : 'BrewA',
description : '',
text : '',
authors : _.sampleSize(['userA','userB','userC','userD'], _.random(0, 3)),
systems : _.sampleSize(['5e', '4e', '3.5e', 'Pathfinder'], _.random(0,2)),
views : _.random(0,1000),
published : !!_.random(0,1)
};
});
},
old : () => {
return [
{
title : 'OLD - div test',
description : '',
authors : ['old'],
text : `<div class='wide' style='text-align:center'> neato </div>`,
systems : [],
views : 0,
published : true,
version : 1
}
]
},
static : () => {
return {
BrewA : {
title : 'Brew-Alpha',
description : 'fancy',
authors : ['userA'],
systems : [],
views : 12,
published : false
},
BrewB : {
title : 'Brew-Beta',
description : 'very fancy',
authors : ['userA'],
systems : [],
views : 7,
published : true
},
BrewC : {
title : 'Brew-Charlie',
description : 'test',
authors : ['userA', 'userB'],
systems : [],
views : 0,
published : false
},
BrewD : {
title : 'Brew-Delta',
description : 'test super amazing brew for 5e. Geared for Rangers.',
authors : ['userC'],
systems : [],
views : 1,
published : true
}
};
},
populateDB : (brewCollection)=>{
PopulatedBrews = {};
return Promise.all(_.map(brewCollection, (brewData, id) => {
return BrewData.create(brewData)
.then((brew)=>{
PopulatedBrews[id] = brew;
});
})
);
},
get : (brewId) => {
return PopulatedBrews[brewId]
},
chaiPlugin : (chai, utils) => {
chai.Assertion.addMethod('brews', function(...brewIds){
new chai.Assertion(this._obj).to.be.instanceof(Array);
const valid = _.every(brewIds, (brewId) => {
const storedBrew = PopulatedBrews[brewId];
if(!storedBrew) return false;
return _.some(this._obj, (brew)=>{
return brew.shareId == storedBrew.shareId &&
brew.title == storedBrew.title &&
brew.views == storedBrew.views;
});
});
this.assert(
valid,
`expect #{this} to have brews ${brewIds.join(', ')}`,
`expect #{this} to not have brews ${brewIds.join(', ')}`
)
});
chai.Assertion.addMethod('brew', function(brewId){
new chai.Assertion(this._obj).to.be.instanceof(Object);
const brew = this._obj;
const storedBrew = PopulatedBrews[brewId];
const valid = storedBrew &&
brew.shareId == storedBrew.shareId &&
brew.title == storedBrew.title &&
brew.views == storedBrew.views;
this.assert(
valid,
`expect #{this} to be brew ${brewId}`,
`expect #{this} to not be brew ${brewId}`
)
});
}
};

111
tests/brew.test.js Normal file
View File

@@ -0,0 +1,111 @@
const testing = require('./test.init.js');
const DB = require('db.js');
const BrewData = require('brew.data.js');
const Error = require('error.js');
let storedBrew = {
title : 'good title',
text : 'original text'
};
describe('Brew Data', () => {
before('Connect DB', DB.connect);
before('Clear DB', BrewData.removeAll);
before('Create brew', ()=>{
return BrewData.create(storedBrew)
.then((brew)=>{ storedBrew = brew; });
});
it('generates edit/share ID on create', () => {
return BrewData.create({
text : 'Brew Text'
}).then((brew) => {
brew.should.have.property('editId').that.is.a('string');
brew.should.have.property('shareId').that.is.a('string');
brew.should.have.property('text').that.is.a('string');
brew.should.have.property('views').equal(0);
});
});
it('generates edit/share ID on create even if given one', () => {
return BrewData.create({
editId : 'NOPE',
shareId : 'NOTTA'
}).then((brew) => {
brew.should.have.property('editId').not.equal('NOPE');
brew.should.have.property('shareId').not.equal('NOTTA');
});
});
it('can update an existing brew', () => {
return BrewData.update(storedBrew.editId,{
text : 'New Text'
}).then((brew) => {
brew.should.have.property('editId').equal(storedBrew.editId);
brew.should.have.property('text').equal('New Text');
brew.should.have.property('title').equal(storedBrew.title);
})
});
it('properly returns a brew if retrieved by just share', () => {
return BrewData.getByShare(storedBrew.shareId)
.then((brew) => {
brew.should.not.have.property('editId');
brew.should.have.property('shareId').equal(storedBrew.shareId);
brew.should.have.property('views').equal(1);
})
});
it('can properly remove a brew', () => {
return BrewData.remove(storedBrew.editId)
.then(() => {
return BrewData.getByEdit(storedBrew.editId)
})
.then(() => { throw 'Brew found when one should not have been'; })
.catch((err) => {
err.should.be.an.instanceof(Error.noBrew);
});
});
it('throws the right error if can not find brew', () => {
return BrewData.getByEdit('NOT A REAL ID')
.then(() => { throw 'Brew found when one should not have been'; })
.catch((err) => {
err.should.be.an.instanceof(Error.noBrew);
});
});
describe('Title Generation', () => {
it('should use the title if given one', () => {
return BrewData.create({
title : 'Actual Title',
text : '# Not this'
}).then((brew) => {
brew.should.have.property('title').equal('Actual Title');
});
});
it.skip('should work with "# title"', ()=>{
});
it('should use the first header found if no title provided', () => {
return BrewData.create({
text : 'Not this \n # But This'
}).then((brew) => {
brew.should.have.property('title').equal('But This');
})
});
it('should use the first line if no headers are found', () => {
return BrewData.create({
text : 'First line \n second line'
}).then((brew) => {
brew.should.have.property('title').equal('First line');
});
});
});
});

3
tests/config.json Normal file
View File

@@ -0,0 +1,3 @@
{
"log_level" : "silent"
}

20
tests/markdown.test.js Normal file
View File

@@ -0,0 +1,20 @@
const testing = require('./test.init.js');
const Markdown = require('../shared/homebrewery/markdown.js');
describe('Markdown', ()=>{
it('should do a thing', ()=>{
const res = Markdown.render(`
test
<div> cool stuff </div>
test2
`)
console.log(res);
});
});

144
tests/middleware.test.js Normal file
View File

@@ -0,0 +1,144 @@
const _ = require('lodash');
const testing = require('./test.init.js');
const request = require('supertest-as-promised');
const jwt = require('jwt-simple');
const DB = require('db.js');
const BrewData = require('brew.data.js');
const Error = require('error.js');
const config = require('nconf');
const mw = require('middleware.js');
const requestHandler = (req, res) => {
return res.status(200).json(_.pick(req, ['brew', 'account', 'admin', 'params', 'query', 'body']));
};
const test_user = {
username : 'cool guy'
};
describe('Middleware', () => {
let app = undefined;
let session_token = '';
before('create session token', () => {
session_token = jwt.encode(test_user, config.get('jwt_secret'));
});
beforeEach('setup test server', ()=>{
app = require('express')();
app.use(require('cookie-parser')());
});
describe('Account', ()=>{
it('should get the account for a session', () => {
app.use(mw.account);
app.use(requestHandler)
return request(app).get('/')
.set('Cookie', `nc_session=${session_token}`)
.send()
.expect(200)
.then((res) => {
const req = res.body;
req.should.have.property('account').is.a('object');
req.account.should.have.property('username').equal(test_user.username);
});
});
it('should not have an account for an invalid session', () => {
app.use(mw.account);
app.use(requestHandler)
return request(app).get('/')
.set('Cookie', `nc_session=BADSESSION`)
.send()
.expect(200)
.then((res) => {
const req = res.body;
req.should.not.have.property('account');
});
});
});
describe('Brew', ()=>{
let storedBrew = {
text : 'brew brew',
authors : [test_user.username]
};
before('Connect DB', DB.connect);
before('Clear DB', BrewData.removeAll);
before('Create brew', ()=>{
return BrewData.create(storedBrew)
.then((brew)=>{ storedBrew = brew; });
});
it('should load brew with editId params', ()=>{
app.get('/:editId', mw.loadBrew, requestHandler);
return request(app).get('/' + storedBrew.editId)
.send()
.expect(200)
.then((res) => {
const req = res.body;
req.should.have.property('brew').is.a('object');
req.brew.should.have.property('editId').equal(storedBrew.editId);
});
});
it('should view brew with shareId params', ()=>{
app.get('/:shareId', mw.viewBrew, requestHandler);
return request(app).get('/' + storedBrew.shareId)
.send()
.expect(200)
.then((res) => {
const req = res.body;
req.should.have.property('brew').is.a('object');
req.brew.should.not.have.property('editId');
req.brew.should.have.property('shareId').equal(storedBrew.shareId);
req.brew.should.have.property('views').equal(1);
});
});
});
describe('Admin', ()=>{
it('should detect when you use the admin key', () => {
app.use(mw.admin);
app.use(requestHandler)
return request(app).get('/')
.set('x-homebrew-admin', config.get('admin:key'))
.expect(200)
.then((res) => {
const req = res.body;
req.should.have.property('admin').equal(true);
});
});
it('should block you if you are not an admin', ()=>{
app.use(mw.admin);
app.use(mw.adminOnly);
app.get(requestHandler);
app.use(Error.expressHandler);
return request(app).get('/')
.set('x-homebrew-admin', 'BADADMIN')
.send()
.expect(401);
});
it('should let your through witch basic auth', () => {
app.use(mw.adminLogin);
app.use(requestHandler);
return request(app).get('/')
.auth(config.get('admin:user'), config.get('admin:pass'))
.send()
.expect(200);
});
it('should block you if basic auth is wrong', () => {
app.use(mw.adminLogin);
app.use(requestHandler);
app.use(Error.expressHandler);
return request(app).get('/')
.auth('baduser', 'badpassword')
.send()
.expect(401);
});
});
});

186
tests/search.test.js Normal file
View File

@@ -0,0 +1,186 @@
const Test = require('./test.init.js');
const _ = require('lodash');
const DB = require('db.js');
const BrewData = require('brew.data.js');
const BrewGen = require('./brew.gen.js');
//const Error = require('error.js');
describe('Brew Search', () => {
before('Connect DB', DB.connect);
before('Clear DB', BrewData.removeAll);
before('Populate brews', ()=>{
return BrewGen.populateDB(BrewGen.static());
});
describe('Searching', ()=>{
it('should return a total and a brew array', ()=>{
return BrewData.search()
.then((result) => {
result.total.should.be.a('number');
result.brews.should.be.an('array');
})
});
it('should be able to search for all brews', ()=>{
return BrewData.search()
.then((result) => {
const brewCount = _.size(BrewGen.static());
result.total.should.be.equal(brewCount);
result.brews.length.should.be.equal(brewCount);
})
});
});
describe('Pagniation', () => {
it('should return the exact number of brews based on limit', () => {
return BrewData.search({}, {
limit : 2
})
.then((result) => {
result.total.should.be.equal(_.size(BrewGen.static()));
result.brews.length.should.be.equal(2);
})
});
it('should return the correct pages when specified', () => {
return BrewData.search({}, {
limit : 2,
page : 1,
sort : { views : 1 }
})
.then((result) => {
result.brews.should.have.brews('BrewA', 'BrewB');
})
});
it('should return a partial list if on the last page', () => {
return BrewData.search({}, {
limit : 3,
page : 1
})
.then((result) => {
result.brews.length.should.be.equal(1);
});
});
});
describe('Sorting', ()=>{
it('should sort ASC', () => {
return BrewData.search({}, {
sort : { views : 1 }
})
.then((result) => {
result.brews[0].should.be.brew('BrewC');
result.brews[1].should.be.brew('BrewD');
result.brews[2].should.be.brew('BrewB');
result.brews[3].should.be.brew('BrewA');
})
});
it('should sort DESC', () => {
return BrewData.search({}, {
sort : { views : -1 }
})
.then((result) => {
result.brews[0].should.be.brew('BrewA');
result.brews[1].should.be.brew('BrewB');
result.brews[2].should.be.brew('BrewD');
result.brews[3].should.be.brew('BrewC');
})
});
});
describe('Permissions', () => {
it('should only fetch published brews', () => {
return BrewData.search({}, {}, false)
.then((result) => {
result.total.should.be.equal(2);
result.brews.should.have.brews('BrewB', 'BrewD');
})
});
it('fetched brews should not have text or editId', () => {
return BrewData.search({}, {}, false)
.then((result) => {
result.brews[0].should.not.have.property('text');
result.brews[0].should.not.have.property('editId');
})
});
it('if full access, brews should have editid, but no text', () => {
return BrewData.search({}, {}, true)
.then((result) => {
result.brews[0].should.not.have.property('text');
result.brews[0].should.have.property('editId');
})
});
});
describe('Term Search', ()=>{
it('should search brews based on title', () => {
return BrewData.termSearch('Charlie')
.then((result) => {
result.total.should.be.equal(1);
result.brews.should.have.brews('BrewC');
})
});
it('should search brews based on description', () => {
return BrewData.termSearch('fancy')
.then((result) => {
result.total.should.be.equal(2);
result.brews.should.have.brews('BrewA', 'BrewB');
})
});
it('should search brews based on multiple terms', () => {
return BrewData.termSearch('ranger 5e')
.then((result) => {
result.total.should.be.equal(1);
result.brews.should.have.brews('BrewD');
})
});
it('should perform an AND operation on the provided terms', () => {
return BrewData.termSearch('Brew Delta GARBAGE')
.then((result) => {
result.total.should.be.equal(0);
});
});
it('should search brews based on a combination of both', () => {
return BrewData.termSearch('Brew Beta fancy')
.then((result) => {
result.total.should.be.equal(1);
result.brews.should.have.brews('BrewB');
});
});
it('should not worry about the case of the terms', () => {
return BrewData.termSearch('FANCY')
.then((result) => {
result.total.should.be.equal(2);
result.brews.should.have.brews('BrewA', 'BrewB');
});
});
});
describe('User Search', ()=>{
it('should return brews just for a single user', () => {
return BrewData.userSearch('userA')
.then((result) => {
result.total.should.be.equal(3);
result.brews.should.have.brews('BrewA', 'BrewB', 'BrewC');
});
});
it('should return nothing if provided a non-exsistent user', () => {
return BrewData.userSearch('userXYZ')
.then((result) => {
result.total.should.be.equal(0);
});
});
});
});

24
tests/test.init.js Normal file
View File

@@ -0,0 +1,24 @@
require('app-module-path').addPath('./server');
const config = require('nconf')
.argv()
.env({ lowerCase: true })
.file('testing', { file: `test/config.json` })
.file('environment', { file: `config/${process.env.NODE_ENV}.json` })
.file('defaults', { file: 'config/default.json' });
const Chai = require('chai')
.use(require('chai-as-promised'))
.use(require('chai-subset'))
.use(require('./brew.gen.js').chaiPlugin);
const log = require('loglevel');
log.setLevel(config.get('log_level'));
const jwt = require('jwt-simple');
module.exports = {
should: Chai.should(),
getSessionToken : (userInfo) => {
return jwt.encode(userInfo, config.get('jwt_secret'));
}
};