poll.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. process.env.NODE_ENV = 'test'
  2. let chai = require('chai')
  3. let server = require('../server')
  4. let should = chai.should()
  5. let { sequelize, PollQuestion, PollAnswer, PollVote, User } = require('../models')
  6. const Errors = require('../lib/errors.js')
  7. chai.use(require('chai-http'))
  8. chai.use(require('chai-things'))
  9. describe('Poll', () => {
  10. let admin = chai.request.agent(server)
  11. let user1 = chai.request.agent(server)
  12. let user2 = chai.request.agent(server)
  13. let user3 = chai.request.agent(server)
  14. //Wait for app to start before commencing
  15. before((done) => {
  16. if(server.locals.appStarted) done()
  17. server.on('appStarted', () => {
  18. done()
  19. })
  20. })
  21. describe('Poll', () => {
  22. before(async () => {
  23. try {
  24. let accounts = []
  25. accounts.push(
  26. admin
  27. .post('/api/v1/user')
  28. .set('content-type', 'application/json')
  29. .send({
  30. username: 'adminaccount',
  31. password: 'password',
  32. admin: true
  33. })
  34. )
  35. accounts.push(
  36. user1
  37. .post('/api/v1/user')
  38. .set('content-type', 'application/json')
  39. .send({
  40. username: 'useraccount1',
  41. password: 'password'
  42. })
  43. )
  44. accounts.push(
  45. user2
  46. .post('/api/v1/user')
  47. .set('content-type', 'application/json')
  48. .send({
  49. username: 'useraccount2',
  50. password: 'password'
  51. })
  52. )
  53. accounts.push(
  54. user3
  55. .post('/api/v1/user')
  56. .set('content-type', 'application/json')
  57. .send({
  58. username: 'useraccount3',
  59. password: 'password'
  60. })
  61. )
  62. await Promise.all(accounts)
  63. return true
  64. } catch (e) {
  65. return e
  66. }
  67. })
  68. describe('POST /poll', () => {
  69. it('should create a PollQuestion and PollAnswers', async () => {
  70. let res = await user1
  71. .post('/api/v1/poll')
  72. .set('content-type', 'application/json')
  73. .send({
  74. question: 'Question here',
  75. answers: ['answer 1', 'answer 2', 'answer 3']
  76. })
  77. res.should.be.json
  78. res.should.have.status(200)
  79. res.body.should.have.property('question', 'Question here')
  80. res.body.should.have.property('id', 1)
  81. let poll = await PollQuestion.findById(1, {
  82. include: [User, PollAnswer]
  83. })
  84. poll.should.have.property('question', 'Question here')
  85. poll.PollAnswers.should.have.property('length', 3)
  86. poll.PollAnswers.should.contain.something.with.property('answer', 'answer 1')
  87. poll.PollAnswers.should.contain.something.with.property('answer', 'answer 2')
  88. poll.PollAnswers.should.contain.something.with.property('answer', 'answer 3')
  89. })
  90. it('should return an error if answers is missing', done => {
  91. user1
  92. .post('/api/v1/poll')
  93. .set('content-type', 'application/json')
  94. .send({
  95. question: 'Question here'
  96. })
  97. .end((err, res) => {
  98. res.should.have.status(400)
  99. res.body.errors.should.contain.something.with.property(
  100. 'message',
  101. 'You must provide at least 2 answers'
  102. )
  103. done()
  104. })
  105. })
  106. it('should return an error if answers is less than two', done => {
  107. user1
  108. .post('/api/v1/poll')
  109. .set('content-type', 'application/json')
  110. .send({
  111. question: 'Question here',
  112. answers: []
  113. })
  114. .end((err, res) => {
  115. res.should.have.status(400)
  116. res.body.errors.should.contain.something.with.property(
  117. 'message',
  118. 'You must provide at least 2 answers'
  119. )
  120. done()
  121. })
  122. })
  123. it('should return an error if answers contains duplicates', done => {
  124. user1
  125. .post('/api/v1/poll')
  126. .set('content-type', 'application/json')
  127. .send({
  128. question: 'Question here',
  129. answers: ['answer', 'answer 1', 'answer']
  130. })
  131. .end((err, res) => {
  132. res.should.have.status(400)
  133. res.body.errors.should.contain.something.with.property(
  134. 'message',
  135. 'Answers cannot contain any duplicates'
  136. )
  137. done()
  138. })
  139. })
  140. it('should return an error if question not provided', done => {
  141. user1
  142. .post('/api/v1/poll')
  143. .set('content-type', 'application/json')
  144. .send({
  145. answers: ['answer 1', 'answer 2']
  146. })
  147. .end((err, res) => {
  148. res.should.have.status(400)
  149. res.body.errors.should.contain.something.with.property(
  150. 'message',
  151. 'question cannot be null'
  152. )
  153. done()
  154. })
  155. })
  156. it('should return an error if not logged in', done => {
  157. chai.request(server)
  158. .post('/api/v1/poll')
  159. .set('content-type', 'application/json')
  160. .send({
  161. question: 'Question here',
  162. answers: ['answer', 'answer 2']
  163. })
  164. .end((err, res) => {
  165. res.should.have.status(401)
  166. res.body.errors.should.contain.something.which.deep.equals(Errors.requestNotAuthorized)
  167. done()
  168. })
  169. })
  170. })
  171. describe('POST /poll/:id', () => {
  172. let id, id2
  173. before(async () => {
  174. try {
  175. let res = await user1
  176. .post('/api/v1/poll')
  177. .set('content-type', 'application/json')
  178. .send({
  179. question: 'Poll question',
  180. answers: ['poll answer 1', 'poll answer 2', 'poll answer 3']
  181. })
  182. id = res.body.id
  183. let res2 = await user1
  184. .post('/api/v1/poll')
  185. .set('content-type', 'application/json')
  186. .send({
  187. question: 'Poll question',
  188. answers: ['poll answer 1', 'poll answer 2', 'poll answer 3']
  189. })
  190. id2 = res2.body.id
  191. return true
  192. } catch (e) {
  193. return e
  194. }
  195. })
  196. it('should add a vote to the poll', async () => {
  197. let res = await user1
  198. .post('/api/v1/poll/' + id)
  199. .set('content-type', 'application/json')
  200. .send({ answer: 'poll answer 1' })
  201. res.should.be.json
  202. res.should.have.status(200)
  203. let answer = await PollAnswer.findOne({
  204. where: {
  205. answer: 'poll answer 1'
  206. }
  207. })
  208. let vote = await PollVote.findById(res.body.id)
  209. vote.should.not.be.null
  210. vote.should.have.property('PollQuestionId', id)
  211. vote.should.have.property('PollAnswerId', answer.id)
  212. })
  213. it('should return an error if voting twice', done => {
  214. user1
  215. .post('/api/v1/poll/' + id)
  216. .set('content-type', 'application/json')
  217. .send({ answer: 'poll answer 2' })
  218. .end((err, res) => {
  219. res.should.have.status(400)
  220. res.body.errors.should.contain.something.that.has.property(
  221. 'message',
  222. 'you cannot vote twice'
  223. )
  224. done()
  225. })
  226. })
  227. it('should return an error if invalid id', done => {
  228. user1
  229. .post('/api/v1/poll/404')
  230. .set('content-type', 'application/json')
  231. .send({ answer: 'poll answer 1' })
  232. .end((err, res) => {
  233. res.should.have.status(400)
  234. res.body.errors.should.contain.something.that.has.property(
  235. 'message',
  236. 'invalid poll id'
  237. )
  238. done()
  239. })
  240. })
  241. it('should return an error if missing answer', done => {
  242. user1
  243. .post('/api/v1/poll/' + id2)
  244. .set('content-type', 'application/json')
  245. .send()
  246. .end((err, res) => {
  247. res.should.have.status(400)
  248. res.body.errors.should.contain.something.that.has.property(
  249. 'message',
  250. 'invalid answer'
  251. )
  252. done()
  253. })
  254. })
  255. it('should return an error if answer is invalid', done => {
  256. user1
  257. .post('/api/v1/poll/' + id2)
  258. .set('content-type', 'application/json')
  259. .send({ answer: 'not an option' })
  260. .end((err, res) => {
  261. res.should.have.status(400)
  262. res.body.errors.should.contain.something.that.has.property(
  263. 'message',
  264. 'invalid answer'
  265. )
  266. done()
  267. })
  268. })
  269. it('should return an error if not logged in', done => {
  270. chai.request(server)
  271. .post('/api/v1/poll/' + id)
  272. .set('content-type', 'application/json')
  273. .send({ answer: 'poll answer 1' })
  274. .end((err, res) => {
  275. res.should.have.status(401)
  276. res.body.errors.should.contain.something.which.deep.equals(Errors.requestNotAuthorized)
  277. })
  278. done()
  279. })
  280. })
  281. describe('GET /poll/:id', () => {
  282. let pollId
  283. before(async () => {
  284. try {
  285. let pollRes = await admin
  286. .post('/api/v1/poll')
  287. .set('content-type', 'application/json')
  288. .send({
  289. question: 'Do you like polls?',
  290. answers: ['yes', 'no', 'meh']
  291. })
  292. pollId = pollRes.body.id
  293. await user1
  294. .post('/api/v1/poll/' + pollId)
  295. .set('content-type', 'application/json')
  296. .send({ answer: 'yes' })
  297. await user2
  298. .post('/api/v1/poll/' + pollId)
  299. .set('content-type', 'application/json')
  300. .send({ answer: 'yes' })
  301. await user3
  302. .post('/api/v1/poll/' + pollId)
  303. .set('content-type', 'application/json')
  304. .send({ answer: 'no' })
  305. return true
  306. } catch (e) {
  307. console.log(e)
  308. return e
  309. }
  310. })
  311. it('should get the poll question and accompanying answers and votes', async () => {
  312. let res = await user1.get('/api/v1/poll/' + pollId)
  313. res.should.be.json
  314. res.should.have.status(200)
  315. res.body.should.have.property('question', 'Do you like polls?')
  316. res.body.PollAnswers.should.have.property('length', 3)
  317. res.body.should.have.property('totalVotes', 3)
  318. res.body.should.have.deep.property('PollAnswers.0.answer', 'yes')
  319. res.body.should.have.deep.property('PollAnswers.0.PollVotes.length', 2)
  320. res.body.should.have.deep.property('PollAnswers.0.percent', 66.7)
  321. res.body.should.have.deep.property('PollAnswers.1.answer', 'no')
  322. res.body.should.have.deep.property('PollAnswers.1.PollVotes.length', 1)
  323. res.body.should.have.deep.property('PollAnswers.1.percent', 33.3)
  324. res.body.should.have.deep.property('PollAnswers.2.answer', 'meh')
  325. res.body.should.have.deep.property('PollAnswers.2.PollVotes.length', 0)
  326. res.body.should.have.deep.property('PollAnswers.2.percent', 0)
  327. })
  328. it('should return an error if invalid id', done => {
  329. chai.request(server)
  330. .get('/api/v1/poll/' + pollId)
  331. .end((err, res) => {
  332. res.should.have.status(400)
  333. res.body.errors.should.contain.something.with.property(
  334. 'message',
  335. 'invalid poll id'
  336. )
  337. })
  338. done()
  339. })
  340. })
  341. })
  342. after(() => {
  343. sequelize.sync({ force: true })
  344. })
  345. })