Skip to content
Snippets Groups Projects
Commit 7dbc8cf9 authored by mateusz-winiarczyk's avatar mateusz-winiarczyk
Browse files

test(plugins): add tests

parent ce76174f
No related branches found
No related tags found
3 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!122feat: add main plugins drawer with tabs (MIN-232),!116feat(plugins): Plugin loading management (MIN-233)
import { ZOD_SEED } from '@/constants';
// eslint-disable-next-line import/no-extraneous-dependencies
import { createFixture } from 'zod-fixture';
import { pluginSchema } from '../pluginSchema';
export const pluginFixture = createFixture(pluginSchema, {
seed: ZOD_SEED,
});
/* eslint-disable no-magic-numbers */
import { z } from 'zod';
export const pluginSchema = z.object({
......@@ -6,5 +7,5 @@ export const pluginSchema = z.object({
version: z.string(),
isPublic: z.boolean(),
isDefault: z.boolean(),
urls: z.array(z.string()),
urls: z.array(z.string().min(1)),
});
/* eslint-disable no-magic-numbers */
import {
ToolkitStoreWithSingleSlice,
createStoreInstanceUsingSliceReducer,
} from '@/utils/createStoreInstanceUsingSliceReducer';
import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
import { HttpStatusCode } from 'axios';
import { pluginFixture } from '@/models/fixtures/pluginFixture';
import { apiPath } from '../apiPath';
import { PluginsState } from './plugins.types';
import pluginsReducer, { removePlugin } from './plugins.slice';
import { registerPlugin } from './plugins.thunk';
const mockedAxiosClient = mockNetworkResponse();
const INITIAL_STATE: PluginsState = {
data: {},
pluginsId: [],
};
describe('plugins reducer', () => {
let store = {} as ToolkitStoreWithSingleSlice<PluginsState>;
beforeEach(() => {
store = createStoreInstanceUsingSliceReducer('plugins', pluginsReducer);
});
it('should match initial state', () => {
const action = { type: 'unknown' };
expect(pluginsReducer(undefined, action)).toEqual(INITIAL_STATE);
});
it('should remove overlay from store properly', () => {
const { type, payload } = store.dispatch(
removePlugin({
pluginId: 'hash1',
}),
);
expect(type).toBe('plugins/removePlugin');
expect(payload).toEqual({ pluginId: 'hash1' });
});
it('should update store after successful registerPlugin query', async () => {
mockedAxiosClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.Ok, pluginFixture);
const { type } = await store.dispatch(
registerPlugin({
hash: pluginFixture.hash,
isPublic: pluginFixture.isPublic,
pluginName: pluginFixture.name,
pluginUrl: pluginFixture.urls[0],
pluginVersion: pluginFixture.version,
}),
);
expect(type).toBe('plugins/registerPlugin/fulfilled');
const { data, pluginsId } = store.getState().plugins;
expect(data[pluginFixture.hash]).toEqual(pluginFixture);
expect(pluginsId).toContain(pluginFixture.hash);
});
it('should update store after failed registerPlugin query', async () => {
mockedAxiosClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.NotFound, undefined);
const { type, payload } = await store.dispatch(
registerPlugin({
hash: pluginFixture.hash,
isPublic: pluginFixture.isPublic,
pluginName: pluginFixture.name,
pluginUrl: pluginFixture.urls[0],
pluginVersion: pluginFixture.version,
}),
);
expect(type).toBe('plugins/registerPlugin/rejected');
expect(payload).toEqual(undefined);
const { data, pluginsId } = store.getState().plugins;
expect(data).toEqual({});
expect(pluginsId).not.toContain(pluginFixture.hash);
});
it('should update store on loading registerPlugin query', async () => {
mockedAxiosClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.NotFound, undefined);
store.dispatch(
registerPlugin({
hash: pluginFixture.hash,
isPublic: pluginFixture.isPublic,
pluginName: pluginFixture.name,
pluginUrl: pluginFixture.urls[0],
pluginVersion: pluginFixture.version,
}),
);
const { data, pluginsId } = store.getState().plugins;
expect(data).toEqual({});
expect(pluginsId).toContain(pluginFixture.hash);
});
});
......@@ -20,11 +20,7 @@ export const registerPluginReducer = (builder: ActionReducerMapBuilder<PluginsSt
state.data[hash] = action.payload;
}
});
builder.addCase(registerPlugin.rejected, (state, action) => {
if (action.payload) {
const { hash } = action.meta.arg;
state.pluginsId = state.pluginsId.filter(pluginId => pluginId !== hash);
}
builder.addCase(registerPlugin.rejected, state => {
state.pluginsId = [];
});
};
/* eslint-disable no-magic-numbers */
import axios, { HttpStatusCode } from 'axios';
import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
import MockAdapter from 'axios-mock-adapter';
import { pluginFixture } from '@/models/fixtures/pluginFixture';
import {
ToolkitStoreWithSingleSlice,
createStoreInstanceUsingSliceReducer,
} from '@/utils/createStoreInstanceUsingSliceReducer';
import { apiPath } from '../apiPath';
import { PluginsState } from './plugins.types';
import pluginsReducer from './plugins.slice';
import { getInitPlugins } from './plugins.thunk';
const mockedAxiosApiClient = mockNetworkResponse();
const mockedAxiosClient = new MockAdapter(axios);
describe('plugins - thunks', () => {
describe('getInitPlugins', () => {
let store = {} as ToolkitStoreWithSingleSlice<PluginsState>;
beforeEach(() => {
store = createStoreInstanceUsingSliceReducer('plugins', pluginsReducer);
});
const setHashedPluginMock = jest.fn();
beforeEach(() => {
setHashedPluginMock.mockClear();
});
it('should fetch and load initial plugins', async () => {
mockedAxiosApiClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.Ok, pluginFixture);
mockedAxiosApiClient
.onGet(apiPath.getPlugin(pluginFixture.hash))
.reply(HttpStatusCode.Ok, pluginFixture);
mockedAxiosClient.onGet(pluginFixture.urls[0]).reply(HttpStatusCode.Ok, '');
await store.dispatch(
getInitPlugins({
pluginsId: [pluginFixture.hash],
setHashedPlugin: setHashedPluginMock,
}),
);
expect(setHashedPluginMock).toHaveBeenCalledTimes(1);
});
it('should not load plugin if fetched plugin is not valid', async () => {
mockedAxiosApiClient.onPost(apiPath.registerPluign()).reply(HttpStatusCode.NotFound, {});
mockedAxiosApiClient
.onGet(apiPath.getPlugin(pluginFixture.hash))
.reply(HttpStatusCode.NotFound, {});
mockedAxiosClient.onGet(pluginFixture.urls[0]).reply(HttpStatusCode.NotFound, '');
await store.dispatch(
getInitPlugins({
pluginsId: [pluginFixture.hash],
setHashedPlugin: setHashedPluginMock,
}),
);
expect(setHashedPluginMock).not.toHaveBeenCalled();
});
});
});
......@@ -20,7 +20,7 @@ import { USER_INITIAL_STATE_MOCK } from '../user/user.mock';
import { STATISTICS_STATE_INITIAL_MOCK } from '../statistics/statistics.mock';
import { COMPARTMENT_PATHWAYS_INITIAL_STATE_MOCK } from '../compartmentPathways/compartmentPathways.mock';
import { EXPORT_INITIAL_STATE_MOCK } from '../export/export.mock';
import { PLUGINS_INITIAL_STATE_MOCK } from '../plugins/overlays.mock';
import { PLUGINS_INITIAL_STATE_MOCK } from '../plugins/plugins.mock';
export const INITIAL_STORE_STATE_MOCK: RootState = {
search: SEARCH_STATE_INITIAL_MOCK,
......
/* eslint-disable no-magic-numbers */
import { store } from '@/redux/store';
import { configurationFixture } from '@/models/fixtures/configurationFixture';
import { configurationMapper } from './pluginsManager.utils';
import { PluginsManager } from './pluginsManager';
jest.mock('../../redux/store');
describe('PluginsManager', () => {
const originalWindow = { ...global.window };
beforeEach(() => {
global.window = { ...originalWindow };
});
afterEach(() => {
global.window = originalWindow;
});
afterEach(() => {
jest.clearAllMocks();
});
it('setHashedPlugin correctly computes hash and updates hashedPlugins', () => {
const pluginUrl = 'https://example.com/plugin.js';
const pluginScript = 'console.log("Hello, Plugin!");';
PluginsManager.setHashedPlugin({ pluginUrl, pluginScript });
expect(PluginsManager.hashedPlugins[pluginUrl]).toBe('edc7eeafccc9e1ab66f713298425947b');
});
it('init subscribes to store changes and updates minerva configuration', () => {
(store.getState as jest.Mock).mockReturnValueOnce({
configuration: { main: { data: configurationFixture } },
});
PluginsManager.init();
expect(store.subscribe).toHaveBeenCalled();
// Simulate store change
(store.subscribe as jest.Mock).mock.calls[0][0]();
expect(store.getState).toHaveBeenCalled();
expect(window.minerva.configuration).toEqual(configurationMapper(configurationFixture));
});
it('init does not update minerva configuration when configuration is undefined', () => {
(store.getState as jest.Mock).mockReturnValueOnce({
configuration: { main: { data: undefined } },
});
PluginsManager.init();
expect(store.subscribe).toHaveBeenCalled();
// Simulate store change
(store.subscribe as jest.Mock).mock.calls[0][0]();
expect(store.getState).toHaveBeenCalled();
expect(window.minerva.configuration).toBeUndefined();
});
it('registerPlugin dispatches action and returns element', () => {
const pluginName = 'TestPlugin';
const pluginVersion = '1.0.0';
const pluginUrl = 'https://example.com/test-plugin.js';
const result = PluginsManager.registerPlugin({ pluginName, pluginVersion, pluginUrl });
expect(store.dispatch).toHaveBeenCalled();
expect(result.element).toBeDefined();
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment