Skip to content

Commit 3b7a67d

Browse files
authored
Fix failing e2e tests (#460)
* fix broken tests * navbar fixes + return pricing * changes * re-remove pricing
1 parent 0a7a04e commit 3b7a67d

File tree

11 files changed

+64
-83
lines changed

11 files changed

+64
-83
lines changed

opensaas-sh/app_diff/src/client/components/NavBar/NavBar.tsx.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
+ </Button>
9898
</WaspRouterLink>
9999
) : (
100-
<div className='space-y-2'>
100+
<ul className='space-y-2'>
101101
@@ -174,7 +187,14 @@
102102
)}
103103
</div>
@@ -114,7 +114,7 @@
114114
</div>
115115
</div>
116116
</div>
117-
@@ -217,6 +237,6 @@
117+
@@ -218,6 +238,6 @@
118118
'size-7': isScrolled,
119119
})}
120120
src={logo}
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
--- template/app/src/client/components/NavBar/constants.ts
22
+++ opensaas-sh/app/src/client/components/NavBar/constants.ts
3-
@@ -9,12 +9,12 @@
3+
@@ -9,7 +9,6 @@
44

55
export const marketingNavigationItems: NavigationItem[] = [
66
{ name: 'Features', to: '/#features' },
77
- { name: 'Pricing', to: routes.PricingPageRoute.to },
88
...staticNavigationItems,
99
] as const;
1010

11-
export const demoNavigationitems: NavigationItem[] = [
12-
{ name: 'AI Scheduler', to: routes.DemoAppRoute.to },
13-
{ name: 'File Upload', to: routes.FileUploadRoute.to },
14-
+ { name: 'Pricing', to: routes.PricingPageRoute.to },
15-
...staticNavigationItems,
16-
] as const;

template/app/src/client/components/NavBar/NavBar.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ function NavBarMobileMenu({
168168
</div>
169169
</WaspRouterLink>
170170
) : (
171-
<div className='space-y-2'>
171+
<ul className='space-y-2'>
172172
<UserMenuItems user={user} onItemClick={() => setMobileMenuOpen(false)} />
173-
</div>
173+
</ul>
174174
)}
175175
</div>
176176
<div className='py-6'>
@@ -202,6 +202,7 @@ function renderNavigationItems(
202202
to={item.to}
203203
className={menuStyles}
204204
onClick={setMobileMenuOpen && (() => setMobileMenuOpen(false))}
205+
target={item.to.startsWith('http') ? '_blank' : undefined}
205206
>
206207
{item.name}
207208
</ReactRouterLink>

template/app/src/client/components/NavBar/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ export const marketingNavigationItems: NavigationItem[] = [
1616
export const demoNavigationitems: NavigationItem[] = [
1717
{ name: 'AI Scheduler', to: routes.DemoAppRoute.to },
1818
{ name: 'File Upload', to: routes.FileUploadRoute.to },
19+
{ name: 'Pricing', to: routes.PricingPageRoute.to },
1920
...staticNavigationItems,
2021
] as const;

template/app/src/demo-ai-app/DemoAppPage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ function NewTaskForm({ handleCreateTask }: { handleCreateTask: typeof createTask
211211
variant='default'
212212
size='default'
213213
className='w-full'
214+
data-testid='generate-schedule-button'
214215
>
215216
{isPlanGenerating ? (
216217
<>
@@ -310,7 +311,7 @@ function Todo({ id, isDone, description, time }: TodoProps) {
310311

311312
function Schedule({ schedule }: { schedule: GeneratedSchedule }) {
312313
return (
313-
<div className='flex flex-col gap-6 py-6'>
314+
<div className='flex flex-col gap-6 py-6' data-testid='schedule'>
314315
<div className='space-y-4'>
315316
{!!schedule.tasks ? (
316317
schedule.tasks

template/app/src/user/UserDropdown.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,25 @@ export function UserDropdown({ user }: { user: Partial<UserEntity> }) {
3131
if (item.isAdminOnly && (!user || !user.isAdmin)) return null;
3232

3333
return (
34-
<DropdownMenuItem asChild>
34+
<DropdownMenuItem key={item.name}>
3535
<WaspRouterLink
3636
to={item.to}
3737
onClick={() => {
3838
setOpen(false);
3939
}}
40-
className='flex items-center gap-3.5 text-sm font-medium duration-300 ease-in-out hover:text-primary'
40+
className='flex items-center gap-3 w-full'
4141
>
4242
<item.icon size='1.1rem' />
4343
{item.name}
4444
</WaspRouterLink>
4545
</DropdownMenuItem>
4646
);
4747
})}
48-
<DropdownMenuItem
49-
onClick={() => logout()}
50-
className='flex items-center gap-3.5 text-sm font-medium duration-300 ease-in-out hover:text-primary'
51-
>
52-
<LogOut size='1.1rem' />
53-
Log Out
48+
<DropdownMenuItem>
49+
<button type='button' onClick={() => logout()} className='flex items-center gap-3 w-full'>
50+
<LogOut size='1.1rem' />
51+
Log Out
52+
</button>
5453
</DropdownMenuItem>
5554
</DropdownMenuContent>
5655
</DropdownMenu>

template/app/src/user/UserMenuItems.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,30 @@ export const UserMenuItems = ({ user, onItemClick }: { user?: Partial<User>; onI
1212
if (item.isAdminOnly && (!user || !user.isAdmin)) return null;
1313

1414
return (
15-
<div key={item.name} className='py-2'>
15+
<li key={item.name}>
1616
<WaspRouterLink
1717
to={item.to}
1818
onClick={onItemClick}
19-
className='flex items-center gap-3.5 text-sm font-medium duration-300 ease-in-out text-foreground hover:text-primary'
19+
className='flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium leading-7 text-foreground hover:bg-accent hover:text-accent-foreground transition-colors'
2020
>
2121
<item.icon size='1.1rem' />
2222
{item.name}
2323
</WaspRouterLink>
24-
</div>
24+
</li>
2525
);
2626
})}
27-
<div className='py-2'>
27+
<li>
2828
<button
2929
onClick={() => {
3030
logout();
3131
onItemClick?.();
3232
}}
33-
className='flex items-center gap-3.5 text-sm font-medium duration-300 ease-in-out text-foreground hover:text-primary'
33+
className='flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium leading-7 text-foreground hover:bg-accent hover:text-accent-foreground transition-colors'
3434
>
3535
<LogOut size='1.1rem' />
3636
Log Out
3737
</button>
38-
</div>
38+
</li>
3939
</>
4040
);
4141
};

template/e2e-tests/tests/demoAppTests.spec.ts

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { test, expect, type Page } from '@playwright/test';
2-
import { signUserUp, logUserIn, createRandomUser, makeStripePayment, type User} from './utils';
1+
import { expect, test, type Page } from '@playwright/test';
2+
import { createRandomUser, logUserIn, makeStripePayment, signUserUp, type User } from './utils';
33

44
let page: Page;
55
let testUser: User;
@@ -23,8 +23,8 @@ test.afterAll(async () => {
2323
await page.close();
2424
});
2525

26-
const task1 = 'create presentation on SaaS';
27-
const task2 = 'build SaaS app draft';
26+
const task1 = 'Create presentation on SaaS';
27+
const task2 = 'Build SaaS app draft';
2828

2929
test('User can make 3 AI schedule generations', async () => {
3030
test.slow(); // Use a longer timeout time in case OpenAI is slow to respond
@@ -38,25 +38,23 @@ test('User can make 3 AI schedule generations', async () => {
3838
await expect(page.getByText(task2)).toBeVisible();
3939

4040
for (let i = 0; i < 3; i++) {
41-
const generateScheduleButton = page.getByRole('button', { name: 'Generate Schedule' });
41+
const generateScheduleButton = page.getByTestId('generate-schedule-button');
4242
await expect(generateScheduleButton).toBeVisible();
4343

4444
await Promise.all([
45-
page.waitForRequest((req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST'),
45+
page.waitForRequest(
46+
(req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST'
47+
),
4648
page.waitForResponse((response) => {
4749
return response.url().includes('/operations/generate-gpt-response') && response.status() === 200;
4850
}),
4951
// We already started waiting before we perform the click that triggers the API calls. So now we just perform the click
5052
generateScheduleButton.click(),
5153
]);
5254

53-
// We already show a table with some dummy data even before the API call
54-
// Now we want to check that the tasks we added are in the generated table
55-
const table = page.getByRole('table');
56-
await expect(table).toBeVisible();
57-
const tableTextContent = (await table.innerText()).toLowerCase();
58-
expect(tableTextContent.includes(task1.toLowerCase())).toBeTruthy();
59-
expect(tableTextContent.includes(task2.toLowerCase())).toBeTruthy();
55+
const schedule = page.getByTestId('schedule');
56+
expect(schedule).toContainText(task1, { ignoreCase: true });
57+
expect(schedule).toContainText(task2, { ignoreCase: true });
6058
}
6159
});
6260

@@ -65,12 +63,13 @@ test('AI schedule generation fails on 4th attempt', async () => {
6563

6664
await page.reload();
6765

68-
const generateScheduleButton = page.getByRole('button', { name: 'Generate Schedule' });
66+
const generateScheduleButton = page.getByTestId('generate-schedule-button');
6967
await expect(generateScheduleButton).toBeVisible();
7068

7169
await Promise.all([
72-
page.waitForRequest((req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST'),
73-
70+
page.waitForRequest(
71+
(req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST'
72+
),
7473
page.waitForResponse((response) => {
7574
// expect the response to be 402 "PAYMENT_REQUIRED"
7675
return response.url().includes('/operations/generate-gpt-response') && response.status() === 402;
@@ -79,14 +78,9 @@ test('AI schedule generation fails on 4th attempt', async () => {
7978
generateScheduleButton.click(),
8079
]);
8180

82-
// We already show a table with some dummy data even before the API call
83-
// Now we want to check that the tasks were NOT added because the API call should have failed
84-
const table = page.getByRole('table');
85-
await expect(table).toBeVisible();
86-
const tableTextContent = (await table.innerText()).toLowerCase();
87-
88-
expect(tableTextContent.includes(task1.toLowerCase())).toBeFalsy();
89-
expect(tableTextContent.includes(task2.toLowerCase())).toBeFalsy();
81+
const schedule = page.getByTestId('schedule');
82+
expect(schedule).not.toContainText(task1, { ignoreCase: true });
83+
expect(schedule).not.toContainText(task2, { ignoreCase: true });
9084
});
9185

9286
test('Make test payment with Stripe for hobby plan', async () => {
@@ -97,12 +91,14 @@ test('Make test payment with Stripe for hobby plan', async () => {
9791
test('User should be able to generate another schedule after payment', async () => {
9892
await page.goto('/demo-app');
9993

100-
const generateScheduleButton = page.getByRole('button', { name: 'Generate Schedule' });
94+
const generateScheduleButton = page.getByTestId('generate-schedule-button');
10195
await expect(generateScheduleButton).toBeVisible();
10296

10397
await Promise.all([
10498
page
105-
.waitForRequest((req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST')
99+
.waitForRequest(
100+
(req) => req.url().includes('operations/generate-gpt-response') && req.method() === 'POST'
101+
)
106102
.catch((err) => console.error(err.message)),
107103
page
108104
.waitForResponse((response) => {
@@ -116,10 +112,7 @@ test('User should be able to generate another schedule after payment', async ()
116112
generateScheduleButton.click(),
117113
]);
118114

119-
await page.waitForSelector('table');
120-
const table = page.getByRole('table');
121-
await expect(table).toBeVisible();
122-
const tableTextContent = (await table.innerText()).toLowerCase();
123-
expect(tableTextContent.includes(task1.toLowerCase())).toBeTruthy();
124-
expect(tableTextContent.includes(task2.toLowerCase())).toBeTruthy();
115+
const schedule = page.getByTestId('schedule');
116+
expect(schedule).toContainText(task1, { ignoreCase: true });
117+
expect(schedule).toContainText(task2, { ignoreCase: true });
125118
});

template/e2e-tests/tests/landingPageTests.spec.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { test, expect, Cookie } from '@playwright/test';
2-
3-
const DOCS_URL = 'https://docs.opensaas.sh';
1+
import { Cookie, expect, test } from '@playwright/test';
42

53
test.describe('general landing page tests', () => {
64
test.beforeEach(async ({ page }) => {
@@ -13,16 +11,12 @@ test.describe('general landing page tests', () => {
1311

1412
test('get started link', async ({ page }) => {
1513
await page.getByRole('link', { name: 'Get started' }).click();
16-
await page.waitForURL(DOCS_URL);
14+
await page.waitForURL('**/signup');
1715
});
1816

1917
test('headings', async ({ page }) => {
20-
await expect(
21-
page.getByRole('heading', { name: 'Frequently asked questions' })
22-
).toBeVisible();
23-
await expect(
24-
page.getByRole('heading', { name: 'Some cool words' })
25-
).toBeVisible();
18+
await expect(page.getByRole('heading', { name: 'Frequently asked questions' })).toBeVisible();
19+
await expect(page.getByRole('heading', { name: 'Some cool words' })).toBeVisible();
2620
});
2721
});
2822

@@ -31,10 +25,7 @@ test.describe('cookie consent tests', () => {
3125
await page.goto('/');
3226
});
3327

34-
test('cookie consent banner rejection does not set cc_cookie', async ({
35-
context,
36-
page,
37-
}) => {
28+
test('cookie consent banner rejection does not set cc_cookie', async ({ context, page }) => {
3829
await page.$$('button:has-text("Reject all")');
3930
await page.click('button:has-text("Reject all")');
4031

@@ -44,10 +35,7 @@ test.describe('cookie consent tests', () => {
4435
expect(cookieObject.categories.includes('analytics')).toBeFalsy();
4536
});
4637

47-
test('cookie consent banner acceptance sets cc_cookie and _ga cookies', async ({
48-
context,
49-
page,
50-
}) => {
38+
test('cookie consent banner acceptance sets cc_cookie and _ga cookies', async ({ context, page }) => {
5139
await page.$$('button:has-text("Accept all")');
5240
await page.click('button:has-text("Accept all")');
5341

template/e2e-tests/tests/pricingPageTests.spec.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
import { test, expect, type Page } from '@playwright/test';
2-
import { signUserUp, logUserIn, createRandomUser, makeStripePayment, type User, acceptAllCookies } from './utils';
1+
import { expect, test, type Page } from '@playwright/test';
2+
import {
3+
acceptAllCookies,
4+
createRandomUser,
5+
logUserIn,
6+
makeStripePayment,
7+
signUserUp,
8+
type User,
9+
} from './utils';
310

411
let page: Page;
512
let testUser: User;

0 commit comments

Comments
 (0)