211 lines
6.4 KiB
TypeScript
211 lines
6.4 KiB
TypeScript
import { createStripeCli } from "@/external/stripe/utils.js";
|
|
import { CusProductStatus } from "@autumn/shared";
|
|
import { expect } from "chai";
|
|
import { addHours, addDays } from "date-fns";
|
|
import Stripe from "stripe";
|
|
import { AutumnCli } from "tests/cli/AutumnCli.js";
|
|
import { compareMainProduct } from "tests/utils/compare.js";
|
|
import { initCustomer } from "tests/utils/init.js";
|
|
import { advanceTestClock } from "tests/utils/stripeUtils.js";
|
|
import { initCustomerWithTestClock } from "tests/utils/testInitUtils.js";
|
|
import { alexProducts } from "./init.js";
|
|
import chalk from "chalk";
|
|
import { timeout } from "tests/utils/genUtils.js";
|
|
|
|
describe(
|
|
chalk.yellowBright(
|
|
"06_switch: Testing upgrades / downgrades from pro <-> premium",
|
|
),
|
|
() => {
|
|
let customerId = "alex-upgrade-downgrade-customer";
|
|
let testClockId = "";
|
|
let fingerprint = "fp1";
|
|
|
|
let stripeCli: Stripe;
|
|
before("initializing customer", async function () {
|
|
stripeCli = createStripeCli({
|
|
org: this.org,
|
|
env: this.env,
|
|
});
|
|
const { testClockId: newTestClockId } = await initCustomerWithTestClock({
|
|
customerId,
|
|
db: this.db,
|
|
org: this.org,
|
|
env: this.env,
|
|
fingerprint,
|
|
});
|
|
testClockId = newTestClockId;
|
|
});
|
|
|
|
describe("First upgrade from pro to premium (trial to trial)", () => {
|
|
it("should attach pro product", async function () {
|
|
await timeout(10000);
|
|
await AutumnCli.attach({
|
|
customerId,
|
|
productId: alexProducts.pro.id,
|
|
});
|
|
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
compareMainProduct({
|
|
sent: alexProducts.pro,
|
|
cusRes,
|
|
status: CusProductStatus.Trialing,
|
|
});
|
|
});
|
|
|
|
it("should upgrade to premium", async function () {
|
|
await AutumnCli.attach({
|
|
customerId,
|
|
productId: alexProducts.premium.id,
|
|
});
|
|
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
compareMainProduct({
|
|
sent: alexProducts.premium,
|
|
cusRes,
|
|
status: CusProductStatus.Trialing,
|
|
});
|
|
|
|
// Should have 2 invoices
|
|
expect(cusRes.invoices.length).to.equal(2);
|
|
expect(cusRes.invoices[0].total).to.equal(0);
|
|
});
|
|
});
|
|
|
|
describe("Downgrade from premium to pro (trial to paid)", () => {
|
|
it("should attach pro product (downgrade from premium trial)", async function () {
|
|
await AutumnCli.attach({
|
|
customerId,
|
|
productId: alexProducts.pro.id,
|
|
});
|
|
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
compareMainProduct({
|
|
sent: alexProducts.premium,
|
|
cusRes,
|
|
status: CusProductStatus.Trialing,
|
|
});
|
|
|
|
let proProduct = cusRes.products.find(
|
|
(p: any) => p.id === alexProducts.pro.id,
|
|
);
|
|
|
|
expect(proProduct.status).to.equal(CusProductStatus.Scheduled);
|
|
expect(proProduct.starts_at).to.exist;
|
|
expect(proProduct.starts_at).to.be.greaterThan(Date.now());
|
|
|
|
await advanceTestClock({
|
|
stripeCli,
|
|
testClockId,
|
|
advanceTo: addHours(new Date(proProduct.starts_at), 10).getTime(),
|
|
});
|
|
});
|
|
|
|
it("should have pro product and last invoice for $20", async function () {
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
compareMainProduct({
|
|
sent: alexProducts.pro,
|
|
cusRes,
|
|
status: CusProductStatus.Active,
|
|
});
|
|
|
|
const lastInvoice = cusRes.invoices[0];
|
|
expect(lastInvoice.total).to.equal(20);
|
|
});
|
|
});
|
|
|
|
describe("Upgrade from pro to premium (paid to paid)", () => {
|
|
// Now, advance 15 days and upgrade again, and check that the new invoice is for between 25 and 35 (because of the prorated amount)
|
|
it("should advance clock by 15 days and attach premium", async function () {
|
|
await advanceTestClock({
|
|
stripeCli,
|
|
testClockId,
|
|
advanceTo: addDays(new Date(), 7 + 15).getTime(),
|
|
});
|
|
|
|
await AutumnCli.attach({
|
|
customerId,
|
|
productId: alexProducts.premium.id,
|
|
});
|
|
|
|
await timeout(10000);
|
|
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
compareMainProduct({
|
|
sent: alexProducts.premium,
|
|
cusRes,
|
|
});
|
|
});
|
|
|
|
it("should have new invoice for roughly 15 days of premium (due to prorated)", async function () {
|
|
let premiumPrice = alexProducts.premium.prices[0].config.amount;
|
|
let proPrice = alexProducts.pro.prices[0].config.amount;
|
|
|
|
let proratedAmount = ((premiumPrice - proPrice) * 15) / 30;
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
const lastInvoice = cusRes.invoices[0];
|
|
|
|
// Expect invoice to be prorated amount +/- 10%
|
|
expect(lastInvoice.product_ids[0]).to.equal(alexProducts.premium.id);
|
|
expect(lastInvoice.total).to.be.greaterThan(proratedAmount * 0.9);
|
|
expect(lastInvoice.total).to.be.lessThan(proratedAmount * 1.1);
|
|
});
|
|
});
|
|
},
|
|
);
|
|
|
|
// Also, downgrade and cancel pro
|
|
describe(chalk.yellowBright("06_switch: Testing fingerprint"), () => {
|
|
let customerId = "alex-fingerprint-test";
|
|
let fingerprint = "fp1";
|
|
|
|
before("initializing customer", async function () {
|
|
await initCustomer({
|
|
customer_data: {
|
|
id: customerId,
|
|
name: "Alex Fingerprint Test",
|
|
email: "alex-fingerprint-test@test.com",
|
|
fingerprint,
|
|
},
|
|
attachPm: true,
|
|
db: this.db,
|
|
org: this.org,
|
|
env: this.env,
|
|
});
|
|
});
|
|
|
|
it("should attach pro product and have invoice for $20", async function () {
|
|
await AutumnCli.attach({
|
|
customerId,
|
|
productId: alexProducts.pro.id,
|
|
});
|
|
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
compareMainProduct({
|
|
sent: alexProducts.pro,
|
|
cusRes,
|
|
status: CusProductStatus.Active,
|
|
});
|
|
|
|
const invoices = cusRes.invoices;
|
|
expect(invoices[0].total).to.equal(20);
|
|
});
|
|
|
|
it("should attach premium product and have invoice for $30", async function () {
|
|
await AutumnCli.attach({
|
|
customerId,
|
|
productId: alexProducts.premium.id,
|
|
});
|
|
|
|
const cusRes = await AutumnCli.getCustomer(customerId);
|
|
compareMainProduct({
|
|
sent: alexProducts.premium,
|
|
cusRes,
|
|
status: CusProductStatus.Active,
|
|
});
|
|
|
|
const invoices = cusRes.invoices;
|
|
expect(invoices[0].total).to.equal(30);
|
|
});
|
|
});
|