Skip to content

Commit 2df7d14

Browse files
authored
fix: restore Sendbird newInstance handling (#1419)
## Summary Restores the legacy `isNewApp -> newInstance` behavior in the migrated `SendbirdProvider` flow. ## Why During the `SendbirdProvider` migration, the old `useConnect` logic that detected app changes and passed `isNewApp` into SDK initialization was removed. The migrated path left `newInstance` commented out in `initSDK`, which regressed the previous behavior. ## What changed - Reintroduced legacy `appId` change tracking in `SendbirdContextManager` - Propagated `isNewApp` through `actions.connect()` into `initSDK()` - Restored `newInstance: isNewApp` in `SendbirdChat.init()` - Added regression coverage for provider behavior, connect propagation, and SDK init params ## Validation - `yarn test -- src/lib/Sendbird/__tests__/SendbirdProvider.spec.tsx src/lib/Sendbird/__tests__/useSendbird.spec.tsx src/lib/Sendbird/__tests__/utils.spec.ts --runInBand` - `yarn eslint src/lib/Sendbird/context/SendbirdProvider.tsx src/lib/Sendbird/context/hooks/useSendbird.tsx src/lib/Sendbird/utils.ts src/lib/Sendbird/__tests__/SendbirdProvider.spec.tsx src/lib/Sendbird/__tests__/useSendbird.spec.tsx src/lib/Sendbird/__tests__/utils.spec.ts` ## Impact This restores the pre-migration SDK initialization behavior when switching to a different `appId`, while keeping regression tests around the migrated provider path.
1 parent b12f4b2 commit 2df7d14

6 files changed

Lines changed: 127 additions & 5 deletions

File tree

src/lib/Sendbird/__tests__/SendbirdProvider.spec.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,71 @@ describe('SendbirdProvider', () => {
5555
expect(mockActions.connect).toHaveBeenCalledWith(
5656
expect.objectContaining({
5757
appId: 'mockAppId',
58+
isNewApp: true,
5859
userId: 'mockUserId',
5960
}),
6061
);
6162
});
6263

64+
it('should preserve the legacy isNewApp behavior across app and user changes', () => {
65+
const { rerender } = render(
66+
<SendbirdContextProvider appId="mockAppId" userId="mockUserId">
67+
<div data-testid="child">Child Component</div>
68+
</SendbirdContextProvider>,
69+
);
70+
71+
expect(mockActions.connect).toHaveBeenNthCalledWith(1, expect.objectContaining({
72+
appId: 'mockAppId',
73+
isNewApp: true,
74+
userId: 'mockUserId',
75+
}));
76+
77+
rerender(
78+
<SendbirdContextProvider appId="mockAppId" userId="nextUserId">
79+
<div data-testid="child">Child Component</div>
80+
</SendbirdContextProvider>,
81+
);
82+
83+
expect(mockActions.connect).toHaveBeenNthCalledWith(2, expect.objectContaining({
84+
appId: 'mockAppId',
85+
isNewApp: false,
86+
userId: 'nextUserId',
87+
}));
88+
89+
rerender(
90+
<SendbirdContextProvider appId="nextAppId" userId="nextUserId">
91+
<div data-testid="child">Child Component</div>
92+
</SendbirdContextProvider>,
93+
);
94+
95+
expect(mockActions.connect).toHaveBeenNthCalledWith(3, expect.objectContaining({
96+
appId: 'nextAppId',
97+
isNewApp: true,
98+
userId: 'nextUserId',
99+
}));
100+
});
101+
102+
it('should reconnect on StrictMode remount with the same appId and userId', () => {
103+
render(
104+
<React.StrictMode>
105+
<SendbirdContextProvider appId="mockAppId" userId="mockUserId">
106+
<div data-testid="child">Child Component</div>
107+
</SendbirdContextProvider>
108+
</React.StrictMode>,
109+
);
110+
111+
expect(mockActions.connect).toHaveBeenCalledTimes(2);
112+
expect(mockActions.connect).toHaveBeenNthCalledWith(1, expect.objectContaining({
113+
appId: 'mockAppId',
114+
isNewApp: true,
115+
userId: 'mockUserId',
116+
}));
117+
expect(mockActions.connect).toHaveBeenNthCalledWith(2, expect.objectContaining({
118+
appId: 'mockAppId',
119+
userId: 'mockUserId',
120+
}));
121+
});
122+
63123
it('should call disconnect on unmount', () => {
64124
const { unmount } = render(
65125
<SendbirdContextProvider appId="mockAppId" userId="mockUserId">

src/lib/Sendbird/__tests__/useSendbird.spec.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,33 @@ describe('useSendbird', () => {
362362
appId: 'mockAppId',
363363
customApiHost: undefined,
364364
customWebSocketHost: undefined,
365+
isNewApp: false,
365366
sdkInitParams: {},
366367
});
367368

368369
expect(mockSetupSDK).toHaveBeenCalled();
369370
});
370371

372+
it('should pass isNewApp through to initSDK during connect', async () => {
373+
const { result } = renderHook(() => useSendbird(), { wrapper });
374+
const mockInitSDK = jest.requireMock('../utils').initSDK;
375+
376+
await act(async () => {
377+
await result.current.actions.connect({
378+
logger: mockLogger,
379+
userId: 'mockUserId',
380+
appId: 'mockAppId',
381+
accessToken: 'mockAccessToken',
382+
isNewApp: true,
383+
});
384+
});
385+
386+
expect(mockInitSDK).toHaveBeenCalledWith(expect.objectContaining({
387+
appId: 'mockAppId',
388+
isNewApp: true,
389+
}));
390+
});
391+
371392
it('should handle connection failure and trigger onFailed event handler', async () => {
372393
const { result } = renderHook(() => useSendbird(), { wrapper });
373394

src/lib/Sendbird/__tests__/utils.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,37 @@ describe('initSDK', () => {
109109
}),
110110
);
111111
});
112+
113+
it('uses isNewApp to set the newInstance init option', () => {
114+
initSDK({
115+
appId: 'testAppId',
116+
isNewApp: true,
117+
});
118+
119+
expect(SendbirdChat.init).toHaveBeenCalledWith(
120+
expect.objectContaining({
121+
appId: 'testAppId',
122+
newInstance: true,
123+
}),
124+
);
125+
});
126+
127+
it('preserves an explicit sdkInitParams.newInstance override', () => {
128+
initSDK({
129+
appId: 'testAppId',
130+
isNewApp: false,
131+
sdkInitParams: {
132+
newInstance: true,
133+
},
134+
});
135+
136+
expect(SendbirdChat.init).toHaveBeenCalledWith(
137+
expect.objectContaining({
138+
appId: 'testAppId',
139+
newInstance: true,
140+
}),
141+
);
142+
});
112143
});
113144

114145
const mockSdk = {

src/lib/Sendbird/context/SendbirdProvider.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,17 @@ const SendbirdContextManager = ({
100100
appInfoStore,
101101
actions,
102102
});
103+
const previousAppIdRef = useRef('');
103104

104105
// Reconnect when necessary
105106
useEffect(() => {
107+
const isNewApp = previousAppIdRef.current !== appId;
108+
previousAppIdRef.current = appId;
109+
106110
actions.connect({
107111
appId,
108112
userId,
113+
isNewApp,
109114
accessToken,
110115
isUserIdUsedForNickname,
111116
isMobile,

src/lib/Sendbird/context/hooks/useSendbird.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export const useSendbird = () => {
178178
logger,
179179
userId,
180180
appId,
181+
isNewApp = false,
181182
accessToken,
182183
nickname,
183184
profileUrl,
@@ -197,6 +198,7 @@ export const useSendbird = () => {
197198

198199
const sdk = initSDK({
199200
appId,
201+
isNewApp,
200202
customApiHost,
201203
customWebSocketHost,
202204
sdkInitParams,

src/lib/Sendbird/utils.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import SendbirdChat, { DeviceOsPlatform, SendbirdChatWith, SendbirdPlatform, Sen
22
import { GroupChannelModule } from '@sendbird/chat/groupChannel';
33
import { OpenChannelModule } from '@sendbird/chat/openChannel';
44

5-
import type { AppInfoStore, CustomExtensionParams, SdkStore, SendbirdState, UserStore } from './types';
5+
import type { AppInfoStore, CustomExtensionParams, SdkStore, SendbirdChatInitParams, SendbirdState, UserStore } from './types';
66
import { LoggerInterface } from '../Logger';
77

88
type UpdateAppInfoStoreType = (state: SendbirdState, payload: AppInfoStore) => SendbirdState;
@@ -47,21 +47,24 @@ export const updateUserStore: UpdateUserStoreType = (state, payload) => {
4747

4848
export function initSDK({
4949
appId,
50+
isNewApp = false,
5051
customApiHost,
5152
customWebSocketHost,
5253
sdkInitParams = {},
5354
}: {
5455
appId: string;
56+
isNewApp?: boolean;
5557
customApiHost?: string;
5658
customWebSocketHost?: string;
57-
sdkInitParams?: Record<string, any>;
59+
sdkInitParams?: SendbirdChatInitParams;
5860
}) {
59-
const params = Object.assign(sdkInitParams, {
61+
const params = {
62+
...sdkInitParams,
6063
appId,
6164
modules: [new GroupChannelModule(), new OpenChannelModule()],
62-
// newInstance: isNewApp,
65+
newInstance: typeof sdkInitParams.newInstance !== 'undefined' ? sdkInitParams.newInstance : isNewApp,
6366
localCacheEnabled: typeof sdkInitParams.localCacheEnabled !== 'undefined' ? sdkInitParams.localCacheEnabled : true,
64-
});
67+
};
6568

6669
if (customApiHost) params.customApiHost = customApiHost;
6770
if (customWebSocketHost) params.customWebSocketHost = customWebSocketHost;

0 commit comments

Comments
 (0)