Fix tests leaks and other minor improvements (#9001)

* Fix tests leaks and other minor improvements

* Fix flaky test and remove unneeded flags

* Add comments

* test: create ci specific test commands (#9010)

* test: create ci specific test commands
* use test:ci as base for test:ci:coverage

---------

Co-authored-by: Rahim Rahman <rahim.rahman@mattermost.com>
This commit is contained in:
Daniel Espino García
2025-07-21 15:29:26 +02:00
committed by GitHub
parent 6cbc2c8118
commit 4444826147
8 changed files with 34 additions and 15 deletions

View File

@@ -74,7 +74,7 @@ runs:
shell: bash
run: |
echo "::group::run-tests"
npm run test:coverage
npm run test:ci:coverage
echo "::endgroup::"
- name: ci/compare-coverage

View File

@@ -20,7 +20,7 @@ runs:
shell: bash
run: |
echo "::group::run-tests"
npm test
npm run test:ci
echo "::endgroup::"
- name: ci/check-i18n

View File

@@ -114,6 +114,7 @@ describe('handleScheduledPosts', () => {
scheduledPosts,
prepareRecordsOnly: false,
});
spyBatchRecords.mockClear();
const {models} = await scheduledPostsAction(
serverUrl,
@@ -122,7 +123,7 @@ describe('handleScheduledPosts', () => {
false,
);
expect(spyBatchRecords).toHaveBeenCalledWith(models, '_deleteScheduledPostByIds');
expect(spyBatchRecords).toHaveBeenCalledWith(models, 'handleScheduledPosts');
expect(models![0].id).toEqual(scheduledPosts[0].id);
});

View File

@@ -80,7 +80,9 @@ class DatabaseManagerSingleton {
const modelClasses = this.appModels;
const schema = appSchema;
const adapter = new LokiJSAdapter({dbName: APP_DATABASE, migrations: AppDatabaseMigrations, schema, useWebWorker: false, useIncrementalIndexedDB: true});
// autosave uses a timeout that doesn't get cleared when we close the database in tests
// disabling it makes it so the tests don't leak memory
const adapter = new LokiJSAdapter({dbName: APP_DATABASE, migrations: AppDatabaseMigrations, schema, useWebWorker: false, useIncrementalIndexedDB: true, extraLokiOptions: {autosave: false}});
const database = new Database({adapter, modelClasses});
const operator = new AppDataOperator(database);
@@ -107,7 +109,9 @@ class DatabaseManagerSingleton {
const modelClasses = this.serverModels;
const schema = serverSchema;
const adapter = new LokiJSAdapter({dbName, migrations, schema, useWebWorker: false, useIncrementalIndexedDB: true});
// autosave uses a timeout that doesn't get cleared when we close the database in tests
// disabling it makes it so the tests don't leak memory
const adapter = new LokiJSAdapter({dbName, migrations, schema, useWebWorker: false, useIncrementalIndexedDB: true, extraLokiOptions: {autosave: false}});
// Registers the new server connection into the DEFAULT database
await this.addServerToAppDatabase({

View File

@@ -129,14 +129,14 @@ const PostHandler = <TBase extends Constructor<ServerDataOperatorBase>>(supercla
case ActionType.SCHEDULED_POSTS.DELETE_SCHEDULED_POST: {
const toDeleteIds = scheduledPosts?.map((post) => post.id) || [];
if (toDeleteIds.length > 0) {
scheduledPostsToDelete.push(...await this._deleteScheduledPostByIds(toDeleteIds, prepareRecordsOnly));
scheduledPostsToDelete.push(...await this._deleteScheduledPostByIds(toDeleteIds, true));
}
break;
}
case ActionType.SCHEDULED_POSTS.CREATE_OR_UPDATED_SCHEDULED_POST: {
const createOrUpdateRawValues = getUniqueRawsBy({raws: scheduledPosts ?? [], key: 'id'}) as ScheduledPost[];
scheduledPostsToCreateAndUpdate.push(...await this._createOrUpdateScheduledPost(createOrUpdateRawValues, prepareRecordsOnly));
scheduledPostsToCreateAndUpdate.push(...await this._createOrUpdateScheduledPost(createOrUpdateRawValues, true));
break;
}
@@ -148,12 +148,12 @@ const PostHandler = <TBase extends Constructor<ServerDataOperatorBase>>(supercla
map((post) => post.id);
if (deletedScheduledPostIds.length > 0) {
scheduledPostsToDelete.push(...await this._deleteScheduledPostByIds(deletedScheduledPostIds, prepareRecordsOnly));
scheduledPostsToDelete.push(...await this._deleteScheduledPostByIds(deletedScheduledPostIds, true));
}
if (scheduledPosts?.length) {
const createOrUpdateRawValues = getUniqueRawsBy({raws: scheduledPosts ?? [], key: 'id'}) as ScheduledPost[];
scheduledPostsToCreateAndUpdate.push(...await this._createOrUpdateScheduledPost(createOrUpdateRawValues, prepareRecordsOnly));
scheduledPostsToCreateAndUpdate.push(...await this._createOrUpdateScheduledPost(createOrUpdateRawValues, true));
}
break;
}

View File

@@ -34,7 +34,7 @@ jest.mock('@utils/log');
describe('WebsocketManager', () => {
let manager: typeof WebsocketManager;
let mockWebSocketClient: any;
let mockCallbacks: {[key: string]: () => void};
let mockCallbacks: {[key: string]: (...args: any[]) => void};
const mockServerUrl = 'https://example.com';
const mockToken = 'mock-token';
const mockCredentials = [{serverUrl: mockServerUrl, token: mockToken} as ServerCredential];
@@ -61,7 +61,9 @@ describe('WebsocketManager', () => {
mockCallbacks.reconnect = cb;
}),
setReliableReconnectCallback: jest.fn(),
setCloseCallback: jest.fn(),
setCloseCallback: jest.fn((cb) => {
mockCallbacks.close = cb;
}),
initialize: jest.fn(),
isConnected: jest.fn().mockReturnValue(true),
close: jest.fn(),
@@ -198,6 +200,9 @@ describe('WebsocketManager', () => {
await new Promise((resolve) => setImmediate(resolve));
expect(fetchStatusByIds).toHaveBeenCalledWith(mockServerUrl, ['user2']);
// Close the websocket to stop the periodic updates
mockCallbacks.close(0);
});
});
});

View File

@@ -5,6 +5,8 @@ import {DeviceEventEmitter, Image, Keyboard} from 'react-native';
import {Navigation} from 'react-native-navigation';
import {measure, type AnimatedRef} from 'react-native-reanimated';
import {waitFor} from '@test/intl-test-helper';
import {clamp, clampVelocity, fileToGalleryItem, freezeOtherScreens, friction, galleryItemToFileInfo, getImageSize, getShouldRender, measureItem, openGalleryAtIndex, typedMemo, workletNoop, workletNoopTrue} from '.';
import type {GalleryItemType, GalleryManagerSharedValues} from '@typings/screens/gallery';
@@ -189,7 +191,8 @@ describe('Gallery utils', () => {
});
describe('openGalleryAtIndex', () => {
it('should open gallery and freeze other screens', () => {
it('should open gallery and freeze other screens', async () => {
const emitSpy = jest.spyOn(DeviceEventEmitter, 'emit');
const galleryIdentifier = 'gallery1';
const initialIndex = 0;
const items = [{id: '1', name: 'item1'}, {id: '2', name: 'item2'}] as GalleryItemType[];
@@ -197,6 +200,10 @@ describe('Gallery utils', () => {
openGalleryAtIndex(galleryIdentifier, initialIndex, items);
expect(Keyboard.dismiss).toHaveBeenCalled();
expect(Navigation.setDefaultOptions).toHaveBeenCalled();
await waitFor(() => {
expect(emitSpy).toHaveBeenCalledWith('FREEZE_SCREEN', true);
});
});
});

View File

@@ -198,8 +198,10 @@
"prepare": "husky",
"preinstall": "./scripts/preinstall.sh && npx solidarity",
"start": "react-native start",
"test": "jest --forceExit --runInBand",
"test:coverage": "jest --coverage",
"test": "jest --runInBand",
"test:ci": "jest --verbose=false --forceExit",
"test:ci:coverage": "npm run test:ci -- --coverage",
"test:coverage": "npm test -- --coverage",
"test:watch": "npm test -- --watch",
"tsc": "NODE_OPTIONS=--max_old_space_size=12000 tsc --noEmit",
"updatesnapshot": "jest --updateSnapshot"
@@ -242,4 +244,4 @@
]
}
}
}
}