Fix routed Redis reset test coverage

This commit is contained in:
Owen Greenhalgh
2026-05-06 15:39:00 +01:00
parent 71ece06479
commit 77aa04463b
5 changed files with 245 additions and 262 deletions

View File

@@ -3,7 +3,6 @@ import {
type ApiCustomer,
type ApiCustomerV3,
customerEntitlements,
type OrgConfig,
} from "@autumn/shared";
import { resetAndGetCusEnt } from "@tests/balances/track/rollovers/rolloverTestUtils.js";
import { findCustomerEntitlement } from "@tests/balances/utils/findCustomerEntitlement.js";
@@ -20,7 +19,6 @@ import { initScenario, s } from "@tests/utils/testInitUtils/initScenario.js";
import chalk from "chalk";
import { eq } from "drizzle-orm";
import { db } from "@/db/initDrizzle.js";
import { OrgService } from "@/internal/orgs/OrgService.js";
const setBalanceInDb = async ({
cusEntId,
@@ -35,33 +33,14 @@ const setBalanceInDb = async ({
.where(eq(customerEntitlements.id, cusEntId));
};
const enablePersistFreeOverage = async ({
orgId,
orgConfig,
}: {
orgId: string;
orgConfig: OrgConfig;
}) => {
await OrgService.update({
db,
orgId,
updates: { config: { ...orgConfig, persist_free_overage: true } },
const persistFreeOverageOrg = ({ slug }: { slug: string }) =>
s.platform.create({
userEmail: `persist-overage-${slug}-${Math.random()
.toString(36)
.slice(2, 8)}@autumn.test`,
configOverrides: { persist_free_overage: true },
setupDefaultFeatures: true,
});
};
const disablePersistFreeOverage = async ({
orgId,
orgConfig,
}: {
orgId: string;
orgConfig: OrgConfig;
}) => {
await OrgService.update({
db,
orgId,
updates: { config: { ...orgConfig, persist_free_overage: false } },
});
};
// ─────────────────────────────────────────────────────────────────
// 1. Lazy reset (DB path)
@@ -73,41 +52,33 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (DB): lazy reset deduc
const { customerId, autumnV2, ctx } = await initScenario({
customerId: "persist-ovg-on-db",
setup: [s.customer({ testClock: false }), s.products({ list: [free] })],
setup: [
persistFreeOverageOrg({ slug: "db" }),
s.customer({ testClock: false }),
s.products({ list: [free] }),
],
actions: [s.attach({ productId: free.id })],
});
await enablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
await setBalanceInDb({ cusEntId: cusEnt!.id, balance: -100 });
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
try {
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
await setBalanceInDb({ cusEntId: cusEnt!.id, balance: -100 });
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
const after = await autumnV2.customers.get<ApiCustomer>(customerId, {
skip_cache: "true",
});
expect(after.balances[TestFeature.Messages].current_balance).toBe(0);
expect(after.balances[TestFeature.Messages].usage).toBe(100);
} finally {
await disablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
});
}
const after = await autumnV2.customers.get<ApiCustomer>(customerId, {
skip_cache: "true",
});
expect(after.balances[TestFeature.Messages].current_balance).toBe(0);
expect(after.balances[TestFeature.Messages].usage).toBe(100);
});
// ─────────────────────────────────────────────────────────────────
@@ -120,59 +91,51 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (cache): lazy reset de
const { customerId, autumnV2, ctx } = await initScenario({
customerId: "persist-ovg-on-cache",
setup: [s.customer({ testClock: false }), s.products({ list: [free] })],
setup: [
persistFreeOverageOrg({ slug: "cache" }),
s.customer({ testClock: false }),
s.products({ list: [free] }),
],
actions: [s.attach({ productId: free.id })],
});
await enablePersistFreeOverage({
await autumnV2.customers.get<ApiCustomer>(customerId);
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
await setBalanceInDb({ cusEntId: cusEnt!.id, balance: -50 });
await setCachedCusEntField({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
env: ctx.env,
customerId,
cusEntId: cusEnt!.id,
field: "balance",
value: -50,
});
await setCachedSubjectBalanceField({
ctx,
orgId: ctx.org.id,
env: ctx.env,
customerId,
featureId: TestFeature.Messages,
customerEntitlementId: cusEnt!.id,
field: "balance",
value: -50,
});
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
try {
await autumnV2.customers.get<ApiCustomer>(customerId);
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
await setBalanceInDb({ cusEntId: cusEnt!.id, balance: -50 });
await setCachedCusEntField({
orgId: ctx.org.id,
env: ctx.env,
customerId,
cusEntId: cusEnt!.id,
field: "balance",
value: -50,
});
await setCachedSubjectBalanceField({
orgId: ctx.org.id,
env: ctx.env,
customerId,
featureId: TestFeature.Messages,
customerEntitlementId: cusEnt!.id,
field: "balance",
value: -50,
redisV2: ctx.redisV2,
});
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
const after = await autumnV2.customers.get<ApiCustomer>(customerId);
expect(after.balances[TestFeature.Messages].current_balance).toBe(50);
expect(after.balances[TestFeature.Messages].usage).toBe(50);
} finally {
await disablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
});
}
const after = await autumnV2.customers.get<ApiCustomer>(customerId);
expect(after.balances[TestFeature.Messages].current_balance).toBe(50);
expect(after.balances[TestFeature.Messages].usage).toBe(50);
});
// ─────────────────────────────────────────────────────────────────
@@ -185,7 +148,11 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (cron): cron reset ded
const { customerId, ctx, customer } = await initScenario({
customerId: "persist-ovg-on-cron",
setup: [s.customer({ testClock: false }), s.products({ list: [free] })],
setup: [
persistFreeOverageOrg({ slug: "cron" }),
s.customer({ testClock: false }),
s.products({ list: [free] }),
],
actions: [s.attach({ productId: free.id })],
});
@@ -219,41 +186,33 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (no overage): positive
const { customerId, autumnV2, ctx } = await initScenario({
customerId: "persist-ovg-on-positive",
setup: [s.customer({ testClock: false }), s.products({ list: [free] })],
setup: [
persistFreeOverageOrg({ slug: "positive" }),
s.customer({ testClock: false }),
s.products({ list: [free] }),
],
actions: [s.attach({ productId: free.id })],
});
await enablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
await setBalanceInDb({ cusEntId: cusEnt!.id, balance: 50 });
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
try {
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
await setBalanceInDb({ cusEntId: cusEnt!.id, balance: 50 });
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
const after = await autumnV2.customers.get<ApiCustomer>(customerId, {
skip_cache: "true",
});
expect(after.balances[TestFeature.Messages].current_balance).toBe(100);
expect(after.balances[TestFeature.Messages].usage).toBe(0);
} finally {
await disablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
});
}
const after = await autumnV2.customers.get<ApiCustomer>(customerId, {
skip_cache: "true",
});
expect(after.balances[TestFeature.Messages].current_balance).toBe(100);
expect(after.balances[TestFeature.Messages].usage).toBe(0);
});
// ─────────────────────────────────────────────────────────────────
@@ -270,6 +229,7 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (per-entity): each ent
const { customerId, ctx } = await initScenario({
customerId: "persist-ovg-on-entity",
setup: [
persistFreeOverageOrg({ slug: "entity" }),
s.customer({ testClock: false }),
s.products({ list: [free] }),
s.entities({ count: 2, featureId: TestFeature.Users }),
@@ -277,56 +237,43 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (per-entity): each ent
actions: [s.attach({ productId: free.id })],
});
await enablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
ctx.org.config = { ...ctx.org.config, persist_free_overage: true };
expect(cusEnt).toBeDefined();
expect(cusEnt!.entities).toBeDefined();
try {
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
expect(cusEnt!.entities).toBeDefined();
const entities = { ...cusEnt!.entities! };
const entityIds = Object.keys(entities);
expect(entityIds.length).toBe(2);
const entities = { ...cusEnt!.entities! };
const entityIds = Object.keys(entities);
expect(entityIds.length).toBe(2);
entities[entityIds[0]].balance = -50;
entities[entityIds[0]].adjustment = 0;
entities[entityIds[1]].balance = 30;
entities[entityIds[1]].adjustment = 0;
entities[entityIds[0]].balance = -50;
entities[entityIds[0]].adjustment = 0;
entities[entityIds[1]].balance = 30;
entities[entityIds[1]].adjustment = 0;
await db
.update(customerEntitlements)
.set({ entities })
.where(eq(customerEntitlements.id, cusEnt!.id));
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
await db
.update(customerEntitlements)
.set({ entities })
.where(eq(customerEntitlements.id, cusEnt!.id));
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
const cusEntAfter = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEntAfter).toBeDefined();
expect(cusEntAfter!.entities).toBeDefined();
const cusEntAfter = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEntAfter).toBeDefined();
expect(cusEntAfter!.entities).toBeDefined();
expect(cusEntAfter!.entities![entityIds[0]].balance).toBe(50);
expect(cusEntAfter!.entities![entityIds[1]].balance).toBe(100);
} finally {
await disablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
});
}
expect(cusEntAfter!.entities![entityIds[0]].balance).toBe(50);
expect(cusEntAfter!.entities![entityIds[1]].balance).toBe(100);
});
// ─────────────────────────────────────────────────────────────────
@@ -343,6 +290,7 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (per-entity mixed): di
const { customerId, ctx } = await initScenario({
customerId: "persist-ovg-on-ent-mix",
setup: [
persistFreeOverageOrg({ slug: "entity-mixed" }),
s.customer({ testClock: false }),
s.products({ list: [free] }),
s.entities({ count: 2, featureId: TestFeature.Users }),
@@ -350,56 +298,43 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (per-entity mixed): di
actions: [s.attach({ productId: free.id })],
});
await enablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
ctx.org.config = { ...ctx.org.config, persist_free_overage: true };
expect(cusEnt).toBeDefined();
expect(cusEnt!.entities).toBeDefined();
try {
const cusEnt = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEnt).toBeDefined();
expect(cusEnt!.entities).toBeDefined();
const entities = { ...cusEnt!.entities! };
const entityIds = Object.keys(entities);
expect(entityIds.length).toBe(2);
const entities = { ...cusEnt!.entities! };
const entityIds = Object.keys(entities);
expect(entityIds.length).toBe(2);
entities[entityIds[0]].balance = -30;
entities[entityIds[0]].adjustment = 0;
entities[entityIds[1]].balance = -200;
entities[entityIds[1]].adjustment = 0;
entities[entityIds[0]].balance = -30;
entities[entityIds[0]].adjustment = 0;
entities[entityIds[1]].balance = -200;
entities[entityIds[1]].adjustment = 0;
await db
.update(customerEntitlements)
.set({ entities })
.where(eq(customerEntitlements.id, cusEnt!.id));
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
await db
.update(customerEntitlements)
.set({ entities })
.where(eq(customerEntitlements.id, cusEnt!.id));
await expireCusEntForReset({
ctx,
customerId,
featureId: TestFeature.Messages,
});
const cusEntAfter = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEntAfter).toBeDefined();
expect(cusEntAfter!.entities).toBeDefined();
const cusEntAfter = await findCustomerEntitlement({
ctx,
customerId,
featureId: TestFeature.Messages,
});
expect(cusEntAfter).toBeDefined();
expect(cusEntAfter!.entities).toBeDefined();
expect(cusEntAfter!.entities![entityIds[0]].balance).toBe(70);
expect(cusEntAfter!.entities![entityIds[1]].balance).toBe(-100);
} finally {
await disablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
});
}
expect(cusEntAfter!.entities![entityIds[0]].balance).toBe(70);
expect(cusEntAfter!.entities![entityIds[1]].balance).toBe(-100);
});
// ─────────────────────────────────────────────────────────────────
@@ -418,6 +353,7 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (prepaid): invoice res
const { customerId, autumnV1, ctx, testClockId } = await initScenario({
customerId: "persist-ovg-on-prepaid",
setup: [
persistFreeOverageOrg({ slug: "prepaid" }),
s.customer({ paymentMethod: "success" }),
s.products({ list: [pro] }),
],
@@ -430,38 +366,24 @@ test.concurrent(`${chalk.yellowBright("persist overage ON (prepaid): invoice res
],
});
// Enable flag BEFORE advancing, so the webhook handler sees it in DB
await enablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
// After attach: prepaid balance = 200 (quantity=200, billingUnits=100, so 2*100=200), lifetime = 50
// Total messages balance = 200 + 50 = 250
// After track 300: deducted 300 from messages
// The prepaid cusEnt's balance should be negative (overage)
// On advance, handlePrepaidPrices resets prepaid with persistFreeOverage
await advanceToNextInvoice({
stripeCli: ctx.stripeCli,
testClockId: testClockId!,
withPause: true,
});
try {
// After attach: prepaid balance = 200 (quantity=200, billingUnits=100, so 2*100=200), lifetime = 50
// Total messages balance = 200 + 50 = 250
// After track 300: deducted 300 from messages
// The prepaid cusEnt's balance should be negative (overage)
// On advance, handlePrepaidPrices resets prepaid with persistFreeOverage
const customer = await autumnV1.customers.get<ApiCustomerV3>(customerId);
await advanceToNextInvoice({
stripeCli: ctx.stripeCli,
testClockId: testClockId!,
withPause: true,
});
const customer = await autumnV1.customers.get<ApiCustomerV3>(customerId);
// Lifetime messages (50) should be untouched by the prepaid reset
// Prepaid: was 200, used 300 -> overage of some amount on the prepaid cusEnt
// After reset with persist_free_overage: new prepaid balance = 200 - overage
// The exact split depends on deduction order, so just verify the feature exists
// and the balance is less than the full 250 (200 prepaid + 50 lifetime)
expect(customer.features[TestFeature.Messages]).toBeDefined();
expect(customer.features[TestFeature.Messages].balance).toBeLessThan(250);
} finally {
await disablePersistFreeOverage({
orgId: ctx.org.id,
orgConfig: ctx.org.config,
});
}
// Lifetime messages (50) should be untouched by the prepaid reset
// Prepaid: was 200, used 300 -> overage of some amount on the prepaid cusEnt
// After reset with persist_free_overage: new prepaid balance = 200 - overage
// The exact split depends on deduction order, so just verify the feature exists
// and the balance is less than the full 250 (200 prepaid + 50 lifetime)
expect(customer.features[TestFeature.Messages]).toBeDefined();
expect(customer.features[TestFeature.Messages].balance).toBeLessThan(250);
});

View File

@@ -7,11 +7,26 @@ import { findCustomerEntitlement } from "@tests/balances/utils/findCustomerEntit
import type { TestContext } from "@tests/utils/testInitUtils/createTestContext.js";
import { eq } from "drizzle-orm";
import type { Redis } from "ioredis";
import { redis } from "@/external/redis/initRedis.js";
import { getCtxWithCustomerRedis } from "@/external/redis/customerRedisRouting.js";
import { redis, waitForRedisReady } from "@/external/redis/initRedis.js";
import { CusService } from "@/internal/customers/CusService.js";
import { buildSharedFullSubjectBalanceKey } from "@/internal/customers/cache/fullSubject/builders/buildSharedFullSubjectBalanceKey.js";
import { buildFullCustomerCacheKey } from "@/internal/customers/cusUtils/fullCustomerCacheUtils/fullCustomerCacheConfig.js";
const getRoutedRedisForCustomer = async ({
ctx,
customerId,
}: {
ctx: TestContext;
customerId: string;
}): Promise<Redis> => {
const { ctx: routedCtx } = getCtxWithCustomerRedis({ ctx, customerId });
await waitForRedisReady(routedCtx.redisV2, "customer-redis", 5000).catch(
() => undefined,
);
return routedCtx.redisV2;
};
/**
* Update next_reset_at for a specific cusEnt in the Redis FullCustomer cache.
* Reads the cached blob, finds the cusEnt by ID, then uses JSON.SET on the exact path.
@@ -70,6 +85,7 @@ export const setCachedCusEntField = async ({
/** Patch next_reset_at on a SubjectBalance in the V2 shared balance hash. */
export const setCachedSubjectBalanceField = async ({
ctx,
orgId,
env,
customerId,
@@ -79,6 +95,7 @@ export const setCachedSubjectBalanceField = async ({
value,
redisV2,
}: {
ctx?: TestContext;
orgId: string;
env: string;
customerId: string;
@@ -86,8 +103,15 @@ export const setCachedSubjectBalanceField = async ({
customerEntitlementId: string;
field: string;
value: number | string | null;
redisV2: Redis;
redisV2?: Redis;
}): Promise<void> => {
const targetRedisV2 =
redisV2 ??
(ctx ? await getRoutedRedisForCustomer({ ctx, customerId }) : null);
if (!targetRedisV2) {
throw new Error("setCachedSubjectBalanceField requires redisV2 or ctx");
}
const balanceKey = buildSharedFullSubjectBalanceKey({
orgId,
env,
@@ -95,12 +119,12 @@ export const setCachedSubjectBalanceField = async ({
featureId,
});
const raw = await redisV2.hget(balanceKey, customerEntitlementId);
const raw = await targetRedisV2.hget(balanceKey, customerEntitlementId);
if (!raw) return;
const subjectBalance = JSON.parse(raw);
subjectBalance[field] = value;
await redisV2.hset(
await targetRedisV2.hset(
balanceKey,
customerEntitlementId,
JSON.stringify(subjectBalance),
@@ -136,6 +160,7 @@ export const expireCusEntForReset = async ({
}
const pastTime = pastTimeMs ?? Date.now() - 1000;
const routedRedisV2 = await getRoutedRedisForCustomer({ ctx, customerId });
// Update Postgres
await ctx.db
@@ -162,7 +187,7 @@ export const expireCusEntForReset = async ({
customerEntitlementId: cusEnt.id,
field: "next_reset_at",
value: pastTime,
redisV2: ctx.redisV2,
redisV2: routedRedisV2,
});
return cusEnt;
@@ -200,6 +225,7 @@ export const expireAllCusEntsForReset = async ({
}
const pastTime = pastTimeMs ?? Date.now() - 1000;
const routedRedisV2 = await getRoutedRedisForCustomer({ ctx, customerId });
for (const cusEnt of cusEnts) {
await ctx.db
@@ -224,7 +250,7 @@ export const expireAllCusEntsForReset = async ({
customerEntitlementId: cusEnt.id,
field: "next_reset_at",
value: pastTime,
redisV2: ctx.redisV2,
redisV2: routedRedisV2,
});
}

View File

@@ -5,6 +5,7 @@ import {
LATEST_VERSION,
type OrgConfig,
} from "@autumn/shared";
import { getFeatures } from "@tests/setup/v2Features.js";
import { initDrizzle } from "@/db/initDrizzle.js";
import { createStripeCli } from "@/external/connect/createStripeCli.js";
import { resolveRedisV2 } from "@/external/redis/resolveRedisV2.js";
@@ -29,11 +30,13 @@ export const createSubOrgTestContext = async ({
testSecretKey,
configOverrides,
taxRegistrations,
setupDefaultFeatures,
}: {
subOrgSlug: string;
testSecretKey: string;
configOverrides?: Partial<OrgConfig>;
taxRegistrations?: TaxRegistrationCountry[];
setupDefaultFeatures?: boolean;
}): Promise<TestContext> => {
const { db } = initDrizzle();
@@ -190,6 +193,14 @@ export const createSubOrgTestContext = async ({
}
}
if (setupDefaultFeatures) {
await FeatureService.insert({
db,
data: Object.values(getFeatures({ orgId: subOrg.id })),
logger,
});
}
// 5. Sub-org features.
const features = await FeatureService.list({
db,

View File

@@ -111,6 +111,19 @@ const lazyDefaultCtx = new Proxy({} as TestContext, {
}
return Reflect.get(ctx, prop);
},
set(_target, prop, value, _receiver) {
const ctx = (globalThis as { __autumnTestContext?: TestContext | null })
.__autumnTestContext;
if (ctx == null) {
throw new Error(
`Default TestContext is not initialized. The integration test ` +
`preload (server/tests/setup-integration-tests.ts) did not ` +
`populate globalThis.__autumnTestContext before "${String(prop)}" ` +
`was assigned.`,
);
}
return Reflect.set(ctx, prop, value);
},
has(_target, prop) {
const ctx = (globalThis as { __autumnTestContext?: TestContext | null })
.__autumnTestContext;
@@ -125,7 +138,15 @@ const lazyDefaultCtx = new Proxy({} as TestContext, {
const ctx = (globalThis as { __autumnTestContext?: TestContext | null })
.__autumnTestContext;
if (ctx == null) return undefined;
return Reflect.getOwnPropertyDescriptor(ctx, prop);
const descriptor = Reflect.getOwnPropertyDescriptor(ctx, prop);
if (!descriptor) return undefined;
return {
configurable: true,
enumerable: descriptor.enumerable,
writable: true,
value: Reflect.get(ctx, prop),
};
},
});

View File

@@ -199,6 +199,7 @@ type PlatformCreateConfig = {
userEmail?: string;
configOverrides?: Partial<OrgConfig>;
taxRegistrations?: TaxRegistrationCountry[];
setupDefaultFeatures?: boolean;
};
type ScenarioConfig = {
@@ -789,6 +790,7 @@ const createAndRedeemReferralCode = ({
* @param userEmail - Owner email; defaults to "platform-tests@autumn.test".
* @param configOverrides - Merged into the sub-org's config jsonb.
* @param taxRegistrations - Countries to register Stripe Tax for.
* @param setupDefaultFeatures - Inserts standard test features on the sub-org.
*
* @example s.platform.create({ configOverrides: { automatic_tax: true }, taxRegistrations: ["AU"] })
*/
@@ -965,6 +967,7 @@ export async function initScenario({
testSecretKey: response.test_secret_key,
configOverrides: config.platformConfig.configOverrides,
taxRegistrations: config.platformConfig.taxRegistrations,
setupDefaultFeatures: config.platformConfig.setupDefaultFeatures,
});
console.log(