Files
habitica/test/api/unit/libs/payments/amazon/checkout.test.js
Matteo Pagliazzi 6d34319455 Stripe: upgrade module and API, switch to Checkout (#12785)
* upgrade stripe module

* switch stripe api to latest version

* fix api version in tests

* start upgrading client and server

* client: switch to redirect

* implement checkout session creation for gems, start implementing webhooks

* stripe: start refactoring one time payments

* working gems and gift payments

* start adding support for subscriptions

* stripe: migrate subscriptions and fix cancelling sub

* allow upgrading group plans

* remove console.log statements

* group plans: upgrade from static page / create new one

* fix #11885, correct group plan modal title

* silence more stripe webhooks

* fix group plans redirects

* implement editing payment method

* start cleaning up code

* fix(stripe): update in-code docs, fix eslint issues

* subscriptions tests

* remove and skip old tests

* skip integration tests

* fix client build

* stripe webhooks: throw error if request fails

* subscriptions: correctly pass groupId

* remove console.log

* stripe: add unit tests for one time payments

* wip: stripe checkout tests

* stripe createCheckoutSession unit tests

* stripe createCheckoutSession unit tests

* stripe createCheckoutSession unit tests (editing card)

* fix existing webhooks tests

* add new webhooks tests

* add more webhooks tests

* fix lint

* stripe integration tests

* better error handling when retrieving customer from stripe

* client: remove unused strings and improve error handling

* payments: limit gift message length (server)

* payments: limit gift message length (client)

* fix redirects when payment is cancelled

* add back "subUpdateCard" string

* fix redirects when editing a sub card, use proper names for products, check subs when gifting
2020-12-14 15:59:17 +01:00

229 lines
6.7 KiB
JavaScript

import { model as User } from '../../../../../../website/server/models/user';
import amzLib from '../../../../../../website/server/libs/payments/amazon';
import payments from '../../../../../../website/server/libs/payments/payments';
import common from '../../../../../../website/common';
import apiError from '../../../../../../website/server/libs/apiError';
import * as gems from '../../../../../../website/server/libs/payments/gems';
const { i18n } = common;
describe('Amazon Payments - Checkout', () => {
const subKey = 'basic_3mo';
let user; let orderReferenceId; let
headers; const gemsBlockKey = '21gems'; const gemsBlock = common.content.gems[gemsBlockKey];
let setOrderReferenceDetailsSpy;
let confirmOrderReferenceSpy;
let authorizeSpy;
let closeOrderReferenceSpy;
let paymentBuyGemsStub;
let paymentCreateSubscritionStub;
let amount = gemsBlock.price / 100;
function expectOrderReferenceSpy () {
expect(setOrderReferenceDetailsSpy).to.be.calledOnce;
expect(setOrderReferenceDetailsSpy).to.be.calledWith({
AmazonOrderReferenceId: orderReferenceId,
OrderReferenceAttributes: {
OrderTotal: {
CurrencyCode: amzLib.constants.CURRENCY_CODE,
Amount: amount,
},
SellerNote: amzLib.constants.SELLER_NOTE,
SellerOrderAttributes: {
SellerOrderId: common.uuid(),
StoreName: amzLib.constants.STORE_NAME,
},
},
});
}
function expectAuthorizeSpy () {
expect(authorizeSpy).to.be.calledOnce;
expect(authorizeSpy).to.be.calledWith({
AmazonOrderReferenceId: orderReferenceId,
AuthorizationReferenceId: common.uuid().substring(0, 32),
AuthorizationAmount: {
CurrencyCode: amzLib.constants.CURRENCY_CODE,
Amount: amount,
},
SellerAuthorizationNote: amzLib.constants.SELLER_NOTE,
TransactionTimeout: 0,
CaptureNow: true,
});
}
function expectAmazonStubs () {
expectOrderReferenceSpy();
expect(confirmOrderReferenceSpy).to.be.calledOnce;
expect(confirmOrderReferenceSpy).to.be.calledWith({ AmazonOrderReferenceId: orderReferenceId });
expectAuthorizeSpy();
expect(closeOrderReferenceSpy).to.be.calledOnce;
expect(closeOrderReferenceSpy).to.be.calledWith({ AmazonOrderReferenceId: orderReferenceId });
}
beforeEach(() => {
user = new User();
headers = {};
orderReferenceId = 'orderReferenceId';
setOrderReferenceDetailsSpy = sinon.stub(amzLib, 'setOrderReferenceDetails');
setOrderReferenceDetailsSpy.resolves({});
confirmOrderReferenceSpy = sinon.stub(amzLib, 'confirmOrderReference');
confirmOrderReferenceSpy.resolves({});
authorizeSpy = sinon.stub(amzLib, 'authorize');
authorizeSpy.resolves({});
closeOrderReferenceSpy = sinon.stub(amzLib, 'closeOrderReference');
closeOrderReferenceSpy.resolves({});
paymentBuyGemsStub = sinon.stub(payments, 'buyGems');
paymentBuyGemsStub.resolves({});
paymentCreateSubscritionStub = sinon.stub(payments, 'createSubscription');
paymentCreateSubscritionStub.resolves({});
sinon.stub(common, 'uuid').returns('uuid-generated');
sandbox.stub(gems, 'validateGiftMessage');
});
afterEach(() => {
amzLib.setOrderReferenceDetails.restore();
amzLib.confirmOrderReference.restore();
amzLib.authorize.restore();
amzLib.closeOrderReference.restore();
payments.buyGems.restore();
payments.createSubscription.restore();
common.uuid.restore();
});
function expectBuyGemsStub (paymentMethod, gift) {
expect(paymentBuyGemsStub).to.be.calledOnce;
const expectedArgs = {
user,
paymentMethod,
headers,
};
if (gift) {
expectedArgs.gift = gift;
expectedArgs.gemsBlock = undefined;
expect(gems.validateGiftMessage).to.be.calledOnce;
expect(gems.validateGiftMessage).to.be.calledWith(gift, user);
} else {
expect(gems.validateGiftMessage).to.not.be.called;
expectedArgs.gemsBlock = gemsBlock;
}
expect(paymentBuyGemsStub).to.be.calledWith(expectedArgs);
}
it('should purchase gems', async () => {
sinon.stub(user, 'canGetGems').resolves(true);
await amzLib.checkout({
user, orderReferenceId, headers, gemsBlock: gemsBlockKey,
});
expectBuyGemsStub(amzLib.constants.PAYMENT_METHOD);
expectAmazonStubs();
expect(user.canGetGems).to.be.calledOnce;
user.canGetGems.restore();
});
it('should error if gem amount is too low', async () => {
const receivingUser = new User();
receivingUser.save();
const gift = {
type: 'gems',
gems: {
amount: 0,
uuid: receivingUser._id,
},
};
await expect(amzLib.checkout({
gift, user, orderReferenceId, headers,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
message: 'Amount must be at least 1.',
name: 'BadRequest',
});
});
it('should error if user cannot get gems gems', async () => {
sinon.stub(user, 'canGetGems').resolves(false);
await expect(amzLib.checkout({
user, orderReferenceId, headers, gemsBlock: gemsBlockKey,
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 401,
message: i18n.t('groupPolicyCannotGetGems'),
name: 'NotAuthorized',
});
user.canGetGems.restore();
});
it('should error if gems block is not valid', async () => {
await expect(amzLib.checkout({
user, orderReferenceId, headers, gemsBlock: 'invalid',
}))
.to.eventually.be.rejected.and.to.eql({
httpCode: 400,
message: apiError('invalidGemsBlock'),
name: 'BadRequest',
});
});
it('should gift gems', async () => {
const receivingUser = new User();
await receivingUser.save();
const gift = {
type: 'gems',
uuid: receivingUser._id,
gems: {
amount: 16,
},
};
amount = 16 / 4;
await amzLib.checkout({
gift, user, orderReferenceId, headers,
});
expectBuyGemsStub(amzLib.constants.PAYMENT_METHOD_GIFT, gift);
expectAmazonStubs();
});
it('should gift a subscription', async () => {
const receivingUser = new User();
receivingUser.save();
const gift = {
type: 'subscription',
subscription: {
key: subKey,
uuid: receivingUser._id,
},
};
amount = common.content.subscriptionBlocks[subKey].price;
await amzLib.checkout({
user, orderReferenceId, headers, gift,
});
gift.member = receivingUser;
expect(paymentCreateSubscritionStub).to.be.calledOnce;
expect(paymentCreateSubscritionStub).to.be.calledWith({
user,
paymentMethod: amzLib.constants.PAYMENT_METHOD_GIFT,
headers,
gift,
gemsBlock: undefined,
});
expectAmazonStubs();
});
});