PageRenderTime 67ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/test/routesTest/account.js

https://gitlab.com/Boelensman1/SpaceS-DB
JavaScript | 342 lines | 253 code | 37 blank | 52 comment | 8 complexity | 2ef22f5c9683fde926e691f0613ea0a7 MD5 | raw file
  1. const q = require('q')
  2. const _ = require('lodash')
  3. const request = require('supertest')
  4. const insertMultiple = require('../util/insertMultiple')
  5. const checkExample = require('../util/checkExample')
  6. const checkMultiple = require('../util/checkMultiple')
  7. const checkBadExampleNoPost = require('../util/checkBadExampleNoPost')
  8. const getSanitizedExample = require('../util/getSanitizedExample')
  9. const prepareTestData = require('../util/prepareTestData')
  10. const createAccountAndResetToken = require('../util/createAccountAndResetToken')
  11. const settings = require('config')
  12. const flarumClient = require('flarum-client')
  13. const createUser = flarumClient.createUser
  14. const deleteUser = flarumClient.deleteUser
  15. const getUser = flarumClient.getUser
  16. const logging = require('../../util/logging')
  17. const logger = logging.createLogger(settings.logs)
  18. const nameOfRoute = 'account'
  19. /**
  20. * Test inserting a object using a route
  21. *
  22. * @param {string} url Url of the server
  23. * @param {object} data Testdata of the model to which the route gives access
  24. * @param {object} models The sequelize models
  25. * @param {function} expect Chai expect
  26. * @returns {Promise} Promise that resolves when done or rejects on error
  27. */
  28. function testInsert(url, data, models, expect) {
  29. const testData = prepareTestData(
  30. data[nameOfRoute].examples[0],
  31. data[nameOfRoute]
  32. )
  33. const locationExpect = new RegExp(`/${nameOfRoute}/(\\d)*`)
  34. const suburl = `/${nameOfRoute}`
  35. // create user and a registerToken
  36. return models.resident.create({
  37. firstname: 'testUser',
  38. surname: 'testUser',
  39. initials: 'tt',
  40. email: 'test@test.com',
  41. }).then((resident) => (
  42. // add the registerToken
  43. models.registerToken.create({
  44. residentId: resident.get('id'),
  45. }).then((registerToken) => (
  46. new q.Promise((resolve, reject) => {
  47. request(url)
  48. .post(suburl)
  49. .send(testData)
  50. .set('Accept', 'application/json')
  51. .set('registerToken', registerToken.get('token'))
  52. .expect(201)
  53. .expect('Location', locationExpect)
  54. .end((err, res) => {
  55. if (err) {
  56. reject(err)
  57. }
  58. return resolve(resident.getAccount().then((account) => {
  59. expect(account).to.be.an('object')
  60. const resp = res.body
  61. const check = account.toJSON()
  62. delete check.profilePictureId
  63. resp.updatedAt = new Date(resp.updatedAt)
  64. resp.createdAt = new Date(resp.createdAt)
  65. const test = prepareTestData(resp, data[nameOfRoute])
  66. const testSanitized = getSanitizedExample(test, data[nameOfRoute])
  67. expect(testSanitized).to.eql(check)
  68. const location = res.headers.location
  69. const re = /\/(\d*?)$/
  70. const id = re.exec(location)[1]
  71. const promises = [
  72. // check the inserted account
  73. getUser(testData.username, logger).then((forumUser) => (
  74. new q.Promise((resolveInner) => {
  75. const attr = forumUser.attributes
  76. const expected = JSON.parse(JSON.stringify(testData))
  77. expect(resident.email).to.equal(attr.email)
  78. expect(expected.username).to.equal(attr.username)
  79. expected.userId = parseInt(forumUser.id, 10)
  80. delete expected.username
  81. delete expected.registerToken
  82. delete expected.password
  83. return resolveInner(checkExample(
  84. id,
  85. models[nameOfRoute],
  86. url,
  87. `/${nameOfRoute}`,
  88. data[nameOfRoute],
  89. testData,
  90. expect
  91. ))
  92. })
  93. )),
  94. // insert again to trigger an already exists error
  95. models.registerToken.create({
  96. residentId: resident.get('id'),
  97. }).then((registerToken2) => {
  98. request(url)
  99. .post(suburl)
  100. .send(testData)
  101. .set('Accept', 'application/json')
  102. .set('registerToken', registerToken2.get('token'))
  103. .expect(400)
  104. .end((errInner, resInner) => (
  105. new q.Promise((resolveInner, rejectInner) => {
  106. if (errInner) {
  107. rejectInner(errInner)
  108. } else {
  109. const errors = resInner.body
  110. expect(errors).to.be.an('object')
  111. expect(errors).to.have.property('username')
  112. resolveInner()
  113. }
  114. })
  115. ))
  116. }),
  117. // insert again but uppercase, to trigger already exists
  118. models.registerToken.create({
  119. residentId: resident.get('id'),
  120. }).then((registerToken2) => {
  121. const testDataUpper = _.clone(testData)
  122. testDataUpper.username = testData.username.toUpperCase()
  123. request(url)
  124. .post(suburl)
  125. .send(testData)
  126. .set('Accept', 'application/json')
  127. .set('registerToken', registerToken2.get('token'))
  128. .expect(400)
  129. .end((errInner, resInner) => (
  130. new q.Promise((resolveInner, rejectInner) => {
  131. if (errInner) {
  132. rejectInner(errInner)
  133. } else {
  134. const errors = resInner.body
  135. expect(errors).to.be.an('object')
  136. expect(errors).to.have.property('username')
  137. resolveInner()
  138. }
  139. })
  140. ))
  141. }),
  142. ]
  143. return q.all(promises)
  144. }))
  145. })
  146. })
  147. ))
  148. ))
  149. }
  150. /**
  151. * Test resetting the password using a reset password link
  152. *
  153. * @param {string} url Url of the server
  154. * @param {object} data Testdata of the file route
  155. * @param {object} models The sequelize models
  156. * @param {function} expect Chai expect
  157. * @returns {Promise} Promise that resolves when done or rejects on error
  158. */
  159. function testResetPassword(url, data, models, expect) {
  160. return createAccountAndResetToken(models).then((acctkn) => {
  161. const account = acctkn.account
  162. const resident = acctkn.resident
  163. const resetPasswordToken = acctkn.resetPasswordToken
  164. return createUser(
  165. data.account.examples[0].username,
  166. data.account.examples[0].password,
  167. resident.email,
  168. resident,
  169. logger).then((result) => models.forumAccount.create({
  170. userId: result.id,
  171. })
  172. .then((forumAccount) => account.setForumAccount(forumAccount).then(() => {
  173. const promises = [
  174. // ok, everything is created, now lets change the password
  175. q.Promise((resolve, reject) => {
  176. request(url)
  177. .post(`/${nameOfRoute}/${account.id}/resetPassword`)
  178. .set('Accept', 'application/json')
  179. .set('ResetPasswordToken', resetPasswordToken.get('token'))
  180. .send({ password: 'newPassword' })
  181. .expect(200)
  182. .end((err, res) => {
  183. if (err) {
  184. reject(err)
  185. return
  186. }
  187. // check if the password is actually changed
  188. resolve(models.account.findById(account.id).then((accountC) => {
  189. const hash = accountC.passwordHash
  190. const updatedAt = accountC.updatedAt
  191. expect(hash).to.not.equal(account.passwordHash)
  192. expect(updatedAt).to.be.afterTime(account.updatedAt)
  193. const accountCData = accountC.toJSON()
  194. const accountData = account.toJSON()
  195. delete accountCData.passwordHash
  196. delete accountCData.updatedAt
  197. delete accountCData.profilePictureId
  198. delete accountData.passwordHash
  199. delete accountData.updatedAt
  200. delete accountData.password
  201. // expect everything else to be the same
  202. expect(accountCData).to.eql(accountData)
  203. // check that the token was deleted
  204. const tokenId = resetPasswordToken.token
  205. return models.resetPasswordToken.findById(tokenId)
  206. .then((tokenResult) => (
  207. expect(tokenResult).to.be.null
  208. ))
  209. }))
  210. })
  211. }),
  212. // without token should give unauthorized
  213. q.Promise((resolve, reject) => {
  214. request(url)
  215. .post(`/${nameOfRoute}/${account.id}/resetPassword`)
  216. .set('Accept', 'application/json')
  217. .expect(401)
  218. .end((err, res) => {
  219. if (err) {
  220. reject(err)
  221. return
  222. }
  223. resolve()
  224. })
  225. }),
  226. ]
  227. return q.all(promises)
  228. })))
  229. })
  230. }
  231. /**
  232. * Test what happens when we try and insert multiple objects using the route
  233. *
  234. * @param {string} url Url of the server
  235. * @param {object} data Testdata of the file route
  236. * @param {object} models The sequelize models
  237. * @param {function} expect Chai expect
  238. * @returns {Promise} Promise that resolves when done or rejects on error
  239. */
  240. function testBulkOutput(url, data, models, expect) {
  241. // slice to start from the 2nd element
  242. const dataList = prepareTestData(
  243. data[nameOfRoute].examples,
  244. data[nameOfRoute]
  245. ).slice(1)
  246. // insert a few works
  247. return insertMultiple(models[nameOfRoute], dataList)
  248. .then((result) => checkMultiple(
  249. result,
  250. url,
  251. `/${nameOfRoute}/`,
  252. data[nameOfRoute],
  253. expect
  254. ))
  255. }
  256. /**
  257. * Test what happens when we try and insert objects that don't validate
  258. *
  259. * @param {object} badExample Part of the testdata containg the bad data
  260. * @param {object} models The sequelize models
  261. * @param {string} url Url of the server
  262. * @param {function} expect Chai expect
  263. * @param {number} n The index of the bad example
  264. * @returns {Promise} Promise that resolves when done or rejects on error
  265. */
  266. function testBadExamples(badExample, models, url, expect, n) {
  267. it(`should give descriptive errors #${n}`, () => (
  268. checkBadExampleNoPost(badExample, models.account, expect)
  269. ))
  270. }
  271. module.exports = function testAccount(url, data, models, expect) {
  272. describe(nameOfRoute, () => {
  273. describe('With real forum user', function withRealForumUser() {
  274. before(function checkForCI() {
  275. // these tests will fail in CI as it needs flarum credentials
  276. if (process.env.CI) {
  277. this.skip()
  278. }
  279. })
  280. // these tests also need a bit more time
  281. this.timeout(20000)
  282. it('should insert and check errors', () => (
  283. testInsert(url, data, models, expect)
  284. ))
  285. it('should change a user\'s password', () => (
  286. testResetPassword(url, data, models, expect)
  287. ))
  288. afterEach(() => (
  289. getUser(data.account.examples[0].username)
  290. .then((user) => (
  291. deleteUser(user.id)
  292. ))
  293. ))
  294. })
  295. describe('Without real forum user', () => {
  296. it('should output all info', () => (
  297. testBulkOutput(url, data, models, expect)
  298. ))
  299. // test all bad examples
  300. data[nameOfRoute].badExamples.forEach((badExample, n) => {
  301. testBadExamples(badExample, models, url, expect, n)
  302. })
  303. })
  304. })
  305. }