diff --git a/opensaas-sh/blog/src/content/docs/guides/deploying.mdx b/opensaas-sh/blog/src/content/docs/guides/deploying.mdx index 3e27214f..09ccff0b 100644 --- a/opensaas-sh/blog/src/content/docs/guides/deploying.mdx +++ b/opensaas-sh/blog/src/content/docs/guides/deploying.mdx @@ -178,6 +178,7 @@ export const stripe = new Stripe(process.env.STRIPE_KEY!, {
- `customer.subscription.deleted`
- `customer.subscription.updated`
- `invoice.paid` +
- `payment_intent.succeeded` signing secret 5. after that, go to the webhook you just created and `reveal` the new signing secret. 6. add this secret to your deployed server's `STRIPE_WEBHOOK_SECRET=` environment variable.
If you've deployed to Fly.io, you can do that easily with the following command: diff --git a/template/e2e-tests/tests/demoAppTests.spec.ts b/template/e2e-tests/tests/demoAppTests.spec.ts index 3d0236c6..c40cc6ab 100644 --- a/template/e2e-tests/tests/demoAppTests.spec.ts +++ b/template/e2e-tests/tests/demoAppTests.spec.ts @@ -89,9 +89,9 @@ test('AI schedule generation fails on 4th attempt', async () => { expect(tableTextContent.includes(task2.toLowerCase())).toBeFalsy(); }); -test('Make test payment with Stripe', async () => { - const PLAN_NAME = 'Hobby'; - await makeStripePayment({ test, page, planName: PLAN_NAME }); +test('Make test payment with Stripe for hobby plan', async () => { + const planId = 'hobby'; + await makeStripePayment({ test, page, planId }); }); test('User should be able to generate another schedule after payment', async () => { diff --git a/template/e2e-tests/tests/pricingPageTests.spec.ts b/template/e2e-tests/tests/pricingPageTests.spec.ts index 92f93d9a..b3cda4db 100644 --- a/template/e2e-tests/tests/pricingPageTests.spec.ts +++ b/template/e2e-tests/tests/pricingPageTests.spec.ts @@ -1,10 +1,10 @@ import { test, expect, type Page } from '@playwright/test'; -import { signUserUp, logUserIn, createRandomUser, makeStripePayment, type User } from './utils'; +import { signUserUp, logUserIn, createRandomUser, makeStripePayment, type User, acceptAllCookies } from './utils'; let page: Page; let testUser: User; -async function logNewUserIn() { +async function createAndLogInNewUser() { testUser = createRandomUser(); await signUserUp({ page: page, user: testUser }); await logUserIn({ page: page, user: testUser }); @@ -33,9 +33,9 @@ test('User should see Log In to Buy Plan button', async () => { }); test('User should see the Buy Plan button before payment', async () => { - // We only need to log the user in once since the tests are running sequentially + // We only need to log the user in once since the tests are running sequentially // and the same page is being shared between all the tests. - await logNewUserIn(); + await createAndLogInNewUser(); await page.goto('/pricing'); // There are three tiers on the page, so we want to retrieve the first of the three buttons const manageSubscriptionButton = page.getByRole('button', { name: 'Buy plan' }).first(); @@ -43,10 +43,10 @@ test('User should see the Buy Plan button before payment', async () => { await expect(manageSubscriptionButton).toBeEnabled(); }); -test('Make test payment with Stripe', async () => { - const PLAN_NAME = 'Hobby'; +test('Make test payment with Stripe for hobby plan', async () => { + const planId = 'hobby'; await page.goto('/'); - await makeStripePayment({ test, page, planName: PLAN_NAME }); + await makeStripePayment({ test, page, planId }); }); test('User should see the Manage Subscription button after payment', async () => { @@ -62,3 +62,11 @@ test('User should see the Manage Subscription button after payment', async () => await newTab.waitForLoadState(); await expect(newTab).toHaveURL(/^https:\/\/billing\.stripe\.com\//); }); + +test('Make test payment with Stripe for 10 credits', async () => { + await createAndLogInNewUser(); + await acceptAllCookies(page); // Clear the cookie consent modal so it doesn't interfere with the payment + const planId = 'credits10'; + await page.goto('/'); + await makeStripePayment({ test, page, planId }); +}); diff --git a/template/e2e-tests/tests/utils.ts b/template/e2e-tests/tests/utils.ts index 584b0784..85072127 100644 --- a/template/e2e-tests/tests/utils.ts +++ b/template/e2e-tests/tests/utils.ts @@ -39,6 +39,20 @@ export const logUserIn = async ({ page, user }: { page: Page; user: User }) => { export const signUserUp = async ({ page, user }: { page: Page; user: User }) => { await page.goto('/'); + + await page.evaluate(() => { + try { + const sessionId = localStorage.getItem('wasp:sessionId'); + if (sessionId) { + localStorage.removeItem('wasp:sessionId'); + } + window.location.reload(); + } catch (e) { + console.error('Failed to clear localStorage:', e); + } + }); + + await page.waitForLoadState('domcontentloaded'); await page.getByRole('link', { name: 'Log in' }).click(); @@ -62,13 +76,22 @@ export const createRandomUser = () => { return { email, password: DEFAULT_PASSWORD } as User; }; -export const makeStripePayment = async ({ test, page, planName }: { test: any; page: Page; planName: string }) => { +export const makeStripePayment = async ({ + test, + page, + planId, +}: { + test: any; + page: Page; + planId: 'hobby' | 'pro' | 'credits10'; +}) => { test.slow(); // Stripe payments take a long time to confirm and can cause tests to fail so we use a longer timeout await page.click('text="Pricing"'); await page.waitForURL('**/pricing'); - const buyBtn = page.getByRole('button', { name: 'Buy plan' }).first(); // "Hobby Plan" is the first of three plans + const buyBtn = page.locator(`button[aria-describedby="${planId}"]`); + await expect(buyBtn).toBeVisible(); await expect(buyBtn).toBeEnabled(); await buyBtn.click(); @@ -92,5 +115,14 @@ export const makeStripePayment = async ({ test, page, planName }: { test: any; p await page.waitForURL('**/checkout?success=true'); await page.waitForURL('**/account'); - await expect(page.getByText(planName)).toBeVisible(); + if (planId === 'credits10') { + await expect(page.getByText('Credits remaining: 13')).toBeVisible(); + } else { + await expect(page.getByText(planId)).toBeVisible(); + } +}; + +export const acceptAllCookies = async (page: Page) => { + await page.waitForSelector('button:has-text("Accept all")'); + await page.click('button:has-text("Accept all")'); };