| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- SandboxedModule = require('sandboxed-module')
- sinon = require 'sinon'
- should = require("chai").should()
- MockRequest = require "../helpers/MockRequest"
- MockResponse = require "../helpers/MockResponse"
- modulePath = '../../../../app/js/Features/Subscription/SubscriptionController'
- mockSubscriptions =
- "subscription-123-active":
- uuid: "subscription-123-active"
- plan:
- name: "Gold"
- plan_code: "gold"
- current_period_ends_at: new Date()
- state: "active"
- unit_amount_in_cents: 999
- account:
- account_code: "user-123"
- describe "SubscriptionController sanboxed", ->
- beforeEach ->
- @user = {email:"tom@yahoo.com"}
- @activeRecurlySubscription = mockSubscriptions["subscription-123-active"]
- @SecurityManager =
- getCurrentUser: sinon.stub().callsArgWith(1, null, @user)
- @SubscriptionHandler =
- createSubscription: sinon.stub().callsArgWith(3)
- updateSubscription: sinon.stub().callsArgWith(3)
- reactivateSubscription: sinon.stub().callsArgWith(1)
- cancelSubscription: sinon.stub().callsArgWith(1)
- recurlyCallback: sinon.stub().callsArgWith(1)
- startFreeTrial: sinon.stub()
- @PlansLocator =
- findLocalPlanInSettings: sinon.stub()
- @LimitationsManager =
- userHasSubscriptionOrIsGroupMember: sinon.stub()
- userHasSubscription : sinon.stub()
- @RecurlyWrapper =
- sign: sinon.stub().callsArgWith(1, null, "somthing")
- @SubscriptionViewModelBuilder =
- buildUsersSubscriptionViewModel:sinon.stub().callsArgWith(1, null, @activeRecurlySubscription)
- buildViewModel: sinon.stub()
- @settings =
- coupon_codes:
- upgradeToAnnualPromo:
- student:"STUDENTCODEHERE"
- collaborator:"COLLABORATORCODEHERE"
- apis:
- recurly:
- subdomain:"sl.recurly.com"
- siteUrl: "http://de.sharelatex.dev:3000"
- gaExperiments:{}
- @GeoIpLookup =
- getCurrencyCode:sinon.stub()
- @SubscriptionDomainHandler =
- getDomainLicencePage:sinon.stub()
- @SubscriptionController = SandboxedModule.require modulePath, requires:
- '../../managers/SecurityManager': @SecurityManager
- './SubscriptionHandler': @SubscriptionHandler
- "./PlansLocator": @PlansLocator
- './SubscriptionViewModelBuilder': @SubscriptionViewModelBuilder
- "./LimitationsManager": @LimitationsManager
- "../../infrastructure/GeoIpLookup":@GeoIpLookup
- './RecurlyWrapper': @RecurlyWrapper
- "logger-sharelatex": log:->
- "settings-sharelatex": @settings
- "./SubscriptionDomainHandler":@SubscriptionDomainHandler
- @res = new MockResponse()
- @req = new MockRequest()
- @req.body = {}
- @req.query =
- planCode:"123123"
- @stubbedCurrencyCode = "GBP"
- describe "plansPage", ->
- beforeEach (done) ->
- @req.ip = "1234.3123.3131.333 313.133.445.666 653.5345.5345.534"
- @GeoIpLookup.getCurrencyCode.callsArgWith(1, null, @stubbedCurrencyCode)
- @res.callback = done
- @SubscriptionController.plansPage(@req, @res)
- it "should set the recommended currency from the geoiplookup", (done)->
- @res.renderedVariables.recomendedCurrency.should.equal(@stubbedCurrencyCode)
- @GeoIpLookup.getCurrencyCode.calledWith(@req.ip).should.equal true
- done()
- describe "editBillingDetailsPage", ->
- describe "with a user with a subscription", ->
- beforeEach (done) ->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, true)
- @user.id = @activeRecurlySubscription.account.account_code
- @res.callback = done
- @SubscriptionController.editBillingDetailsPage(@req, @res)
- it "should render the edit billing details page", ->
- @res.rendered.should.equal true
- @res.renderedTemplate.should.equal "subscriptions/edit-billing-details"
- it "should set the correct variables for the template", ->
- should.exist @res.renderedVariables.signature
- @res.renderedVariables.successURL.should.equal "#{@settings.siteUrl}/user/subscription/update"
- @res.renderedVariables.user.id.should.equal @user.id
- describe "with a user without subscription", ->
- beforeEach (done) ->
- @res.callback = done
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
- @SubscriptionController.reactivateSubscription @req, @res
- it "should redirect to the subscription dashboard", ->
- @res.redirected.should.equal true
- @res.redirectedTo.should.equal "/user/subscription"
- describe "paymentPage", ->
- beforeEach ->
- @req.headers = {}
- @GeoIpLookup.getCurrencyCode.callsArgWith(1, null, @stubbedCurrencyCode)
- describe "with a user without a subscription", ->
- beforeEach ->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
- @PlansLocator.findLocalPlanInSettings.returns({})
- describe "with a valid plan code", ->
- it "should render the new subscription page", (done)->
- @res.render = (page, opts)=>
- page.should.equal "subscriptions/new"
- done()
- @SubscriptionController.paymentPage @req, @res
- it "should set the successURL", (done)->
- @req.session._csrf = @csrfToken = "mock-csrf-token"
- @res.render = (page, opts)=>
- url = JSON.parse(opts.subscriptionFormOptions).successURL
- url.should.equal("#{@settings.siteUrl}/user/subscription/create?_csrf=#{@csrfToken}")
- done()
- @SubscriptionController.paymentPage @req, @res
- describe "with a user with subscription", ->
- it "should redirect to the subscription dashboard", (done)->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, true)
- @res.redirect = (url)=>
- url.should.equal "/user/subscription"
- done()
- @SubscriptionController.paymentPage(@req, @res)
- describe "with an invalid plan code", ->
- it "should redirect to the subscription dashboard", (done)->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
- @PlansLocator.findLocalPlanInSettings.returns(null)
- @res.redirect = (url)=>
- url.should.equal "/user/subscription"
- done()
- @SubscriptionController.paymentPage(@req, @res)
- describe "which currency to use", ->
- beforeEach ->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
- @PlansLocator.findLocalPlanInSettings.returns({})
- it "should use the set currency from the query string", (done)->
- @req.query.currency = "EUR"
- @res.render = (page, opts)=>
- opts.currency.should.equal "EUR"
- opts.currency.should.not.equal @stubbedCurrencyCode
- done()
- @SubscriptionController.paymentPage @req, @res
- it "should upercase the currency code", (done)->
- @req.query.currency = "eur"
- @res.render = (page, opts)=>
- opts.currency.should.equal "EUR"
- done()
- @SubscriptionController.paymentPage @req, @res
- it "should use the geo ip currency if non is provided", (done)->
- @req.query.currency = null
- @res.render = (page, opts)=>
- opts.currency.should.equal @stubbedCurrencyCode
- done()
- @SubscriptionController.paymentPage @req, @res
-
- describe "successful_subscription", ->
- beforeEach (done) ->
- @SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel.callsArgWith(1, null, {})
- @res.callback = done
- @SubscriptionController.successful_subscription @req, @res
- describe "userSubscriptionPage", ->
- describe "with a user without a subscription", ->
- beforeEach (done) ->
- @res.callback = done
- @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, false)
- @SubscriptionController.userSubscriptionPage @req, @res
- it "should redirect to the plans page", ->
- @res.redirected.should.equal true
- @res.redirectedTo.should.equal "/user/subscription/plans"
- describe "with a potential domain licence", ->
- beforeEach () ->
- @groupUrl = "/go/over-here"
- @SubscriptionDomainHandler.getDomainLicencePage.returns(@groupUrl)
- describe "without an existing subscription", ->
- beforeEach (done)->
- @res.callback = done
- @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, false)
- @SubscriptionController.userSubscriptionPage @req, @res
- it "should redirect to the group invite url", ->
- @res.redirected.should.equal true
- @res.redirectedTo.should.equal @groupUrl
- describe "with an existing subscription", ->
- beforeEach (done)->
- @res.callback = done
- @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, true)
- @SubscriptionController.userSubscriptionPage @req, @res
- it "should render the dashboard", ->
- @res.renderedTemplate.should.equal "subscriptions/dashboard"
-
- describe "with a user with a paid subscription", ->
- beforeEach (done) ->
- @res.callback = done
- @SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel.callsArgWith(1, null, @activeRecurlySubscription)
- @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, true)
- @SubscriptionController.userSubscriptionPage @req, @res
- it "should render the dashboard", (done)->
- @res.rendered.should.equal true
- @res.renderedTemplate.should.equal "subscriptions/dashboard"
- done()
-
- it "should set the correct subscription details", ->
- @res.renderedVariables.subscription.should.deep.equal @activeRecurlySubscription
- describe "with a user with a free trial", ->
- beforeEach (done) ->
- @res.callback = done
- @SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel.callsArgWith(1, null, @activeRecurlySubscription)
- @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, true)
- @SubscriptionController.userSubscriptionPage @req, @res
- it "should render the dashboard", ->
- @res.renderedTemplate.should.equal "subscriptions/dashboard"
-
- it "should set the correct subscription details", ->
- @res.renderedVariables.subscription.should.deep.equal @activeRecurlySubscription
- describe "when its a custom subscription which is non recurly", ->
- beforeEach ()->
- @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, true, {customAccount:true})
- @SubscriptionController.userSubscriptionPage @req, @res
- it "should redirect to /user/subscription/custom_account", ->
- @res.redirectedTo.should.equal("/user/subscription/custom_account")
- describe "userCustomSubscriptionPage", ->
- beforeEach (done) ->
- @res.callback = done
- @LimitationsManager.userHasSubscriptionOrIsGroupMember.callsArgWith(1, null, true)
- @SubscriptionController.userCustomSubscriptionPage @req, @res
- it "should render the page", (done)->
- @res.rendered.should.equal true
- @res.renderedTemplate.should.equal "subscriptions/custom_account"
- done()
- describe "createSubscription", ->
- beforeEach (done)->
- @res =
- sendStatus:->
- done()
- sinon.spy @res, "sendStatus"
- @subscriptionDetails =
- card:"1234"
- cvv:"123"
- @req.body.recurly_token_id = "1234"
- @req.body.subscriptionDetails = @subscriptionDetails
- @SubscriptionController.createSubscription @req, @res
- it "should send the user and subscriptionId to the handler", (done)->
- @SubscriptionHandler.createSubscription.calledWith(@user, @subscriptionDetails, @req.body.recurly_token_id).should.equal true
- done()
- it "should redurect to the subscription page", (done)->
- @res.sendStatus.calledWith(201).should.equal true
- done()
- describe "updateSubscription via post", ->
- beforeEach (done)->
- @res =
- redirect:->
- done()
- sinon.spy @res, "redirect"
- @plan_code = "1234"
- @req.body.plan_code = @plan_code
- @SubscriptionController.updateSubscription @req, @res
- it "should send the user and subscriptionId to the handler", (done)->
- @SubscriptionHandler.updateSubscription.calledWith(@user, @plan_code).should.equal true
- done()
- it "should redurect to the subscription page", (done)->
- @res.redirect.calledWith("/user/subscription").should.equal true
- done()
- describe "reactivateSubscription", ->
- beforeEach (done)->
- @res =
- redirect:->
- done()
- sinon.spy @res, "redirect"
- @SubscriptionController.reactivateSubscription @req, @res
- it "should tell the handler to reactivate this user", (done)->
- @SubscriptionHandler.reactivateSubscription.calledWith(@user).should.equal true
- done()
- it "should redurect to the subscription page", (done)->
- @res.redirect.calledWith("/user/subscription").should.equal true
- done()
- describe "cancelSubscription", ->
- beforeEach (done)->
- @res =
- redirect:->
- done()
- sinon.spy @res, "redirect"
- @SubscriptionController.cancelSubscription @req, @res
- it "should tell the handler to cancel this user", (done)->
- @SubscriptionHandler.cancelSubscription.calledWith(@user).should.equal true
- done()
- it "should redurect to the subscription page", (done)->
- @res.redirect.calledWith("/user/subscription").should.equal true
- done()
- describe "recurly callback", ->
- describe "with a actionable request", ->
- beforeEach (done)->
- @req =
- body:
- expired_subscription_notification:
- subscription:
- uuid: @activeRecurlySubscription.uuid
- @res = sendStatus:->
- done()
- sinon.spy @res, "sendStatus"
- @SubscriptionController.recurlyCallback @req, @res
- it "should tell the SubscriptionHandler to process the recurly callback", (done)->
- @SubscriptionHandler.recurlyCallback.called.should.equal true
- done()
- it "should send a 200", (done)->
- @res.sendStatus.calledWith(200)
- done()
- describe "with a non-actionable request", ->
- beforeEach (done) ->
- @user.id = @activeRecurlySubscription.account.account_code
- @req =
- body:
- new_subscription_notification:
- subscription:
- uuid: @activeRecurlySubscription.uuid
- @res = sendStatus:->
- done()
- sinon.spy @res, "sendStatus"
- @SubscriptionController.recurlyCallback @req, @res
- it "should not call the subscriptionshandler", ->
- @SubscriptionHandler.recurlyCallback.called.should.equal false
- it "should respond with a 200 status", ->
- @res.sendStatus.calledWith(200)
- describe "renderUpgradeToAnnualPlanPage", ->
- it "should redirect to the plans page if the user does not have a subscription", (done)->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, false)
- @res.redirect = (url)->
- url.should.equal "/user/subscription/plans"
- done()
- @SubscriptionController.renderUpgradeToAnnualPlanPage @req, @res
- it "should pass the plan code to the view - student", (done)->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, true, {planCode:"Student free trial 14 days"})
- @res.render = (view, opts)->
- view.should.equal "subscriptions/upgradeToAnnual"
- opts.planName.should.equal "student"
- done()
- @SubscriptionController.renderUpgradeToAnnualPlanPage @req, @res
- it "should pass the plan code to the view - collaborator", (done)->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, true, {planCode:"free trial for Collaborator free trial 14 days"})
- @res.render = (view, opts)->
- opts.planName.should.equal "collaborator"
- done()
- @SubscriptionController.renderUpgradeToAnnualPlanPage @req, @res
- it "should pass annual as the plan name if the user is already on an annual plan", (done)->
- @LimitationsManager.userHasSubscription.callsArgWith(1, null, true, {planCode:"student annual with free trial"})
- @res.render = (view, opts)->
- opts.planName.should.equal "annual"
- done()
- @SubscriptionController.renderUpgradeToAnnualPlanPage @req, @res
- describe "processUpgradeToAnnualPlan", ->
- beforeEach ->
-
- it "should tell the subscription handler to update the subscription with the annual plan and apply a coupon code", (done)->
- @req.body =
- planName:"student"
- @res.sendStatus = ()=>
- @SubscriptionHandler.updateSubscription.calledWith(@user, "student-annual", "STUDENTCODEHERE").should.equal true
- done()
- @SubscriptionController.processUpgradeToAnnualPlan @req, @res
- it "should get the collaborator coupon code", (done)->
- @req.body =
- planName:"collaborator"
- @res.sendStatus = (url)=>
- @SubscriptionHandler.updateSubscription.calledWith(@user, "collaborator-annual", "COLLABORATORCODEHERE").should.equal true
- done()
- @SubscriptionController.processUpgradeToAnnualPlan @req, @res
|