Skip to content

Commit d54c736

Browse files
feat(mosaic): show the Add passkey button pending while the passkey request runs
1 parent dbd0823 commit d54c736

3 files changed

Lines changed: 27 additions & 4 deletions

File tree

‎.changeset/passkey-add-pending.md‎

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

‎packages/mosaic/src/features/user-profile/user-profile-passkeys-section/__tests__/user-profile-passkeys-lifecycle.feature.test.tsx‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,26 @@ describe('Passkey action errors', () => {
8282
});
8383
});
8484

85+
describe('Adding a passkey', () => {
86+
it('shows the Add button pending while the passkey request runs', async () => {
87+
serveAccounts();
88+
await renderWithClerk(<UserProfilePasskeysSection />);
89+
const creation = holdRequests('post', '/v1/me/passkeys');
90+
const user = userEvent.setup();
91+
92+
try {
93+
await user.click(screen.getByRole('button', { name: 'Add passkey' }));
94+
await waitFor(() => expect(creation.requests).toHaveLength(1));
95+
expect(screen.getByRole('button', { name: 'Add passkey' })).toHaveAttribute('aria-busy', 'true');
96+
await waitFor(() => expect(screen.getByRole('progressbar')).toBeVisible());
97+
} finally {
98+
creation.fail('form_param_invalid', 'Credential failed');
99+
}
100+
await waitFor(() => expect(screen.getByRole('button', { name: 'Add passkey' })).toBeEnabled());
101+
await waitFor(() => expect(screen.queryByRole('progressbar')).toBeNull());
102+
});
103+
});
104+
85105
describe('Changing the active passkey account', () => {
86106
it('clears the previous account Add error after a user switch', async () => {
87107
serveAccounts();

‎packages/mosaic/src/features/user-profile/user-profile-passkeys-section/user-profile-passkeys-section.view.tsx‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Ref } from 'react';
33
import type { ConfirmController } from '../../../blocks/confirm';
44
import { Confirmation } from '../../../blocks/confirmation';
55
import { ReverificationDialog } from '../../../blocks/reverification';
6-
import { Button } from '../../../components/button';
6+
import { SubmitButton } from '../../../components/button';
77
import type { DialogFocusTarget } from '../../../components/dialog';
88
import { Field } from '../../../components/field';
99
import { Icon } from '../../../components/icon';
@@ -69,14 +69,15 @@ export function UserProfilePasskeysSectionView({
6969
</Section.Content>
7070
{onAdd ? (
7171
<Section.Actions>
72-
<Button
72+
<SubmitButton
7373
ref={addButtonRef}
74+
type='button'
7475
aria-label={m.addLabel}
7576
color='neutral'
7677
size='sm'
7778
variant='outline'
79+
isPending={isAdding && !addReverification?.visible}
7880
disabled={isAdding}
79-
aria-busy={isAdding}
8081
onClick={onAdd}
8182
>
8283
<Icon
@@ -85,7 +86,7 @@ export function UserProfilePasskeysSectionView({
8586
size='sm'
8687
/>
8788
{m.add}
88-
</Button>
89+
</SubmitButton>
8990
</Section.Actions>
9091
) : null}
9192
</Section.Header>

0 commit comments

Comments
 (0)