mirror of
https://github.com/formbricks/formbricks.git
synced 2026-03-16 11:41:41 -05:00
Compare commits
1 Commits
4.8.0-rc.2
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
046c56b9dd |
@@ -33,14 +33,14 @@ describe("Password Management", () => {
|
||||
const hashedPassword = await hashPassword(password);
|
||||
const isValid = await verifyPassword(password, hashedPassword);
|
||||
expect(isValid).toBe(true);
|
||||
});
|
||||
}, 15000);
|
||||
|
||||
test("verifyPassword should reject an incorrect password", async () => {
|
||||
const password = "testPassword123";
|
||||
const hashedPassword = await hashPassword(password);
|
||||
const isValid = await verifyPassword("wrongPassword", hashedPassword);
|
||||
expect(isValid).toBe(false);
|
||||
});
|
||||
}, 15000);
|
||||
});
|
||||
|
||||
describe("Organization Access", () => {
|
||||
|
||||
@@ -34,7 +34,7 @@ describe("Crypto Utils", () => {
|
||||
|
||||
const isValid = await verifySecret(secret, hash);
|
||||
expect(isValid).toBe(true);
|
||||
});
|
||||
}, 15000);
|
||||
|
||||
test("should reject wrong secrets", async () => {
|
||||
const secret = "test-secret-123";
|
||||
@@ -43,7 +43,7 @@ describe("Crypto Utils", () => {
|
||||
|
||||
const isValid = await verifySecret(wrongSecret, hash);
|
||||
expect(isValid).toBe(false);
|
||||
});
|
||||
}, 15000);
|
||||
|
||||
test("should generate different hashes for the same secret (due to salt)", async () => {
|
||||
const secret = "test-secret-123";
|
||||
@@ -64,7 +64,7 @@ describe("Crypto Utils", () => {
|
||||
// Verify the cost factor is in the hash
|
||||
expect(hash).toMatch(/^\$2[aby]\$10\$/);
|
||||
expect(await verifySecret(secret, hash)).toBe(true);
|
||||
});
|
||||
}, 15000);
|
||||
|
||||
test("should return false for invalid hash format", async () => {
|
||||
const secret = "test-secret-123";
|
||||
|
||||
@@ -1021,6 +1021,6 @@ describe("updateSurveyDraftAction", () => {
|
||||
|
||||
// Expect validation error (skipValidation = false)
|
||||
await expect(updateSurveyInternal(incompleteSurvey, false)).rejects.toThrow();
|
||||
});
|
||||
}, 15000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -159,6 +159,12 @@ describe("organization-billing", () => {
|
||||
mocks.getCloudPlanFromProduct.mockReturnValue("pro");
|
||||
mocks.subscriptionsList.mockResolvedValue({ data: [] });
|
||||
mocks.customersList.mockResolvedValue({ data: [] });
|
||||
mocks.customersRetrieve.mockResolvedValue({
|
||||
id: "cus_1",
|
||||
deleted: false,
|
||||
invoice_settings: { default_payment_method: null },
|
||||
default_source: null,
|
||||
});
|
||||
mocks.prismaMembershipFindFirst.mockResolvedValue(null);
|
||||
mocks.productsList.mockResolvedValue({
|
||||
data: [
|
||||
@@ -639,6 +645,64 @@ describe("organization-billing", () => {
|
||||
expect(mocks.cacheDel).toHaveBeenCalledWith(["billing-cache-key"]);
|
||||
});
|
||||
|
||||
test("syncOrganizationBillingFromStripe marks migrated customers with customer-level payment methods", async () => {
|
||||
mocks.prismaOrganizationBillingFindUnique.mockResolvedValue({
|
||||
stripeCustomerId: "cus_1",
|
||||
limits: {
|
||||
projects: 3,
|
||||
monthly: {
|
||||
responses: 1500,
|
||||
},
|
||||
},
|
||||
usageCycleAnchor: new Date(),
|
||||
stripe: { lastSyncedEventId: null },
|
||||
});
|
||||
mocks.subscriptionsList.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
id: "sub_1",
|
||||
status: "active",
|
||||
default_payment_method: null,
|
||||
billing_cycle_anchor: 1739923200,
|
||||
items: {
|
||||
data: [
|
||||
{
|
||||
price: {
|
||||
metadata: {},
|
||||
product: { id: "prod_pro", metadata: { formbricks_plan: "pro" } },
|
||||
recurring: { usage_type: "licensed", interval: "month" },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
mocks.customersRetrieve.mockResolvedValue({
|
||||
id: "cus_1",
|
||||
deleted: false,
|
||||
invoice_settings: { default_payment_method: "pm_legacy_default" },
|
||||
default_source: null,
|
||||
});
|
||||
mocks.entitlementsList.mockResolvedValue({
|
||||
data: [],
|
||||
has_more: false,
|
||||
});
|
||||
|
||||
const result = await syncOrganizationBillingFromStripe("org_1");
|
||||
|
||||
expect(result?.stripe?.hasPaymentMethod).toBe(true);
|
||||
expect(mocks.prismaOrganizationBillingUpdate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
data: expect.objectContaining({
|
||||
stripe: expect.objectContaining({
|
||||
hasPaymentMethod: true,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("createPaidPlanCheckoutSession rejects mixed-interval yearly checkout", async () => {
|
||||
await expect(
|
||||
createPaidPlanCheckoutSession({
|
||||
|
||||
@@ -1107,6 +1107,21 @@ const resolvePendingPlanChange = async (subscription: Stripe.Subscription | null
|
||||
return null;
|
||||
};
|
||||
|
||||
const resolveHasPaymentMethod = (
|
||||
subscription: Stripe.Subscription | null,
|
||||
customer: Stripe.Customer | Stripe.DeletedCustomer
|
||||
) => {
|
||||
if (subscription?.default_payment_method != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (customer.deleted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return customer.invoice_settings.default_payment_method != null || customer.default_source != null;
|
||||
};
|
||||
|
||||
export const syncOrganizationBillingFromStripe = async (
|
||||
organizationId: string,
|
||||
event?: { id: string; created: number }
|
||||
@@ -1132,9 +1147,10 @@ export const syncOrganizationBillingFromStripe = async (
|
||||
return billing;
|
||||
}
|
||||
|
||||
const [subscription, featureLookupKeys] = await Promise.all([
|
||||
const [subscription, featureLookupKeys, customer] = await Promise.all([
|
||||
resolveCurrentSubscription(customerId),
|
||||
listAllActiveEntitlements(customerId),
|
||||
stripeClient.customers.retrieve(customerId),
|
||||
]);
|
||||
|
||||
const cloudPlan = resolveCloudPlanFromSubscription(subscription);
|
||||
@@ -1160,7 +1176,7 @@ export const syncOrganizationBillingFromStripe = async (
|
||||
interval: billingInterval,
|
||||
subscriptionStatus,
|
||||
subscriptionId: subscription?.id ?? null,
|
||||
hasPaymentMethod: subscription?.default_payment_method != null,
|
||||
hasPaymentMethod: resolveHasPaymentMethod(subscription, customer),
|
||||
features: featureLookupKeys,
|
||||
pendingChange,
|
||||
lastStripeEventCreatedAt: toIsoStringOrNull(incomingEventDate ?? previousEventDate),
|
||||
|
||||
Reference in New Issue
Block a user