Skip to content

Commit a658ac5

Browse files
committed
test: add concrete assertions to verify null-update handling in shouldIgnoreNullUpdate tests
1 parent 6fd3543 commit a658ac5

1 file changed

Lines changed: 38 additions & 18 deletions

File tree

packages/clerk-js/src/core/__tests__/state.test.ts

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,51 +59,71 @@ describe('State', () => {
5959
expect(signUpResourceSignal().resource?.id).toBe('signup_123');
6060
});
6161

62-
it('should allow null resource update when previous resource exists and canBeDiscarded is true', () => {
63-
// Arrange: Set up a SignUp with id
62+
it('should allow null resource update when previous resource exists and canBeDiscarded is true', async () => {
63+
// Arrange: Set up a SignUp with id and mock setActive
64+
const mockSetActive = vi.fn().mockResolvedValue({});
65+
SignUp.clerk = { setActive: mockSetActive } as any;
66+
6467
const existingSignUp = new SignUp({
6568
id: 'signup_123',
6669
status: 'complete',
6770
created_session_id: 'session_123',
6871
} as any);
6972
expect(signUpResourceSignal().resource).toBe(existingSignUp);
73+
expect(existingSignUp.__internal_future.canBeDiscarded).toBe(false);
7074

71-
// Simulate finalize() being called - which sets canBeDiscarded to true
72-
// We need to access the private field, so we'll use a workaround
73-
// by calling the internal method that sets it
74-
const mockSetActive = vi.fn().mockResolvedValue({});
75-
SignUp.clerk = { setActive: mockSetActive } as any;
75+
// Act: Call finalize() which sets canBeDiscarded to true
76+
await existingSignUp.__internal_future.finalize();
77+
78+
// Verify canBeDiscarded is now true
79+
expect(existingSignUp.__internal_future.canBeDiscarded).toBe(true);
80+
expect(mockSetActive).toHaveBeenCalledWith({ session: 'session_123', navigate: undefined });
7681

77-
// Note: We can't easily call finalize() here because it's async and calls setActive
78-
// Instead, let's directly test the scenario by creating a new SignUp and checking behavior
82+
// Now emit a null resource update (simulating client refresh with null sign_up)
83+
const nullSignUp = new SignUp(null);
7984

80-
// For this test, we'll verify the opposite case is working
81-
// The null update should be blocked when canBeDiscarded is false
85+
// Assert: The null update SHOULD be allowed because canBeDiscarded is true
86+
// shouldIgnoreNullUpdate returns false when canBeDiscarded is true
87+
expect(signUpResourceSignal().resource).toBe(nullSignUp);
88+
expect(signUpResourceSignal().resource?.id).toBeUndefined();
8289
});
8390

8491
it('should allow null resource update after reset() is called', async () => {
85-
// Arrange: Set up mock client
92+
// Arrange: Set up mock client that tracks the new SignUp created during reset
93+
let newSignUpFromReset: SignUp | null = null;
8694
const mockClient = {
8795
signUp: new SignUp(null),
8896
resetSignUp: vi.fn().mockImplementation(function (this: typeof mockClient) {
89-
const newSignUp = new SignUp(null);
90-
this.signUp = newSignUp;
91-
eventBus.emit('resource:error', { resource: newSignUp, error: null });
97+
newSignUpFromReset = new SignUp(null);
98+
this.signUp = newSignUpFromReset;
99+
// reset() emits resource:error to clear errors, but the signal update
100+
// happens via resource:update when the new SignUp is created
101+
eventBus.emit('resource:error', { resource: newSignUpFromReset, error: null });
102+
// Emit resource:update to update the signal (simulating what happens in real flow)
103+
eventBus.emit('resource:update', { resource: newSignUpFromReset });
92104
}),
93105
};
94106
SignUp.clerk = { client: mockClient } as any;
95107

96108
// Create a SignUp with id
97109
const existingSignUp = new SignUp({ id: 'signup_123', status: 'missing_requirements' } as any);
98110
expect(signUpResourceSignal().resource?.id).toBe('signup_123');
111+
expect(existingSignUp.__internal_future.canBeDiscarded).toBe(false);
99112

100113
// Act: Call reset() - this sets canBeDiscarded to true before resetting
101114
await existingSignUp.__internal_future.reset();
102115

103-
// Assert: After reset, the signal should have a new null SignUp
104-
// Note: reset() calls client.resetSignUp() which emits resource:error, not resource:update
105-
// So the signal update happens through a different path
116+
// Assert: Verify reset was called
106117
expect(mockClient.resetSignUp).toHaveBeenCalled();
118+
119+
// Assert: Verify canBeDiscarded was set to true on the original SignUp
120+
expect(existingSignUp.__internal_future.canBeDiscarded).toBe(true);
121+
122+
// Assert: Verify the signal was updated with a new SignUp that has no id
123+
// The previous id 'signup_123' should be gone
124+
expect(signUpResourceSignal().resource).toBe(newSignUpFromReset);
125+
expect(signUpResourceSignal().resource?.id).toBeUndefined();
126+
expect(signUpResourceSignal().resource).not.toBe(existingSignUp);
107127
});
108128

109129
it('should allow resource update when new resource has an id (not a null update)', () => {

0 commit comments

Comments
 (0)