diff --git a/app/definitions/ILoginCredentials.ts b/app/definitions/ILoginCredentials.ts index 11b9020fe8..081218fb81 100644 --- a/app/definitions/ILoginCredentials.ts +++ b/app/definitions/ILoginCredentials.ts @@ -1,12 +1,6 @@ export type { - ICredentialsAppleAPI, - ICredentialsAuthenticated, ICredentialsCasAPI, - ICredentialsCrowdAPI, - ICredentialsLdapAPI, - ICredentialsOAuth, ICredentialsPasswordAPI, ICredentialsSamlAPI, - ICredentialsTotpAPI, ILoginCredentials } from '@rocket.chat/sdk/interfaces'; diff --git a/app/lib/methods/subscriptions/__tests__/roomSubscription.integration.test.ts b/app/lib/methods/subscriptions/__tests__/roomSubscription.integration.test.ts index 2cd653af94..463f9d2094 100644 --- a/app/lib/methods/subscriptions/__tests__/roomSubscription.integration.test.ts +++ b/app/lib/methods/subscriptions/__tests__/roomSubscription.integration.test.ts @@ -74,7 +74,7 @@ import buildMessage from '../../helpers/buildMessage'; import { subscribeRoom, unsubscribeRoom } from '../../../../actions/room'; import { clearUserTyping } from '../../../../actions/usersTyping'; import { - flush, + flushMicrotasksAndTimers, framesOn, makeCollection as makeBaseCollection, makeReduxStore, @@ -131,18 +131,18 @@ afterEach(() => { async function connectDriver() { sdk.initialize('https://example.com'); const connectPromise = sdk.connect(); - await flush(); + await flushMicrotasksAndTimers(); mockConnections[0].onopen(); - await flush(); + await flushMicrotasksAndTimers(); await connectPromise; } async function subscribeToRoom(rid: string) { const room = new RoomSubscription(rid); const subscribing = room.subscribe(); - await flush(); + await flushMicrotasksAndTimers(); await subscribing; - await flush(); + await flushMicrotasksAndTimers(); return room; } @@ -165,7 +165,7 @@ describe('RoomSubscription over the real SDK', () => { collection: 'stream-room-messages', fields: { eventName: 'room-rid', args: [MESSAGE] } }); - await flush(); + await flushMicrotasksAndTimers(); expect(buildMessage).toHaveBeenCalledTimes(1); expect(getMessageById).toHaveBeenCalledWith('msg-1'); @@ -179,7 +179,7 @@ describe('RoomSubscription over the real SDK', () => { const room = await subscribeToRoom('room-rid'); await room.unsubscribe(); - await flush(); + await flushMicrotasksAndTimers(); expect(framesOn(mockConnections[0], 'unsub')).toHaveLength(5); expect(redux.store.dispatch).toHaveBeenCalledWith(unsubscribeRoom('room-rid')); @@ -190,7 +190,7 @@ describe('RoomSubscription over the real SDK', () => { collection: 'stream-room-messages', fields: { eventName: 'room-rid', args: [MESSAGE] } }); - await flush(); + await flushMicrotasksAndTimers(); expect(buildMessage).not.toHaveBeenCalled(); }); diff --git a/app/lib/services/__tests__/connect.integration.test.ts b/app/lib/services/__tests__/connect.integration.test.ts index bdb75990c6..f8d1b6a556 100644 --- a/app/lib/services/__tests__/connect.integration.test.ts +++ b/app/lib/services/__tests__/connect.integration.test.ts @@ -9,7 +9,7 @@ import { setActiveUsers } from '../../../actions/activeUsers'; import { updateSettings } from '../../../actions/settings'; import { updatePermission } from '../../../actions/permissions'; import { _activeUsers, _setUserTimer } from '../../methods/setUser'; -import { flush, framesOn, makeCollection, makeReduxStore, receiveFrame } from '../../testUtils/sdkIntegration'; +import { flushMicrotasksAndTimers, framesOn, makeCollection, makeReduxStore, receiveFrame } from '../../testUtils/sdkIntegration'; import type { MockConnection } from '../../testUtils/sdkIntegration'; import type * as SdkIntegration from '../../testUtils/sdkIntegration'; @@ -119,10 +119,10 @@ afterEach(() => { async function connectAndDriveHandshake(server = 'https://example.com') { await connect({ server }); - await flush(); + await flushMicrotasksAndTimers(); expect(mockConnections.length).toBeGreaterThan(0); mockConnections[0].onopen(); - await flush(); + await flushMicrotasksAndTimers(); } describe('connect() over the real SDK', () => { @@ -139,7 +139,7 @@ describe('connect() over the real SDK', () => { redux.state.meteor.connected = true; receiveFrame(mockConnections[0], { msg: 'connected', session: 'again' }); - await flush(); + await flushMicrotasksAndTimers(); expect(redux.store.dispatch.mock.calls.filter(([action]) => action.type === connectSuccess().type)).toHaveLength(1); }); @@ -148,7 +148,7 @@ describe('connect() over the real SDK', () => { await connectAndDriveHandshake(); mockConnections[0].onclose({ code: 1006 }); - await flush(); + await flushMicrotasksAndTimers(); expect(redux.store.dispatch).toHaveBeenCalledWith(disconnectAction()); }); @@ -168,12 +168,12 @@ describe('connect() over the real SDK', () => { const before = successCount(); await connect({ server: 'https://b.example.com' }); - await flush(); + await flushMicrotasksAndTimers(); expect(firstConnection.close).toHaveBeenCalled(); firstConnection.onmessage({ data: JSON.stringify({ msg: 'connected', session: 'x' }) }); - await flush(); + await flushMicrotasksAndTimers(); expect(successCount()).toBe(before); }); @@ -188,7 +188,7 @@ describe('login() over the real SDK', () => { await connectLoggedIn(); const loginPromise = login({ user: 'the-user', password: 'secret' }); - await flush(); + await flushMicrotasksAndTimers(); const user = await loginPromise; expect(user).toEqual( @@ -211,7 +211,7 @@ describe('login() over the real SDK', () => { await connectLoggedIn(); const loginPromise = login({ user: 'the-user', password: 'secret' }); - await flush(); + await flushMicrotasksAndTimers(); const user = await loginPromise; expect(user).toEqual( @@ -230,7 +230,7 @@ describe('login() over the real SDK', () => { await connectLoggedIn(); const loginPromise = login({ user: 'the-user', password: 'secret' }); - await flush(); + await flushMicrotasksAndTimers(); const user = await loginPromise; expect(user).toEqual( @@ -246,7 +246,7 @@ describe('login() over the real SDK', () => { await connectLoggedIn(); const loginPromise = loginWithPassword({ user: 'the-user', password: 'secret' }); - await flush(); + await flushMicrotasksAndTimers(); await loginPromise; const loginCall = (global.fetch as jest.Mock).mock.calls.find(([url]) => String(url).includes('/api/v1/login')); @@ -259,7 +259,7 @@ describe('login() over the real SDK', () => { await connectLoggedIn(); const loginPromise = loginWithPassword({ user: 'the-user', password: 'secret' }); - await flush(); + await flushMicrotasksAndTimers(); await loginPromise; const loginCall = (global.fetch as jest.Mock).mock.calls.find(([url]) => String(url).includes('/api/v1/login')); @@ -278,7 +278,7 @@ describe('onStreamData handlers over real frames', () => { collection: 'stream-notify-all', fields: { eventName: 'public-settings-changed', args: [null, { _id: 'Site_Name', value: 'New Name' }] } }); - await flush(); + await flushMicrotasksAndTimers(); expect(redux.store.dispatch).toHaveBeenCalledWith(updateSettings('Site_Name', 'New Name')); }); @@ -292,7 +292,7 @@ describe('onStreamData handlers over real frames', () => { collection: 'stream-user-presence', fields: { uid: 'user-id', args: [['user-id', 1, '', '', undefined]] } }); - await flush(); + await flushMicrotasksAndTimers(); expect(redux.store.dispatch).toHaveBeenCalledWith( setActiveUsers({ 'user-id': expect.objectContaining({ status: 'online' }) }) @@ -309,7 +309,7 @@ describe('onStreamData handlers over real frames', () => { collection: 'stream-notify-logged', fields: { eventName: 'user-status', args: [['user-id', 'online', 1, '', '', undefined]] } }); - await flush(); + await flushMicrotasksAndTimers(); expect(_activeUsers.activeUsers['user-id']).toEqual(expect.objectContaining({ status: 'online' })); expect(redux.store.dispatch).toHaveBeenCalledWith(setUser(expect.objectContaining({ status: 'online' }))); @@ -324,7 +324,7 @@ describe('onStreamData handlers over real frames', () => { collection: 'stream-notify-logged', fields: { eventName: 'permissions-changed', args: [null, { _id: 'create-c', roles: ['admin'] }] } }); - await flush(); + await flushMicrotasksAndTimers(); expect(redux.store.dispatch).toHaveBeenCalledWith(updatePermission('create-c', ['admin'])); }); @@ -339,7 +339,7 @@ describe('onStreamData handlers over real frames', () => { collection: 'stream-notify-logged', fields: { eventName: 'Users:NameChanged', args: [{ _id: 'user-id', username: 'renamed' }] } }); - await flush(); + await flushMicrotasksAndTimers(); expect(collection.find).toHaveBeenCalledWith('user-id'); expect(database.active.write).toHaveBeenCalled(); @@ -349,7 +349,7 @@ describe('onStreamData handlers over real frames', () => { await connectAndDriveHandshake(); receiveFrame(mockConnections[0], { msg: 'changed', collection: 'stream-force_logout', fields: {} }); - await flush(); + await flushMicrotasksAndTimers(); expect(redux.store.dispatch).toHaveBeenCalledWith(logout(true)); }); @@ -363,7 +363,7 @@ describe('onStreamData handlers over real frames', () => { id: 'user-id', fields: { username: 'the-user', status: 'online' } }); - await flush(); + await flushMicrotasksAndTimers(); expect(_activeUsers.activeUsers['user-id']).toEqual(expect.objectContaining({ status: 'online' })); }); @@ -375,7 +375,7 @@ describe('sdk.subscribeRoom() over the real SDK', () => { await connectAndDriveHandshake(); const subscribing = sdk.subscribeRoom('room-rid'); - await flush(); + await flushMicrotasksAndTimers(); await subscribing; const subs = framesOn(mockConnections[0], 'sub'); @@ -400,7 +400,7 @@ describe('sdk.subscribeRoom() over the real SDK', () => { await connectAndDriveHandshake(); const subscribing = sdk.subscribeRoom('room-rid'); - await flush(); + await flushMicrotasksAndTimers(); await subscribing; const subs = framesOn(mockConnections[0], 'sub'); diff --git a/app/lib/services/__tests__/socketHealth.integration.test.ts b/app/lib/services/__tests__/socketHealth.integration.test.ts index aaae464b76..0b33c773c1 100644 --- a/app/lib/services/__tests__/socketHealth.integration.test.ts +++ b/app/lib/services/__tests__/socketHealth.integration.test.ts @@ -45,10 +45,6 @@ describe('recoverSocket against the real SDK socket', () => { jest.useRealTimers(); }); - it('exposes the ping interval the health classification depends on', () => { - expect(driver.pingInterval).toBe(PING_INTERVAL); - }); - it('keeps a doubtful socket when the round trip gets a pong', async () => { backdateLastPing(driver, PING_INTERVAL + 5000); diff --git a/app/lib/services/__tests__/socketHealth.test.ts b/app/lib/services/__tests__/socketHealth.test.ts index ef51619afb..c0883cb301 100644 --- a/app/lib/services/__tests__/socketHealth.test.ts +++ b/app/lib/services/__tests__/socketHealth.test.ts @@ -1,5 +1,5 @@ -import sdk, { type ISocketDriver } from '../sdk'; -import { classifySocketHealth, recoverSocket } from '../socketHealth'; +import sdk from '../sdk'; +import { recoverSocket } from '../socketHealth'; import { buildConnectedDriver } from '../../testUtils/sdkIntegration'; import type { IMockSdk, IMockSdkDriver, MockConnection } from '../../testUtils/sdkIntegration'; import type * as SdkIntegration from '../../testUtils/sdkIntegration'; @@ -44,17 +44,6 @@ describe('socket health against a driver from the shared harness', () => { jest.useRealTimers(); }); - describe('classifySocketHealth', () => { - it('returns round-trip-check for a connected socket rather than trusting it outright', () => { - expect(classifySocketHealth(driver as unknown as ISocketDriver)).toBe('round-trip-check'); - }); - - it('returns reopen for a closed socket even when lastPing is fresh', () => { - mockConnections[0].readyState = CLOSED; - expect(classifySocketHealth(driver as unknown as ISocketDriver)).toBe('reopen'); - }); - }); - describe('recoverSocket', () => { it('keeps a socket whose round trip answers', async () => { await expect(recoverSocket()).resolves.toBe('confirmed-alive'); diff --git a/app/lib/services/connect.test.ts b/app/lib/services/connect.test.ts index 252b71c58d..ff0f4cbca7 100644 --- a/app/lib/services/connect.test.ts +++ b/app/lib/services/connect.test.ts @@ -104,7 +104,6 @@ jest.mock('../methods/helpers/log', () => ({ const flushMicrotasks = async (): Promise => { for (let i = 0; i < 5; i += 1) { - // eslint-disable-next-line no-await-in-loop await Promise.resolve(); } }; @@ -695,7 +694,7 @@ describe('loginTOTP', () => { mockSdkLogin.mockImplementationOnce(() => Promise.reject({ data: { error: 'totp-required', details: {} } })); mockSdkCurrent.currentLogin = { result: { userId: 'userId', authToken: 'authToken', me: { username: 'username' } } }; - await loginTOTP({ username: 'user', ldapPass: 'password', ldap: true, ldapOptions: {} }, true); + await loginTOTP({ username: 'user', ldapPass: 'password', ldap: true, ldapOptions: {} }, { retryWithPassword: true }); expect(mockSdkLogin).toHaveBeenLastCalledWith({ user: 'user', password: 'password', code: '123456' }); }, 2000); @@ -704,7 +703,7 @@ describe('loginTOTP', () => { mockSdkLogin.mockImplementationOnce(() => Promise.reject({ data: { error: 'totp-required', details: {} } })); mockSdkCurrent.currentLogin = { result: { userId: 'userId', authToken: 'authToken', me: { username: 'username' } } }; - await loginTOTP({ username: 'user', crowdPassword: 'password', crowd: true }, true); + await loginTOTP({ username: 'user', crowdPassword: 'password', crowd: true }, { retryWithPassword: true }); expect(mockSdkLogin).toHaveBeenLastCalledWith({ user: 'user', password: 'password', code: '123456' }); }, 2000); diff --git a/app/lib/services/connect.ts b/app/lib/services/connect.ts index 0f6abd2fc6..3635b32c33 100644 --- a/app/lib/services/connect.ts +++ b/app/lib/services/connect.ts @@ -354,7 +354,7 @@ function toPasswordLogin(params: ILoginCredentials): ICredentialsPasswordAPI | u } } -async function loginTOTP(params: ILoginCredentials, loginEmailPassword?: boolean): Promise { +async function loginTOTP(params: ILoginCredentials, options?: { retryWithPassword?: boolean }): Promise { try { return await login(params); } catch (e: any) { @@ -366,11 +366,11 @@ async function loginTOTP(params: ILoginCredentials, loginEmailPassword?: boolean invalid: (details.error || error) === 'totp-invalid' }); - const passwordParams = loginEmailPassword ? toPasswordLogin(params) : undefined; + const passwordParams = options?.retryWithPassword ? toPasswordLogin(params) : undefined; if (passwordParams) { store.dispatch(setUser({ username: passwordParams.user || passwordParams.username })); - return loginTOTP({ ...passwordParams, code: code?.twoFactorCode }, loginEmailPassword); + return loginTOTP({ ...passwordParams, code: code?.twoFactorCode }, options); } return loginTOTP({ @@ -403,11 +403,11 @@ function loginWithPassword({ user, password }: { user: string; password: string }; } - return loginTOTP(params, true); + return loginTOTP(params, { retryWithPassword: true }); } async function loginOAuthOrSso(params: ILoginCredentials) { - const result = await loginTOTP(params, false); + const result = await loginTOTP(params); store.dispatch(loginRequest({ resume: result.token }, false)); } diff --git a/app/lib/services/restApi.test.ts b/app/lib/services/restApi.test.ts index 7405c6d633..ea289c825a 100644 --- a/app/lib/services/restApi.test.ts +++ b/app/lib/services/restApi.test.ts @@ -1,4 +1,3 @@ -import type { ServerMediaSignal } from '@rocket.chat/media-signaling'; import { Platform } from 'react-native'; import type * as SdkIntegration from '../testUtils/sdkIntegration'; @@ -94,19 +93,6 @@ describe('mediaCallsStateSignals', () => { expect(result).toEqual({ signals: [], success: true }); }); - it('returns signals and success from the API response', async () => { - const mockSignals = [ - { type: 'new', callId: 'call-1' } as unknown as ServerMediaSignal, - { type: 'notification', notification: 'ringing' } as unknown as ServerMediaSignal - ]; - mockSdkGet.mockResolvedValueOnce({ signals: mockSignals, success: true }); - - const result = await mediaCallsStateSignals('device-id'); - - expect(result.signals).toHaveLength(2); - expect(result.success).toBe(true); - }); - it('returns empty signals and success false when sdk.get throws', async () => { mockSdkGet.mockRejectedValueOnce(new Error('Network error')); diff --git a/app/lib/services/sdk.test.ts b/app/lib/services/sdk.test.ts index 66f806efb1..abaef92ef5 100644 --- a/app/lib/services/sdk.test.ts +++ b/app/lib/services/sdk.test.ts @@ -13,8 +13,6 @@ jest.mock('@rocket.chat/sdk', () => ({ settings: { customHeaders: {} } })); -jest.mock('../constants/twoFactor', () => ({ TWO_FACTOR: 'TWO_FACTOR' })); - jest.mock('./twoFactor/twoFactor', () => ({ twoFactor: (...args: unknown[]) => mockTwoFactor(...args) })); diff --git a/app/lib/services/socketHealth.ts b/app/lib/services/socketHealth.ts index 771fb1cb01..24d352a008 100644 --- a/app/lib/services/socketHealth.ts +++ b/app/lib/services/socketHealth.ts @@ -1,23 +1,5 @@ import { onAbort } from '../methods/helpers/onAbort'; -import sdk, { type ISocketDriver } from './sdk'; - -/** - * The recovery plan — what classification decides. - * `'round-trip-check'` means a stored ping timestamp can't vouch for a socket - * the OS may have frozen, so anything young enough is verified by a round trip, - * never trusted outright. - * - * Exported for unit tests; callers never branch on it — they call - * `recoverSocket()` and see outcomes. - */ -export type SocketRecoveryPlan = 'reopen' | 'round-trip-check'; - -export function classifySocketHealth(driver: ISocketDriver): SocketRecoveryPlan { - if (!driver.connected) { - return 'reopen'; - } - return 'round-trip-check'; -} +import sdk from './sdk'; /** * Errors from `reopenNow()`/`probe()` REJECT the promise rather than becoming @@ -38,10 +20,13 @@ function shareRecovery(): Promise { return Promise.resolve('no-socket'); } const recovery = (async (): Promise => { - if (classifySocketHealth(driver) === 'reopen') { + if (!driver.connected) { await driver.reopenNow(); return 'reopened'; } + // A connected socket is still verified by a round trip, never trusted outright: + // `connected` already folds in the ping-age test, but onOpen refreshes lastPing + // before the handshake reply lands. const alive = await driver.probe(2000); if (alive) { return 'confirmed-alive'; @@ -60,21 +45,6 @@ function shareRecovery(): Promise { } /** - * The single entry point for both callers. Classifies, then executes: - * `reopen` → `reopenNow()`; `round-trip-check` → `probe(2000)`, reopening on a - * dead round trip. - * - * One entry, two usage postures — the semantics live in the call site, not in - * two named functions: - * - * // Foreground ladder (app/sagas/state.js) — fire-and-forget: - * recoverSocket().catch(log); - * - * // Accept gate (acceptNativeCall.ts) — awaited, abortable: - * const outcome = await recoverSocket({ abortSignal: controller.signal }); - * if (outcome === 'no-socket') return handleFailure(callId, mediaSession); - * if (outcome === 'abandoned') return; - * * Concurrency: overlapping calls share one in-flight recovery — the second * caller awaits the same work and receives its outcome. An abort signal * detaches the caller from the shared wait (`'abandoned'`); it never cancels diff --git a/app/lib/services/twoFactor/twoFactorCancellation.test.ts b/app/lib/services/twoFactor/twoFactorCancellation.test.ts index 0151025e9b..e3b87aa2db 100644 --- a/app/lib/services/twoFactor/twoFactorCancellation.test.ts +++ b/app/lib/services/twoFactor/twoFactorCancellation.test.ts @@ -4,7 +4,6 @@ import bugsnag from '@bugsnag/react-native'; import log from '../../methods/helpers/log'; import { showErrorAlertWithEMessage } from '../../methods/helpers/info'; import handleSaveUserProfileError from '../../methods/helpers/handleSaveUserProfileError'; -import { handleLoginErrors } from '../../../views/LoginView/handleLoginErrors'; import { TwoFactorCancelledError } from './twoFactorCancelled'; jest.mock('../../../i18n', () => ({ @@ -57,8 +56,4 @@ describe('two-factor cancellation', () => { handleSaveUserProfileError({ error: 'error-invalid-password' }, 'saving_profile'); expect(Alert.alert).toHaveBeenCalled(); }); - - it('surfaces a generic login error when the login path reports a cancellation', () => { - expect(handleLoginErrors((cancelled as any).error)).toBe('Login_error'); - }); }); diff --git a/app/lib/services/voip/MediaSessionInstance.test.ts b/app/lib/services/voip/MediaSessionInstance.test.ts index 1a35d57edc..8a8e9a3a2e 100644 --- a/app/lib/services/voip/MediaSessionInstance.test.ts +++ b/app/lib/services/voip/MediaSessionInstance.test.ts @@ -799,7 +799,7 @@ describe('MediaSessionInstance', () => { mediaSessionInstance.startCallByRoom({ rid: 'rid-dm', t: 'd', uids: ['a', 'b'] } as any); - // startCall is async (awaits permission on Android); flush microtask queue + // startCall is async (awaits permission on Android); flush the microtask queue await Promise.resolve(); await Promise.resolve(); diff --git a/app/lib/testUtils/sdkIntegration.ts b/app/lib/testUtils/sdkIntegration.ts index f56f47d873..29e9424291 100644 --- a/app/lib/testUtils/sdkIntegration.ts +++ b/app/lib/testUtils/sdkIntegration.ts @@ -5,7 +5,7 @@ import type { IApplicationState } from '../../definitions'; import type sdk from '../services/sdk'; import type { ISocketDriver } from '../services/sdk'; -export interface IDdpMessage { +interface IDdpMessage { msg: string; id?: string; name?: string; @@ -58,7 +58,7 @@ export interface IMockSdkDriver extends ISocketDriver { }; } -export interface IMockSdkClient { +interface IMockSdkClient { host?: string; driver?: ISocketDriver; } @@ -156,7 +156,7 @@ export function makeCollection(name: string): IMockCollection { }; } -export async function flush(turns = 10): Promise { +export async function flushMicrotasksAndTimers(turns = 10): Promise { for (let i = 0; i < turns; i++) { await Promise.resolve(); await jest.advanceTimersByTimeAsync(0); @@ -166,11 +166,11 @@ export async function flush(turns = 10): Promise { export async function settleUntil(isSettled: () => boolean, maxRounds = 20): Promise { for (let round = 0; round < maxRounds && !isSettled(); round++) { await jest.runOnlyPendingTimersAsync(); - await flush(); + await flushMicrotasksAndTimers(); } } -export interface IMockReduxState { +interface IMockReduxState { meteor: { connected: boolean }; login: { user: Record | null; isAuthenticated: boolean }; server: { version: string }; @@ -178,7 +178,7 @@ export interface IMockReduxState { room: { subscribedRoom: string | null }; } -export interface IMockReduxStore { +interface IMockReduxStore { state: IMockReduxState; store: Store & { dispatch: jest.Mock }; } diff --git a/app/sagas/__tests__/foregroundResume.integration.test.ts b/app/sagas/__tests__/foregroundResume.integration.test.ts index 307a06838d..60fdd57b0b 100644 --- a/app/sagas/__tests__/foregroundResume.integration.test.ts +++ b/app/sagas/__tests__/foregroundResume.integration.test.ts @@ -109,7 +109,7 @@ import reducers from '../../reducers'; import loginRoot from '../login'; import stateRoot from '../state'; import { - flush, + flushMicrotasksAndTimers, framesOn, latestConnection, makeCollection, @@ -171,17 +171,17 @@ function bootApp(): void { async function openSocket(): Promise { await connect({ server: SERVER }); - await flush(); + await flushMicrotasksAndTimers(); mockConnections[0].onopen(); - await flush(); + await flushMicrotasksAndTimers(); store.dispatch(connectSuccess()); - await flush(); + await flushMicrotasksAndTimers(); } async function openSignedInSocket(): Promise { await openSocket(); store.dispatch(loginSuccess({ id: USER_ID, token: RESUME_TOKEN } as never)); - await flush(); + await flushMicrotasksAndTimers(); } function resumedUser(): unknown { @@ -192,9 +192,9 @@ function resumedUser(): unknown { async function subscribeToRoom(rid: string): Promise { const room = new RoomSubscription(rid); const subscribing = room.subscribe(); - await flush(); + await flushMicrotasksAndTimers(); await subscribing; - await flush(); + await flushMicrotasksAndTimers(); return room; } @@ -220,7 +220,7 @@ beforeEach(() => { afterEach(async () => { sdk.disconnect(); - await flush(); + await flushMicrotasksAndTimers(); jest.useRealTimers(); }); @@ -238,7 +238,7 @@ describe('foreground resume over the real SDK socket', () => { jest.mocked(loadMissedMessages).mockClear(); store.dispatch({ type: APP_STATE.FOREGROUND }); - await flush(); + await flushMicrotasksAndTimers(); await jest.advanceTimersByTimeAsync(RECOVERY_WINDOW); expect(framesOn(frozen, 'ping').length).toBeGreaterThan(pingsBefore); @@ -264,7 +264,7 @@ describe('foreground resume over the real SDK socket', () => { dropped.readyState = CLOSED; dropped.onclose({ code: 1006 }); - await flush(); + await flushMicrotasksAndTimers(); expect(dispatched).toContainEqual(disconnect()); dispatched.length = 0; @@ -272,7 +272,7 @@ describe('foreground resume over the real SDK socket', () => { expect(mockConnections).toHaveLength(1); store.dispatch({ type: APP_STATE.FOREGROUND }); - await flush(); + await flushMicrotasksAndTimers(); await jest.advanceTimersByTimeAsync(RECOVERY_WINDOW); expect(mockConnections.length).toBeGreaterThan(1); @@ -304,7 +304,7 @@ describe('foreground resume over the real SDK socket', () => { dispatched.length = 0; store.dispatch({ type: APP_STATE.FOREGROUND }); - await flush(); + await flushMicrotasksAndTimers(); await jest.advanceTimersByTimeAsync(RECOVERY_WINDOW); expect(framesOn(alive, 'ping').length).toBeGreaterThan(pingsBefore); @@ -322,7 +322,7 @@ describe('foreground resume over the real SDK socket', () => { dispatched.length = 0; store.dispatch({ type: APP_STATE.FOREGROUND }); - await flush(); + await flushMicrotasksAndTimers(); await jest.advanceTimersByTimeAsync(RECOVERY_WINDOW); expect(framesOn(frozen, 'ping')).toHaveLength(0); @@ -336,12 +336,12 @@ describe('foreground resume over the real SDK socket', () => { const frozen = mockConnections[0]; stopAnsweringFrames(frozen); store.dispatch(appStart({ root: RootEnum.ROOT_OUTSIDE })); - await flush(); + await flushMicrotasksAndTimers(); const pingsBefore = framesOn(frozen, 'ping').length; dispatched.length = 0; store.dispatch({ type: APP_STATE.FOREGROUND }); - await flush(); + await flushMicrotasksAndTimers(); await jest.advanceTimersByTimeAsync(RECOVERY_WINDOW); expect(framesOn(frozen, 'ping')).toHaveLength(pingsBefore); @@ -354,7 +354,7 @@ describe('foreground resume over the real SDK socket', () => { await openSignedInSocket(); store.dispatch({ type: APP_STATE.BACKGROUND }); - await flush(); + await flushMicrotasksAndTimers(); expect(saveLastLocalAuthenticationSession).toHaveBeenCalledWith(SERVER); expect(setUserPresenceAway).toHaveBeenCalled(); @@ -365,7 +365,7 @@ describe('foreground resume over the real SDK socket', () => { await openSocket(); store.dispatch({ type: APP_STATE.BACKGROUND }); - await flush(); + await flushMicrotasksAndTimers(); expect(saveLastLocalAuthenticationSession).not.toHaveBeenCalled(); expect(setUserPresenceAway).not.toHaveBeenCalled(); @@ -375,10 +375,10 @@ describe('foreground resume over the real SDK socket', () => { bootApp(); await openSignedInSocket(); store.dispatch(disconnect()); - await flush(); + await flushMicrotasksAndTimers(); store.dispatch({ type: APP_STATE.BACKGROUND }); - await flush(); + await flushMicrotasksAndTimers(); expect(saveLastLocalAuthenticationSession).not.toHaveBeenCalled(); expect(setUserPresenceAway).not.toHaveBeenCalled(); @@ -388,10 +388,10 @@ describe('foreground resume over the real SDK socket', () => { bootApp(); await openSignedInSocket(); store.dispatch(appStart({ root: RootEnum.ROOT_OUTSIDE })); - await flush(); + await flushMicrotasksAndTimers(); store.dispatch({ type: APP_STATE.BACKGROUND }); - await flush(); + await flushMicrotasksAndTimers(); expect(saveLastLocalAuthenticationSession).not.toHaveBeenCalled(); expect(setUserPresenceAway).not.toHaveBeenCalled(); diff --git a/app/sagas/init.js b/app/sagas/init.js index 54e0d51e9a..5c7b0487c1 100644 --- a/app/sagas/init.js +++ b/app/sagas/init.js @@ -23,7 +23,7 @@ export const initLocalSettings = function* initLocalSettings() { yield put(setAllPreferences(sortPreferences)); }; -const findServerToRestore = async () => { +const restoreServer = async () => { const server = UserPreferences.getString(CURRENT_SERVER); const restoredServer = isLoggedInServer(server) ? await getServerById(server) : await findLoggedInServer(); @@ -34,9 +34,9 @@ const findServerToRestore = async () => { return restoredServer; }; -const serverToRestore = function* serverToRestore() { +const getServerToRestore = function* getServerToRestore() { try { - return (yield call(findServerToRestore)) || null; + return (yield call(restoreServer)) || null; } catch (e) { log(e); return null; @@ -61,7 +61,7 @@ const deliverPendingPushNotification = function* deliverPendingPushNotification( }; const restore = function* restore() { - const restoredServer = yield* serverToRestore(); + const restoredServer = yield* getServerToRestore(); if (restoredServer) { yield put(selectServerRequest(restoredServer.id, restoredServer.version));