From 1aaf610baab0d965576a9e52de5034983460329d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tadeusz=20Miesi=C4=85c?= <tadeusz.miesiac@gmail.com>
Date: Fri, 29 Sep 2023 00:56:17 +0200
Subject: [PATCH] feat(fetch drugs data): fetch drugs data and save to store

---
 jest.config.ts                         |   1 +
 package-lock.json                      | 100 ++++++++++++++++++++++++-
 package.json                           |   5 +-
 pages/redux-api-poc.tsx                |   8 +-
 src/constants/httpResponses.ts         |   2 +
 src/constants/mapId.ts                 |   1 +
 src/constants/zodSeed.ts               |   1 +
 src/models/fixtures/drugFixtures.ts    |  10 +++
 src/models/referenceSchema.ts          |  20 ++---
 src/redux/drugs/drugs.reducers.test.ts |  85 +++++++++++++++++++++
 src/redux/drugs/drugs.reducers.ts      |  17 +++++
 src/redux/drugs/drugs.slice.ts         |  20 +++++
 src/redux/drugs/drugs.thunks.ts        |  20 +++++
 src/redux/drugs/drugs.types.ts         |   8 ++
 src/redux/project/project.thunks.ts    |   2 +-
 src/redux/project/project.types.ts     |   5 +-
 src/redux/store.ts                     |   2 +
 src/types/api.ts                       |   9 ---
 src/types/loadingState.ts              |   1 +
 src/types/models.ts                    |  10 +++
 src/utils/mockNetworkResponse.ts       |   8 ++
 21 files changed, 306 insertions(+), 29 deletions(-)
 create mode 100644 src/constants/httpResponses.ts
 create mode 100644 src/constants/mapId.ts
 create mode 100644 src/constants/zodSeed.ts
 create mode 100644 src/models/fixtures/drugFixtures.ts
 create mode 100644 src/redux/drugs/drugs.reducers.test.ts
 create mode 100644 src/redux/drugs/drugs.reducers.ts
 create mode 100644 src/redux/drugs/drugs.slice.ts
 create mode 100644 src/redux/drugs/drugs.thunks.ts
 create mode 100644 src/redux/drugs/drugs.types.ts
 create mode 100644 src/types/loadingState.ts
 create mode 100644 src/types/models.ts
 create mode 100644 src/utils/mockNetworkResponse.ts

diff --git a/jest.config.ts b/jest.config.ts
index 7e7dad84..610effde 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -25,6 +25,7 @@ const config = {
   ],
   coverageReporters: ['html', 'text', 'text-summary', 'cobertura'],
   setupFilesAfterEnv: ['<rootDir>/setupTests.ts'],
+  prettierPath: require.resolve('prettier-2'),
 };
 
 // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
diff --git a/package-lock.json b/package-lock.json
index 1a168c99..9ae79cb7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,6 +35,7 @@
         "@types/react-redux": "^7.1.26",
         "@typescript-eslint/eslint-plugin": "^6.7.0",
         "@typescript-eslint/parser": "^6.7.0",
+        "axios-mock-adapter": "^1.22.0",
         "cypress": "^13.2.0",
         "cz-conventional-changelog": "^3.3.0",
         "eslint": "^8.49.0",
@@ -54,7 +55,9 @@
         "jest-junit": "^16.0.0",
         "lint-staged": "^14.0.1",
         "prettier": "^3.0.3",
-        "typescript": "^5.2.2"
+        "prettier-2": "npm:prettier@^2",
+        "typescript": "^5.2.2",
+        "zod-fixture": "^2.5.0"
       }
     },
     "node_modules/@aashutoshrathi/word-wrap": {
@@ -3256,6 +3259,19 @@
         "proxy-from-env": "^1.1.0"
       }
     },
+    "node_modules/axios-mock-adapter": {
+      "version": "1.22.0",
+      "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.22.0.tgz",
+      "integrity": "sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "is-buffer": "^2.0.5"
+      },
+      "peerDependencies": {
+        "axios": ">= 0.17.0"
+      }
+    },
     "node_modules/axios/node_modules/proxy-from-env": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -5099,6 +5115,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/drange": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz",
+      "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/eastasianwidth": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -7357,6 +7382,29 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-buffer": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+      "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/is-callable": {
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
@@ -10484,6 +10532,22 @@
         "url": "https://github.com/prettier/prettier?sponsor=1"
       }
     },
+    "node_modules/prettier-2": {
+      "name": "prettier",
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+      "dev": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
     "node_modules/pretty-bytes": {
       "version": "5.6.0",
       "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@@ -10655,6 +10719,19 @@
         "node": ">=8"
       }
     },
+    "node_modules/randexp": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz",
+      "integrity": "sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==",
+      "dev": true,
+      "dependencies": {
+        "drange": "^1.0.2",
+        "ret": "^0.2.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/react": {
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
@@ -11122,6 +11199,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/ret": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz",
+      "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/reusify": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -12805,6 +12891,18 @@
       "funding": {
         "url": "https://github.com/sponsors/colinhacks"
       }
+    },
+    "node_modules/zod-fixture": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/zod-fixture/-/zod-fixture-2.5.0.tgz",
+      "integrity": "sha512-lMQcUI5RC9zdkU26RUaOTDsUo1xWHEHtkVrERn6Cs/sRe+s/0qzltHQlRZMwYuvGh5SGPRI3Xy4eOToVJCj9sQ==",
+      "dev": true,
+      "dependencies": {
+        "randexp": "^0.5.3"
+      },
+      "peerDependencies": {
+        "zod": ">=3.0.0"
+      }
     }
   }
 }
diff --git a/package.json b/package.json
index 30e182e0..ce0430aa 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,7 @@
     "@types/react-redux": "^7.1.26",
     "@typescript-eslint/eslint-plugin": "^6.7.0",
     "@typescript-eslint/parser": "^6.7.0",
+    "axios-mock-adapter": "^1.22.0",
     "cypress": "^13.2.0",
     "cz-conventional-changelog": "^3.3.0",
     "eslint": "^8.49.0",
@@ -72,7 +73,9 @@
     "jest-junit": "^16.0.0",
     "lint-staged": "^14.0.1",
     "prettier": "^3.0.3",
-    "typescript": "^5.2.2"
+    "prettier-2": "npm:prettier@^2",
+    "typescript": "^5.2.2",
+    "zod-fixture": "^2.5.0"
   },
   "config": {
     "commitizen": {
diff --git a/pages/redux-api-poc.tsx b/pages/redux-api-poc.tsx
index 4a195e6e..7e51bc3b 100644
--- a/pages/redux-api-poc.tsx
+++ b/pages/redux-api-poc.tsx
@@ -1,18 +1,14 @@
 import { useSelector } from 'react-redux';
 import { selectSearchValue } from '@/redux/search/search.selectors';
-import { setSearchValue } from '@/redux/search/search.slice';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
-import { getProjectById } from '@/redux/project/project.thunks';
+import { getDrugs } from '@/redux/drugs/drugs.thunks';
 
 const ReduxPage = (): JSX.Element => {
   const dispatch = useAppDispatch();
   const searchValue = useSelector(selectSearchValue);
 
   const triggerSyncUpdate = (): void => {
-    // eslint-disable-next-line prefer-template
-    const newValue = searchValue + 'test';
-    dispatch(setSearchValue(newValue));
-    dispatch(getProjectById('pd_map_winter_23'));
+    dispatch(getDrugs('aspirin'));
   };
 
   return (
diff --git a/src/constants/httpResponses.ts b/src/constants/httpResponses.ts
new file mode 100644
index 00000000..e017a787
--- /dev/null
+++ b/src/constants/httpResponses.ts
@@ -0,0 +1,2 @@
+export const HTTP_OK = 200;
+export const HTTP_NOT_FOUND = 404;
diff --git a/src/constants/mapId.ts b/src/constants/mapId.ts
new file mode 100644
index 00000000..6c76bb70
--- /dev/null
+++ b/src/constants/mapId.ts
@@ -0,0 +1 @@
+export const PROJECT_ID = 'pd_map_winter_23';
diff --git a/src/constants/zodSeed.ts b/src/constants/zodSeed.ts
new file mode 100644
index 00000000..1f6c322d
--- /dev/null
+++ b/src/constants/zodSeed.ts
@@ -0,0 +1 @@
+export const ZOD_SEED = 997;
diff --git a/src/models/fixtures/drugFixtures.ts b/src/models/fixtures/drugFixtures.ts
new file mode 100644
index 00000000..76c0b54c
--- /dev/null
+++ b/src/models/fixtures/drugFixtures.ts
@@ -0,0 +1,10 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { createFixture } from 'zod-fixture';
+import { z } from 'zod';
+import { drugSchema } from '@/models/drugSchema';
+import { ZOD_SEED } from '@/constants/zodSeed';
+
+export const drugsFixture = createFixture(z.array(drugSchema), {
+  seed: ZOD_SEED,
+  array: { min: 2, max: 2 },
+});
diff --git a/src/models/referenceSchema.ts b/src/models/referenceSchema.ts
index 029c6ecb..ed8f782f 100644
--- a/src/models/referenceSchema.ts
+++ b/src/models/referenceSchema.ts
@@ -2,15 +2,17 @@ import { z } from 'zod';
 
 export const referenceSchema = z.object({
   link: z.string(),
-  article: z.object({
-    title: z.string(),
-    authors: z.array(z.string()),
-    journal: z.string(),
-    year: z.number(),
-    link: z.string(),
-    pubmedId: z.string(),
-    citationCount: z.number(),
-  }),
+  article: z
+    .object({
+      title: z.string(),
+      authors: z.array(z.string()),
+      journal: z.string(),
+      year: z.number(),
+      link: z.string(),
+      pubmedId: z.string(),
+      citationCount: z.number(),
+    })
+    .optional(),
   type: z.string(),
   resource: z.string(),
   id: z.number(),
diff --git a/src/redux/drugs/drugs.reducers.test.ts b/src/redux/drugs/drugs.reducers.test.ts
new file mode 100644
index 00000000..73053159
--- /dev/null
+++ b/src/redux/drugs/drugs.reducers.test.ts
@@ -0,0 +1,85 @@
+import { AnyAction, ThunkMiddleware } from '@reduxjs/toolkit';
+import { ToolkitStore, configureStore } from '@reduxjs/toolkit/dist/configureStore';
+import { PROJECT_ID } from '@/constants/mapId';
+import { drugsFixture } from '@/models/fixtures/drugFixtures';
+import { HTTP_NOT_FOUND, HTTP_OK } from '@/constants/httpResponses';
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { getDrugs } from './drugs.thunks';
+import drugsReducer from './drugs.slice';
+import { DrugsState } from './drugs.types';
+
+const mockedAxiosClient = mockNetworkResponse();
+const SEARCH_QUERY = 'aspirin';
+
+const INITIAL_STATE: DrugsState = {
+  data: [],
+  loading: 'idle',
+  error: { name: '', message: '' },
+};
+
+type SliceReducerType = ToolkitStore<
+  {
+    drugs: DrugsState;
+  },
+  AnyAction,
+  [
+    ThunkMiddleware<
+      {
+        drugs: DrugsState;
+      },
+      AnyAction
+    >,
+  ]
+>;
+
+const createStoreInstanceUsingSliceReducer = (): SliceReducerType =>
+  configureStore({
+    reducer: {
+      drugs: drugsReducer,
+    },
+  });
+
+describe('drugs reducer', () => {
+  let store = {} as SliceReducerType;
+
+  beforeEach(() => {
+    store = createStoreInstanceUsingSliceReducer();
+  });
+
+  it('should match initial state', () => {
+    const action = { type: 'unknown' };
+
+    expect(drugsReducer(undefined, action)).toEqual(INITIAL_STATE);
+  });
+  it('should update store after succesfull getDrugs query', async () => {
+    mockedAxiosClient
+      .onGet(`projects/${PROJECT_ID}/drugs:search?query=${SEARCH_QUERY}`)
+      .reply(HTTP_OK, drugsFixture);
+
+    const { type } = await store.dispatch(getDrugs(SEARCH_QUERY));
+    const { data, loading, error } = store.getState().drugs;
+
+    expect(type).toBe('project/getDrugs/fulfilled');
+    expect(loading).toEqual('succeeded');
+    expect(error).toEqual({ message: '', name: '' });
+    expect(data).toEqual(drugsFixture);
+  });
+
+  it('should update store after failed getDrugs query', async () => {
+    mockedAxiosClient
+      .onGet(`projects/${PROJECT_ID}/drugs:search?query=${SEARCH_QUERY}`)
+      .reply(HTTP_NOT_FOUND, []);
+
+    const { type } = await store.dispatch(getDrugs(SEARCH_QUERY));
+    const { data, loading, error } = store.getState().drugs;
+
+    expect(type).toBe('project/getDrugs/rejected');
+    expect(loading).toEqual('failed');
+    expect(error).toEqual({ message: '', name: '' });
+    expect(data).toEqual([]);
+  });
+
+  it.skip('should update store on loading getDrugs query', () => {
+    // TODO
+  });
+});
diff --git a/src/redux/drugs/drugs.reducers.ts b/src/redux/drugs/drugs.reducers.ts
new file mode 100644
index 00000000..8ca4b350
--- /dev/null
+++ b/src/redux/drugs/drugs.reducers.ts
@@ -0,0 +1,17 @@
+import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
+import { DrugsState } from './drugs.types';
+import { getDrugs } from './drugs.thunks';
+
+export const getDrugsReducer = (builder: ActionReducerMapBuilder<DrugsState>): void => {
+  builder.addCase(getDrugs.pending, state => {
+    state.loading = 'pending';
+  });
+  builder.addCase(getDrugs.fulfilled, (state, action) => {
+    state.data = action.payload;
+    state.loading = 'succeeded';
+  });
+  builder.addCase(getDrugs.rejected, state => {
+    state.loading = 'failed';
+    // TODO to discuss manage state of failure
+  });
+};
diff --git a/src/redux/drugs/drugs.slice.ts b/src/redux/drugs/drugs.slice.ts
new file mode 100644
index 00000000..651c68ae
--- /dev/null
+++ b/src/redux/drugs/drugs.slice.ts
@@ -0,0 +1,20 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { DrugsState } from '@/redux/drugs/drugs.types';
+import { getDrugsReducer } from './drugs.reducers';
+
+const initialState: DrugsState = {
+  data: [],
+  loading: 'idle',
+  error: { name: '', message: '' },
+};
+
+export const drugsSlice = createSlice({
+  name: 'drugs',
+  initialState,
+  reducers: {},
+  extraReducers: builder => {
+    getDrugsReducer(builder);
+  },
+});
+
+export default drugsSlice.reducer;
diff --git a/src/redux/drugs/drugs.thunks.ts b/src/redux/drugs/drugs.thunks.ts
new file mode 100644
index 00000000..c1726ee6
--- /dev/null
+++ b/src/redux/drugs/drugs.thunks.ts
@@ -0,0 +1,20 @@
+import { z } from 'zod';
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { axiosInstance } from '@/services/api/utils/axiosInstance';
+import { PROJECT_ID } from '@/constants/mapId';
+import { Drug } from '@/types/models';
+import { drugSchema } from '@/models/drugSchema';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+
+export const getDrugs = createAsyncThunk(
+  'project/getDrugs',
+  async (searchQuery: string): Promise<Drug[] | undefined> => {
+    const response = await axiosInstance.get<Drug[]>(
+      `projects/${PROJECT_ID}/drugs:search?query=${searchQuery}`,
+    );
+
+    const isDataValid = validateDataUsingZodSchema(response.data, z.array(drugSchema));
+
+    return isDataValid ? response.data : undefined;
+  },
+);
diff --git a/src/redux/drugs/drugs.types.ts b/src/redux/drugs/drugs.types.ts
new file mode 100644
index 00000000..fb38d5e0
--- /dev/null
+++ b/src/redux/drugs/drugs.types.ts
@@ -0,0 +1,8 @@
+import { Loading } from '@/types/loadingState';
+import { Drug } from '@/types/models';
+
+export type DrugsState = {
+  data: Drug[] | undefined;
+  loading: Loading;
+  error: Error;
+};
diff --git a/src/redux/project/project.thunks.ts b/src/redux/project/project.thunks.ts
index d26bbdda..944895cf 100644
--- a/src/redux/project/project.thunks.ts
+++ b/src/redux/project/project.thunks.ts
@@ -1,6 +1,6 @@
 import { createAsyncThunk } from '@reduxjs/toolkit';
 import { axiosInstance } from '@/services/api/utils/axiosInstance';
-import { Project } from '@/types/api';
+import { Project } from '@/types/models';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
 import { projectSchema } from '@/models/project';
 
diff --git a/src/redux/project/project.types.ts b/src/redux/project/project.types.ts
index b5ace9d7..f88c4b6b 100644
--- a/src/redux/project/project.types.ts
+++ b/src/redux/project/project.types.ts
@@ -1,7 +1,8 @@
-import { Project } from '@/types/api';
+import { Project } from '@/types/models';
+import { Loading } from '@/types/loadingState';
 
 export type ProjectState = {
   data: Project | undefined | [];
-  loading: 'idle' | 'pending' | 'succeeded' | 'failed';
+  loading: Loading;
   error: Error;
 };
diff --git a/src/redux/store.ts b/src/redux/store.ts
index d1335018..4996b2a3 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -1,11 +1,13 @@
 import { configureStore } from '@reduxjs/toolkit';
 import searchReducer from '@/redux/search/search.slice';
 import projectSlice from '@/redux/project/project.slice';
+import drugsReducer from '@/redux/drugs/drugs.slice';
 
 export const store = configureStore({
   reducer: {
     search: searchReducer,
     project: projectSlice,
+    drugs: drugsReducer,
   },
   devTools: true,
 });
diff --git a/src/types/api.ts b/src/types/api.ts
index 98a13076..84702d16 100644
--- a/src/types/api.ts
+++ b/src/types/api.ts
@@ -1,8 +1,3 @@
-import { z } from 'zod';
-import { disease } from '@/models/disease';
-import { organism } from '@/models/organism';
-import { projectSchema } from '@/models/project';
-
 export interface QueryOptions<Response> {
   method: 'GET' | 'POST';
   path: string;
@@ -12,7 +7,3 @@ export interface QueryOptions<Response> {
 export interface Query<Params, Response> {
   (params: Params): QueryOptions<Response>;
 }
-
-export type Project = z.infer<typeof projectSchema>;
-export type Organism = z.infer<typeof organism>;
-export type Disease = z.infer<typeof disease>;
diff --git a/src/types/loadingState.ts b/src/types/loadingState.ts
new file mode 100644
index 00000000..12859c95
--- /dev/null
+++ b/src/types/loadingState.ts
@@ -0,0 +1 @@
+export type Loading = 'idle' | 'pending' | 'succeeded' | 'failed';
diff --git a/src/types/models.ts b/src/types/models.ts
new file mode 100644
index 00000000..a7bc1e1e
--- /dev/null
+++ b/src/types/models.ts
@@ -0,0 +1,10 @@
+import { disease } from '@/models/disease';
+import { drugSchema } from '@/models/drugSchema';
+import { organism } from '@/models/organism';
+import { projectSchema } from '@/models/project';
+import { z } from 'zod';
+
+export type Project = z.infer<typeof projectSchema>;
+export type Organism = z.infer<typeof organism>;
+export type Disease = z.infer<typeof disease>;
+export type Drug = z.infer<typeof drugSchema>;
diff --git a/src/utils/mockNetworkResponse.ts b/src/utils/mockNetworkResponse.ts
new file mode 100644
index 00000000..4f7bd109
--- /dev/null
+++ b/src/utils/mockNetworkResponse.ts
@@ -0,0 +1,8 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import MockAdapter from 'axios-mock-adapter';
+import { axiosInstance } from '@/services/api/utils/axiosInstance';
+
+export const mockNetworkResponse = (): MockAdapter => {
+  const mock = new MockAdapter(axiosInstance);
+  return mock;
+};
-- 
GitLab