mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-30 19:06:59 -05:00
bb6262483f
Address some code review feedback Correct error code in test Don't try to send emails to empty addresses Add tests for subscriptions Add tests for Next Steps email Fix specs Add reason for disabled test
1751 lines
85 KiB
CoffeeScript
1751 lines
85 KiB
CoffeeScript
async = require 'async'
|
|
config = require '../../../server_config'
|
|
require '../common'
|
|
appUtils = require '../../../app/core/utils' # Must come after require /common
|
|
utils = require '../utils'
|
|
mongoose = require 'mongoose'
|
|
TRAVIS = process.env.COCO_TRAVIS_TEST
|
|
nockUtils = require '../nock-utils'
|
|
User = require '../../../server/models/User'
|
|
Payment = require '../../../server/models/Payment'
|
|
Prepaid = require '../../../server/models/Prepaid'
|
|
request = require '../request'
|
|
|
|
subPrice = 100
|
|
subGems = 3500
|
|
subGemsBrazil = 1500
|
|
|
|
# sample data that comes in through the webhook when you subscribe
|
|
invoiceChargeSampleEvent = {
|
|
id: 'evt_155TBeKaReE7xLUdrKM72O5R',
|
|
created: 1417574898,
|
|
livemode: false,
|
|
type: 'invoice.payment_succeeded',
|
|
data: {
|
|
object: {
|
|
date: 1417574897,
|
|
id: 'in_155TBdKaReE7xLUdv8z8ipWl',
|
|
period_start: 1417574897,
|
|
period_end: 1417574897,
|
|
lines: {},
|
|
subtotal: 100,
|
|
total: 100,
|
|
customer: 'cus_5Fz9MVWP2bDPGV',
|
|
object: 'invoice',
|
|
attempted: true,
|
|
closed: true,
|
|
forgiven: false,
|
|
paid: true,
|
|
livemode: false,
|
|
attempt_count: 1,
|
|
amount_due: 100,
|
|
currency: 'usd',
|
|
starting_balance: 0,
|
|
ending_balance: 0,
|
|
next_payment_attempt: null,
|
|
webhooks_delivered_at: null,
|
|
charge: 'ch_155TBdKaReE7xLUdRU0WcMzR',
|
|
discount: null,
|
|
application_fee: null,
|
|
subscription: 'sub_5Fz99gXrBtreNe',
|
|
metadata: {},
|
|
statement_description: null,
|
|
description: null,
|
|
receipt_number: null
|
|
}
|
|
},
|
|
object: 'event',
|
|
pending_webhooks: 1,
|
|
request: 'iar_5Fz9c4BZJyNNsM',
|
|
api_version: '2015-02-18'
|
|
}
|
|
|
|
customerSubscriptionDeletedSampleEvent = {
|
|
id: 'evt_155Tj4KaReE7xLUdpoMx0UaA',
|
|
created: 1417576970,
|
|
livemode: false,
|
|
type: 'customer.subscription.deleted',
|
|
data: {
|
|
object: {
|
|
id: 'sub_5FziOkege03vT7',
|
|
plan: [Object],
|
|
object: 'subscription',
|
|
start: 1417576967,
|
|
status: 'canceled',
|
|
customer: 'cus_5Fzi54gMvGG9Px',
|
|
cancel_at_period_end: true,
|
|
current_period_start: 1417576967,
|
|
current_period_end: 1420255367,
|
|
ended_at: 1417576970,
|
|
trial_start: null,
|
|
trial_end: null,
|
|
canceled_at: 1417576970,
|
|
quantity: 1,
|
|
application_fee_percent: null,
|
|
discount: null,
|
|
metadata: {}
|
|
}
|
|
},
|
|
object: 'event',
|
|
pending_webhooks: 1,
|
|
request: 'iar_5FziYQJ4oQdL6w',
|
|
api_version: '2015-02-18'
|
|
}
|
|
|
|
|
|
describe '/db/user, editing stripe property', ->
|
|
afterEach nockUtils.teardownNock
|
|
|
|
stripe = require('stripe')(config.stripe.secretKey)
|
|
userURL = getURL('/db/user')
|
|
webhookURL = getURL('/stripe/webhook')
|
|
headers = {'X-Change-Plan': 'true'}
|
|
|
|
it 'clears the db first', (done) ->
|
|
clearModels [User, Payment], (err) ->
|
|
throw err if err
|
|
resetUserIDCounter(100000) # because fixtures depend on dependable user ids
|
|
done()
|
|
|
|
it 'denies anonymous users trying to subscribe', (done) ->
|
|
request.get getURL('/auth/whoami'), (err, res, body) ->
|
|
body = JSON.parse(body)
|
|
body.stripe = { planID: 'basic', token: '12345' }
|
|
request.put {uri: userURL, json: body, headers: headers}, (err, res, body) ->
|
|
expect(res.statusCode).toBe 403
|
|
done()
|
|
|
|
it 'denies username-only users trying to subscribe', utils.wrap (done) ->
|
|
user = yield utils.initUser({ email: undefined, })
|
|
yield utils.loginUser(user)
|
|
[res, body] = yield request.putAsync(getURL("/db/user/#{user.id}"), { headers, json: { stripe: { planID: 'basic', token: '12345' } } })
|
|
expect(res.statusCode).toBe(403)
|
|
done()
|
|
|
|
#- shared data between tests
|
|
joeData = null
|
|
firstSubscriptionID = null
|
|
|
|
it 'returns client error when a token fails to charge', (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-1.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4000000000000002', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
stripeTokenID = token.id
|
|
loginJoe (joe) ->
|
|
joeData = joe.toObject()
|
|
joeData.stripe = {
|
|
token: stripeTokenID
|
|
planID: 'basic'
|
|
}
|
|
request.put {uri: userURL, json: joeData, headers: headers }, (err, res, body) ->
|
|
expect(res.statusCode).toBe(402)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'creates a subscription when you put a token and plan', (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-2.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
stripeTokenID = token.id
|
|
loginJoe (joe) ->
|
|
joeData = joe.toObject()
|
|
joeData.stripe = {
|
|
token: stripeTokenID
|
|
planID: 'basic'
|
|
}
|
|
request.put {uri: userURL, json: joeData, headers: headers }, (err, res, body) ->
|
|
joeData = body
|
|
expect(res.statusCode).toBe(200)
|
|
expect(joeData.purchased.gems).toBe(subGems)
|
|
expect(joeData.stripe.customerID).toBeDefined()
|
|
expect(firstSubscriptionID = joeData.stripe.subscriptionID).toBeDefined()
|
|
expect(joeData.stripe.planID).toBe('basic')
|
|
expect(joeData.stripe.token).toBeUndefined()
|
|
nockDone()
|
|
done()
|
|
|
|
it 'records a payment through the webhook', (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-3.json', (err, nockDone) ->
|
|
# Don't even want to think about hooking in tests to webhooks, so... put in some data manually
|
|
stripe.invoices.list {customer: joeData.stripe.customerID}, (err, invoices) ->
|
|
expect(invoices.data.length).toBe(1)
|
|
event = _.cloneDeep(invoiceChargeSampleEvent)
|
|
event.data.object = invoices.data[0]
|
|
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
expect(res.statusCode).toBe(201)
|
|
Payment.find {}, (err, payments) ->
|
|
expect(payments.length).toBe(1)
|
|
User.findById joeData._id, (err, user) ->
|
|
expect(user.get('purchased').gems).toBe(subGems)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'schedules the stripe subscription to be cancelled when stripe.planID is removed from the user', (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-4.json', {keep: {cancel_at_period_end: true}}, (err, nockDone) ->
|
|
delete joeData.stripe.planID
|
|
request.put {uri: userURL, json: joeData, headers: headers }, (err, res, body) ->
|
|
joeData = body
|
|
expect(res.statusCode).toBe(200)
|
|
expect(joeData.stripe.subscriptionID).toBeDefined()
|
|
expect(joeData.stripe.planID).toBeUndefined()
|
|
expect(joeData.stripe.customerID).toBeDefined()
|
|
stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
|
|
expect(customer.subscriptions.data.length).toBe(1)
|
|
expect(customer.subscriptions.data[0].cancel_at_period_end).toBe(true)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'allows you to sign up again using the same customer ID as before, no token necessary', (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-5.json', (err, nockDone) ->
|
|
joeData.stripe.planID = 'basic'
|
|
request.put {uri: userURL, json: joeData, headers: headers }, (err, res, body) ->
|
|
joeData = body
|
|
|
|
expect(res.statusCode).toBe(200)
|
|
expect(joeData.stripe.customerID).toBeDefined()
|
|
expect(joeData.stripe.subscriptionID).toBeDefined()
|
|
expect(joeData.stripe.subscriptionID).not.toBe(firstSubscriptionID)
|
|
expect(joeData.stripe.planID).toBe('basic')
|
|
nockDone()
|
|
done()
|
|
|
|
it 'will not have immediately created new payments when signing back up from a cancelled subscription', (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-6.json', (err, nockDone) ->
|
|
stripe.invoices.list {customer: joeData.stripe.customerID}, (err, invoices) ->
|
|
expect(invoices.data.length).toBe(2)
|
|
expect(invoices.data[0].total).toBe(0)
|
|
event = _.cloneDeep(invoiceChargeSampleEvent)
|
|
event.data.object = invoices.data[0]
|
|
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
expect(res.statusCode).toBe(200)
|
|
Payment.find {}, (err, payments) ->
|
|
expect(payments.length).toBe(1)
|
|
User.findById joeData._id, (err, user) ->
|
|
expect(user.get('purchased').gems).toBe(subGems)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'deletes the subscription from the user object when an event about it comes through the webhook', (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-7.json', (err, nockDone) ->
|
|
stripe.customers.retrieveSubscription joeData.stripe.customerID, joeData.stripe.subscriptionID, (err, subscription) ->
|
|
event = _.cloneDeep(customerSubscriptionDeletedSampleEvent)
|
|
event.data.object = subscription
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
User.findById joeData._id, (err, user) ->
|
|
expect(user.get('purchased').gems).toBe(subGems)
|
|
expect(user.get('stripe').subscriptionID).toBeUndefined()
|
|
expect(user.get('stripe').planID).toBeUndefined()
|
|
nockDone()
|
|
done()
|
|
|
|
it "updates the customer's email when you change the user's email", (done) ->
|
|
nockUtils.setupNock 'db-user-sub-test-8.json', {keep: {email: true}}, (err, nockDone) ->
|
|
joeData.email = 'newEmail@gmail.com'
|
|
request.put {uri: userURL, json: joeData, headers: headers }, (err, res, body) ->
|
|
f = -> stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
|
|
expect(customer.email).toBe('newEmail@gmail.com')
|
|
nockDone()
|
|
done()
|
|
setTimeout(f, 500) # bit of a race condition here, response returns before stripe has been updated
|
|
|
|
|
|
describe 'Subscriptions', ->
|
|
# TODO: Test recurring billing via webhooks
|
|
# TODO: Test error rollbacks, Stripe is authority
|
|
|
|
stripe = require('stripe')(config.stripe.secretKey)
|
|
userURL = getURL('/db/user')
|
|
webhookURL = getURL('/stripe/webhook')
|
|
headers = {'X-Change-Plan': 'true'}
|
|
invoicesWebHooked = {}
|
|
afterEach nockUtils.teardownNock
|
|
|
|
# Start helpers
|
|
|
|
getSubscribedQuantity = (numSponsored) ->
|
|
return 0 if numSponsored < 1
|
|
if numSponsored <= 10
|
|
Math.round(numSponsored * subPrice * 0.8)
|
|
else
|
|
Math.round(10 * subPrice * 0.8 + (numSponsored - 10) * subPrice * 0.6)
|
|
|
|
getUnsubscribedQuantity = (numSponsored) ->
|
|
return 0 if numSponsored < 1
|
|
if numSponsored <= 1
|
|
subPrice
|
|
else if numSponsored <= 11
|
|
Math.round(subPrice + (numSponsored - 1) * subPrice * 0.8)
|
|
else
|
|
Math.round(subPrice + 10 * subPrice * 0.8 + (numSponsored - 11) * subPrice * 0.6)
|
|
|
|
verifyNotRecipient = (userID, done) ->
|
|
User.findById userID, (err, user) ->
|
|
expect(err).toBeNull()
|
|
if stripeInfo = user.get('stripe')
|
|
expect(stripeInfo.sponsorID).toBeUndefined()
|
|
done()
|
|
|
|
verifyNotSponsoring = (sponsorID, recipientID, done) ->
|
|
# console.log 'verifyNotSponsoring', sponsorID, recipientID
|
|
User.findById sponsorID, (err, sponsor) ->
|
|
expect(err).toBeNull()
|
|
expect(sponsor).not.toBeNull()
|
|
return done() unless sponsor
|
|
stripeInfo = sponsor.get('stripe')
|
|
return done() unless stripeInfo?.customerID?
|
|
checkSubscriptions = (starting_after, done) ->
|
|
options = {}
|
|
options.starting_after = starting_after if starting_after
|
|
stripe.customers.listSubscriptions stripeInfo.customerID, options, (err, subscriptions) ->
|
|
expect(err).toBeNull()
|
|
for subscription in subscriptions.data
|
|
if subscription.plan.id is 'basic'
|
|
expect(subscription.metadata.id).not.toEqual(recipientID)
|
|
if subscription.plan.id is 'incremental'
|
|
expect(subscription.metadata.id).toEqual(sponsorID)
|
|
if subscriptions.has_more
|
|
checkSubscriptions subscriptions.data[subscriptions.data.length - 1].id, done
|
|
else
|
|
done()
|
|
checkSubscriptions null, done
|
|
|
|
verifySponsorship = (sponsorUserID, sponsoredUserID, done) ->
|
|
# console.log 'verifySponsorship', sponsorUserID, sponsoredUserID
|
|
User.findById sponsorUserID, (err, user) ->
|
|
expect(err).toBeNull()
|
|
expect(user).not.toBeNull()
|
|
return done() unless user
|
|
sponsorStripe = user.get('stripe')
|
|
sponsorCustomerID = sponsorStripe.customerID
|
|
numSponsored = sponsorStripe.recipients?.length
|
|
expect(sponsorCustomerID).toBeDefined()
|
|
expect(sponsorStripe.sponsorSubscriptionID).toBeDefined()
|
|
expect(sponsorStripe.token).toBeUndefined()
|
|
expect(numSponsored).toBeGreaterThan(0)
|
|
|
|
# Verify Stripe sponsor subscription data
|
|
return done() unless sponsorCustomerID and sponsorStripe.sponsorSubscriptionID
|
|
stripe.customers.retrieveSubscription sponsorCustomerID, sponsorStripe.sponsorSubscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription?).toBe(true)
|
|
return done() unless subscription?
|
|
expect(subscription.plan.amount).toEqual(1)
|
|
expect(subscription.customer).toEqual(sponsorCustomerID)
|
|
expect(subscription.quantity).toEqual(appUtils.getSponsoredSubsAmount(subPrice, numSponsored, sponsorStripe.subscriptionID?))
|
|
|
|
# Verify sponsor payment
|
|
# May be greater than expected amount due to multiple subscribes and unsubscribes
|
|
paymentQuery =
|
|
purchaser: mongoose.Types.ObjectId(sponsorUserID)
|
|
recipient: mongoose.Types.ObjectId(sponsorUserID)
|
|
"stripe.customerID": sponsorCustomerID
|
|
"stripe.subscriptionID": sponsorStripe.sponsorSubscriptionID
|
|
expectedAmount = appUtils.getSponsoredSubsAmount(subPrice, numSponsored, sponsorStripe.subscriptionID?)
|
|
Payment.find paymentQuery, (err, payments) ->
|
|
expect(err).toBeNull()
|
|
expect(payments).not.toBeNull()
|
|
amount = 0
|
|
for payment in payments
|
|
amount += payment.get('amount')
|
|
expect(payment.get('gems')).toBeUndefined()
|
|
|
|
# NOTE: this amount may be greater than the expected amount due to proration accumlation
|
|
# NOTE: during localy execution, this is usually only 1-2 cents
|
|
expect(amount).toBeGreaterThan(expectedAmount - 50)
|
|
|
|
# Find recipient info from sponsor stripe data
|
|
for r in sponsorStripe.recipients
|
|
if r.userID is sponsoredUserID
|
|
recipientInfo = r
|
|
break
|
|
expect(recipientInfo).toBeDefined()
|
|
expect(recipientInfo.subscriptionID).toBeDefined()
|
|
expect(recipientInfo.subscriptionID).not.toEqual(sponsorStripe.sponsorSubscriptionID)
|
|
expect(recipientInfo.couponID).toEqual('free')
|
|
|
|
# Verify Stripe recipient subscription data
|
|
return done() unless sponsorCustomerID and recipientInfo.subscriptionID
|
|
stripe.customers.retrieveSubscription sponsorCustomerID, recipientInfo.subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription.plan.amount).toEqual(subPrice)
|
|
expect(subscription.customer).toEqual(sponsorCustomerID)
|
|
expect(subscription.quantity).toEqual(1)
|
|
expect(subscription.metadata.id).toEqual(sponsoredUserID)
|
|
expect(subscription.discount.coupon.id).toEqual(recipientInfo.couponID)
|
|
|
|
# Verify recipient internal data
|
|
User.findById sponsoredUserID, (err, recipient) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = recipient.get('stripe')
|
|
expect(stripeInfo.sponsorID).toEqual(sponsorUserID)
|
|
unless stripeInfo.sponsorSubscriptionID?
|
|
expect(stripeInfo.customerID).toBeUndefined()
|
|
expect(stripeInfo.token).toBeUndefined()
|
|
expect(recipient.get('purchased').gems).toBeGreaterThan(subGems - 1)
|
|
expect(recipient.isPremium()).toEqual(true)
|
|
|
|
# Verify recipient payment
|
|
# TODO: Not accurate enough when resubscribing a user
|
|
paymentQuery =
|
|
purchaser: mongoose.Types.ObjectId(sponsorUserID)
|
|
recipient: mongoose.Types.ObjectId(sponsoredUserID)
|
|
"stripe.customerID": sponsorCustomerID
|
|
Payment.findOne paymentQuery, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment).not.toBeNull()
|
|
return done() if payment is null
|
|
expect(payment.get('amount')).toEqual(0)
|
|
expect(payment.get('gems')).toBeGreaterThan(subGems - 1)
|
|
done()
|
|
|
|
subscribeUser = (user, token, prepaidCode, done) ->
|
|
requestBody = user.toObject()
|
|
requestBody.stripe =
|
|
planID: 'basic'
|
|
requestBody.stripe.token = token.id if token?
|
|
requestBody.stripe.prepaidCode = prepaidCode if prepaidCode?
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
return done() if err
|
|
expect(res.statusCode).toBe(200)
|
|
expect(body.stripe).toBeDefined()
|
|
return done() unless body.stripe
|
|
expect(body.stripe.customerID).toBeDefined()
|
|
expect(body.stripe.planID).toBe('basic')
|
|
expect(body.stripe.token).toBeUndefined()
|
|
if prepaidCode?
|
|
expect(body.stripe.prepaidCode).toEqual(prepaidCode)
|
|
expect(body.stripe.couponID).toEqual('free')
|
|
expect(body.purchased.gems).toBeGreaterThan(subGems - 1)
|
|
User.findById user.id, (err, user) ->
|
|
stripeInfo = user.get('stripe')
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(stripeInfo.planID).toBe('basic')
|
|
expect(stripeInfo.token).toBeUndefined()
|
|
if prepaidCode?
|
|
expect(stripeInfo.prepaidCode).toEqual(prepaidCode)
|
|
expect(stripeInfo.couponID).toEqual('free')
|
|
expect(user.get('purchased').gems).toBeGreaterThan(subGems - 1)
|
|
done()
|
|
|
|
unsubscribeUser = (user, done) ->
|
|
requestBody = user.toObject()
|
|
delete requestBody.stripe.planID
|
|
delete requestBody.stripe.prepaidCode
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
User.findById user.id, (err, user) ->
|
|
expect(user.get('stripe').customerID).toBeDefined()
|
|
expect(user.get('stripe').planID).toBeUndefined()
|
|
expect(user.get('stripe').token).toBeUndefined()
|
|
expect(user.get('stripe').subscriptionID).toBeDefined()
|
|
return done() unless user.get('stripe').subscriptionID
|
|
stripe.customers.retrieveSubscription user.get('stripe').customerID, user.get('stripe').subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
expect(subscription?.cancel_at_period_end).toEqual(true)
|
|
done()
|
|
|
|
subscribeRecipients = (sponsor, recipients, token, done) ->
|
|
# console.log 'subscribeRecipients', sponsor.id, (recipient.id for recipient in recipients), token?
|
|
requestBody = sponsor.toObject()
|
|
requestBody.stripe =
|
|
subscribeEmails: (recipient.get('email') for recipient in recipients)
|
|
requestBody.stripe.token = token.id if token?
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
return done() if err
|
|
expect(res.statusCode).toBe(200)
|
|
expect(body.stripe?.customerID).toBeDefined()
|
|
updatedUser = body
|
|
|
|
# Call webhooks for invoices
|
|
options = customer: body.stripe?.customerID, limit: 100
|
|
stripe.invoices.list options, (err, invoices) ->
|
|
expect(err).toBeNull()
|
|
expect(invoices).not.toBeNull()
|
|
return done(updatedUser) unless invoices?
|
|
expect(invoices.has_more).toEqual(false)
|
|
makeWebhookCall = (invoice) ->
|
|
(callback) ->
|
|
event = _.cloneDeep(invoiceChargeSampleEvent)
|
|
event.data.object = invoice
|
|
# console.log 'Calling webhook', event.type, invoice.id
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
callback err
|
|
webhookTasks = []
|
|
for invoice in invoices.data
|
|
unless invoice.id of invoicesWebHooked
|
|
invoicesWebHooked[invoice.id] = true
|
|
webhookTasks.push makeWebhookCall(invoice)
|
|
async.series webhookTasks, (err, results) ->
|
|
expect(err?).toEqual(false)
|
|
done(updatedUser)
|
|
|
|
unsubscribeRecipient = (sponsor, recipient, done) ->
|
|
# console.log 'unsubscribeRecipient', sponsor.id, recipient.id
|
|
stripeInfo = sponsor.get('stripe')
|
|
customerID = stripeInfo.customerID
|
|
expect(stripeInfo.recipients).toBeDefined()
|
|
return done() unless stripeInfo.recipients
|
|
for r in stripeInfo.recipients
|
|
if r.userID is recipient.id
|
|
subscriptionID = r.subscriptionID
|
|
break
|
|
expect(customerID).toBeDefined()
|
|
expect(subscriptionID).toBeDefined()
|
|
|
|
# Find Stripe subscription
|
|
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
|
|
# Call unsubscribe API
|
|
requestBody = sponsor.toObject()
|
|
requestBody.stripe = unsubscribeEmail: recipient.get('email')
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
done()
|
|
|
|
# Subscribe a bunch of recipients at once, used for bulk discount testing
|
|
class SubbedRecipients
|
|
constructor: (@count, @toVerify) ->
|
|
@index = 0
|
|
@recipients = []
|
|
|
|
length: ->
|
|
@recipients.length
|
|
|
|
get: (i) ->
|
|
@recipients[i]
|
|
|
|
createRecipients: (done) ->
|
|
return done() if @recipients.length is @count
|
|
createNewUser (user) =>
|
|
@recipients.push user
|
|
@createRecipients done
|
|
|
|
subRecipients: (user1, token=null, done) ->
|
|
# console.log 'subRecipients', user1.id, @recipients.length
|
|
User.findById user1.id, (err, user1) =>
|
|
subscribeRecipients user1, @recipients, token, (updatedUser) =>
|
|
verifyIndex = 0
|
|
verify = =>
|
|
return done(updatedUser) if verifyIndex >= @toVerify.length
|
|
verifySponsorship user1.id, @recipients[verifyIndex].id, =>
|
|
verifyIndex++
|
|
verify()
|
|
verify()
|
|
|
|
# End helpers
|
|
|
|
|
|
# TODO: Use beforeAll()
|
|
it 'Clear database users and payments', (done) ->
|
|
clearModels [User, Payment], (err) ->
|
|
throw err if err
|
|
done()
|
|
|
|
describe 'Personal', ->
|
|
it 'Subscribe user with new token', (done) ->
|
|
nockUtils.setupNock 'sub-test-01.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'User delete unsubscribes', (done) ->
|
|
nockUtils.setupNock 'sub-test-02.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
customerID = user1.get('stripe').customerID
|
|
subscriptionID = user1.get('stripe').subscriptionID
|
|
request.del {uri: "#{userURL}/#{user1.id}"}, (err, res) ->
|
|
expect(err).toBeNull()
|
|
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription?.cancel_at_period_end).toEqual(true)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'User subscribes, deletes themselves, subscription ends', (done) ->
|
|
nockUtils.setupNock 'sub-test-03.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
# Subscribe user
|
|
subscribeUser user1, token, null, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
customerID = user1.get('stripe').customerID
|
|
subscriptionID = user1.get('stripe').subscriptionID
|
|
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
# Delete user
|
|
request.del {uri: "#{userURL}/#{user1.id}"}, (err, res) ->
|
|
expect(err).toBeNull()
|
|
# Simulate Stripe subscription deleted via webhook
|
|
event = _.cloneDeep(customerSubscriptionDeletedSampleEvent)
|
|
event.data.object = subscription
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toEqual(200)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribe with prepaid, then delete', (done) ->
|
|
nockUtils.setupNock 'sub-test-04.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
|
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
|
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
unsubscribeUser user1, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.prepaidCode).toEqual(prepaid.get('code'))
|
|
expect(stripeInfo.subscriptionID).toBeDefined()
|
|
return done() unless stripeInfo.subscriptionID
|
|
|
|
# Delete subscription
|
|
stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
event = _.cloneDeep(customerSubscriptionDeletedSampleEvent)
|
|
event.data.object = subscription
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.planID).toBeUndefined()
|
|
expect(stripeInfo.prepaidCode).toBeUndefined()
|
|
expect(stripeInfo.subscriptionID).toBeUndefined()
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribe normally, subscribe with valid prepaid', (done) ->
|
|
nockUtils.setupNock 'sub-test-05.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
subscribeUser user1, token, null, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
|
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
|
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
customerID = user1.get('stripe').customerID
|
|
subscriptionID = user1.get('stripe').subscriptionID
|
|
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
return done() unless subscription
|
|
expect(subscription.discount?.coupon?.id).toEqual('free')
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribe with coupon, subscribe with valid prepaid', (done) ->
|
|
nockUtils.setupNock 'sub-test-06.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
requestBody = user1.toObject()
|
|
requestBody.stripe =
|
|
planID: 'basic'
|
|
token: token.id
|
|
couponID: '20pct'
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, updatedUser) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
|
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
|
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
customerID = user1.get('stripe').customerID
|
|
subscriptionID = user1.get('stripe').subscriptionID
|
|
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
expect(subscription?.discount?.coupon?.id).toEqual('free')
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribe with prepaid, then cancel', (done) ->
|
|
nockUtils.setupNock 'sub-test-07.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
|
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
|
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
unsubscribeUser user1, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe').prepaidCode).toEqual(prepaid.get('code'))
|
|
nockDone()
|
|
done()
|
|
|
|
it 'User2 subscribes with used prepaid', (done) ->
|
|
nockUtils.setupNock 'sub-test-08.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
loginNewUser (user2) ->
|
|
requestBody = user2.toObject()
|
|
requestBody.stripe =
|
|
planID: 'basic'
|
|
requestBody.stripe.prepaidCode = prepaid.code
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(403)
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
|
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
|
nockDone()
|
|
done()
|
|
|
|
it 'User2 subscribes with same active prepaid', (done) ->
|
|
nockUtils.setupNock 'sub-test-09.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 2, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
loginNewUser (user2) ->
|
|
subscribeUser user2, null, prepaid.code, ->
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
expect(prepaid.get('redeemers').length).toEqual(2)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Admin subscribes self with valid prepaid', (done) ->
|
|
nockUtils.setupNock 'sub-test-10.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
|
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
|
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Admin subscribes self with valid prepaid twice', (done) ->
|
|
nockUtils.setupNock 'sub-test-11.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 2, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
Prepaid.findById prepaid._id, (err, prepaid) ->
|
|
expect(err).toBeNull()
|
|
prepaid.set 'redeemers', [{userID: user1.get('_id'), date: new Date()}]
|
|
prepaid.save (err) ->
|
|
expect(err).toBeNull()
|
|
requestBody = user1.toObject()
|
|
requestBody.stripe =
|
|
planID: 'basic'
|
|
requestBody.stripe.prepaidCode = prepaid.get('code')
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(403)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Admin subscribes self with invalid prepaid', (done) ->
|
|
nockUtils.setupNock 'sub-test-12.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
requestBody = user1.toObject()
|
|
requestBody.stripe =
|
|
planID: 'basic'
|
|
requestBody.stripe.prepaidCode = 'MattMatt'
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(404)
|
|
nockDone()
|
|
done()
|
|
|
|
describe 'Sponsored', ->
|
|
it 'Unsubscribed user1 subscribes user2', (done) ->
|
|
nockUtils.setupNock 'sub-test-13.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
verifySponsorship user1.id, user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
|
|
it 'Recipient user delete unsubscribes', (done) ->
|
|
nockUtils.setupNock 'sub-test-14.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
expect(updatedUser).not.toBeNull()
|
|
return done() unless updatedUser
|
|
customerID = updatedUser.stripe?.customerID
|
|
expect(customerID).toBeDefined()
|
|
subscriptionID = updatedUser.stripe?.recipients[0]?.subscriptionID
|
|
expect(subscriptionID).toBeDefined()
|
|
return done() unless customerID and subscriptionID
|
|
loginUser user2, (user2) ->
|
|
request.del {uri: "#{userURL}/#{user2.id}"}, (err, res) ->
|
|
expect(err).toBeNull()
|
|
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
|
expect(err).not.toBeNull()
|
|
expect(subscription).toBeNull()
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(_.isEmpty(user1.get('stripe').recipients))
|
|
stripe.customers.retrieveSubscription customerID, user1.get('stripe').sponsorSubscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription.quantity).toEqual(0)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribed user1 subscribes user2, one token', (done) ->
|
|
nockUtils.setupNock 'sub-test-15.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
subscribeRecipients user1, [user2], null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe').subscriptionID).toBeDefined()
|
|
expect(user1.isPremium()).toEqual(true)
|
|
verifySponsorship user1.id, user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Clean up sponsorships upon sub cancel after setup sponsor sub fails', (done) ->
|
|
nockUtils.setupNock 'sub-test-16.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
subscribeRecipients user1, [user2], null, (updatedUser) ->
|
|
|
|
# Delete user1 sponsorSubscriptionID to simulate failed sponsor sub
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = _.cloneDeep(user1.get('stripe') ? {})
|
|
delete stripeInfo.sponsorSubscriptionID
|
|
user1.set 'stripe', stripeInfo
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
|
|
User.findById user1.id, (err, user1) ->
|
|
unsubscribeRecipient user1, user2, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe').subscriptionID).toBeDefined()
|
|
expect(_.isEmpty(user1.get('stripe').recipients)).toEqual(true)
|
|
expect(user1.isPremium()).toEqual(true)
|
|
User.findById user2.id, (err, user2) ->
|
|
verifyNotSponsoring user1.id, user2.id, ->
|
|
verifyNotRecipient user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
|
|
it 'Unsubscribed user1 unsubscribes user2 and their sub ends', (done) ->
|
|
nockUtils.setupNock 'sub-test-17.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
unsubscribeRecipient user1, user2, ->
|
|
verifyNotSponsoring user1.id, user2.id, ->
|
|
verifyNotRecipient user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
|
|
it 'Unsubscribed user1 immediately resubscribes user2, one token', (done) ->
|
|
nockUtils.setupNock 'sub-test-18.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
unsubscribeRecipient user1, user2, ->
|
|
subscribeRecipients user1, [user2], null, (updatedUser) ->
|
|
verifySponsorship user1.id, user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Sponsored user2 subscribes their sponsor user1', (done) ->
|
|
nockUtils.setupNock 'sub-test-19.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
loginUser user2, (user2) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
subscribeRecipients user2, [user1], token, (updatedUser) ->
|
|
verifySponsorship user1.id, user2.id, ->
|
|
verifySponsorship user2.id, user1.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Unsubscribed user1 subscribes user1', (done) ->
|
|
nockUtils.setupNock 'sub-test-20.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
|
|
requestBody = user1.toObject()
|
|
requestBody.stripe =
|
|
subscribeEmails: [user1.get('email')]
|
|
token: token.id
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
|
|
User.findById user1.id, (err, user) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user.get('stripe')
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(stripeInfo.planID).toBeUndefined()
|
|
expect(stripeInfo.subscriptionID).toBeUndefined()
|
|
expect(stripeInfo.recipients.length).toEqual(0)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribed user1 unsubscribes user2', (done) ->
|
|
nockUtils.setupNock 'sub-test-21.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
subscribeRecipients user1, [user2], null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
unsubscribeRecipient user1, user2, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe').subscriptionID).toBeDefined()
|
|
expect(user1.isPremium()).toEqual(true)
|
|
User.findById user2.id, (err, user2) ->
|
|
verifyNotSponsoring user1.id, user2.id, ->
|
|
verifyNotRecipient user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribed user1 subscribes user2, unsubscribes themselves', (done) ->
|
|
nockUtils.setupNock 'sub-test-22.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
subscribeRecipients user1, [user2], null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
unsubscribeUser user1, ->
|
|
verifySponsorship user1.id, user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Sponsored user2 tries to subscribe', (done) ->
|
|
nockUtils.setupNock 'sub-test-23.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
loginUser user2, (user2) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
requestBody = user2.toObject()
|
|
requestBody.stripe =
|
|
token: token.id
|
|
planID: 'basic'
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(403)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Sponsored user2 tries to subscribe with valid prepaid', (done) ->
|
|
nockUtils.setupNock 'sub-test-24.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
loginUser user2, (user2) ->
|
|
user2.set('permissions', ['admin'])
|
|
user2.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user2.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
requestBody = user2.toObject()
|
|
requestBody.stripe =
|
|
planID: 'basic'
|
|
prepaidCode: prepaid.code
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(403)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Sponsored user2 tries to unsubscribe', (done) ->
|
|
nockUtils.setupNock 'sub-test-25.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
loginUser user2, (user2) ->
|
|
requestBody = user2.toObject()
|
|
requestBody.stripe =
|
|
recipient: user2.id
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
verifySponsorship user1.id, user2.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Cancel sponsor subscription with 2 recipient subscriptions, then subscribe 1 old and 1 new', (done) ->
|
|
nockUtils.setupNock 'sub-test-26.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user3) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2, user3], token, (updatedUser) ->
|
|
customerID = updatedUser?.stripe?.customerID
|
|
subscriptionID = updatedUser?.stripe?.sponsorSubscriptionID
|
|
expect(customerID).toBeDefined()
|
|
expect(subscriptionID).toBeDefined()
|
|
return done() unless customerID and subscriptionID
|
|
|
|
# Find Stripe sponsor subscription
|
|
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
|
|
# Cancel Stripe sponsor subscription
|
|
stripe.customers.cancelSubscription customerID, subscriptionID, (err) ->
|
|
expect(err).toBeNull()
|
|
|
|
# Simulate customer.subscription.deleted webhook event for sponsor subscription
|
|
event = _.cloneDeep(customerSubscriptionDeletedSampleEvent)
|
|
event.data.object = subscription
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
|
|
# Should have 2 cancelled recipient subs with cancel_at_period_end = true
|
|
# TODO: is this correct, or do we terminate recipient subs immediately now?
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.sponsorSubscriptionID).toBeUndefined()
|
|
expect(stripeInfo.recipients).toBeUndefined()
|
|
stripe.customers.listSubscriptions stripeInfo.customerID, (err, subscriptions) ->
|
|
expect(err).toBeNull()
|
|
expect(subscriptions.data.length).toEqual(2)
|
|
for sub in subscriptions.data
|
|
expect(sub.plan.id).toEqual('basic')
|
|
expect(sub.cancel_at_period_end).toEqual(true)
|
|
|
|
# Subscribe user3 back
|
|
User.findById user1.id, (err, user1) ->
|
|
subscribeRecipients user1, [user3], null, (updatedUser) ->
|
|
verifySponsorship user1.id, user3.id, ->
|
|
|
|
# Subscribe new user4
|
|
createNewUser (user4) ->
|
|
loginUser user1, (user1) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
subscribeRecipients user1, [user4], null, (updatedUser) ->
|
|
verifySponsorship user1.id, user4.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribing two users separately yields proration payment', (done) ->
|
|
nockUtils.setupNock 'sub-test-27.json', (err, nockDone) ->
|
|
# TODO: Use test plan with low duration + setTimeout to test delay between 2 subscribes
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user3) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
subscribeRecipients user1, [user3], null, (updatedUser) ->
|
|
# TODO: What do we expect invoices to show here?
|
|
stripe.invoices.list {customer: updatedUser.stripe.customerID}, (err, invoices) ->
|
|
expect(err).toBeNull()
|
|
|
|
# Verify for proration invoice
|
|
foundProratedInvoice = false
|
|
for invoice in invoices.data
|
|
line = invoice.lines.data[0]
|
|
if line.type is 'invoiceitem' and line.proration
|
|
totalAmount = appUtils.getSponsoredSubsAmount(subPrice, 2, false)
|
|
expect(invoice.total).toBeLessThan(totalAmount)
|
|
expect(invoice.total).toEqual(totalAmount - subPrice)
|
|
Payment.findOne "stripe.invoiceID": invoice.id, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment.get('amount')).toEqual(invoice.total)
|
|
nockDone()
|
|
done()
|
|
foundProratedInvoice = true
|
|
break
|
|
unless foundProratedInvoice
|
|
expect(foundProratedInvoice).toEqual(true)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Invalid subscribeEmails', (done) ->
|
|
nockUtils.setupNock 'sub-test-28.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
requestBody = user1.toObject()
|
|
requestBody.stripe =
|
|
subscribeEmails: ['invalid@user.com', 'notemailformat', '', null, undefined]
|
|
requestBody.stripe.token = token.id
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
expect(body.stripe).toBeDefined()
|
|
User.findById user1.id, (err, sponsor) ->
|
|
expect(err).toBeNull()
|
|
expect(sponsor.get('stripe')).toBeDefined()
|
|
expect(sponsor.get('stripe').customerID).toBeDefined()
|
|
expect(sponsor.get('stripe').sponsorSubscriptionID).toBeDefined()
|
|
expect(sponsor.get('stripe').recipients?.length).toEqual(0)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'User1 subscribes user2 then themselves', (done) ->
|
|
nockUtils.setupNock 'sub-test-29.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
verifySponsorship user1.id, user2.id, ->
|
|
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
subscribeUser user1, token, null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe').subscriptionID).toBeDefined()
|
|
expect(user1.isPremium()).toEqual(true)
|
|
|
|
stripe.customers.listSubscriptions user1.get('stripe').customerID, (err, subscriptions) ->
|
|
expect(err).toBeNull()
|
|
expect(subscriptions.data.length).toEqual(3)
|
|
for sub in subscriptions.data
|
|
if sub.plan.id is 'basic'
|
|
if sub.discount?.coupon?.id is 'free'
|
|
expect(sub.metadata?.id).toEqual(user2.id)
|
|
else
|
|
expect(sub.metadata?.id).toEqual(user1.id)
|
|
else
|
|
expect(sub.plan.id).toEqual('incremental')
|
|
expect(sub.metadata?.id).toEqual(user1.id)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribe with prepaid, then get sponsored', (done) ->
|
|
nockUtils.setupNock 'sub-test-30.json', (err, nockDone) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('permissions', ['admin'])
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.isAdmin()).toEqual(true)
|
|
createPrepaid 'subscription', 1, 0, (err, res, prepaid) ->
|
|
expect(err).toBeNull()
|
|
subscribeUser user1, null, prepaid.code, ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user2) ->
|
|
requestBody = user2.toObject()
|
|
requestBody.stripe =
|
|
token: token.id
|
|
subscribeEmails: [user1.get('emailLower')]
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
User.findById user1.id, (err, user) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user.get('stripe')
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(stripeInfo.planID).toBeDefined()
|
|
expect(stripeInfo.subscriptionID).toBeDefined()
|
|
expect(stripeInfo.sponsorID).toBeUndefined()
|
|
nockDone()
|
|
done()
|
|
|
|
|
|
describe 'Bulk discounts', ->
|
|
# Bulk discount algorithm (includes personal sub):
|
|
# 1 100%
|
|
# 2-11 80%
|
|
# 12+ 60%
|
|
|
|
it 'Unsubscribed user1 subscribes two users', (done) ->
|
|
nockUtils.setupNock 'sub-test-31.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
createNewUser (user3) ->
|
|
createNewUser (user2) ->
|
|
loginNewUser (user1) ->
|
|
subscribeRecipients user1, [user2, user3], token, (updatedUser) ->
|
|
verifySponsorship user1.id, user2.id, ->
|
|
verifySponsorship user1.id, user3.id, ->
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribed user1 subscribes 2 users, unsubscribes 2', (done) ->
|
|
nockUtils.setupNock 'sub-test-32.json', (err, nockDone) ->
|
|
recipientCount = 2
|
|
recipientsToVerify = [0, 1]
|
|
recipients = new SubbedRecipients recipientCount, recipientsToVerify
|
|
|
|
# Create recipients
|
|
recipients.createRecipients ->
|
|
expect(recipients.length()).toEqual(recipientCount)
|
|
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
|
|
# Create sponsor user
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
|
|
# Subscribe recipients
|
|
recipients.subRecipients user1, null, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
|
|
# Unsubscribe recipient0
|
|
unsubscribeRecipient user1, recipients.get(0), ->
|
|
User.findById user1.id, (err, user1) ->
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.recipients.length).toEqual(1)
|
|
verifyNotSponsoring user1.id, recipients.get(0).id, ->
|
|
verifyNotRecipient recipients.get(0).id, ->
|
|
stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
expect(subscription?.quantity).toEqual(getSubscribedQuantity(1))
|
|
|
|
# Unsubscribe recipient1
|
|
unsubscribeRecipient user1, recipients.get(1), ->
|
|
User.findById user1.id, (err, user1) ->
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.recipients.length).toEqual(0)
|
|
verifyNotSponsoring user1.id, recipients.get(1).id, ->
|
|
verifyNotRecipient recipients.get(1).id, ->
|
|
stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
return done() unless subscription
|
|
expect(subscription.quantity).toEqual(0)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'Subscribed user1 subscribes 3 users, unsubscribes 2, themselves, then 1', (done) ->
|
|
nockUtils.setupNock 'sub-test-33.json', (err, nockDone) ->
|
|
recipientCount = 3
|
|
recipientsToVerify = [0, 1, 2]
|
|
recipients = new SubbedRecipients recipientCount, recipientsToVerify
|
|
|
|
# Create recipients
|
|
recipients.createRecipients ->
|
|
expect(recipients.length()).toEqual(recipientCount)
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
|
|
# Create sponsor user
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, (updatedUser) ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
|
|
# Subscribe recipients
|
|
recipients.subRecipients user1, null, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
|
|
# Unsubscribe first recipient
|
|
unsubscribeRecipient user1, recipients.get(0), ->
|
|
User.findById user1.id, (err, user1) ->
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(stripeInfo.sponsorSubscriptionID).toBeDefined()
|
|
return done() unless stripeInfo.customerID and stripeInfo.sponsorSubscriptionID
|
|
expect(stripeInfo.recipients.length).toEqual(recipientCount - 1)
|
|
verifyNotSponsoring user1.id, recipients.get(0).id, ->
|
|
verifyNotRecipient recipients.get(0).id, ->
|
|
stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
expect(subscription?.quantity).toEqual(getSubscribedQuantity(recipientCount - 1))
|
|
|
|
# Unsubscribe second recipient
|
|
unsubscribeRecipient user1, recipients.get(1), ->
|
|
User.findById user1.id, (err, user1) ->
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.recipients.length).toEqual(recipientCount - 2)
|
|
verifyNotSponsoring user1.id, recipients.get(1).id, ->
|
|
verifyNotRecipient recipients.get(1).id, ->
|
|
stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
expect(subscription?.quantity).toEqual(getSubscribedQuantity(recipientCount - 2))
|
|
|
|
# Unsubscribe self
|
|
User.findById user1.id, (err, user1) ->
|
|
unsubscribeUser user1, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.planID).toBeUndefined()
|
|
|
|
# Unsubscribe third recipient
|
|
verifySponsorship user1.id, recipients.get(2).id, ->
|
|
unsubscribeRecipient user1, recipients.get(2), ->
|
|
User.findById user1.id, (err, user1) ->
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo.recipients.length).toEqual(recipientCount - 3)
|
|
verifyNotSponsoring user1.id, recipients.get(2).id, ->
|
|
verifyNotRecipient recipients.get(2).id, ->
|
|
stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
expect(subscription?.quantity).toEqual(getSubscribedQuantity(recipientCount - 3))
|
|
nockDone()
|
|
done()
|
|
|
|
# xit 'Unsubscribed user1 subscribes 13 users, unsubcribes 2', (done) ->
|
|
# nockUtils.setupNock 'sub-test-34.json', (err, nockDone) ->
|
|
# # TODO: Hits the Stripe error 'Request rate limit exceeded'.
|
|
# # TODO: Need a better test for 12+ bulk discounts. Or, we could update the bulk disount logic.
|
|
# # TODO: verify interim invoices?
|
|
# recipientCount = 13
|
|
# recipientsToVerify = [0, 1, 10, 11, 12]
|
|
# recipients = new SubbedRecipients recipientCount, recipientsToVerify
|
|
#
|
|
# # Create recipients
|
|
# recipients.createRecipients ->
|
|
# expect(recipients.length()).toEqual(recipientCount)
|
|
#
|
|
# stripe.tokens.create {
|
|
# card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
# }, (err, token) ->
|
|
#
|
|
# # Create sponsor user
|
|
# loginNewUser (user1) ->
|
|
#
|
|
# # Subscribe recipients
|
|
# recipients.subRecipients user1, token, ->
|
|
# User.findById user1.id, (err, user1) ->
|
|
#
|
|
# # Unsubscribe first recipient
|
|
# unsubscribeRecipient user1, recipients.get(0), ->
|
|
# User.findById user1.id, (err, user1) ->
|
|
#
|
|
# stripeInfo = user1.get('stripe')
|
|
# expect(stripeInfo.recipients.length).toEqual(recipientCount - 1)
|
|
# verifyNotSponsoring user1.id, recipients.get(0).id, ->
|
|
# verifyNotRecipient recipients.get(0).id, ->
|
|
# stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, (err, subscription) ->
|
|
# expect(err).toBeNull()
|
|
# expect(subscription).not.toBeNull()
|
|
# expect(subscription.quantity).toEqual(getUnsubscribedQuantity(recipientCount - 1))
|
|
#
|
|
# # Unsubscribe last recipient
|
|
# unsubscribeRecipient user1, recipients.get(recipientCount - 1), ->
|
|
# User.findById user1.id, (err, user1) ->
|
|
# stripeInfo = user1.get('stripe')
|
|
# expect(stripeInfo.recipients.length).toEqual(recipientCount - 2)
|
|
# verifyNotSponsoring user1.id, recipients.get(recipientCount - 1).id, ->
|
|
# verifyNotRecipient recipients.get(recipientCount - 1).id, ->
|
|
# stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, (err, subscription) ->
|
|
# expect(err).toBeNull()
|
|
# expect(subscription).not.toBeNull()
|
|
# numSponsored = recipientCount - 2
|
|
# if numSponsored <= 1
|
|
# expect(subscription.quantity).toEqual(subPrice)
|
|
# else if numSponsored <= 11
|
|
# expect(subscription.quantity).toEqual(subPrice + (numSponsored - 1) * subPrice * 0.8)
|
|
# else
|
|
# expect(subscription.quantity).toEqual(subPrice + 10 * subPrice * 0.8 + (numSponsored - 11) * subPrice * 0.6)
|
|
# nockDone()
|
|
# done()
|
|
|
|
describe 'APIs', ->
|
|
subscriptionURL = getURL('/db/subscription')
|
|
|
|
it 'year_sale', (done) ->
|
|
nockUtils.setupNock 'sub-test-35.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
expect(user1.get('stripe')?.free).toBeUndefined()
|
|
requestBody =
|
|
stripe:
|
|
token: token.id
|
|
timestamp: new Date()
|
|
request.put {uri: "#{subscriptionURL}/-/year_sale", json: requestBody, headers: headers }, (err, res) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo).toBeDefined()
|
|
return done() unless stripeInfo
|
|
endDate = new Date()
|
|
endDate.setUTCFullYear(endDate.getUTCFullYear() + 1)
|
|
expect(stripeInfo.free).toEqual(endDate.toISOString().substring(0, 10))
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(user1.get('purchased')?.gems).toEqual(subGems*12)
|
|
Payment.findOne 'stripe.customerID': stripeInfo.customerID, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment).toBeTruthy()
|
|
expect(payment.get('gems')).toEqual(subGems*12)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'year_sale when stripe.free === true', (done) ->
|
|
nockUtils.setupNock 'sub-test-36.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('stripe', {free: true})
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe')?.free).toEqual(true)
|
|
requestBody =
|
|
stripe:
|
|
token: token.id
|
|
timestamp: new Date()
|
|
request.put {uri: "#{subscriptionURL}/-/year_sale", json: requestBody, headers: headers }, (err, res) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo).toBeDefined()
|
|
return done() unless stripeInfo
|
|
endDate = new Date()
|
|
endDate.setUTCFullYear(endDate.getUTCFullYear() + 1)
|
|
expect(stripeInfo.free).toEqual(endDate.toISOString().substring(0, 10))
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(user1.get('purchased')?.gems).toEqual(subGems*12)
|
|
Payment.findOne 'stripe.customerID': stripeInfo.customerID, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment).toBeTruthy()
|
|
expect(payment.get('gems')).toEqual(subGems*12)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'year_sale when stripe.free < today', (done) ->
|
|
nockUtils.setupNock 'sub-test-37.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
endDate = new Date()
|
|
endDate.setUTCFullYear(endDate.getUTCFullYear() - 1)
|
|
user1.set('stripe', {free: endDate.toISOString().substring(0, 10)})
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe')?.free).toEqual(endDate.toISOString().substring(0, 10))
|
|
requestBody =
|
|
stripe:
|
|
token: token.id
|
|
timestamp: new Date()
|
|
request.put {uri: "#{subscriptionURL}/-/year_sale", json: requestBody, headers: headers }, (err, res) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo).toBeDefined()
|
|
return done() unless stripeInfo
|
|
endDate = new Date()
|
|
endDate.setUTCFullYear(endDate.getUTCFullYear() + 1)
|
|
expect(stripeInfo.free).toEqual(endDate.toISOString().substring(0, 10))
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(user1.get('purchased')?.gems).toEqual(subGems*12)
|
|
Payment.findOne 'stripe.customerID': stripeInfo.customerID, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment).toBeTruthy()
|
|
expect(payment.get('gems')).toEqual(subGems*12)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'year_sale when stripe.free > today', (done) ->
|
|
nockUtils.setupNock 'sub-test-38.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
endDate = new Date()
|
|
endDate.setUTCDate(endDate.getUTCDate() + 5)
|
|
user1.set('stripe', {free: endDate.toISOString().substring(0, 10)})
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
expect(user1.get('stripe')?.free).toEqual(endDate.toISOString().substring(0, 10))
|
|
requestBody =
|
|
stripe:
|
|
token: token.id
|
|
timestamp: new Date()
|
|
request.put {uri: "#{subscriptionURL}/-/year_sale", json: requestBody, headers: headers }, (err, res) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo).toBeDefined()
|
|
return done() unless stripeInfo
|
|
endDate = new Date()
|
|
endDate.setUTCFullYear(endDate.getUTCFullYear() + 1)
|
|
endDate.setUTCDate(endDate.getUTCDate() + 5)
|
|
expect(stripeInfo.free).toEqual(endDate.toISOString().substring(0, 10))
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(user1.get('purchased')?.gems).toEqual(subGems*12)
|
|
Payment.findOne 'stripe.customerID': stripeInfo.customerID, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment).toBeTruthy()
|
|
expect(payment.get('gems')).toEqual(subGems*12)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'year_sale with monthly sub', (done) ->
|
|
nockUtils.setupNock 'sub-test-39.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
subscribeUser user1, token, null, ->
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
stripe.customers.retrieveSubscription stripeInfo.customerID, stripeInfo.subscriptionID, (err, subscription) ->
|
|
expect(err).toBeNull()
|
|
expect(subscription).not.toBeNull()
|
|
stripeSubscriptionPeriodEndDate = new Date(subscription.current_period_end * 1000)
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
requestBody =
|
|
stripe:
|
|
token: token.id
|
|
timestamp: new Date()
|
|
request.put {uri: "#{subscriptionURL}/-/year_sale", json: requestBody, headers: headers }, (err, res) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
User.findById user1.id, (err, user1) ->
|
|
expect(err).toBeNull()
|
|
stripeInfo = user1.get('stripe')
|
|
expect(stripeInfo).toBeDefined()
|
|
return done() unless stripeInfo
|
|
endDate = stripeSubscriptionPeriodEndDate
|
|
endDate.setUTCFullYear(endDate.getUTCFullYear() + 1)
|
|
expect(stripeInfo.free).toEqual(endDate.toISOString().substring(0, 10))
|
|
expect(stripeInfo.customerID).toBeDefined()
|
|
expect(user1.get('purchased')?.gems).toEqual(subGems+subGems*12)
|
|
Payment.findOne 'stripe.customerID': stripeInfo.customerID, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment).toBeTruthy()
|
|
expect(payment.get('gems')).toEqual(subGems*12)
|
|
nockDone()
|
|
done()
|
|
|
|
it 'year_sale with sponsored sub', (done) ->
|
|
nockUtils.setupNock 'sub-test-40.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('stripe', {sponsorID: 'dummyID'})
|
|
user1.save (err, user1) ->
|
|
expect(err).toBeNull()
|
|
requestBody =
|
|
stripe:
|
|
token: token.id
|
|
timestamp: new Date()
|
|
request.put {uri: "#{subscriptionURL}/-/year_sale", json: requestBody, headers: headers }, (err, res) ->
|
|
expect(err).toBeNull()
|
|
nockDone()
|
|
done()
|
|
|
|
describe 'Countries', ->
|
|
it 'Brazil users get Brazil coupon', (done) ->
|
|
nockUtils.setupNock 'sub-test-41.json', (err, nockDone) ->
|
|
stripe.tokens.create {
|
|
card: { number: '4242424242424242', exp_month: 12, exp_year: 2030, cvc: '123' }
|
|
}, (err, token) ->
|
|
loginNewUser (user1) ->
|
|
user1.set('country', 'brazil')
|
|
user1.save (err, user1) ->
|
|
requestBody = user1.toObject()
|
|
requestBody.stripe =
|
|
planID: 'basic'
|
|
token: token.id
|
|
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, updatedUser) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(200)
|
|
expect(updatedUser.country).toBe('brazil')
|
|
expect(updatedUser.purchased.gems).toBe(subGemsBrazil)
|
|
expect(updatedUser.stripe.planID).toBe('basic')
|
|
expect(updatedUser.stripe.customerID).toBeTruthy()
|
|
|
|
stripe.invoices.list {customer: updatedUser.stripe.customerID}, (err, invoices) ->
|
|
expect(err).toBeNull()
|
|
expect(invoices).not.toBeNull()
|
|
expect(invoices.data.length).toBe(1)
|
|
expect(invoices.data[0].discount?.coupon).toBeTruthy()
|
|
expect(invoices.data[0].discount?.coupon?.id).toBe('brazil')
|
|
expect(invoices.data[0].total).toBeLessThan(subPrice)
|
|
|
|
# Now we hit our webhook to see if the right Payment is made.
|
|
event = _.cloneDeep(invoiceChargeSampleEvent)
|
|
event.data.object = invoices.data[0]
|
|
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
|
expect(err).toBeNull()
|
|
expect(res.statusCode).toBe(201)
|
|
Payment.findOne 'stripe.customerID': updatedUser.stripe.customerID, (err, payment) ->
|
|
expect(err).toBeNull()
|
|
expect(payment).toBeTruthy()
|
|
return done() unless payment
|
|
expect(payment.get('gems')).toEqual(subGemsBrazil)
|
|
expect(payment.get('amount')).toBeLessThan(subPrice)
|
|
nockDone()
|
|
done()
|