| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- SandboxedModule = require('sandboxed-module')
- should = require('chai').should()
- sinon = require 'sinon'
- querystring = require 'querystring'
- modulePath = "../../../../app/js/Features/Subscription/SubscriptionHandler"
- mockRecurlySubscriptions =
- "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 "SubscriptionHandler", ->
- beforeEach ->
- @Settings =
- plans : [{
- planCode: "collaborator"
- name: "Collaborator"
- features:
- collaborators: -1
- versioning: true
- }]
- defaultPlanCode :
- collaborators: 0
- versioning: false
- @activeRecurlySubscription = mockRecurlySubscriptions["subscription-123-active"]
- @User = {}
- @user =
- _id: @user_id = "user_id_here_"
- @subscription =
- recurlySubscription_id: @activeRecurlySubscription.uuid
- @RecurlyWrapper =
- getSubscription: sinon.stub().callsArgWith(2, null, @activeRecurlySubscription)
- updateSubscription: sinon.stub().callsArgWith(2, null, @activeRecurlySubscription)
- cancelSubscription: sinon.stub().callsArgWith(1)
- reactivateSubscription: sinon.stub().callsArgWith(1)
- redeemCoupon:sinon.stub().callsArgWith(2)
- createSubscription: sinon.stub().callsArgWith(3, null, @activeRecurlySubscription)
- @DropboxHandler =
- unlinkAccount:sinon.stub().callsArgWith(1)
- @SubscriptionUpdater =
- syncSubscription: sinon.stub().callsArgWith(2)
- startFreeTrial: sinon.stub().callsArgWith(1)
- @LimitationsManager =
- userHasV2Subscription: sinon.stub()
- @EmailHandler =
- sendEmail:sinon.stub()
- @AnalyticsManager =
- recordEvent:sinon.stub()
-
- @SubscriptionHandler = SandboxedModule.require modulePath, requires:
- "./RecurlyWrapper": @RecurlyWrapper
- "settings-sharelatex": @Settings
- '../../models/User': User:@User
- './SubscriptionUpdater': @SubscriptionUpdater
- "logger-sharelatex":{log:->}
- './LimitationsManager':@LimitationsManager
- "../Email/EmailHandler":@EmailHandler
- "../Dropbox/DropboxHandler":@DropboxHandler
- "../../infrastructure/Events": @Events = {emit: sinon.stub()}
- "../Analytics/AnalyticsManager": @AnalyticsManager
- @SubscriptionHandler.syncSubscriptionToUser = sinon.stub().callsArgWith(2)
- describe "createSubscription", ->
- beforeEach ->
- @callback = sinon.stub()
- @subscriptionDetails =
- cvv:"123"
- number:"12345"
- @recurly_token_id = "45555666"
- @SubscriptionHandler.validateNoSubscriptionInRecurly = sinon.stub().yields(null, true)
- describe "successfully", ->
- beforeEach ->
- @SubscriptionHandler.createSubscription(@user, @subscriptionDetails, @recurly_token_id, @callback)
- it "should create the subscription with the wrapper", ->
- @RecurlyWrapper.createSubscription.calledWith(@user, @subscriptionDetails, @recurly_token_id).should.equal true
- it "should sync the subscription to the user", ->
- @SubscriptionUpdater.syncSubscription.calledOnce.should.equal true
- @SubscriptionUpdater.syncSubscription.args[0][0].should.deep.equal @activeRecurlySubscription
- @SubscriptionUpdater.syncSubscription.args[0][1].should.deep.equal @user._id
- describe "when there is already a subscription in Recurly", ->
- beforeEach ->
- @SubscriptionHandler.validateNoSubscriptionInRecurly = sinon.stub().yields(null, false)
- @SubscriptionHandler.createSubscription(@user, @subscriptionDetails, @recurly_token_id, @callback)
-
- it "should return an error", ->
- @callback.calledWith(new Error("user already has subscription in recurly"))
- describe "updateSubscription", ->
- describe "with a user with a subscription", ->
- describe "with a valid plan code", ->
- beforeEach (done) ->
- @plan_code = "collaborator"
- @LimitationsManager.userHasV2Subscription.callsArgWith(1, null, true, @subscription)
- @SubscriptionHandler.updateSubscription(@user, @plan_code, null, done)
- it "should update the subscription", ->
- @RecurlyWrapper.updateSubscription.calledWith(@subscription.recurlySubscription_id).should.equal true
- updateOptions = @RecurlyWrapper.updateSubscription.args[0][1]
- updateOptions.plan_code.should.equal @plan_code
-
- it "should update immediately", ->
- updateOptions = @RecurlyWrapper.updateSubscription.args[0][1]
- updateOptions.timeframe.should.equal "now"
- it "should sync the new subscription to the user", ->
- @SubscriptionUpdater.syncSubscription.calledOnce.should.equal true
- @SubscriptionUpdater.syncSubscription.args[0][0].should.deep.equal @activeRecurlySubscription
- @SubscriptionUpdater.syncSubscription.args[0][1].should.deep.equal @user._id
- describe "with a user without a subscription", ->
- beforeEach (done) ->
- @LimitationsManager.userHasV2Subscription.callsArgWith(1, null, false)
- @SubscriptionHandler.updateSubscription(@user, @plan_code, null, done)
- it "should redirect to the subscription dashboard", ->
- @RecurlyWrapper.updateSubscription.called.should.equal false
- @SubscriptionHandler.syncSubscriptionToUser.called.should.equal false
- describe "with a coupon code", ->
- beforeEach (done) ->
- @plan_code = "collaborator"
- @coupon_code = "1231312"
- @LimitationsManager.userHasV2Subscription.callsArgWith(1, null, true, @subscription)
- @SubscriptionHandler.updateSubscription(@user, @plan_code, @coupon_code, done)
- it "should get the users account", ->
- @RecurlyWrapper.getSubscription.calledWith(@activeRecurlySubscription.uuid).should.equal true
- it "should redeme the coupon", (done)->
- @RecurlyWrapper.redeemCoupon.calledWith(@activeRecurlySubscription.account.account_code, @coupon_code).should.equal true
- done()
- it "should update the subscription", ->
- @RecurlyWrapper.updateSubscription.calledWith(@subscription.recurlySubscription_id).should.equal true
- updateOptions = @RecurlyWrapper.updateSubscription.args[0][1]
- updateOptions.plan_code.should.equal @plan_code
- describe "cancelSubscription", ->
- describe "with a user without a subscription", ->
- beforeEach (done) ->
- @LimitationsManager.userHasV2Subscription.callsArgWith(1, null, false, @subscription)
- @SubscriptionHandler.cancelSubscription @user, done
- it "should redirect to the subscription dashboard", ->
- @RecurlyWrapper.cancelSubscription.called.should.equal false
- describe "with a user with a subscription", ->
- beforeEach (done) ->
- @LimitationsManager.userHasV2Subscription.callsArgWith(1, null, true, @subscription)
- @SubscriptionHandler.cancelSubscription @user, done
- it "should cancel the subscription", ->
- @RecurlyWrapper.cancelSubscription.called.should.equal true
- @RecurlyWrapper.cancelSubscription.calledWith(@subscription.recurlySubscription_id).should.equal true
- it "should trigger the cancel subscription event", ->
- @Events.emit.calledWith("cancelSubscription", @user._id).should.equal true
- describe "reactiveRecurlySubscription", ->
- describe "with a user without a subscription", ->
- beforeEach (done) ->
- @LimitationsManager.userHasV2Subscription.callsArgWith(1, null, false, @subscription)
- @SubscriptionHandler.reactivateSubscription @user, done
- it "should redirect to the subscription dashboard", ->
- @RecurlyWrapper.reactivateSubscription.called.should.equal false
- describe "with a user with a subscription", ->
- beforeEach (done) ->
- @LimitationsManager.userHasV2Subscription.callsArgWith(1, null, true, @subscription)
- @SubscriptionHandler.reactivateSubscription @user, done
- it "should reactivate the subscription", ->
- @RecurlyWrapper.reactivateSubscription.called.should.equal true
- @RecurlyWrapper.reactivateSubscription.calledWith(@subscription.recurlySubscription_id).should.equal true
- describe "recurlyCallback", ->
- describe "with an actionable request", ->
- beforeEach (done) ->
- @user.id = @activeRecurlySubscription.account.account_code
- @User.findById = (userId, callback) =>
- userId.should.equal @user.id
- callback null, @user
- @SubscriptionHandler.recurlyCallback(@activeRecurlySubscription, done)
- it "should request the affected subscription from the API", ->
- @RecurlyWrapper.getSubscription.calledWith(@activeRecurlySubscription.uuid).should.equal true
- it "should request the account details of the subscription", ->
- options = @RecurlyWrapper.getSubscription.args[0][1]
- options.includeAccount.should.equal true
- it "should sync the subscription to the user", ->
- @SubscriptionUpdater.syncSubscription.calledOnce.should.equal true
- @SubscriptionUpdater.syncSubscription.args[0][0].should.deep.equal @activeRecurlySubscription
- @SubscriptionUpdater.syncSubscription.args[0][1].should.deep.equal @user._id
- describe "validateNoSubscriptionInRecurly", ->
- beforeEach ->
- @subscriptions = []
- @RecurlyWrapper.listAccountActiveSubscriptions = sinon.stub().yields(null, @subscriptions)
- @SubscriptionUpdater.syncSubscription = sinon.stub().yields()
- @callback = sinon.stub()
- describe "with no subscription in recurly", ->
- beforeEach ->
- @subscriptions.push @subscription = { "mock": "subscription" }
- @SubscriptionHandler.validateNoSubscriptionInRecurly @user_id, @callback
- it "should call RecurlyWrapper.listAccountActiveSubscriptions with the user id", ->
- @RecurlyWrapper.listAccountActiveSubscriptions
- .calledWith(@user_id)
- .should.equal true
- it "should sync the subscription", ->
- @SubscriptionUpdater.syncSubscription
- .calledWith(@subscription, @user_id)
- .should.equal true
- it "should call the callback with valid == false", ->
- @callback.calledWith(null, false).should.equal true
- describe "with a subscription in recurly", ->
- beforeEach ->
- @SubscriptionHandler.validateNoSubscriptionInRecurly @user_id, @callback
- it "should not sync the subscription", ->
- @SubscriptionUpdater.syncSubscription
- .called
- .should.equal false
- it "should call the callback with valid == true", ->
- @callback.calledWith(null, true).should.equal true
|