Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix]: complete unit test and add router auth #264

Merged
merged 1 commit into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 57 additions & 75 deletions src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { cleanup, render, act } from '@testing-library/react';
import { shallow } from 'enzyme';
import { cleanup, render, act, screen } from '@testing-library/react';
import { useDispatch, useSelector } from 'react-redux';
import { BrowserRouter, useLocation } from 'react-router-dom';
import { BrowserRouter } from 'react-router-dom';
import global from './api/global';
import App, { Wrapper } from './App';
import {
Expand All @@ -10,23 +9,25 @@ import {
SystemRole,
} from './data/common';
import { ModalName } from './data/ModalName';
import {
mockBindProjects,
mockManagementPermissions,
} from './hooks/useCurrentUser/index.test';
import useNavigate from './hooks/useNavigate';
import { mockGetCurrentUser } from './hooks/useUserInfo/index.test';
import { SupportLanguage } from './locale';
import {
mockGetCurrentUser,
mockUseAuditPlanTypes,
resolveErrorThreeSecond,
resolveThreeSecond,
} from './testUtils/mockRequest';

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: jest.fn(),
}));
import {
mockBindProjects,
mockManagementPermissions,
} from './hooks/useCurrentUser/index.test.data';
import {
renderLocationDisplay,
renderWithMemoryRouter,
renderWithThemeAndRouter,
} from './testUtils/customRender';
import { getBySelector } from './testUtils/customQuery';
import configuration from './api/configuration';

jest.mock('react-redux', () => {
return {
Expand All @@ -42,23 +43,23 @@ describe('App test', () => {
let getUserSpy: jest.SpyInstance;
const scopeDispatch = jest.fn();
const navigateSpy = jest.fn();
const useLocationMock: jest.Mock = useLocation as jest.Mock;
const useHistoryMock: jest.Mock = useNavigate as jest.Mock;
let getSqleInfoSpy: jest.SpyInstance;

const mockGetOauth2Tips = () => {
const spy = jest.spyOn(configuration, 'getOauth2Tips');
spy.mockImplementation(() =>
resolveThreeSecond({ enable_oauth2: true, login_tip: 'login with QQ' })
);
return spy;
};

beforeEach(() => {
getUserSpy = mockGetCurrentUser();
getSqleInfoSpy = mockGetSqleInfo();

mockGetOauth2Tips();
mockUseAuditPlanTypes();
jest.useFakeTimers();
useLocationMock.mockReturnValue({
pathname: '/rule',
search: '',
hash: '',
state: null,
key: '5nvxpbdafa',
});

(useSelector as jest.Mock).mockImplementation((e) =>
e({
Expand All @@ -73,7 +74,6 @@ describe('App test', () => {
jest.clearAllMocks();
jest.clearAllTimers();
jest.useRealTimers();
useLocationMock.mockRestore();
useHistoryMock.mockRestore();
});

Expand All @@ -94,7 +94,9 @@ describe('App test', () => {
user: { token: '' },
})
);
render(<Wrapper>children</Wrapper>);
renderWithMemoryRouter(<Wrapper>children</Wrapper>, undefined, {
initialEntries: ['/rule'],
});

expect(navigateSpy).toBeCalledTimes(1);
expect(navigateSpy).nthCalledWith(
Expand All @@ -109,7 +111,9 @@ describe('App test', () => {
user: { token: 'token' },
})
);
render(<Wrapper>children</Wrapper>);
renderWithMemoryRouter(<Wrapper>children</Wrapper>, undefined, {
initialEntries: ['/rule'],
});
expect(navigateSpy).toBeCalledTimes(0);
cleanup();
navigateSpy.mockClear();
Expand All @@ -119,84 +123,62 @@ describe('App test', () => {
user: { token: '' },
})
);
useLocationMock.mockReturnValue({
pathname: '/login',
search: '',
hash: '',
state: null,
key: '5nvxpbdafa',

renderWithMemoryRouter(<Wrapper>children</Wrapper>, undefined, {
initialEntries: ['/login'],
});
render(<Wrapper>children</Wrapper>);
expect(navigateSpy).toBeCalledTimes(0);
cleanup();
navigateSpy.mockClear();

useLocationMock.mockReturnValue({
pathname: '/user/bind',
search: '',
hash: '',
state: null,
key: '5nvxpbdafa',
renderWithMemoryRouter(<Wrapper>children</Wrapper>, undefined, {
initialEntries: ['/user/bind'],
});
render(<Wrapper>children</Wrapper>);
expect(navigateSpy).toBeCalledTimes(0);
cleanup();
navigateSpy.mockClear();
});

test.skip('should render login route when token is falsy', async () => {
test('should render login route when token is falsy', async () => {
(useSelector as jest.Mock).mockImplementation((e) =>
e({
user: { token: '', role: '' },
locale: { language: SupportLanguage.zhCN },
nav: { modalStatus: { [ModalName.SHOW_VERSION]: false } },
system: { webTitle: SQLE_DEFAULT_WEB_TITLE, webLogoUrl: 'test' },
})
);

const wrapper = shallow(<App />);
const route = wrapper.find('Route');
expect(route.length).toBe(2);
expect(route.at(0).prop('path')).toBe('/login');
const redirect = wrapper.find('Redirect');
expect(redirect.length).toBe(1);
expect(redirect.at(0).prop('to')).toBe('/login');
const [, LocationComponent] = renderLocationDisplay();

renderWithThemeAndRouter(
<>
<App /> <LocationComponent />
</>
);

await act(async () => jest.advanceTimersByTime(3000));
expect(screen.getByText('login.login')).toBeInTheDocument();
expect(screen.getByTestId('location-display')).toHaveTextContent('/login');
});

test.skip('should render Nav and inner route when token is truthy and role is admin', () => {
test('should render Nav and inner route when token is truthy and role is admin', async () => {
(useSelector as jest.Mock).mockImplementation((e) =>
e({
user: { token: 'testToken', role: SystemRole.admin },
locale: { language: SupportLanguage.zhCN },
nav: { modalStatus: { [ModalName.SHOW_VERSION]: false } },
system: { webTitle: SQLE_DEFAULT_WEB_TITLE, webLogoUrl: 'test' },
})
);
const wrapper = shallow(<App />);
const Nav = wrapper.find('Nav');
expect(Nav.length).toBe(1);
const Switch = Nav.find('Switch');
expect(Switch.length).toBe(1);
const routes = Switch.find('Route');
expect(routes.length).toBe(12);
const redirect = Switch.find('Redirect');
expect(redirect.length).toBe(1);
expect(redirect.at(0).prop('to')).toBe('/');
});

test.skip('should render Nav and some inner route when token is truthy and role is not admin', () => {
(useSelector as jest.Mock).mockImplementation((e) =>
e({
user: { token: 'testToken', role: '' },
locale: { language: SupportLanguage.zhCN },
})
renderWithThemeAndRouter(
<>
<App />
</>
);
const wrapper = shallow(<App />);
const Nav = wrapper.find('Nav');
expect(Nav.length).toBe(1);
const Switch = Nav.find('Switch');
expect(Switch.length).toBe(1);
const routes = Switch.find('Route');
expect(routes.length).toBe(10);
const redirect = Switch.find('Redirect');
expect(redirect.length).toBe(1);
expect(redirect.at(0).prop('to')).toBe('/');
await act(async () => jest.advanceTimersByTime(3000));
expect(getBySelector('.sqle-layout')).toBeInTheDocument();
});

test('should get user info when token is not empty', async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import global from './api/global';
import { updateWebTitleAndLog } from './store/system';
import useNavigate from './hooks/useNavigate';
import { ThemeProvider } from '@mui/system';
import RouterAuth from './router/RouterAuth';

//fix https://github.com/actiontech/sqle/issues/1350
export const Wrapper: React.FC<{ children: ReactNode }> = ({ children }) => {
Expand Down Expand Up @@ -58,7 +59,6 @@ function App() {
);
})
);

React.useEffect(() => {
if (!!token) {
getUserInfo();
Expand All @@ -77,7 +77,7 @@ function App() {
<Nav>
<Suspense fallback={<HeaderProgress />}>
<EmptyBox if={!getUserInfoLoading}>
<>{elements}</>
<RouterAuth>{elements}</RouterAuth>
</EmptyBox>
</Suspense>
</Nav>
Expand Down
42 changes: 42 additions & 0 deletions src/components/Link/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { cleanup } from '@testing-library/react';
import { Link } from '.';
import { SQLE_BASE_URL } from '../../data/common';
import { getHrefByText } from '../../testUtils/customQuery';
import { renderWithRouter } from '../../testUtils/customRender';

describe('test CustomLink', () => {
afterEach(() => {
cleanup();
});
test('should render href', () => {
renderWithRouter(<Link to="/test">test</Link>);

expect(getHrefByText('test')).toBe('/test');
});

test('should be add custom prefix', () => {
renderWithRouter(<Link to="test">test</Link>);
expect(getHrefByText('test')).toBe(`${SQLE_BASE_URL}test`);
cleanup();

renderWithRouter(<Link to={`${SQLE_BASE_URL}test`}>test</Link>);
expect(getHrefByText('test')).toBe(`${SQLE_BASE_URL}test`);
cleanup();

renderWithRouter(
<Link to={{ pathname: 'test', search: '123' }}>test</Link>
);
expect(getHrefByText('test')).toBe(`${SQLE_BASE_URL}test?123`);
cleanup();

renderWithRouter(
<Link to={{ pathname: `${SQLE_BASE_URL}test`, search: '123' }}>test</Link>
);
expect(getHrefByText('test')).toBe(`${SQLE_BASE_URL}test?123`);

cleanup();

renderWithRouter(<Link to={{ pathname: undefined }}>test</Link>);
expect(getHrefByText('test')).toBe('/');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import HeaderMenu from '../HeaderMenu';
import { cleanup, fireEvent, screen } from '@testing-library/react';
import { DEFAULT_PROJECT_NAME } from '../../../../../page/ProjectManage/ProjectDetail';
import { SystemRole } from '../../../../../data/common';
import { mockBindProjects } from '../../../../../hooks/useCurrentUser/index.test';
import { useSelector } from 'react-redux';
import useNavigate from '../../../../../hooks/useNavigate';
import { mockBindProjects } from '../../../../../hooks/useCurrentUser/index.test.data';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
Expand Down
Loading