/test/routesTest/account.js
JavaScript | 342 lines | 253 code | 37 blank | 52 comment | 8 complexity | 2ef22f5c9683fde926e691f0613ea0a7 MD5 | raw file
- const q = require('q')
- const _ = require('lodash')
- const request = require('supertest')
- const insertMultiple = require('../util/insertMultiple')
- const checkExample = require('../util/checkExample')
- const checkMultiple = require('../util/checkMultiple')
- const checkBadExampleNoPost = require('../util/checkBadExampleNoPost')
- const getSanitizedExample = require('../util/getSanitizedExample')
- const prepareTestData = require('../util/prepareTestData')
- const createAccountAndResetToken = require('../util/createAccountAndResetToken')
- const settings = require('config')
- const flarumClient = require('flarum-client')
- const createUser = flarumClient.createUser
- const deleteUser = flarumClient.deleteUser
- const getUser = flarumClient.getUser
- const logging = require('../../util/logging')
- const logger = logging.createLogger(settings.logs)
- const nameOfRoute = 'account'
- /**
- * Test inserting a object using a route
- *
- * @param {string} url Url of the server
- * @param {object} data Testdata of the model to which the route gives access
- * @param {object} models The sequelize models
- * @param {function} expect Chai expect
- * @returns {Promise} Promise that resolves when done or rejects on error
- */
- function testInsert(url, data, models, expect) {
- const testData = prepareTestData(
- data[nameOfRoute].examples[0],
- data[nameOfRoute]
- )
- const locationExpect = new RegExp(`/${nameOfRoute}/(\\d)*`)
- const suburl = `/${nameOfRoute}`
- // create user and a registerToken
- return models.resident.create({
- firstname: 'testUser',
- surname: 'testUser',
- initials: 'tt',
- email: 'test@test.com',
- }).then((resident) => (
- // add the registerToken
- models.registerToken.create({
- residentId: resident.get('id'),
- }).then((registerToken) => (
- new q.Promise((resolve, reject) => {
- request(url)
- .post(suburl)
- .send(testData)
- .set('Accept', 'application/json')
- .set('registerToken', registerToken.get('token'))
- .expect(201)
- .expect('Location', locationExpect)
- .end((err, res) => {
- if (err) {
- reject(err)
- }
- return resolve(resident.getAccount().then((account) => {
- expect(account).to.be.an('object')
- const resp = res.body
- const check = account.toJSON()
- delete check.profilePictureId
- resp.updatedAt = new Date(resp.updatedAt)
- resp.createdAt = new Date(resp.createdAt)
- const test = prepareTestData(resp, data[nameOfRoute])
- const testSanitized = getSanitizedExample(test, data[nameOfRoute])
- expect(testSanitized).to.eql(check)
- const location = res.headers.location
- const re = /\/(\d*?)$/
- const id = re.exec(location)[1]
- const promises = [
- // check the inserted account
- getUser(testData.username, logger).then((forumUser) => (
- new q.Promise((resolveInner) => {
- const attr = forumUser.attributes
- const expected = JSON.parse(JSON.stringify(testData))
- expect(resident.email).to.equal(attr.email)
- expect(expected.username).to.equal(attr.username)
- expected.userId = parseInt(forumUser.id, 10)
- delete expected.username
- delete expected.registerToken
- delete expected.password
- return resolveInner(checkExample(
- id,
- models[nameOfRoute],
- url,
- `/${nameOfRoute}`,
- data[nameOfRoute],
- testData,
- expect
- ))
- })
- )),
- // insert again to trigger an already exists error
- models.registerToken.create({
- residentId: resident.get('id'),
- }).then((registerToken2) => {
- request(url)
- .post(suburl)
- .send(testData)
- .set('Accept', 'application/json')
- .set('registerToken', registerToken2.get('token'))
- .expect(400)
- .end((errInner, resInner) => (
- new q.Promise((resolveInner, rejectInner) => {
- if (errInner) {
- rejectInner(errInner)
- } else {
- const errors = resInner.body
- expect(errors).to.be.an('object')
- expect(errors).to.have.property('username')
- resolveInner()
- }
- })
- ))
- }),
- // insert again but uppercase, to trigger already exists
- models.registerToken.create({
- residentId: resident.get('id'),
- }).then((registerToken2) => {
- const testDataUpper = _.clone(testData)
- testDataUpper.username = testData.username.toUpperCase()
- request(url)
- .post(suburl)
- .send(testData)
- .set('Accept', 'application/json')
- .set('registerToken', registerToken2.get('token'))
- .expect(400)
- .end((errInner, resInner) => (
- new q.Promise((resolveInner, rejectInner) => {
- if (errInner) {
- rejectInner(errInner)
- } else {
- const errors = resInner.body
- expect(errors).to.be.an('object')
- expect(errors).to.have.property('username')
- resolveInner()
- }
- })
- ))
- }),
- ]
- return q.all(promises)
- }))
- })
- })
- ))
- ))
- }
- /**
- * Test resetting the password using a reset password link
- *
- * @param {string} url Url of the server
- * @param {object} data Testdata of the file route
- * @param {object} models The sequelize models
- * @param {function} expect Chai expect
- * @returns {Promise} Promise that resolves when done or rejects on error
- */
- function testResetPassword(url, data, models, expect) {
- return createAccountAndResetToken(models).then((acctkn) => {
- const account = acctkn.account
- const resident = acctkn.resident
- const resetPasswordToken = acctkn.resetPasswordToken
- return createUser(
- data.account.examples[0].username,
- data.account.examples[0].password,
- resident.email,
- resident,
- logger).then((result) => models.forumAccount.create({
- userId: result.id,
- })
- .then((forumAccount) => account.setForumAccount(forumAccount).then(() => {
- const promises = [
- // ok, everything is created, now lets change the password
- q.Promise((resolve, reject) => {
- request(url)
- .post(`/${nameOfRoute}/${account.id}/resetPassword`)
- .set('Accept', 'application/json')
- .set('ResetPasswordToken', resetPasswordToken.get('token'))
- .send({ password: 'newPassword' })
- .expect(200)
- .end((err, res) => {
- if (err) {
- reject(err)
- return
- }
- // check if the password is actually changed
- resolve(models.account.findById(account.id).then((accountC) => {
- const hash = accountC.passwordHash
- const updatedAt = accountC.updatedAt
- expect(hash).to.not.equal(account.passwordHash)
- expect(updatedAt).to.be.afterTime(account.updatedAt)
- const accountCData = accountC.toJSON()
- const accountData = account.toJSON()
- delete accountCData.passwordHash
- delete accountCData.updatedAt
- delete accountCData.profilePictureId
- delete accountData.passwordHash
- delete accountData.updatedAt
- delete accountData.password
- // expect everything else to be the same
- expect(accountCData).to.eql(accountData)
- // check that the token was deleted
- const tokenId = resetPasswordToken.token
- return models.resetPasswordToken.findById(tokenId)
- .then((tokenResult) => (
- expect(tokenResult).to.be.null
- ))
- }))
- })
- }),
- // without token should give unauthorized
- q.Promise((resolve, reject) => {
- request(url)
- .post(`/${nameOfRoute}/${account.id}/resetPassword`)
- .set('Accept', 'application/json')
- .expect(401)
- .end((err, res) => {
- if (err) {
- reject(err)
- return
- }
- resolve()
- })
- }),
- ]
- return q.all(promises)
- })))
- })
- }
- /**
- * Test what happens when we try and insert multiple objects using the route
- *
- * @param {string} url Url of the server
- * @param {object} data Testdata of the file route
- * @param {object} models The sequelize models
- * @param {function} expect Chai expect
- * @returns {Promise} Promise that resolves when done or rejects on error
- */
- function testBulkOutput(url, data, models, expect) {
- // slice to start from the 2nd element
- const dataList = prepareTestData(
- data[nameOfRoute].examples,
- data[nameOfRoute]
- ).slice(1)
- // insert a few works
- return insertMultiple(models[nameOfRoute], dataList)
- .then((result) => checkMultiple(
- result,
- url,
- `/${nameOfRoute}/`,
- data[nameOfRoute],
- expect
- ))
- }
- /**
- * Test what happens when we try and insert objects that don't validate
- *
- * @param {object} badExample Part of the testdata containg the bad data
- * @param {object} models The sequelize models
- * @param {string} url Url of the server
- * @param {function} expect Chai expect
- * @param {number} n The index of the bad example
- * @returns {Promise} Promise that resolves when done or rejects on error
- */
- function testBadExamples(badExample, models, url, expect, n) {
- it(`should give descriptive errors #${n}`, () => (
- checkBadExampleNoPost(badExample, models.account, expect)
- ))
- }
- module.exports = function testAccount(url, data, models, expect) {
- describe(nameOfRoute, () => {
- describe('With real forum user', function withRealForumUser() {
- before(function checkForCI() {
- // these tests will fail in CI as it needs flarum credentials
- if (process.env.CI) {
- this.skip()
- }
- })
- // these tests also need a bit more time
- this.timeout(20000)
- it('should insert and check errors', () => (
- testInsert(url, data, models, expect)
- ))
- it('should change a user\'s password', () => (
- testResetPassword(url, data, models, expect)
- ))
- afterEach(() => (
- getUser(data.account.examples[0].username)
- .then((user) => (
- deleteUser(user.id)
- ))
- ))
- })
- describe('Without real forum user', () => {
- it('should output all info', () => (
- testBulkOutput(url, data, models, expect)
- ))
- // test all bad examples
- data[nameOfRoute].badExamples.forEach((badExample, n) => {
- testBadExamples(badExample, models, url, expect, n)
- })
- })
- })
- }