SubscriptionControllerTests.coffee 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. SandboxedModule = require('sandboxed-module')
  2. sinon = require 'sinon'
  3. Settings = require 'settings-sharelatex'
  4. should = require("chai").should()
  5. MockRequest = require "../helpers/MockRequest"
  6. MockResponse = require "../helpers/MockResponse"
  7. modulePath = '../../../../app/js/Features/Subscription/SubscriptionController'
  8. mockSubscriptions =
  9. "subscription-123-active":
  10. uuid: "subscription-123-active"
  11. plan:
  12. name: "Gold"
  13. plan_code: "gold"
  14. current_period_ends_at: new Date()
  15. state: "active"
  16. unit_amount_in_cents: 999
  17. account:
  18. account_code: "user-123"
  19. describe "SubscriptionController sanboxed", ->
  20. beforeEach ->
  21. @user = {}
  22. @activeRecurlySubscription = mockSubscriptions["subscription-123-active"]
  23. @SecurityManager =
  24. getCurrentUser: sinon.stub().callsArgWith(1, null, @user)
  25. @SubscriptionHandler =
  26. createSubscription: sinon.stub().callsArgWith(2)
  27. updateSubscription: sinon.stub().callsArgWith(3)
  28. reactivateSubscription: sinon.stub().callsArgWith(1)
  29. cancelSubscription: sinon.stub().callsArgWith(1)
  30. recurlyCallback: sinon.stub().callsArgWith(1)
  31. startFreeTrial: sinon.stub()
  32. @PlansLocator =
  33. findLocalPlanInSettings: sinon.stub()
  34. @LimitationsManager =
  35. userHasSubscriptionOrIsGroupMember: sinon.stub()
  36. userHasSubscription : sinon.stub()
  37. @RecurlyWrapper =
  38. sign: sinon.stub().callsArgWith(1, null, "somthing")
  39. @SubscriptionViewModelBuilder =
  40. buildUsersSubscriptionViewModel:sinon.stub().callsArgWith(1, null, @activeRecurlySubscription)
  41. buildViewModel: sinon.stub()
  42. @settings =
  43. coupon_codes:
  44. upgradeToAnnualPromo:
  45. student:"STUDENTCODEHERE"
  46. collaborator:"COLLABORATORCODEHERE"
  47. apis:
  48. recurly:
  49. subdomain:"sl.recurly.com"
  50. siteUrl: "http://www.sharelatex.dev:3000"
  51. @SubscriptionController = SandboxedModule.require modulePath, requires:
  52. '../../managers/SecurityManager': @SecurityManager
  53. './SubscriptionHandler': @SubscriptionHandler
  54. "./PlansLocator": @PlansLocator
  55. './SubscriptionViewModelBuilder': @SubscriptionViewModelBuilder
  56. "./LimitationsManager": @LimitationsManager
  57. './RecurlyWrapper': @RecurlyWrapper
  58. "logger-sharelatex": log:->
  59. "settings-sharelatex": @settings
  60. @res = new MockResponse()
  61. @req = new MockRequest()
  62. @req.body = {}
  63. @req.query =
  64. planCode:"123123"
  65. describe "editBillingDetailsPage", ->
  66. describe "with a user with a subscription", ->
  67. beforeEach (done) ->
  68. @LimitationsManager.userHasSubscription.callsArgWith(1, null, true)
  69. @user.id = @activeRecurlySubscription.account.account_code
  70. @res.callback = done
  71. @SubscriptionController.editBillingDetailsPage(@req, @res)
  72. it "should render the edit billing details page", ->
  73. @res.rendered.should.equal true
  74. @res.renderedTemplate.should.equal "subscriptions/edit-billing-details"
  75. it "should set the correct variables for the template", ->
  76. should.exist @res.renderedVariables.signature
  77. @res.renderedVariables.successURL.should.equal "#{Settings.siteUrl}/user/subscription/update"
  78. @res.renderedVariables.user.id.should.equal @user.id
  79. describe "with a user without subscription", ->
  80. beforeEach (done) ->
  81. @res.callback = done
  82. @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
  83. @SubscriptionController.reactivateSubscription @req, @res
  84. it "should redirect to the subscription dashboard", ->
  85. @res.redirected.should.equal true
  86. @res.redirectedTo.should.equal "/user/subscription"
  87. describe "paymentPage", ->
  88. describe "with a user without a subscription", ->
  89. beforeEach ->
  90. @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
  91. @PlansLocator.findLocalPlanInSettings.returns({})
  92. describe "with a valid plan code", ->
  93. it "should render the new subscription page", (done)->
  94. @res.render = (page, opts)=>
  95. page.should.equal "subscriptions/new"
  96. done()
  97. @SubscriptionController.paymentPage @req, @res
  98. it "should set the successURL", (done)->
  99. @req.session._csrf = @csrfToken = "mock-csrf-token"
  100. @res.render = (page, opts)=>
  101. url = JSON.parse(opts.subscriptionFormOptions).successURL
  102. url.should.equal("#{Settings.siteUrl}/user/subscription/create?_csrf=#{@csrfToken}")
  103. done()
  104. @SubscriptionController.paymentPage @req, @res
  105. describe "with a user with subscription", ->
  106. it "should redirect to the subscription dashboard", (done)->
  107. @LimitationsManager.userHasSubscription.callsArgWith(1, null, true)
  108. @res.redirect = (url)=>
  109. url.should.equal "/user/subscription"
  110. done()
  111. @SubscriptionController.paymentPage(@req, @res)
  112. describe "with an invalid plan code", ->
  113. it "should redirect to the subscription dashboard", (done)->
  114. @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
  115. @PlansLocator.findLocalPlanInSettings.returns(null)
  116. @res.redirect = (url)=>
  117. url.should.equal "/user/subscription"
  118. done()
  119. @SubscriptionController.paymentPage(@req, @res)
  120. describe "successful_subscription", ->
  121. beforeEach (done) ->
  122. @SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel.callsArgWith(1, null, {})
  123. @res.callback = done
  124. @SubscriptionController.successful_subscription @req, @res
  125. describe "userSubscriptionPage", ->
  126. describe "with a user without a subscription", ->
  127. beforeEach (done) ->
  128. @res.callback = done
  129. @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, false)
  130. @SubscriptionController.userSubscriptionPage @req, @res
  131. it "should redirect to the plans page", ->
  132. @res.redirected.should.equal true
  133. @res.redirectedTo.should.equal "/user/subscription/plans"
  134. describe "with a user with a paid subscription", ->
  135. beforeEach (done) ->
  136. @res.callback = done
  137. @SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel.callsArgWith(1, null, @activeRecurlySubscription)
  138. @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, true)
  139. @SubscriptionController.userSubscriptionPage @req, @res
  140. it "should render the dashboard", (done)->
  141. @res.rendered.should.equal true
  142. @res.renderedTemplate.should.equal "subscriptions/dashboard"
  143. done()
  144. it "should set the correct subscription details", ->
  145. @res.renderedVariables.subscription.should.deep.equal @activeRecurlySubscription
  146. describe "with a user with a free trial", ->
  147. beforeEach (done) ->
  148. @res.callback = done
  149. @SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel.callsArgWith(1, null, @activeRecurlySubscription)
  150. @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, true)
  151. @SubscriptionController.userSubscriptionPage @req, @res
  152. it "should render the dashboard", ->
  153. @res.renderedTemplate.should.equal "subscriptions/dashboard"
  154. it "should set the correct subscription details", ->
  155. @res.renderedVariables.subscription.should.deep.equal @activeRecurlySubscription
  156. describe "createSubscription", ->
  157. beforeEach (done)->
  158. @res =
  159. redirect:->
  160. done()
  161. sinon.spy @res, "redirect"
  162. @req.body.recurly_token = "1234"
  163. @SubscriptionController.createSubscription @req, @res
  164. it "should send the user and subscriptionId to the handler", (done)->
  165. @SubscriptionHandler.createSubscription.calledWith(@user, @req.body.recurly_token).should.equal true
  166. done()
  167. it "should redurect to the subscription page", (done)->
  168. @res.redirect.calledWith("/user/subscription/thank-you").should.equal true
  169. done()
  170. describe "updateSubscription via post", ->
  171. beforeEach (done)->
  172. @res =
  173. redirect:->
  174. done()
  175. sinon.spy @res, "redirect"
  176. @plan_code = "1234"
  177. @req.body.plan_code = @plan_code
  178. @SubscriptionController.updateSubscription @req, @res
  179. it "should send the user and subscriptionId to the handler", (done)->
  180. @SubscriptionHandler.updateSubscription.calledWith(@user, @plan_code).should.equal true
  181. done()
  182. it "should redurect to the subscription page", (done)->
  183. @res.redirect.calledWith("/user/subscription").should.equal true
  184. done()
  185. describe "reactivateSubscription", ->
  186. beforeEach (done)->
  187. @res =
  188. redirect:->
  189. done()
  190. sinon.spy @res, "redirect"
  191. @SubscriptionController.reactivateSubscription @req, @res
  192. it "should tell the handler to reactivate this user", (done)->
  193. @SubscriptionHandler.reactivateSubscription.calledWith(@user).should.equal true
  194. done()
  195. it "should redurect to the subscription page", (done)->
  196. @res.redirect.calledWith("/user/subscription").should.equal true
  197. done()
  198. describe "cancelSubscription", ->
  199. beforeEach (done)->
  200. @res =
  201. redirect:->
  202. done()
  203. sinon.spy @res, "redirect"
  204. @SubscriptionController.cancelSubscription @req, @res
  205. it "should tell the handler to cancel this user", (done)->
  206. @SubscriptionHandler.cancelSubscription.calledWith(@user).should.equal true
  207. done()
  208. it "should redurect to the subscription page", (done)->
  209. @res.redirect.calledWith("/user/subscription").should.equal true
  210. done()
  211. describe "recurly callback", ->
  212. describe "with a actionable request", ->
  213. beforeEach (done)->
  214. @req =
  215. body:
  216. expired_subscription_notification:
  217. subscription:
  218. uuid: @activeRecurlySubscription.uuid
  219. @res = send:->
  220. done()
  221. sinon.spy @res, "send"
  222. @SubscriptionController.recurlyCallback @req, @res
  223. it "should tell the SubscriptionHandler to process the recurly callback", (done)->
  224. @SubscriptionHandler.recurlyCallback.called.should.equal true
  225. done()
  226. it "should send a 200", (done)->
  227. @res.send.calledWith(200)
  228. done()
  229. describe "with a non-actionable request", ->
  230. beforeEach (done) ->
  231. @user.id = @activeRecurlySubscription.account.account_code
  232. @req =
  233. body:
  234. new_subscription_notification:
  235. subscription:
  236. uuid: @activeRecurlySubscription.uuid
  237. @res = send:->
  238. done()
  239. sinon.spy @res, "send"
  240. @SubscriptionController.recurlyCallback @req, @res
  241. it "should not call the subscriptionshandler", ->
  242. @SubscriptionHandler.recurlyCallback.called.should.equal false
  243. it "should respond with a 200 status", ->
  244. @res.send.calledWith(200)
  245. describe "renderUpgradeToAnnualPlanPage", ->
  246. it "should redirect to the plans page if the user does not have a subscription", (done)->
  247. @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
  248. @res.redirect = (url)->
  249. url.should.equal "/user/subscription/plans"
  250. done()
  251. @SubscriptionController.renderUpgradeToAnnualPlanPage @req, @res
  252. it "should pass the plan code to the view - student", (done)->
  253. @LimitationsManager.userHasSubscription.callsArgWith(1, null, true, {planCode:"Student free trial 14 days"})
  254. @res.render = (view, opts)->
  255. view.should.equal "subscriptions/upgradeToAnnual"
  256. opts.planName.should.equal "student"
  257. done()
  258. @SubscriptionController.renderUpgradeToAnnualPlanPage @req, @res
  259. it "should pass the plan code to the view - collaborator", (done)->
  260. @LimitationsManager.userHasSubscription.callsArgWith(1, null, true, {planCode:"free trial for Collaborator free trial 14 days"})
  261. @res.render = (view, opts)->
  262. opts.planName.should.equal "collaborator"
  263. done()
  264. @SubscriptionController.renderUpgradeToAnnualPlanPage @req, @res
  265. describe "processUpgradeToAnnualPlan", ->
  266. beforeEach ->
  267. it "should tell the subscription handler to update the subscription with the annual plan and apply a coupon code", (done)->
  268. @req.body =
  269. planName:"student"
  270. @res.send = ()=>
  271. @SubscriptionHandler.updateSubscription.calledWith(@user, "student-annual", "STUDENTCODEHERE").should.equal true
  272. done()
  273. @SubscriptionController.processUpgradeToAnnualPlan @req, @res
  274. it "should get the collaborator coupon code", (done)->
  275. @req.body =
  276. planName:"collaborator"
  277. @res.send = (url)=>
  278. @SubscriptionHandler.updateSubscription.calledWith(@user, "collaborator-annual", "COLLABORATORCODEHERE").should.equal true
  279. done()
  280. @SubscriptionController.processUpgradeToAnnualPlan @req, @res