Skip to content

Commit b16518e

Browse files
authored
fix(clerk-js): Allow signUp.password after signUp.create (#7680)
1 parent 0a9cce3 commit b16518e

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

.changeset/slick-streets-stick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Fix issue where `signUp.password()` created a new sign-up when called after `signUp.create()`

packages/clerk-js/src/core/resources/SignUp.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,11 @@ class SignUpFuture implements SignUpFutureResource {
766766
unsafeMetadata: params.unsafeMetadata ? normalizeUnsafeMetadata(params.unsafeMetadata) : undefined,
767767
};
768768

769-
await this.#resource.__internal_basePost({ path: this.#resource.pathRoot, body });
769+
if (this.#resource.id) {
770+
await this.#resource.__internal_basePatch({ body });
771+
} else {
772+
await this.#resource.__internal_basePost({ path: this.#resource.pathRoot, body });
773+
}
770774
});
771775
}
772776

packages/clerk-js/src/core/resources/__tests__/SignUp.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,71 @@ describe('SignUp', () => {
596596
});
597597
});
598598

599+
describe('password', () => {
600+
afterEach(() => {
601+
vi.clearAllMocks();
602+
vi.unstubAllGlobals();
603+
});
604+
605+
it('creates signup with password when no existing signup', async () => {
606+
const mockFetch = vi.fn().mockResolvedValue({
607+
client: null,
608+
response: { id: 'signup_123', status: 'missing_requirements' },
609+
});
610+
BaseResource._fetch = mockFetch;
611+
612+
const signUp = new SignUp();
613+
await signUp.__internal_future.password({ password: 'test-password-123' });
614+
615+
expect(mockFetch).toHaveBeenCalledWith(
616+
expect.objectContaining({
617+
method: 'POST',
618+
path: '/client/sign_ups',
619+
body: expect.objectContaining({
620+
strategy: 'password',
621+
password: 'test-password-123',
622+
}),
623+
}),
624+
);
625+
});
626+
627+
it('updates existing signup when already created', async () => {
628+
const mockFetch = vi.fn().mockResolvedValue({
629+
client: null,
630+
response: { id: 'signup_123', status: 'missing_requirements' },
631+
});
632+
BaseResource._fetch = mockFetch;
633+
634+
const signUp = new SignUp({ id: 'signup_123' } as any);
635+
await signUp.__internal_future.password({ password: 'test-password-123' });
636+
637+
// Should use PATCH to update existing signup, not POST to create a new one
638+
expect(mockFetch).toHaveBeenCalledWith(
639+
expect.objectContaining({
640+
method: 'PATCH',
641+
path: '/client/sign_ups/signup_123',
642+
body: expect.objectContaining({
643+
strategy: 'password',
644+
password: 'test-password-123',
645+
}),
646+
}),
647+
);
648+
});
649+
650+
it('returns error property on success', async () => {
651+
const mockFetch = vi.fn().mockResolvedValue({
652+
client: null,
653+
response: { id: 'signup_123', status: 'missing_requirements' },
654+
});
655+
BaseResource._fetch = mockFetch;
656+
657+
const signUp = new SignUp();
658+
const result = await signUp.__internal_future.password({ password: 'test-password-123' });
659+
660+
expect(result).toHaveProperty('error', null);
661+
});
662+
});
663+
599664
describe('ticket', () => {
600665
afterEach(() => {
601666
vi.clearAllMocks();

0 commit comments

Comments
 (0)