/test/controllers/ContentController.spec.js

https://github.com/popcorn-official/popcorn-api · JavaScript · 326 lines · 215 code · 36 blank · 75 comment · 0 complexity · 61c6101bf8f65f0906eb733dc70239c1 MD5 · raw file

  1. // Import the necessary modules.
  2. // @flow
  3. /* eslint-disable no-unused-expressions */
  4. import 'dotenv/config'
  5. import { expect } from 'chai'
  6. import express, { type $Application } from 'express'
  7. import request from 'supertest'
  8. import sinon from 'sinon'
  9. import {
  10. ContentService,
  11. Database,
  12. PopApi
  13. } from 'pop-api'
  14. import type { MongooseModel } from 'mongoose'
  15. import ContentController from '../../src/controllers/ContentController'
  16. import testAnime from '../data/animeshow'
  17. import testMovie from '../data/movie'
  18. import testShow from '../data/show'
  19. import {
  20. AnimeShow as Anime,
  21. Movie,
  22. Show
  23. } from '../../src/models'
  24. import { name } from '../../package.json'
  25. /**
  26. * Test suite for fetching content from the database.
  27. * @param {!string} content - The content to test.
  28. * @param {!Model} Model - The model object of the content to fetch.
  29. * @param {!Object} testContent - The test content to test with.
  30. * @returns {undefined}
  31. */
  32. function testContentController(
  33. content: string,
  34. Model: MongooseModel,
  35. testContent: Object
  36. ): void {
  37. /** @test {ContentController} */
  38. describe('ContentController', () => {
  39. /**
  40. * The express instance to test with.
  41. * @type {Express}
  42. */
  43. let app: $Application
  44. /**
  45. * The base content controller object to test.
  46. * @type {ContentController}
  47. */
  48. let contentController: ContentController
  49. /**
  50. * The id of the content to get.
  51. * @type {string}
  52. */
  53. let id: string
  54. /**
  55. * The database middleware from `pop-api`.
  56. * @type {Database}
  57. */
  58. let database: Database
  59. /**
  60. * The content service for the controller.
  61. * @type {ContentService}
  62. */
  63. let service: ContentService
  64. /**
  65. * Hook for setting up the Controller tests.
  66. * @type {Function}
  67. */
  68. before(done => {
  69. app = express()
  70. service = new ContentService({
  71. Model,
  72. projection: {
  73. imdb_id: 1
  74. }
  75. })
  76. contentController = new ContentController({
  77. basePath: content,
  78. service
  79. })
  80. contentController.registerRoutes(app)
  81. database = new Database(PopApi, {
  82. database: name
  83. })
  84. database.connect()
  85. .then(() => done())
  86. .catch(done)
  87. })
  88. /** @test {ContentController#constructor} */
  89. it('should check the attributes of the ContentController', () => {
  90. expect(contentController.basePath).to.be.a('string')
  91. expect(contentController.basePath).to.equal(content)
  92. expect(contentController.service).to.be.an('object')
  93. expect(contentController.service).to.equal(service)
  94. })
  95. /** @test {ContentController#registerRoutes} */
  96. it('should not throw an error when calling the implemented registerRoutes method', () => {
  97. expect(contentController.registerRoutes)
  98. .to.not.throw('Using default method: \'registerRoutes\'')
  99. })
  100. /** @test {ContentController} */
  101. describe('with an empty database', () => {
  102. /**
  103. * Hook for setting up the AudioController tests.
  104. * @type {Function}
  105. */
  106. before(done => {
  107. Model.remove({})
  108. .then(() => done())
  109. .catch(done)
  110. })
  111. /** @test {ContentController#getContents} */
  112. it(`should get a 204 status from the GET [/${content}s] route`, done => {
  113. request(app).get(`/${content}s`)
  114. .expect(204)
  115. .then(() => done())
  116. .catch(done)
  117. })
  118. /** @test {ContentController#getPage} */
  119. it(`should get a 204 status from the GET [/${content}s/:page] route`, done => {
  120. request(app).get(`/${content}s/1`)
  121. .expect(204)
  122. .then(() => done())
  123. .catch(done)
  124. })
  125. /** @test {ContentController#getContent} */
  126. it(`should get a 204 status from the GET [/${content}/:id] route`, done => {
  127. request(app).get(`/${content}/${id}`)
  128. .expect(204)
  129. .then(() => done())
  130. .catch(done)
  131. })
  132. /** @test {ContentController#getRandomContent} */
  133. it(`should get a 204 status from the GET [/random/${content}] route`, done => {
  134. request(app).get(`/random/${content}`)
  135. .expect(204)
  136. .then(() => done())
  137. .catch(done)
  138. })
  139. })
  140. /** @test {ContentController} */
  141. describe('with a filled database', () => {
  142. /**
  143. * The query object passed along to the 'getAudios' tests.
  144. * @type {[type]}
  145. */
  146. let query: Object
  147. /**
  148. * Hook for setting up the AudioController tests.
  149. * @type {Function}
  150. */
  151. before(done => {
  152. query = {
  153. keywords: 'String',
  154. genre: 'all',
  155. order: -1
  156. }
  157. new Model(testContent).save()
  158. .then(() => done())
  159. .catch(done)
  160. })
  161. /** @test {ContentController#getContents} */
  162. it(`should get a 200 status from the GET [/${content}] route`, done => {
  163. request(app).get(`/${content}s`)
  164. .expect(200)
  165. .then(() => done())
  166. .catch(done)
  167. })
  168. /** @test {ContentController#getPage} */
  169. it(`should get a 200 status from the GET [/${content}s/:page] route`, done => {
  170. request(app).get(`/${content}s/1`).query({
  171. genre: 'sci-fi'
  172. }).expect(200)
  173. .then(res => {
  174. const random = Math.floor(Math.random() * res.body.length)
  175. id = res.body[random].imdb_id
  176. done()
  177. }).catch(done)
  178. })
  179. /**
  180. * Helper function to test the `/contents/:page` route.
  181. * @param {!string} sort - The sorting method to use.
  182. * @returns {undefined}
  183. */
  184. function testGetPage(sort: string): void {
  185. /** @test {ContentController#getPage} */
  186. it(`should get a 200 status from the GET [/${content}s/:page] route`, done => {
  187. request(app).get(`/${content}s/1`).query({
  188. ...query,
  189. genre: 'string',
  190. sort
  191. }).expect(200)
  192. .then(() => done())
  193. .catch(done)
  194. })
  195. }
  196. // Execute the tests.
  197. [
  198. 'faulty',
  199. 'name',
  200. 'rating',
  201. 'released',
  202. 'trending',
  203. 'year'
  204. ].map(testGetPage)
  205. /** @test {ContentController#getContent} */
  206. it(`should get a 200 status from the GET [/${content}/:id] route`, done => {
  207. request(app).get(`/${content}/${id}`)
  208. .expect(200)
  209. .then(() => done())
  210. .catch(done)
  211. })
  212. /** @test {ContentController#getRandomContent} */
  213. it(`should get a 200 status from the GET [/random/${content}] route`, done => {
  214. request(app).get(`/random/${content}`)
  215. .expect(200)
  216. .then(() => done())
  217. .catch(done)
  218. })
  219. })
  220. /** @test {ContentController} */
  221. describe('will throw errors', () => {
  222. /** @test {ContentController#getContents} */
  223. it(`should get a 500 status from the GET [/${content}s] route`, done => {
  224. const stub = sinon.stub(Model, 'count')
  225. stub.rejects()
  226. request(app).get(`/${content}s`)
  227. .expect(500)
  228. .then(() => {
  229. stub.restore()
  230. done()
  231. })
  232. .catch(done)
  233. })
  234. /** @test {ContentController#getPage} */
  235. it(`should get a 500 status from the GET [/${content}s/:page] route`, done => {
  236. const stub = sinon.stub(Model, 'aggregate')
  237. stub.rejects()
  238. request(app).get(`/${content}s/1`)
  239. .expect(500)
  240. .then(() => {
  241. stub.restore()
  242. done()
  243. })
  244. .catch(done)
  245. })
  246. /** @test {ContentController#getContent} */
  247. it(`should get a 500 status from the GET [/${content}/:id] route`, done => {
  248. const stub = sinon.stub(Model, 'findOne')
  249. stub.rejects()
  250. request(app).get(`/${content}/${id}`)
  251. .expect(500)
  252. .then(() => {
  253. stub.restore()
  254. done()
  255. })
  256. .catch(done)
  257. })
  258. /** @test {ContentController#getRandomContent} */
  259. it(`should get a 500 status from the GET [/random/${content}] route`, done => {
  260. const stub = sinon.stub(Model, 'aggregate')
  261. stub.rejects()
  262. request(app).get(`/random/${content}`)
  263. .expect(500)
  264. .then(() => {
  265. stub.restore()
  266. done()
  267. })
  268. .catch(done)
  269. })
  270. })
  271. /**
  272. * Hook for tearing down the AudioController tests.
  273. * @type {Function}
  274. */
  275. after(done => {
  276. Model.findOneAndRemove({
  277. _id: testContent.id
  278. }).exec()
  279. .then(() => database.disconnect())
  280. .then(() => done())
  281. .catch(done)
  282. })
  283. })
  284. }
  285. const itemTypes = [
  286. ['anime', Anime, testAnime],
  287. ['movie', Movie, testMovie],
  288. ['show', Show, testShow]
  289. ]
  290. itemTypes.map(i => testContentController(...i))