feat: Use vitest instead of jest, run all the specs anywhere in app/ folder in the CI (#9722)

Due to the pattern `**/specs/*.spec.js` defined in CircleCI, none of the
frontend spec in the folders such as
`specs/<domain-name>/getters.spec.js` were not executed in Circle CI.

This PR fixes the issue, along with the following changes: 
- Use vitest instead of jest
- Remove jest dependancies
- Update tests to work with vitest

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Pranav
2024-07-10 08:32:16 -07:00
committed by GitHub
parent 9498d1f003
commit 9de8c27368
140 changed files with 1678 additions and 2810 deletions

View File

@@ -1,13 +1,13 @@
import helperObject, { AnalyticsHelper } from '../';
jest.mock('@june-so/analytics-next', () => ({
vi.mock('@june-so/analytics-next', () => ({
AnalyticsBrowser: {
load: () => [
{
identify: jest.fn(),
track: jest.fn(),
page: jest.fn(),
group: jest.fn(),
identify: vi.fn(),
track: vi.fn(),
page: vi.fn(),
group: vi.fn(),
},
],
},
@@ -40,7 +40,7 @@ describe('AnalyticsHelper', () => {
describe('identify', () => {
beforeEach(() => {
analyticsHelper.analytics = { identify: jest.fn(), group: jest.fn() };
analyticsHelper.analytics = { identify: vi.fn(), group: vi.fn() };
});
it('should call identify on analytics browser with correct arguments', () => {
@@ -87,7 +87,7 @@ describe('AnalyticsHelper', () => {
describe('track', () => {
beforeEach(() => {
analyticsHelper.analytics = { track: jest.fn() };
analyticsHelper.analytics = { track: vi.fn() };
analyticsHelper.user = { id: '123' };
});
@@ -118,7 +118,7 @@ describe('AnalyticsHelper', () => {
describe('page', () => {
beforeEach(() => {
analyticsHelper.analytics = { page: jest.fn() };
analyticsHelper.analytics = { page: vi.fn() };
});
it('should call the analytics.page method with the correct arguments', () => {

View File

@@ -2,34 +2,35 @@ import Vue from 'vue';
import plugin from '../plugin';
import analyticsHelper from '../index';
vi.spyOn(analyticsHelper, 'init');
vi.spyOn(analyticsHelper, 'track');
describe('Vue Analytics Plugin', () => {
beforeEach(() => {
jest.spyOn(analyticsHelper, 'init');
jest.spyOn(analyticsHelper, 'track');
Vue.use(plugin);
});
afterEach(() => {
jest.resetModules();
jest.clearAllMocks();
it('should call the init method on analyticsHelper once during plugin installation', () => {
expect(analyticsHelper.init).toHaveBeenCalledTimes(1);
});
it('should call the init method on the analyticsHelper', () => {
expect(analyticsHelper.init).toHaveBeenCalled();
});
it('should add the analyticsHelper to the Vue prototype', () => {
it('should add the analyticsHelper to the Vue prototype as $analytics', () => {
expect(Vue.prototype.$analytics).toBe(analyticsHelper);
});
it('should add the track method to the Vue prototype', () => {
it('should add a track method to the Vue prototype as $track', () => {
expect(typeof Vue.prototype.$track).toBe('function');
Vue.prototype.$track('eventName');
expect(analyticsHelper.track).toHaveBeenCalledWith('eventName');
expect(analyticsHelper.track)
.toHaveBeenCalledTimes(1)
.toHaveBeenCalledWith('eventName');
});
it('should call the track method on the analyticsHelper when $track is called', () => {
Vue.prototype.$track('eventName');
expect(analyticsHelper.track).toHaveBeenCalledWith('eventName');
it('should call the track method on analyticsHelper with the correct event name when $track is called', () => {
const eventName = 'testEvent';
Vue.prototype.$track(eventName);
expect(analyticsHelper.track)
.toHaveBeenCalledTimes(1)
.toHaveBeenCalledWith(eventName);
});
});

View File

@@ -4,7 +4,7 @@ describe('DataManager', () => {
const accountId = 'test-account';
let dataManager;
beforeAll(async () => {
beforeEach(async () => {
dataManager = new DataManager(accountId);
await dataManager.initDb();
});

View File

@@ -8,26 +8,26 @@ import {
} from 'dashboard/helper/routeHelpers';
import ReconnectService from 'dashboard/helper/ReconnectService';
jest.mock('shared/helpers/mitt', () => ({
vi.mock('shared/helpers/mitt', () => ({
emitter: {
on: jest.fn(),
off: jest.fn(),
emit: jest.fn(),
on: vi.fn(),
off: vi.fn(),
emit: vi.fn(),
},
}));
jest.mock('date-fns', () => ({
differenceInSeconds: jest.fn(),
vi.mock('date-fns', () => ({
differenceInSeconds: vi.fn(),
}));
jest.mock('dashboard/helper/routeHelpers', () => ({
isAConversationRoute: jest.fn(),
isAInboxViewRoute: jest.fn(),
isNotificationRoute: jest.fn(),
vi.mock('dashboard/helper/routeHelpers', () => ({
isAConversationRoute: vi.fn(),
isAInboxViewRoute: vi.fn(),
isNotificationRoute: vi.fn(),
}));
const storeMock = {
dispatch: jest.fn(),
dispatch: vi.fn(),
getters: {
getAppliedConversationFiltersQuery: [],
'customViews/getActiveConversationFolder': { query: {} },
@@ -46,17 +46,17 @@ describe('ReconnectService', () => {
let reconnectService;
beforeEach(() => {
window.addEventListener = jest.fn();
window.removeEventListener = jest.fn();
window.addEventListener = vi.fn();
window.removeEventListener = vi.fn();
Object.defineProperty(window, 'location', {
configurable: true,
value: { reload: jest.fn() },
value: { reload: vi.fn() },
});
reconnectService = new ReconnectService(storeMock, routerMock);
});
afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
describe('constructor', () => {
@@ -111,7 +111,7 @@ describe('ReconnectService', () => {
describe('handleOnlineEvent', () => {
it('should reload the page if disconnected for more than 3 hours', () => {
reconnectService.getSecondsSinceDisconnect = jest
reconnectService.getSecondsSinceDisconnect = vi
.fn()
.mockReturnValue(10801);
reconnectService.handleOnlineEvent();
@@ -119,7 +119,7 @@ describe('ReconnectService', () => {
});
it('should not reload the page if disconnected for less than 3 hours', () => {
reconnectService.getSecondsSinceDisconnect = jest
reconnectService.getSecondsSinceDisconnect = vi
.fn()
.mockReturnValue(10799);
reconnectService.handleOnlineEvent();
@@ -129,9 +129,7 @@ describe('ReconnectService', () => {
describe('fetchConversations', () => {
it('should dispatch updateChatListFilters and fetchAllConversations', async () => {
reconnectService.getSecondsSinceDisconnect = jest
.fn()
.mockReturnValue(100);
reconnectService.getSecondsSinceDisconnect = vi.fn().mockReturnValue(100);
await reconnectService.fetchConversations();
expect(storeMock.dispatch).toHaveBeenCalledWith('updateChatListFilters', {
page: null,
@@ -141,9 +139,7 @@ describe('ReconnectService', () => {
});
it('should dispatch updateChatListFilters and reset updatedWithin', async () => {
reconnectService.getSecondsSinceDisconnect = jest
.fn()
.mockReturnValue(100);
reconnectService.getSecondsSinceDisconnect = vi.fn().mockReturnValue(100);
await reconnectService.fetchConversations();
expect(storeMock.dispatch).toHaveBeenCalledWith('updateChatListFilters', {
updatedWithin: null,
@@ -173,7 +169,7 @@ describe('ReconnectService', () => {
},
],
};
const spy = jest.spyOn(
const spy = vi.spyOn(
reconnectService,
'fetchFilteredOrSavedConversations'
);
@@ -191,7 +187,7 @@ describe('ReconnectService', () => {
query: null,
};
const spy = jest.spyOn(reconnectService, 'fetchConversations');
const spy = vi.spyOn(reconnectService, 'fetchConversations');
await reconnectService.fetchConversationsOnReconnect();
@@ -204,7 +200,7 @@ describe('ReconnectService', () => {
query: { test: 'activeFolderQuery' },
};
const spy = jest.spyOn(
const spy = vi.spyOn(
reconnectService,
'fetchFilteredOrSavedConversations'
);
@@ -270,11 +266,11 @@ describe('ReconnectService', () => {
describe('handleRouteSpecificFetch', () => {
it('should fetch conversations and messages if current route is a conversation route', async () => {
isAConversationRoute.mockReturnValue(true);
const spyConversations = jest.spyOn(
const spyConversations = vi.spyOn(
reconnectService,
'fetchConversationsOnReconnect'
);
const spyMessages = jest.spyOn(
const spyMessages = vi.spyOn(
reconnectService,
'fetchConversationMessagesOnReconnect'
);
@@ -285,14 +281,14 @@ describe('ReconnectService', () => {
it('should fetch notifications if current route is an inbox view route', async () => {
isAInboxViewRoute.mockReturnValue(true);
const spy = jest.spyOn(reconnectService, 'fetchNotificationsOnReconnect');
const spy = vi.spyOn(reconnectService, 'fetchNotificationsOnReconnect');
await reconnectService.handleRouteSpecificFetch();
expect(spy).toHaveBeenCalled();
});
it('should fetch notifications if current route is a notification route', async () => {
isNotificationRoute.mockReturnValue(true);
const spy = jest.spyOn(reconnectService, 'fetchNotificationsOnReconnect');
const spy = vi.spyOn(reconnectService, 'fetchNotificationsOnReconnect');
await reconnectService.handleRouteSpecificFetch();
expect(spy).toHaveBeenCalled();
});
@@ -320,7 +316,7 @@ describe('ReconnectService', () => {
describe('onDisconnect', () => {
it('should set disconnectTime and call setConversationLastMessageId', () => {
reconnectService.setConversationLastMessageId = jest.fn();
reconnectService.setConversationLastMessageId = vi.fn();
reconnectService.onDisconnect();
expect(reconnectService.disconnectTime).toBeInstanceOf(Date);
expect(reconnectService.setConversationLastMessageId).toHaveBeenCalled();
@@ -329,8 +325,8 @@ describe('ReconnectService', () => {
describe('onReconnect', () => {
it('should handle route-specific fetch, revalidate caches, and emit WEBSOCKET_RECONNECT_COMPLETED event', async () => {
reconnectService.handleRouteSpecificFetch = jest.fn();
reconnectService.revalidateCaches = jest.fn();
reconnectService.handleRouteSpecificFetch = vi.fn();
reconnectService.revalidateCaches = vi.fn();
await reconnectService.onReconnect();
expect(reconnectService.handleRouteSpecificFetch).toHaveBeenCalled();
expect(reconnectService.revalidateCaches).toHaveBeenCalled();

View File

@@ -36,16 +36,14 @@ describe('#createPendingMessage', () => {
message: 'hi',
};
it('returns the pending message with expected new keys', () => {
expect(createPendingMessage(message)).toHaveProperty(
'content',
'id',
'status',
'echo_id',
'status',
'created_at',
'message_type',
'conversation_id'
);
expect(createPendingMessage(message)).toMatchObject({
content: expect.anything(),
id: expect.anything(),
status: expect.anything(),
echo_id: expect.anything(),
created_at: expect.anything(),
message_type: expect.anything(),
});
});
it('returns the pending message with status progress', () => {
@@ -61,23 +59,20 @@ describe('#createPendingMessage', () => {
});
});
it('returns the pending message with attachmnet key if file is passed', () => {
it('returns the pending message with attachment key if file is passed', () => {
const messageWithFile = {
message: 'hi',
file: {},
};
expect(createPendingMessage(messageWithFile)).toHaveProperty(
'content',
'id',
'status',
'echo_id',
'status',
'created_at',
'message_type',
'conversation_id',
'attachments',
'private'
);
expect(createPendingMessage(messageWithFile)).toMatchObject({
content: expect.anything(),
id: expect.anything(),
status: expect.anything(),
echo_id: expect.anything(),
created_at: expect.anything(),
message_type: expect.anything(),
attachments: [{ id: expect.anything() }],
});
});
it('returns the pending message to have one attachment', () => {

View File

@@ -19,19 +19,19 @@ describe('resize directive', () => {
beforeEach(() => {
el = document.createElement('div');
binding = {
value: jest.fn(),
value: vi.fn(),
};
observer = {
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
};
window.ResizeObserver = ResizeObserverMock;
jest.spyOn(window, 'ResizeObserver').mockImplementation(() => observer);
vi.spyOn(window, 'ResizeObserver').mockImplementation(() => observer);
});
afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
it('should create ResizeObserver on bind', () => {
@@ -44,7 +44,7 @@ describe('resize directive', () => {
it('should call callback on observer callback', () => {
el = document.createElement('div');
binding = {
value: jest.fn(),
value: vi.fn(),
};
resize.bind(el, binding);

View File

@@ -283,17 +283,17 @@ describe('findNodeToInsertImage', () => {
mockEditorState = {
selection: {
$from: {
node: jest.fn(() => ({})),
node: vi.fn(() => ({})),
},
from: 0,
},
schema: {
nodes: {
image: {
create: jest.fn(attrs => ({ type: { name: 'image' }, attrs })),
create: vi.fn(attrs => ({ type: { name: 'image' }, attrs })),
},
paragraph: {
create: jest.fn((_, node) => ({
create: vi.fn((_, node) => ({
type: { name: 'paragraph' },
content: [node],
})),
@@ -381,11 +381,11 @@ describe('setURLWithQueryAndSize', () => {
beforeEach(() => {
selectedNode = {
setAttribute: jest.fn(),
setAttribute: vi.fn(),
};
const tr = {
setNodeMarkup: jest.fn().mockReturnValue({
setNodeMarkup: vi.fn().mockReturnValue({
docChanged: true,
}),
};
@@ -397,7 +397,7 @@ describe('setURLWithQueryAndSize', () => {
editorView = {
state,
dispatch: jest.fn(),
dispatch: vi.fn(),
};
});
@@ -420,7 +420,7 @@ describe('setURLWithQueryAndSize', () => {
});
it('does not update the editor view if the document has not changed', () => {
editorView.state.tr.setNodeMarkup = jest.fn().mockReturnValue({
editorView.state.tr.setNodeMarkup = vi.fn().mockReturnValue({
docChanged: false,
});

View File

@@ -1,7 +1,7 @@
import { setColorTheme } from 'dashboard/helper/themeHelper.js';
import { LocalStorage } from 'shared/helpers/localStorage';
jest.mock('shared/helpers/localStorage');
vi.mock('shared/helpers/localStorage');
describe('setColorTheme', () => {
it('should set body class to dark if selectedColorScheme is dark', () => {

View File

@@ -1,9 +1,8 @@
import { uploadFile } from '../uploadHelper';
import axios from 'axios';
// Mocking axios using jest-mock-axios
global.axios = axios;
jest.mock('axios');
vi.mock('axios');
describe('#Upload Helpers', () => {
afterEach(() => {