Skip to content

Commit 5ee24ff

Browse files
refactor(ui): Clean up row structure (#9745)
1 parent 3862e47 commit 5ee24ff

16 files changed

Lines changed: 415 additions & 263 deletions

‎.changeset/wild-carpets-make.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

‎packages/swingset/src/stories/fixtures/user-profile-edit-name.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { UserProfileFormError } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.types';
22
import { UserProfileSaveError } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-account-section.types';
3-
import type { UserProfileEditNameValue } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-edit-name.view';
3+
import type { UserProfileEditNameValue } from '@clerk/ui/mosaic/user-profile/user-profile-account-section/user-profile-edit-name.dialog';
44
import { useState } from 'react';
55

66
export interface UserProfileEditNameFixtureOptions {

packages/ui/src/mosaic/user-profile/__tests__/user-profile-edit-name.view.test.tsx renamed to packages/ui/src/mosaic/user-profile/__tests__/user-profile-edit-name.dialog.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { describe, expect, it, vi } from 'vitest';
44

55
import { Button } from '../../components/button';
66
import { MosaicProvider } from '../../MosaicProvider';
7-
import type { UserProfileEditNameViewProps } from '../user-profile-account-section/user-profile-edit-name.view';
8-
import { UserProfileEditNameView } from '../user-profile-account-section/user-profile-edit-name.view';
7+
import type { UserProfileEditNameDialogProps } from '../user-profile-account-section/user-profile-edit-name.dialog';
8+
import { UserProfileEditNameDialog } from '../user-profile-account-section/user-profile-edit-name.dialog';
99

10-
function renderView(overrides: Partial<UserProfileEditNameViewProps> = {}) {
11-
const props: UserProfileEditNameViewProps = {
10+
function renderView(overrides: Partial<UserProfileEditNameDialogProps> = {}) {
11+
const props: UserProfileEditNameDialogProps = {
1212
open: true,
1313
onOpenChange: vi.fn(),
1414
firstName: 'Preston',
@@ -22,7 +22,7 @@ function renderView(overrides: Partial<UserProfileEditNameViewProps> = {}) {
2222
props,
2323
...render(
2424
<MosaicProvider>
25-
<UserProfileEditNameView {...props} />
25+
<UserProfileEditNameDialog {...props} />
2626
</MosaicProvider>,
2727
),
2828
};
@@ -32,7 +32,7 @@ const firstNameField = () => screen.getByLabelText('First name');
3232
const lastNameField = () => screen.getByLabelText('Last name');
3333
const saveButton = () => screen.getByRole('button', { name: 'Save changes' });
3434

35-
describe('UserProfileEditNameView', () => {
35+
describe('UserProfileEditNameDialog', () => {
3636
it('renders nothing until the caller opens it', () => {
3737
renderView({ open: false });
3838

packages/ui/src/mosaic/user-profile/__tests__/user-profile-edit-username.view.test.tsx renamed to packages/ui/src/mosaic/user-profile/__tests__/user-profile-edit-username.dialog.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { describe, expect, it, vi } from 'vitest';
44

55
import { Button } from '../../components/button';
66
import { MosaicProvider } from '../../MosaicProvider';
7-
import type { UserProfileEditUsernameViewProps } from '../user-profile-account-section/user-profile-edit-username.view';
8-
import { UserProfileEditUsernameView } from '../user-profile-account-section/user-profile-edit-username.view';
7+
import type { UserProfileEditUsernameDialogProps } from '../user-profile-account-section/user-profile-edit-username.dialog';
8+
import { UserProfileEditUsernameDialog } from '../user-profile-account-section/user-profile-edit-username.dialog';
99

10-
function renderView(overrides: Partial<UserProfileEditUsernameViewProps> = {}) {
11-
const props: UserProfileEditUsernameViewProps = {
10+
function renderView(overrides: Partial<UserProfileEditUsernameDialogProps> = {}) {
11+
const props: UserProfileEditUsernameDialogProps = {
1212
open: true,
1313
onOpenChange: vi.fn(),
1414
username: 'prestonxyz',
@@ -20,7 +20,7 @@ function renderView(overrides: Partial<UserProfileEditUsernameViewProps> = {}) {
2020
props,
2121
...render(
2222
<MosaicProvider>
23-
<UserProfileEditUsernameView {...props} />
23+
<UserProfileEditUsernameDialog {...props} />
2424
</MosaicProvider>,
2525
),
2626
};
@@ -29,7 +29,7 @@ function renderView(overrides: Partial<UserProfileEditUsernameViewProps> = {}) {
2929
const usernameField = () => screen.getByLabelText('Username');
3030
const saveButton = () => screen.getByRole('button', { name: 'Save changes' });
3131

32-
describe('UserProfileEditUsernameView', () => {
32+
describe('UserProfileEditUsernameDialog', () => {
3333
it('renders nothing until the caller opens it', () => {
3434
renderView({ open: false });
3535

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { render, screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
3+
import { describe, expect, it, vi } from 'vitest';
4+
5+
import { MosaicProvider } from '../../MosaicProvider';
6+
import type { UserProfilePictureRowViewProps } from '../user-profile-account-section/user-profile-picture-row.view';
7+
import { UserProfilePictureRowView } from '../user-profile-account-section/user-profile-picture-row.view';
8+
9+
function renderView(overrides: Partial<UserProfilePictureRowViewProps> = {}) {
10+
return render(
11+
<MosaicProvider>
12+
<UserProfilePictureRowView
13+
name='Preston Booth'
14+
{...overrides}
15+
/>
16+
</MosaicProvider>,
17+
);
18+
}
19+
20+
describe('UserProfilePictureRowView', () => {
21+
it('renders and clears the error supplied by the section', () => {
22+
const { rerender } = renderView({ errorMessage: 'File size exceeds the maximum limit of 10MB.' });
23+
24+
expect(screen.getByRole('alert')).toHaveTextContent('File size exceeds the maximum limit of 10MB.');
25+
26+
rerender(
27+
<MosaicProvider>
28+
<UserProfilePictureRowView name='Preston Booth' />
29+
</MosaicProvider>,
30+
);
31+
32+
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
33+
});
34+
35+
it('offers Upload while the avatar is only a generated default', () => {
36+
renderView({
37+
hasImage: false,
38+
imageUrl: 'https://img.clerk.com/generated-default.png',
39+
onChange: vi.fn(),
40+
onRemove: vi.fn(),
41+
});
42+
43+
expect(screen.getByRole('button', { name: 'Upload' })).toBeInTheDocument();
44+
expect(screen.queryByRole('button', { name: 'Manage profile picture' })).toBeNull();
45+
});
46+
47+
it('offers change and remove in a menu once a profile picture is set', async () => {
48+
const onChange = vi.fn();
49+
const onRemove = vi.fn();
50+
const user = userEvent.setup();
51+
renderView({
52+
hasImage: true,
53+
imageUrl: 'https://example.com/avatar.png',
54+
onChange,
55+
onRemove,
56+
});
57+
58+
expect(screen.queryByRole('button', { name: 'Upload' })).toBeNull();
59+
await user.click(screen.getByRole('button', { name: 'Manage profile picture' }));
60+
61+
expect(screen.getByRole('menuitem', { name: 'Change avatar' })).toBeInTheDocument();
62+
await user.click(screen.getByRole('menuitem', { name: 'Remove avatar' }));
63+
64+
expect(onRemove).toHaveBeenCalledOnce();
65+
});
66+
});

‎packages/ui/src/mosaic/user-profile/__tests__/user-profile-profile-panel.view.test.tsx‎

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ describe('UserProfileProfilePanelView', () => {
7171
expect(screen.queryByRole('button', { name: 'Manage profile picture' })).toBeNull();
7272

7373
const input = container.querySelector<HTMLInputElement>('input[type="file"]');
74-
expect(input).not.toBeNull();
74+
if (!input) {
75+
throw new Error('File picker not found');
76+
}
7577
const file = new File(['avatar'], 'avatar.png', { type: 'image/png' });
76-
await user.upload(input as HTMLInputElement, file);
78+
await user.upload(input, file);
7779

7880
expect(onProfilePictureChange).toHaveBeenCalledWith(file);
7981
});
@@ -85,7 +87,11 @@ describe('UserProfileProfilePanelView', () => {
8587
const { container } = renderView({ onProfilePictureChange, onProfilePictureReject });
8688

8789
const oversized = new File([new Uint8Array(10 * 1000 * 1000 + 1)], 'big.png', { type: 'image/png' });
88-
await user.upload(container.querySelector<HTMLInputElement>('input[type="file"]') as HTMLInputElement, oversized);
90+
const input = container.querySelector<HTMLInputElement>('input[type="file"]');
91+
if (!input) {
92+
throw new Error('File picker not found');
93+
}
94+
await user.upload(input, oversized);
8995

9096
expect(onProfilePictureChange).not.toHaveBeenCalled();
9197
expect(onProfilePictureReject).toHaveBeenCalledWith([{ file: oversized, reason: 'size' }]);
@@ -96,7 +102,10 @@ describe('UserProfileProfilePanelView', () => {
96102
it('clears the rejection once an acceptable file is picked', async () => {
97103
const user = userEvent.setup();
98104
const { container } = renderView({ onProfilePictureChange: vi.fn() });
99-
const input = container.querySelector<HTMLInputElement>('input[type="file"]') as HTMLInputElement;
105+
const input = container.querySelector<HTMLInputElement>('input[type="file"]');
106+
if (!input) {
107+
throw new Error('File picker not found');
108+
}
100109

101110
await user.upload(input, new File([new Uint8Array(10 * 1000 * 1000 + 1)], 'big.png', { type: 'image/png' }));
102111
expect(screen.getByRole('alert')).toBeInTheDocument();
@@ -105,38 +114,6 @@ describe('UserProfileProfilePanelView', () => {
105114
expect(screen.queryByRole('alert')).toBeNull();
106115
});
107116

108-
it('offers Upload while the avatar is only a generated default', () => {
109-
renderView({
110-
hasImage: false,
111-
imageUrl: 'https://img.clerk.com/generated-default.png',
112-
onProfilePictureChange: vi.fn(),
113-
onRemoveProfilePicture: vi.fn(),
114-
});
115-
116-
expect(screen.getByRole('button', { name: 'Upload' })).toBeInTheDocument();
117-
expect(screen.queryByRole('button', { name: 'Manage profile picture' })).toBeNull();
118-
});
119-
120-
it('offers change and remove in a menu once a profile picture is set', async () => {
121-
const onProfilePictureChange = vi.fn();
122-
const onRemoveProfilePicture = vi.fn();
123-
const user = userEvent.setup();
124-
renderView({
125-
hasImage: true,
126-
imageUrl: 'https://example.com/avatar.png',
127-
onProfilePictureChange,
128-
onRemoveProfilePicture,
129-
});
130-
131-
expect(screen.queryByRole('button', { name: 'Upload' })).toBeNull();
132-
await user.click(screen.getByRole('button', { name: 'Manage profile picture' }));
133-
134-
expect(screen.getByRole('menuitem', { name: 'Change avatar' })).toBeInTheDocument();
135-
await user.click(screen.getByRole('menuitem', { name: 'Remove avatar' }));
136-
137-
expect(onRemoveProfilePicture).toHaveBeenCalledOnce();
138-
});
139-
140117
it('breaks out both contact types when multiple accounts are allowed', () => {
141118
renderView({
142119
emails: [{ id: 'email_1', value: '[email protected]', isDefault: true }],
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as stylex from '@stylexjs/stylex';
2+
3+
import { space } from '../../tokens.stylex';
4+
5+
export const styles = stylex.create({
6+
sections: {
7+
gap: space['8'],
8+
display: 'flex',
9+
flexDirection: 'column',
10+
width: '100%',
11+
},
12+
});

0 commit comments

Comments
 (0)