diff --git a/src/__tests__/LoginPage/SignIn.test.js b/src/__tests__/LoginPage/SignIn.test.js index e3d1d6a..813d0f2 100644 --- a/src/__tests__/LoginPage/SignIn.test.js +++ b/src/__tests__/LoginPage/SignIn.test.js @@ -24,7 +24,7 @@ describe('Signin component automatic navigation', () => { it('navigates to homepage when auth is disabled', async () => { // mock request to check auth - jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: {} }); + jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { http: {} } }); render( {}} isLoggedIn={false} setIsLoggedIn={() => {}} />); await waitFor(() => { expect(mockedUsedNavigate).toHaveBeenCalledWith('/home'); diff --git a/src/__tests__/api.test.js b/src/__tests__/api.test.js new file mode 100644 index 0000000..7c24854 --- /dev/null +++ b/src/__tests__/api.test.js @@ -0,0 +1,19 @@ +import { api } from '../api'; + +describe('api module', () => { + it('should redirect to login if a 401 error is received', () => { + const location = new URL('https://www.test.com'); + location.replace = jest.fn(); + delete window.location; + window.location = location; + const axiosInstance = api.getAxiosInstance(); + expect( + axiosInstance.interceptors.response.handlers[0].rejected({ + response: { statusText: 'Unauthorized', status: 401 } + }) + ).rejects.toMatchObject({ + response: { statusText: 'Unauthorized', status: 401 } + }); + expect(location.replace).toHaveBeenCalledWith('/login'); + }); +}); diff --git a/src/api.js b/src/api.js index 7193a45..6cbf73e 100644 --- a/src/api.js +++ b/src/api.js @@ -9,12 +9,15 @@ axios.interceptors.response.use( (error) => { if (error.response.status === 401) { localStorage.clear(); + window.location.replace('/login'); return Promise.reject(error); } } ); const api = { + getAxiosInstance: () => axios, + getRequestCfg: () => { const genericHeaders = { Accept: 'application/json', @@ -71,6 +74,7 @@ const api = { }; const endpoints = { + authConfig: `/v2/_zot/ext/mgmt`, repoList: ({ pageNumber = 1, pageSize = 15 } = {}) => `/v2/_zot/ext/search?query={RepoListWithNewestImage(requestedPage: {limit:${pageSize} offset:${ (pageNumber - 1) * pageSize diff --git a/src/components/Login/SignIn.jsx b/src/components/Login/SignIn.jsx index 3e10ac9..014de65 100644 --- a/src/components/Login/SignIn.jsx +++ b/src/components/Login/SignIn.jsx @@ -3,7 +3,8 @@ import React, { useEffect, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { host } from '../../host'; // utility -import { api } from '../../api'; +import { api, endpoints } from '../../api'; +import { isEmpty } from 'lodash'; // components import Button from '@mui/material/Button'; @@ -117,15 +118,15 @@ export default function SignIn({ isLoggedIn, setIsLoggedIn, wrapperSetLoading = navigate('/home'); } else { api - .get(`${host()}/v2/`, abortController.signal) + .get(`${host()}${endpoints.authConfig}`, abortController.signal) .then((response) => { - if (response.status === 200) { + if (response.data?.http && isEmpty(response.data?.http?.auth)) { localStorage.setItem('token', '-'); setIsLoggedIn(true); - setIsLoading(false); - wrapperSetLoading(false); navigate('/home'); } + setIsLoading(false); + wrapperSetLoading(false); }) .catch(() => { setIsLoading(false);