mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-08-04 03:05:00 +02:00
* improve one-time payment webhook logic * Update paymentProcessor.ts.diff * update tests and docs * fix requested changes
126 lines
5.2 KiB
TypeScript
126 lines
5.2 KiB
TypeScript
import { test, expect, type Page } from '@playwright/test';
|
|
import { signUserUp, logUserIn, createRandomUser, makeStripePayment, type User} from './utils';
|
|
|
|
let page: Page;
|
|
let testUser: User;
|
|
|
|
/**
|
|
* Each user is given 3 credits for free on signup. This will allow them to call the OpenAI API 3 times.
|
|
* After that, if they haven't paid, they will not be able to generate a schedule.
|
|
* In this test file, we run all tests sequentially so that we use up the user's first 3 credits
|
|
* and the 4th generation should fail. We can then test stripe payments and the ability to generate a schedule after payment.
|
|
*/
|
|
test.describe.configure({ mode: 'serial' });
|
|
|
|
test.beforeAll(async ({ browser }) => {
|
|
page = await browser.newPage();
|
|
testUser = createRandomUser();
|
|
await signUserUp({ page: page, user: testUser });
|
|
await logUserIn({ page: page, user: testUser });
|
|
});
|
|
|
|
test.afterAll(async () => {
|
|
await page.close();
|
|
});
|
|
|
|
const task1 = 'create presentation on SaaS';
|
|
const task2 = 'build SaaS app draft';
|
|
|
|
test('User can make 3 AI schedule generations', async () => {
|
|
test.slow(); // Use a longer timeout time in case OpenAI is slow to respond
|
|
|
|
expect(page.url()).toContain('/demo-app');
|
|
await page.fill('input[id="description"]', task1);
|
|
await page.click('button:has-text("Add task")');
|
|
await expect(page.getByText(task1)).toBeVisible();
|
|
await page.fill('input[id="description"]', task2);
|
|
await page.click('button:has-text("Add task")');
|
|
await expect(page.getByText(task2)).toBeVisible();
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
const generateScheduleButton = page.getByRole('button', { name: 'Generate Schedule' });
|
|
await expect(generateScheduleButton).toBeVisible();
|
|
|
|
await Promise.all([
|
|
page.waitForRequest((req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST'),
|
|
page.waitForResponse((response) => {
|
|
return response.url().includes('/operations/generate-gpt-response') && response.status() === 200;
|
|
}),
|
|
// We already started waiting before we perform the click that triggers the API calls. So now we just perform the click
|
|
generateScheduleButton.click(),
|
|
]);
|
|
|
|
// We already show a table with some dummy data even before the API call
|
|
// Now we want to check that the tasks we added are in the generated table
|
|
const table = page.getByRole('table');
|
|
await expect(table).toBeVisible();
|
|
const tableTextContent = (await table.innerText()).toLowerCase();
|
|
expect(tableTextContent.includes(task1.toLowerCase())).toBeTruthy();
|
|
expect(tableTextContent.includes(task2.toLowerCase())).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('AI schedule generation fails on 4th attempt', async () => {
|
|
test.slow(); // Use a longer timeout time in case OpenAI is slow to respond
|
|
|
|
await page.reload();
|
|
|
|
const generateScheduleButton = page.getByRole('button', { name: 'Generate Schedule' });
|
|
await expect(generateScheduleButton).toBeVisible();
|
|
|
|
await Promise.all([
|
|
page.waitForRequest((req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST'),
|
|
|
|
page.waitForResponse((response) => {
|
|
// expect the response to be 402 "PAYMENT_REQUIRED"
|
|
return response.url().includes('/operations/generate-gpt-response') && response.status() === 402;
|
|
}),
|
|
// We already started waiting before we perform the click that triggers the API calls. So now we just perform the click
|
|
generateScheduleButton.click(),
|
|
]);
|
|
|
|
// We already show a table with some dummy data even before the API call
|
|
// Now we want to check that the tasks were NOT added because the API call should have failed
|
|
const table = page.getByRole('table');
|
|
await expect(table).toBeVisible();
|
|
const tableTextContent = (await table.innerText()).toLowerCase();
|
|
|
|
expect(tableTextContent.includes(task1.toLowerCase())).toBeFalsy();
|
|
expect(tableTextContent.includes(task2.toLowerCase())).toBeFalsy();
|
|
});
|
|
|
|
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 () => {
|
|
await page.goto('/demo-app');
|
|
|
|
const generateScheduleButton = page.getByRole('button', { name: 'Generate Schedule' });
|
|
await expect(generateScheduleButton).toBeVisible();
|
|
|
|
await Promise.all([
|
|
page
|
|
.waitForRequest((req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST')
|
|
.catch((err) => console.error(err.message)),
|
|
page
|
|
.waitForResponse((response) => {
|
|
if (response.url().includes('/operations/generate-gpt-response') && response.status() === 200) {
|
|
return true;
|
|
}
|
|
return false;
|
|
})
|
|
.catch((err) => console.error(err.message)),
|
|
// We already started waiting before we perform the click that triggers the API calls. So now we just perform the click
|
|
generateScheduleButton.click(),
|
|
]);
|
|
|
|
await page.waitForSelector('table');
|
|
const table = page.getByRole('table');
|
|
await expect(table).toBeVisible();
|
|
const tableTextContent = (await table.innerText()).toLowerCase();
|
|
expect(tableTextContent.includes(task1.toLowerCase())).toBeTruthy();
|
|
expect(tableTextContent.includes(task2.toLowerCase())).toBeTruthy();
|
|
});
|