@hoodie/account-server
Version:
Account JSON API backed by PouchDB
125 lines (105 loc) • 4.29 kB
JavaScript
var _ = require('lodash')
var Joi = require('joi')
var nock = require('nock')
var test = require('tap').test
var lolex = require('lolex')
var authorizationHeaderNotAllowedErrorTest = require('../../utils/authorization-header-not-allowed-error')
var couchdbErrorTests = require('../../utils/couchdb-error-tests')
var getServer = require('../../utils/get-server')
var invalidTypeErrors = require('../../utils/invalid-type-errors.js')
var routeOptions = {
method: 'PUT',
url: '/session/account',
headers: {
accept: 'application/vnd.api+json',
'content-type': 'application/vnd.api+json'
},
payload: {
data: {
type: 'account',
attributes: {
username: 'pat-doe',
createdAt: '1970-01-01T00:00:00.000Z',
password: 'secret'
}
}
}
}
function mockCouchDbPutUser () {
return nock('http://localhost:5984')
.put('/_users/org.couchdb.user%3Apat-doe', function (body) {
return Joi.object({
_id: Joi.any().only('org.couchdb.user:pat-doe').required(),
name: Joi.any().only('pat-doe').required(),
type: Joi.any().only('user').required(),
createdAt: Joi.any().only('1970-01-01T00:00:00.000Z').required(),
signedUpAt: Joi.any().only('1970-01-01T00:00:00.000Z').required(),
salt: Joi.string().required(),
derived_key: Joi.string().required(),
iterations: Joi.any().only(10).required(),
password_scheme: Joi.any().only('pbkdf2').required(),
roles: Joi.array().items(Joi.string().regex(/^id:[0-9a-f-]{36}$/)).max(1).min(1)
}).validate(body).error === null
})
.query(true)
}
test('PUT /session/account', function (group) {
group.beforeEach(getServer)
couchdbErrorTests(group, mockCouchDbPutUser, routeOptions)
authorizationHeaderNotAllowedErrorTest(group, routeOptions)
invalidTypeErrors(group, routeOptions, 'account')
group.test('User not found', function (t) {
var couchdb = mockCouchDbPutUser()
.reply(201, {
ok: true,
id: 'org.couchdb.user:pat-doe',
rev: '1-234'
})
var accountFixture = require('../../fixtures/account.json')
var clock = lolex.install({now: 0, toFake: ['Date']})
this.server.inject(routeOptions, function (response) {
clock.uninstall()
t.is(couchdb.pendingMocks()[0], undefined, 'CouchDB received request')
delete response.result.meta
t.is(response.statusCode, 201, 'returns 201 status')
t.ok(/^[0-9a-f-]{36}$/.test(response.result.data.id), 'sets id')
response.result.data.id = 'userid123'
response.result.data.relationships.profile.data.id = 'userid123-profile'
t.deepEqual(response.result, accountFixture, 'returns account in right format')
t.is(response.result.data.attributes.createdAt, new Date(0).toISOString(), 'createdAt is epoch 0')
t.is(response.result.data.attributes.signedUpAt, new Date(0).toISOString(), 'signedUpAt is epoch 0')
t.end()
})
})
group.test('CouchDB User already exists', function (t) {
var couchdb = mockCouchDbPutUser()
.reply(409, {
error: 'conflict',
reason: 'Document update conflict'
})
var clock = lolex.install({now: 0, toFake: ['Date']})
this.server.inject(routeOptions, function (response) {
clock.uninstall()
t.is(couchdb.pendingMocks()[0], undefined, 'CouchDB received request')
t.is(response.statusCode, 409, 'returns 409 status')
t.is(response.result.errors.length, 1, 'returns one error')
t.is(response.result.errors[0].title, 'Conflict', 'returns "Conflict" error')
t.is(response.result.errors[0].detail, 'An account with that username already exists', 'returns "An account with that username already exists." error message')
t.end()
})
})
group.end()
})
test('PUT /session/account?include=foobar', function (t) {
getServer(function (error, server) {
t.error(error)
var options = _.defaultsDeep({
url: '/session/account?include=foobar'
}, routeOptions)
server.inject(options, function (response) {
t.is(response.statusCode, 400, 'returns 400 status')
t.deepEqual(response.result.errors[0].detail, 'Allowed value for ?include is \'profile\'', 'returns error message')
t.end()
})
})
})