This commit is contained in:
John Yeo
2026-01-07 18:10:03 +00:00
parent ef5e44fb84
commit 959ef784cf
5 changed files with 1369 additions and 454 deletions

View File

@@ -37,6 +37,44 @@ const autumn = new AutumnInt({
## Common Test Patterns
### Product IDs - Use Variable References, Not Hardcoded Strings
When using `initScenario`, products are automatically prefixed with the `customerId`. When referencing product IDs in API calls or assertions, **always use the product variable's `.id` property** instead of hardcoding the prefixed string:
```typescript
const pro = products.pro({ id: "pro", items: [messagesItem] });
const premium = constructProduct({ id: "premium", items: [...], type: "premium" });
const { autumnV1, ctx, entities } = await initScenario({
customerId,
options: [
s.products({ list: [pro, premium] }),
s.attach({ productId: "pro", entityIndex: 0 }), // s.attach uses unprefixed ID
],
});
// ✅ GOOD - Use product variable's .id (includes prefix automatically)
await autumnV1.attach({
customer_id: customerId,
product_id: pro.id, // Returns prefixed ID like "my-test_pro"
entity_id: entities[0].id,
});
await expectProductActive({
customer: customerData,
productId: premium.id, // Use variable reference
});
// ❌ BAD - Don't hardcode prefixed product IDs
await autumnV1.attach({
customer_id: customerId,
product_id: `${customerId}_pro`, // Avoid hardcoding
entity_id: entities[0].id,
});
```
**Note:** The `s.attach()` and `s.cancel()` helpers in `initScenario` take the **unprefixed** product ID (e.g., `"pro"`), but direct API calls require the **full prefixed ID** which you get from `pro.id`.
### Wait for Async Processing
```typescript
await new Promise((resolve) => setTimeout(resolve, 2000));

View File

@@ -1,418 +0,0 @@
import { expect, test } from "bun:test";
import { expectCustomerFeatureCorrect } from "@tests/billing/utils/expectCustomerFeatureCorrect";
import { expectCustomerInvoiceCorrect } from "@tests/billing/utils/expectCustomerInvoiceCorrect";
import { expectSubToBeCorrect } from "@tests/merged/mergeUtils/expectSubCorrect";
import { TestFeature } from "@tests/setup/v2Features.js";
import { items } from "@tests/utils/fixtures/items.js";
import { products } from "@tests/utils/fixtures/products.js";
import { initTestScenario } from "@tests/utils/testInitUtils/initTestScenario.js";
import chalk from "chalk";
// 1. Adding a monthly base price to free product
test.concurrent(`${chalk.yellowBright("free-to-paid: add monthly base price")}`, async () => {
const messagesItem = items.monthlyMessages({ includedUsage: 300 });
const free = products.base({ items: [messagesItem] });
const { customerId, autumnV1, ctx } = await initTestScenario({
customerId: "f2p-add-base",
products: [free],
attachProducts: [free.id],
customerOptions: {
withTestClock: true,
attachPm: "success",
},
});
await autumnV1.track(
{
customer_id: customerId,
feature_id: TestFeature.Messages,
value: 100,
},
{ timeout: 2000 },
);
const priceItem = items.monthlyPrice();
// Preview should show $20 charge
const preview = await autumnV1.subscriptions.previewUpdate({
customer_id: customerId,
product_id: free.id,
items: [messagesItem, priceItem],
});
expect(preview.total).toEqual(20);
await autumnV1.subscriptions.update({
customer_id: customerId,
product_id: free.id,
items: [messagesItem, priceItem],
});
const customer = await autumnV1.customers.get(customerId);
expectCustomerFeatureCorrect({
customer,
featureId: TestFeature.Messages,
includedUsage: messagesItem.included_usage,
balance: messagesItem.included_usage - 100,
usage: 100,
});
expectCustomerInvoiceCorrect({
customer,
count: 1,
latestTotal: 20,
});
await expectSubToBeCorrect({
db: ctx.db,
customerId,
org: ctx.org,
env: ctx.env,
});
});
// 2. Adding monthly base price + consumable to free product
test.concurrent(`${chalk.yellowBright("free-to-paid: add monthly base + consumable")}`, async () => {
const messagesItem = items.monthlyMessages({ includedUsage: 100 });
const free = products.base({ items: [messagesItem] });
const { customerId, autumnV1, ctx } = await initTestScenario({
customerId: "f2p-add-base-cons",
products: [free],
attachProducts: [free.id],
customerOptions: {
withTestClock: true,
attachPm: "success",
},
});
// Track some usage before update
const messagesUsage = 30;
await autumnV1.track(
{
customer_id: customerId,
feature_id: TestFeature.Messages,
value: messagesUsage,
},
{ timeout: 2000 },
);
const priceItem = items.monthlyPrice();
const consumableItem = items.consumableMessages({ includedUsage: 50 });
const preview = await autumnV1.subscriptions.previewUpdate({
customer_id: customerId,
product_id: free.id,
items: [consumableItem, priceItem],
});
expect(preview.total).toEqual(20);
await autumnV1.subscriptions.update({
customer_id: customerId,
product_id: free.id,
items: [consumableItem, priceItem],
});
const customer = await autumnV1.customers.get(customerId);
expectCustomerFeatureCorrect({
customer,
featureId: TestFeature.Messages,
includedUsage: consumableItem.included_usage,
balance: consumableItem.included_usage - messagesUsage,
usage: messagesUsage,
});
expectCustomerInvoiceCorrect({
customer,
count: 1,
latestTotal: 20,
});
await expectSubToBeCorrect({
db: ctx.db,
customerId,
org: ctx.org,
env: ctx.env,
});
});
// 3. Adding annual base price + monthly consumable to free product
test.concurrent(`${chalk.yellowBright("free-to-paid: add annual base + monthly consumable")}`, async () => {
const messagesItem = items.monthlyMessages({ includedUsage: 100 });
const free = products.base({ items: [messagesItem] });
const { customerId, autumnV1, ctx } = await initTestScenario({
customerId: "f2p-add-annual-cons",
products: [free],
attachProducts: [free.id],
customerOptions: {
withTestClock: true,
attachPm: "success",
},
});
const priceItem = items.annualPrice();
const consumableItem = items.consumableMessages({ includedUsage: 50 });
const preview = await autumnV1.subscriptions.previewUpdate({
customer_id: customerId,
product_id: free.id,
items: [consumableItem, priceItem],
});
expect(preview.total).toEqual(200);
await autumnV1.subscriptions.update(
{
customer_id: customerId,
product_id: free.id,
items: [consumableItem, priceItem],
},
{ timeout: 2000 },
);
const customer = await autumnV1.customers.get(customerId);
expectCustomerFeatureCorrect({
customer,
featureId: TestFeature.Messages,
includedUsage: consumableItem.included_usage,
balance: consumableItem.included_usage,
usage: 0,
});
expectCustomerInvoiceCorrect({
customer,
count: 1,
latestTotal: 200,
});
await expectSubToBeCorrect({
db: ctx.db,
customerId,
org: ctx.org,
env: ctx.env,
});
});
// 4. Updating free feature item to consumable
test.concurrent(`${chalk.yellowBright("free-to-paid: update free item to consumable")}`, async () => {
const messagesItem = items.monthlyMessages({ includedUsage: 100 });
const free = products.base({ items: [messagesItem] });
const { customerId, autumnV1, ctx } = await initTestScenario({
customerId: "f2p-update-to-cons",
products: [free],
attachProducts: [free.id],
customerOptions: {
withTestClock: true,
attachPm: "success",
},
});
// Track some usage first
const messagesUsage = 50;
await autumnV1.track(
{
customer_id: customerId,
feature_id: TestFeature.Messages,
value: messagesUsage,
},
{ timeout: 2000 },
);
// Update to consumable (pay-per-use after included usage)
const consumableItem = items.consumableMessages({ includedUsage: 100 });
const preview = await autumnV1.subscriptions.previewUpdate({
customer_id: customerId,
product_id: free.id,
items: [consumableItem],
});
// No immediate charge - consumable bills in arrears
expect(preview.total).toEqual(0);
await autumnV1.subscriptions.update({
customer_id: customerId,
product_id: free.id,
items: [consumableItem],
});
const customer = await autumnV1.customers.get(customerId);
expectCustomerFeatureCorrect({
customer,
featureId: TestFeature.Messages,
includedUsage: consumableItem.included_usage,
balance: consumableItem.included_usage - messagesUsage,
usage: messagesUsage,
});
// No invoice - consumable bills in arrears, no immediate charge
expectCustomerInvoiceCorrect({
customer,
count: 0,
});
await expectSubToBeCorrect({
db: ctx.db,
customerId,
org: ctx.org,
env: ctx.env,
});
});
// 5. Updating free feature item to prepaid
test.concurrent(`${chalk.yellowBright("free-to-paid: update free item to prepaid")}`, async () => {
const messagesItem = items.monthlyMessages({ includedUsage: 100 });
const free = products.base({ items: [messagesItem] });
const { customerId, autumnV1, ctx } = await initTestScenario({
customerId: "f2p-update-to-prepaid",
products: [free],
attachProducts: [free.id],
customerOptions: {
withTestClock: true,
attachPm: "success",
},
});
// Track some usage first
const messagesUsage = 30;
await autumnV1.track(
{
customer_id: customerId,
feature_id: TestFeature.Messages,
value: messagesUsage,
},
{ timeout: 2000 },
);
// Update to prepaid (purchase units upfront)
const prepaidItem = items.prepaidMessages();
const preview = await autumnV1.subscriptions.previewUpdate({
customer_id: customerId,
product_id: free.id,
items: [prepaidItem],
});
// No immediate charge for switching to prepaid model
expect(preview.total).toEqual(0);
await autumnV1.subscriptions.update({
customer_id: customerId,
product_id: free.id,
items: [prepaidItem],
options: [
{
feature_id: TestFeature.Messages,
quantity: 100,
},
],
});
const customer = await autumnV1.customers.get(customerId);
expectCustomerFeatureCorrect({
customer,
featureId: TestFeature.Messages,
includedUsage: 100,
balance: 100 - messagesUsage,
usage: messagesUsage,
});
// Prepaid charges upfront - $10 for 100 units
expectCustomerInvoiceCorrect({
customer,
count: 1,
latestTotal: 10,
});
await expectSubToBeCorrect({
db: ctx.db,
customerId,
org: ctx.org,
env: ctx.env,
});
});
// 6. Updating free users to allocated users
test.concurrent(`${chalk.yellowBright("free-to-paid: update free users to allocated")}`, async () => {
const usersItem = items.monthlyUsers({ includedUsage: 5 });
const free = products.base({ items: [usersItem] });
const { customerId, autumnV1, ctx } = await initTestScenario({
customerId: "f2p-free-to-allocated",
products: [free],
attachProducts: [free.id],
customerOptions: {
withTestClock: true,
attachPm: "success",
},
});
// Use some users (continuous use feature)
const usersUsed = 3;
await autumnV1.track(
{
customer_id: customerId,
feature_id: TestFeature.Users,
value: usersUsed,
},
{ timeout: 2000 },
);
// Verify initial state
const initialCustomer = await autumnV1.customers.get(customerId);
expect(initialCustomer.features[TestFeature.Users].balance).toEqual(
usersItem.included_usage - usersUsed,
);
// Update to allocated users ($10/seat prorated billing)
const allocatedUsersItem = items.allocatedUsers({ includedUsage: 2 });
const preview = await autumnV1.subscriptions.previewUpdate({
customer_id: customerId,
product_id: free.id,
items: [allocatedUsersItem],
});
// Should charge for (usersUsed - includedUsage) extra seats = (3 - 2) = 1 seat @ $10
expect(preview.total).toEqual(10);
await autumnV1.subscriptions.update({
customer_id: customerId,
product_id: free.id,
items: [allocatedUsersItem],
});
const customer = await autumnV1.customers.get(customerId);
expectCustomerFeatureCorrect({
customer,
featureId: TestFeature.Users,
includedUsage: allocatedUsersItem.included_usage,
balance: allocatedUsersItem.included_usage - usersUsed,
usage: usersUsed,
});
// Invoice for the extra seat
expectCustomerInvoiceCorrect({
customer,
count: 1,
latestTotal: 10,
});
await expectSubToBeCorrect({
db: ctx.db,
customerId,
org: ctx.org,
env: ctx.env,
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,95 @@ import { products } from "@tests/utils/fixtures/products.js";
import { initScenario, s } from "@tests/utils/testInitUtils/initScenario.js";
import chalk from "chalk";
// 1. Entity 1 has paid sub, entity 2 upgrades free to paid
// 1. Entity 1 pro, Entity 2 free - Entity 2 updates free items (stays free)
test.concurrent(`${chalk.yellowBright("multi-entity-from-free: update free items")}`, async () => {
const customerId = "multi-ent-update-free";
const messagesItem = items.monthlyMessages({ includedUsage: 100 });
const pro = products.pro({
id: "pro",
items: [messagesItem],
});
const free = products.base({
id: "free",
items: [messagesItem],
});
const { autumnV1, ctx, entities } = await initScenario({
customerId,
options: [
s.customer({ paymentMethod: "success" }),
s.products({ list: [pro, free] }),
s.entities({ count: 2, featureId: TestFeature.Users }),
s.attach({ productId: "pro", entityIndex: 0 }),
s.attach({ productId: "free", entityIndex: 1 }),
],
});
// Verify entity 2 starts with 100 included usage
const entity2Before = await autumnV1.entities.get(customerId, entities[1].id);
await expectProductActive({ customer: entity2Before, productId: free.id });
expectCustomerFeatureCorrect({
customer: entity2Before,
featureId: TestFeature.Messages,
includedUsage: 100,
balance: 100,
usage: 0,
});
// Entity 2 updates free product to have more included usage (still free)
const updatedMessagesItem = items.monthlyMessages({ includedUsage: 200 });
const preview = await autumnV1.subscriptions.previewUpdate({
customer_id: customerId,
entity_id: entities[1].id,
product_id: free.id,
items: [updatedMessagesItem],
});
// Should be $0 since it's still a free product
expect(preview.total).toEqual(0);
await autumnV1.subscriptions.update({
customer_id: customerId,
entity_id: entities[1].id,
product_id: free.id,
items: [updatedMessagesItem],
});
// Verify entity 2 has updated included usage
const entity2After = await autumnV1.entities.get(customerId, entities[1].id);
await expectProductActive({ customer: entity2After, productId: free.id });
expectCustomerFeatureCorrect({
customer: entity2After,
featureId: TestFeature.Messages,
includedUsage: 200,
balance: 200,
usage: 0,
});
// Verify only 1 invoice (from entity1's pro attachment)
const customer = await autumnV1.customers.get(customerId);
expectCustomerInvoiceCorrect({
customer,
count: 1,
latestTotal: 20, // Only entity 1's pro
});
// Should still have 1 subscription (entity 1's pro)
await expectSubToBeCorrect({
db: ctx.db,
customerId,
org: ctx.org,
env: ctx.env,
entityId: entities[0].id,
subCount: 1,
});
});
// 2. Entity 1 has paid sub, entity 2 upgrades free to paid
test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: entity 2 upgrades free to paid")}`, async () => {
const customerId = "multi-ent-free-to-paid";
@@ -87,7 +175,7 @@ test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: entity 2 upgra
});
});
// 2. Free to paid with base price + consumable + prepaid
// 3. Free to paid with base price + consumable + prepaid
test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: base + consumable + prepaid")}`, async () => {
const customerId = "multi-ent-f2p-combo";
@@ -182,7 +270,7 @@ test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: base + consuma
});
});
// 3. Free to paid with annual price
// 4. Free to paid with annual price
test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: annual price")}`, async () => {
const customerId = "multi-ent-f2p-annual";
@@ -260,7 +348,7 @@ test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: annual price")
});
});
// 4. Free to paid with annual price MID-CYCLE
// 5. Free to paid with annual price MID-CYCLE
test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: annual mid-cycle")}`, async () => {
const customerId = "multi-ent-f2p-annual-mid";
@@ -340,7 +428,7 @@ test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: annual mid-cyc
});
});
// 5. Monthly price mid-cycle (existing test)
// 6. Monthly price mid-cycle
test.concurrent(`${chalk.yellowBright("multi-entity-free-to-paid: monthly mid-cycle")}`, async () => {
const customerId = "multi-ent-f2p-midcycle";

View File

@@ -50,7 +50,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: cancel entity 1, update en
);
await expectProductCanceled({
customer: entity1AfterCancel,
productId: `${customerId}_pro`,
productId: pro.id,
});
// Entity 2 updates pro's items (change price)
@@ -59,7 +59,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: cancel entity 1, update en
await autumnV1.subscriptions.update({
customer_id: customerId,
entity_id: entities[1].id,
product_id: `${customerId}_pro`,
product_id: pro.id,
items: [messagesItem, newPriceItem],
});
@@ -67,7 +67,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: cancel entity 1, update en
const entity2Data = await autumnV1.entities.get(customerId, entities[1].id);
await expectProductActive({
customer: entity2Data,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectSubToBeCorrect({
@@ -96,11 +96,11 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: cancel entity 1, update en
await expectProductNotPresent({
customer: entity1AfterCycle,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectProductActive({
customer: entity2AfterCycle,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectSubToBeCorrect({
@@ -144,7 +144,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade entity 1, update
// Entity 1 downgrades from Premium to Pro (scheduled)
await autumnV1.attach({
customer_id: customerId,
product_id: `${customerId}_pro`,
product_id: pro.id,
entity_id: entities[0].id,
});
@@ -164,7 +164,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade entity 1, update
await autumnV1.subscriptions.update({
customer_id: customerId,
entity_id: entities[1].id,
product_id: `${customerId}_premium`,
product_id: premium.id,
items: [consumableItem, newPriceItem],
});
@@ -172,7 +172,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade entity 1, update
const entity2Data = await autumnV1.entities.get(customerId, entities[1].id);
await expectProductActive({
customer: entity2Data,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectSubToBeCorrect({
@@ -202,15 +202,15 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade entity 1, update
await expectProductNotPresent({
customer: entity1AfterCycle,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectProductActive({
customer: entity1AfterCycle,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectProductActive({
customer: entity2AfterCycle,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectSubToBeCorrect({
@@ -266,14 +266,14 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: annual + monthly downgrade
// Entity 1 downgrades from Premium Annual to Pro (scheduled for end of annual period)
await autumnV1.attach({
customer_id: customerId,
product_id: `${customerId}_pro`,
product_id: pro.id,
entity_id: entities[0].id,
});
// Entity 2 downgrades from Premium Monthly to Pro (scheduled for end of month)
await autumnV1.attach({
customer_id: customerId,
product_id: `${customerId}_pro`,
product_id: pro.id,
entity_id: entities[1].id,
});
@@ -284,7 +284,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: annual + monthly downgrade
await autumnV1.subscriptions.update({
customer_id: customerId,
entity_id: entities[2].id,
product_id: `${customerId}_premium`,
product_id: premium.id,
items: [newConsumable, newPriceItem],
});
@@ -292,7 +292,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: annual + monthly downgrade
const entity3Data = await autumnV1.entities.get(customerId, entities[2].id);
await expectProductActive({
customer: entity3Data,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectSubToBeCorrect({
@@ -328,23 +328,23 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: annual + monthly downgrade
// Entity 1 should still have premium-annual (annual cycle not over)
await expectProductActive({
customer: entity1AfterCycle,
productId: `${customerId}_premium-annual`,
productId: premiumAnnual.id,
});
// Entity 2 should be on pro now
await expectProductNotPresent({
customer: entity2AfterCycle,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectProductActive({
customer: entity2AfterCycle,
productId: `${customerId}_pro`,
productId: pro.id,
});
// Entity 3 should still have premium
await expectProductActive({
customer: entity3AfterCycle,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectSubToBeCorrect({
@@ -382,18 +382,18 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: update to free item remove
const entity2Before = await autumnV1.entities.get(customerId, entities[1].id);
await expectProductActive({
customer: entity1Before,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectProductActive({
customer: entity2Before,
productId: `${customerId}_pro`,
productId: pro.id,
});
// Entity 2 updates Pro's items to be free (no price items, only feature)
await autumnV1.subscriptions.update({
customer_id: customerId,
entity_id: entities[1].id,
product_id: `${customerId}_pro`,
product_id: pro.id,
items: [messagesItem], // Only messages, no price - makes it free
});
@@ -401,7 +401,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: update to free item remove
const entity2Data = await autumnV1.entities.get(customerId, entities[1].id);
await expectProductActive({
customer: entity2Data,
productId: `${customerId}_pro`,
productId: pro.id,
});
// Should only have 1 subscription (entity 1's pro)
@@ -432,11 +432,11 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: update to free item remove
await expectProductActive({
customer: entity1AfterCycle,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectProductActive({
customer: entity2AfterCycle,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectSubToBeCorrect({
@@ -482,7 +482,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade + update to free
// Entity 1 downgrades from Premium to Pro (scheduled)
await autumnV1.attach({
customer_id: customerId,
product_id: `${customerId}_pro`,
product_id: pro.id,
entity_id: entities[0].id,
});
@@ -500,7 +500,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade + update to free
await autumnV1.subscriptions.update({
customer_id: customerId,
entity_id: entities[1].id,
product_id: `${customerId}_premium`,
product_id: premium.id,
items: [consumableItem], // Only consumable, no base price - makes it free
});
@@ -508,7 +508,7 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade + update to free
const entity2Data = await autumnV1.entities.get(customerId, entities[1].id);
await expectProductActive({
customer: entity2Data,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectSubToBeCorrect({
@@ -539,15 +539,15 @@ test.concurrent(`${chalk.yellowBright("schedules-p2p: downgrade + update to free
await expectProductNotPresent({
customer: entity1AfterCycle,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectProductActive({
customer: entity1AfterCycle,
productId: `${customerId}_pro`,
productId: pro.id,
});
await expectProductActive({
customer: entity2AfterCycle,
productId: `${customerId}_premium`,
productId: premium.id,
});
await expectSubToBeCorrect({