fix(stripe): cancel_url /tarifs → /plan
La route /tarifs n'existe pas côté frontend (route réelle: /plan). Cancellation Stripe Checkout aboutissait sur un 404. Bug détecté lors du Sprint 5c frontend (gestion des retours post-Checkout). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6671bac347
commit
28f8373f5d
3 changed files with 100 additions and 65 deletions
|
|
@ -1,9 +1,9 @@
|
|||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
|
||||
// Capture du dernier appel à sessions.create pour inspection
|
||||
const sessionsCreateMock = vi.fn()
|
||||
const sessionsCreateMock = vi.fn();
|
||||
|
||||
vi.mock('stripe', () => ({
|
||||
vi.mock("stripe", () => ({
|
||||
default: vi.fn(() => ({
|
||||
checkout: {
|
||||
sessions: {
|
||||
|
|
@ -11,88 +11,119 @@ vi.mock('stripe', () => ({
|
|||
},
|
||||
},
|
||||
})),
|
||||
}))
|
||||
}));
|
||||
|
||||
import { createCheckoutSession } from '../stripe'
|
||||
import { createCheckoutSession } from "../stripe";
|
||||
|
||||
describe('createCheckoutSession', () => {
|
||||
describe("createCheckoutSession", () => {
|
||||
beforeEach(() => {
|
||||
sessionsCreateMock.mockReset()
|
||||
process.env.APP_URL = 'https://expria.app'
|
||||
})
|
||||
sessionsCreateMock.mockReset();
|
||||
process.env.APP_URL = "https://expria.app";
|
||||
});
|
||||
|
||||
it('retourne l\'URL de la session Stripe', async () => {
|
||||
sessionsCreateMock.mockResolvedValue({ url: 'https://checkout.stripe.com/pay/cs_test_123' })
|
||||
it("retourne l'URL de la session Stripe", async () => {
|
||||
sessionsCreateMock.mockResolvedValue({
|
||||
url: "https://checkout.stripe.com/pay/cs_test_123",
|
||||
});
|
||||
|
||||
const result = await createCheckoutSession({
|
||||
userId: 'user-abc',
|
||||
priceId: 'price_standard',
|
||||
planName: 'standard',
|
||||
})
|
||||
userId: "user-abc",
|
||||
priceId: "price_standard",
|
||||
planName: "standard",
|
||||
});
|
||||
|
||||
expect(result.url).toBe('https://checkout.stripe.com/pay/cs_test_123')
|
||||
})
|
||||
expect(result.url).toBe("https://checkout.stripe.com/pay/cs_test_123");
|
||||
});
|
||||
|
||||
it('passe metadata { userId, planName } à Stripe', async () => {
|
||||
sessionsCreateMock.mockResolvedValue({ url: 'https://checkout.stripe.com/pay/cs_test_123' })
|
||||
it("passe metadata { userId, planName } à Stripe", async () => {
|
||||
sessionsCreateMock.mockResolvedValue({
|
||||
url: "https://checkout.stripe.com/pay/cs_test_123",
|
||||
});
|
||||
|
||||
await createCheckoutSession({
|
||||
userId: 'user-xyz',
|
||||
priceId: 'price_premium',
|
||||
planName: 'premium',
|
||||
})
|
||||
userId: "user-xyz",
|
||||
priceId: "price_premium",
|
||||
planName: "premium",
|
||||
});
|
||||
|
||||
const callArg = sessionsCreateMock.mock.calls[0][0]
|
||||
expect(callArg.metadata).toEqual({ userId: 'user-xyz', planName: 'premium' })
|
||||
expect(callArg.client_reference_id).toBe('user-xyz')
|
||||
expect(callArg.mode).toBe('subscription')
|
||||
expect(callArg.line_items).toEqual([{ price: 'price_premium', quantity: 1 }])
|
||||
})
|
||||
const callArg = sessionsCreateMock.mock.calls[0][0];
|
||||
expect(callArg.metadata).toEqual({
|
||||
userId: "user-xyz",
|
||||
planName: "premium",
|
||||
});
|
||||
expect(callArg.client_reference_id).toBe("user-xyz");
|
||||
expect(callArg.mode).toBe("subscription");
|
||||
expect(callArg.line_items).toEqual([
|
||||
{ price: "price_premium", quantity: 1 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('construit success_url et cancel_url depuis APP_URL', async () => {
|
||||
process.env.APP_URL = 'https://app.example.test'
|
||||
sessionsCreateMock.mockResolvedValue({ url: 'https://checkout.stripe.com/pay/cs_x' })
|
||||
it("construit success_url et cancel_url depuis APP_URL", async () => {
|
||||
process.env.APP_URL = "https://app.example.test";
|
||||
sessionsCreateMock.mockResolvedValue({
|
||||
url: "https://checkout.stripe.com/pay/cs_x",
|
||||
});
|
||||
|
||||
await createCheckoutSession({
|
||||
userId: 'u1',
|
||||
priceId: 'p1',
|
||||
planName: 'standard',
|
||||
})
|
||||
userId: "u1",
|
||||
priceId: "p1",
|
||||
planName: "standard",
|
||||
});
|
||||
|
||||
const callArg = sessionsCreateMock.mock.calls[0][0]
|
||||
expect(callArg.success_url).toBe('https://app.example.test/dashboard?upgrade=success')
|
||||
expect(callArg.cancel_url).toBe('https://app.example.test/tarifs?upgrade=cancelled')
|
||||
})
|
||||
const callArg = sessionsCreateMock.mock.calls[0][0];
|
||||
expect(callArg.success_url).toBe(
|
||||
"https://app.example.test/dashboard?upgrade=success",
|
||||
);
|
||||
expect(callArg.cancel_url).toBe(
|
||||
"https://app.example.test/plan?upgrade=cancelled",
|
||||
);
|
||||
});
|
||||
|
||||
it('rejette si userId est vide', async () => {
|
||||
it("rejette si userId est vide", async () => {
|
||||
await expect(
|
||||
createCheckoutSession({ userId: '', priceId: 'p1', planName: 'standard' })
|
||||
).rejects.toThrow('userId requis')
|
||||
})
|
||||
createCheckoutSession({
|
||||
userId: "",
|
||||
priceId: "p1",
|
||||
planName: "standard",
|
||||
}),
|
||||
).rejects.toThrow("userId requis");
|
||||
});
|
||||
|
||||
it('rejette si priceId est vide', async () => {
|
||||
it("rejette si priceId est vide", async () => {
|
||||
await expect(
|
||||
createCheckoutSession({ userId: 'u1', priceId: '', planName: 'standard' })
|
||||
).rejects.toThrow('priceId requis')
|
||||
})
|
||||
createCheckoutSession({
|
||||
userId: "u1",
|
||||
priceId: "",
|
||||
planName: "standard",
|
||||
}),
|
||||
).rejects.toThrow("priceId requis");
|
||||
});
|
||||
|
||||
it('rejette si planName est vide', async () => {
|
||||
it("rejette si planName est vide", async () => {
|
||||
await expect(
|
||||
createCheckoutSession({ userId: 'u1', priceId: 'p1', planName: '' })
|
||||
).rejects.toThrow('planName requis')
|
||||
})
|
||||
createCheckoutSession({ userId: "u1", priceId: "p1", planName: "" }),
|
||||
).rejects.toThrow("planName requis");
|
||||
});
|
||||
|
||||
it('rejette si APP_URL est absent', async () => {
|
||||
delete process.env.APP_URL
|
||||
it("rejette si APP_URL est absent", async () => {
|
||||
delete process.env.APP_URL;
|
||||
await expect(
|
||||
createCheckoutSession({ userId: 'u1', priceId: 'p1', planName: 'standard' })
|
||||
).rejects.toThrow('APP_URL')
|
||||
})
|
||||
createCheckoutSession({
|
||||
userId: "u1",
|
||||
priceId: "p1",
|
||||
planName: "standard",
|
||||
}),
|
||||
).rejects.toThrow("APP_URL");
|
||||
});
|
||||
|
||||
it('rejette si Stripe ne retourne pas d\'URL', async () => {
|
||||
sessionsCreateMock.mockResolvedValue({ url: null })
|
||||
it("rejette si Stripe ne retourne pas d'URL", async () => {
|
||||
sessionsCreateMock.mockResolvedValue({ url: null });
|
||||
await expect(
|
||||
createCheckoutSession({ userId: 'u1', priceId: 'p1', planName: 'standard' })
|
||||
).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
createCheckoutSession({
|
||||
userId: "u1",
|
||||
priceId: "p1",
|
||||
planName: "standard",
|
||||
}),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export async function createCheckoutSession(
|
|||
mode: "subscription",
|
||||
line_items: [{ price: priceId, quantity: 1 }],
|
||||
success_url: `${appUrl}/dashboard?upgrade=success`,
|
||||
cancel_url: `${appUrl}/tarifs?upgrade=cancelled`,
|
||||
cancel_url: `${appUrl}/plan?upgrade=cancelled`,
|
||||
client_reference_id: userId,
|
||||
metadata: { userId, planName },
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue