Skip to content

Commit 0b86fd7

Browse files
test(mosaic): cover UserProfile and the UserButton profile modal in integration tests
1 parent 3680afa commit 0b86fd7

3 files changed

Lines changed: 110 additions & 4 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use client';
2+
3+
import { MosaicProvider, UserProfile } from '@clerk/mosaic';
4+
5+
export default function Page() {
6+
return (
7+
<MosaicProvider>
8+
<UserProfile customPages={[{ label: 'Custom page', path: 'custom-page', content: <p>custom-page-content</p> }]} />
9+
</MosaicProvider>
10+
);
11+
}

‎integration/tests/mosaic/user-button.test.ts‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ testAgainstRunningApps({ withPattern: ['next.appRouterMosaic.*'] })('Mosaic User
4949
async function openProfileSettings(page: Page) {
5050
await popup(page).getByRole('button', { name: 'Settings' }).click();
5151
const profileSettings = page.getByRole('menuitem', { name: 'Manage profile' });
52-
await profileSettings.or(page.locator('.cl-userProfile-root')).first().waitFor();
52+
const profile = page.getByRole('tab', { name: 'Account', exact: true });
53+
await profileSettings.or(profile).first().waitFor();
5354
if (await profileSettings.isVisible()) {
5455
await profileSettings.click();
5556
}
@@ -101,14 +102,26 @@ testAgainstRunningApps({ withPattern: ['next.appRouterMosaic.*'] })('Mosaic User
101102
await expect(page.getByText('custom-link-target')).toBeVisible();
102103
});
103104

105+
test('opens the Mosaic UserProfile in a modal', async ({ page, context }) => {
106+
await page.setViewportSize({ width: 1280, height: 800 });
107+
await signIn({ page, context });
108+
109+
await trigger(page).click();
110+
await openProfileSettings(page);
111+
112+
await expect(page.getByRole('tab', { name: 'Account', exact: true })).toHaveAttribute('aria-selected', 'true');
113+
await expect(page.locator('.cl-userProfile-root')).toHaveCount(0);
114+
await expect(popup(page)).toBeHidden();
115+
});
116+
104117
test('renders a custom page inside the UserProfile modal', async ({ page, context }) => {
105-
const u = await signIn({ page, context }, '/custom');
118+
await page.setViewportSize({ width: 1280, height: 800 });
119+
await signIn({ page, context }, '/custom');
106120

107121
await trigger(page).click();
108122
await openProfileSettings(page);
109-
await u.po.userProfile.waitForUserProfileModal();
110123

111-
await page.locator('.cl-userProfile-root').getByText('Custom page').click();
124+
await page.getByRole('tab', { name: 'Custom page', exact: true }).click();
112125
await expect(page.getByText('custom-page-content')).toBeVisible();
113126
});
114127
});
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import type { Organization } from '@clerk/backend';
2+
import type { BrowserContext, Page } from '@playwright/test';
3+
import { expect, test } from '@playwright/test';
4+
5+
import type { FakeUser } from '../../testUtils';
6+
import { createTestUtils, testAgainstRunningApps } from '../../testUtils';
7+
8+
testAgainstRunningApps({ withPattern: ['next.appRouterMosaic.*'] })('Mosaic UserProfile @mosaic', ({ app }) => {
9+
test.describe.configure({ mode: 'serial' });
10+
11+
let fakeUser: FakeUser;
12+
let organization: Organization;
13+
const cleanups: Array<() => Promise<unknown>> = [];
14+
15+
test.beforeAll(async () => {
16+
const u = await createTestUtils({ app });
17+
fakeUser = u.services.users.createFakeUser(test);
18+
cleanups.push(() => fakeUser.deleteIfExists());
19+
const user = await u.services.users.createBapiUser(fakeUser);
20+
organization = await u.services.clerk.organizations.createOrganization({
21+
name: `Mosaic ${Date.now()}`,
22+
createdBy: user.id,
23+
});
24+
cleanups.push(() => u.services.clerk.organizations.deleteOrganization(organization.id));
25+
});
26+
27+
test.afterAll(async () => {
28+
const results = await Promise.allSettled(cleanups.map(cleanup => cleanup()));
29+
await app.teardown();
30+
const failures = results.flatMap(result => (result.status === 'rejected' ? [result.reason] : []));
31+
if (failures.length > 0) {
32+
throw new AggregateError(failures, 'Mosaic UserProfile cleanup failed');
33+
}
34+
});
35+
36+
const path = '/user-profile';
37+
const tab = (page: Page, name: string) => page.getByRole('tab', { name, exact: true });
38+
39+
async function signIn({ page, context }: { page: Page; context: BrowserContext }) {
40+
const u = await createTestUtils({ app, page, context });
41+
await page.setViewportSize({ width: 1280, height: 800 });
42+
await u.po.signIn.goTo();
43+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
44+
await u.page.goToRelative(path);
45+
await u.po.expect.toBeSignedIn();
46+
await expect(tab(page, 'Account')).toBeVisible();
47+
return u;
48+
}
49+
50+
test('renders nothing when signed out', async ({ page, context }) => {
51+
const u = await createTestUtils({ app, page, context });
52+
await u.page.goToRelative(path);
53+
await u.page.waitForClerkJsLoaded();
54+
55+
await expect(tab(page, 'Account')).toHaveCount(0);
56+
});
57+
58+
test('opens on the account page with the signed-in user', async ({ page, context }) => {
59+
await signIn({ page, context });
60+
61+
await expect(tab(page, 'Account')).toHaveAttribute('aria-selected', 'true');
62+
await expect(page.getByText(fakeUser.email)).toBeVisible();
63+
});
64+
65+
test("lists the active organization's pages after the account's", async ({ page, context }) => {
66+
await signIn({ page, context });
67+
68+
await page.evaluate(orgId => window.Clerk?.setActive({ organization: orgId }), organization.id);
69+
await page.waitForFunction(orgId => window.Clerk?.organization?.id === orgId, organization.id);
70+
71+
await tab(page, 'General').click();
72+
await expect(tab(page, 'General')).toHaveAttribute('aria-selected', 'true');
73+
await expect(page.getByText(organization.name).first()).toBeVisible();
74+
});
75+
76+
test('renders a custom page', async ({ page, context }) => {
77+
await signIn({ page, context });
78+
79+
await tab(page, 'Custom page').click();
80+
await expect(page.getByText('custom-page-content')).toBeVisible();
81+
});
82+
});

0 commit comments

Comments
 (0)