Skip to content

Commit

Permalink
Merged in feature/SHIBUI-1926 (pull request #490)
Browse files Browse the repository at this point in the history
Feature/SHIBUI-1926
  • Loading branch information
rmathis committed Jun 29, 2021
2 parents 5250647 + b312552 commit bae0760
Show file tree
Hide file tree
Showing 69 changed files with 3,600 additions and 2,120 deletions.
7 changes: 7 additions & 0 deletions ui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ npm_run_build {
outputs.dir 'build'
}

task test(type: NpmTask) {
environment = ['CI': 'true']
args = ['run', 'test']
}

check.dependsOn(test)

npm_run_buildProd {
inputs.dir 'src'
inputs.dir 'public'
Expand Down
3,536 changes: 1,559 additions & 1,977 deletions ui/package-lock.json

Large diffs are not rendered by default.

72 changes: 70 additions & 2 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"@testing-library/jest-dom": "^5.13.0",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.1.10",
"fast-check": "^2.16.0",
"http-proxy-middleware": "^1.2.0",
"jest-fast-check": "^1.0.2",
"react-scripts": "4.0.3",
"sass": "1.32.11"
},
Expand All @@ -49,10 +51,76 @@
"copy": "npm run copy:static && npm run build:static"
},
"jest": {
"testMatch": [
"**/?(*.)+(spec|test).[jt]s?(x)"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx}",
"!src/test/**/*.*"
]
"!src/testing/**/*.*",
"!src/*.js"
],
"coverageThreshold": {
"global": {
"branches": 0,
"functions": 0,
"lines": 0,
"statements": 0
},
"./src/app/i18n/": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/core/": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/metadata/domain/filter/definition": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/metadata/domain/provider/definition/": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/metadata/domain/source/definition/": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/metadata/domain/attribute/": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/metadata/hooks/": {
"branches": 50,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/metadata/contention/": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/app/metadata/component/": {
"branches": 0,
"functions": 0,
"lines": 0,
"statements": 0
}
}
},
"eslintConfig": {
"extends": [
Expand Down
41 changes: 41 additions & 0 deletions ui/src/app/core/components/AdminRoute.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { act, render, fireEvent, waitFor, screen } from '@testing-library/react';
import { BrowserRouter, MemoryRouter, Route } from 'react-router-dom';
import { AdminRoute } from './AdminRoute';

const mockIsAdmin = jest.fn();

jest.mock('../user/UserContext', () => ({
useIsAdmin: () => mockIsAdmin()
}));

const renderWithRouter = (ui, { route = '/' } = {}) => {
window.history.pushState({}, 'Test page', route)

return render(ui, { wrapper: BrowserRouter })
}

describe('AdminRoute user is admin', () => {
beforeEach(() => {
mockIsAdmin.mockReturnValue(true);
});

it('should render the component if user is an admin', () => {
render(<AdminRoute><React.Fragment>hi there</React.Fragment></AdminRoute>, { wrapper: MemoryRouter });
expect(screen.getByText('hi there')).toBeInTheDocument();
});
});

describe('AdminRoute user is NOT admin', () => {
beforeEach(() => {
mockIsAdmin.mockReturnValue(false);
});

it('should redirect the user to the dashboard if not admin', () => {
renderWithRouter(<React.Fragment>
<AdminRoute path="/foo"><React.Fragment>hi there</React.Fragment></AdminRoute>
<Route path="/dashboard" render={ () => 'dashboard' } />
</React.Fragment>, {route: '/foo'});
expect(screen.getByText('dashboard')).toBeInTheDocument();
});
});
4 changes: 3 additions & 1 deletion ui/src/app/core/components/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function FooterLink ({ link }) {
);
}

export default function Footer () {
export function Footer () {
return (
<footer>
<div className="row">
Expand Down Expand Up @@ -49,3 +49,5 @@ export default function Footer () {
</footer>
);
}

export default Footer;
12 changes: 12 additions & 0 deletions ui/src/app/core/components/Footer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { Footer } from './Footer';

jest.mock('../../i18n/hooks', () => ({
useTranslation: (value) => value
}));

it('should display the footer', () => {
render(<Footer />);
expect(screen.getByText('brand.footer.text')).toBeInTheDocument();
});
27 changes: 27 additions & 0 deletions ui/src/app/core/components/Header.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import { Header } from './Header';

jest.mock('../../i18n/hooks', () => ({
useTranslator: () => (value) => value,
useTranslation: (value) => value
}));

const mockIsAdmin = jest.fn();

jest.mock('../user/UserContext', () => ({
useIsAdmin: () => mockIsAdmin()
}));

describe('header for admins', () => {
beforeEach(() => {
mockIsAdmin.mockReturnValue(true);
});

it('should display logo and navigation', () => {
render(<Router><Header /></Router>);
expect(screen.getByText('brand.logo-link-label')).toBeInTheDocument();
});
});

4 changes: 2 additions & 2 deletions ui/src/app/core/components/UserConfirmation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Modal from 'react-bootstrap/Modal';
import Button from 'react-bootstrap/Button';
import Translate from '../../i18n/components/translate';
import { useHistory } from 'react-router-dom';

import { reload } from '../utility/window';

export function UserConfirmation({children}) {
const [confirm, setConfirm] = React.useState(false);
Expand All @@ -27,7 +27,7 @@ export function ConfirmWindow ({message, confirm, setConfirm, confirmCallback})
setConfirm(false);
confirmCallback(true);
if (history.location.pathname.includes('provider/new')) {
window.location.reload();
reload();
}
}

Expand Down
95 changes: 95 additions & 0 deletions ui/src/app/core/components/UserConfirmation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from 'react';
import { act, render, fireEvent, waitFor, screen } from '@testing-library/react';
import { UserConfirmation, ConfirmWindow } from './UserConfirmation';

jest.mock('../../i18n/hooks', () => ({
useTranslator: () => (value) => value,
useTranslation: (value) => value
}));

const mockReload = jest.fn();

jest.mock('../utility/window', () => ({
reload: () => mockReload()
}))

const mockIncludes = jest.fn();

jest.mock('react-router-dom', () => ({
useHistory: () => ({
location: {
pathname: {
includes: mockIncludes
}
}
})
}));

const TestWindow = ({getConfirmation, message}) => {
React.useEffect(() => getConfirmation('foo', jest.fn()), [])
return <span>{message}</span>;
}

describe('user confirmation context', () => {
it('should render its children with a function', () => {
render(<UserConfirmation>
{(message, confirm, confirmCallback, setConfirm, getConfirmation) => <p><span>hi there</span> <TestWindow message={message} getConfirmation={getConfirmation} /></p>}
</UserConfirmation>);
expect(screen.getByText('hi there')).toBeInTheDocument();
expect(screen.getByText('foo')).toBeInTheDocument();
});
});

describe('confirmation window', () => {

it('should provide buttons to confirm', async () => {

const message = 'hi there';
const confirm = true;
const confirmCallback = jest.fn();
const setConfirm = jest.fn();

render(<ConfirmWindow message={message} confirm={confirm} confirmCallback={confirmCallback} setConfirm={setConfirm} /> );
expect(screen.getByText('hi there')).toBeInTheDocument();

fireEvent.click(screen.getByText('action.discard-changes'));

expect(confirmCallback).toHaveBeenCalledWith(true);

});

it('should provide buttons to stop', async () => {

const message = 'hi there';
const confirm = true;
const confirmCallback = jest.fn();
const setConfirm = jest.fn();

render(<ConfirmWindow message={message} confirm={confirm} confirmCallback={confirmCallback} setConfirm={setConfirm} />);
expect(screen.getByText('hi there')).toBeInTheDocument();

fireEvent.click(screen.getByText('action.cancel'));

expect(confirmCallback).toHaveBeenCalledWith(false);

});

it('should redirect if on a provider', () => {
mockIncludes.mockReturnValue(true);

const message = 'hi there';
const confirm = true;
const confirmCallback = jest.fn();
const setConfirm = jest.fn();

render(<ConfirmWindow message={message} confirm={confirm} confirmCallback={confirmCallback} setConfirm={setConfirm} />);
expect(screen.getByText('hi there')).toBeInTheDocument();

fireEvent.click(screen.getByText('action.discard-changes'));

expect(confirmCallback).toHaveBeenCalledWith(true);

expect(mockReload).toHaveBeenCalled();
})
});

5 changes: 0 additions & 5 deletions ui/src/app/core/hooks/utils.js

This file was deleted.

18 changes: 18 additions & 0 deletions ui/src/app/core/user/SessionModal.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { SessionModal } from './SessionModal';

jest.mock('../../i18n/hooks', () => ({
useTranslator: () => (value) => value,
useTranslation: (value) => value
}));

describe('session modal', () => {

it('should provide buttons to confirm', async () => {

render(<SessionModal show={true} />);
expect(screen.getByText('message.session-timeout-heading')).toBeInTheDocument();

});
});
47 changes: 47 additions & 0 deletions ui/src/app/core/user/UserContext.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { UserProvider, useIsAdmin } from './UserContext';

const getFn = jest.fn();
const okFn = jest.fn();

const mockUseFetch = {
get: getFn,
response: {}
};

Object.defineProperty(mockUseFetch.response, 'ok', {
get: okFn
});

jest.mock('use-http', () => () => mockUseFetch);

const TestAdmin = () => {
const isAdmin = useIsAdmin();
return (<>{ isAdmin ? 'yes' : 'no' }</>)
}

describe('User Context defined', () => {

beforeEach(() => {
getFn.mockReturnValue(Promise.resolve({
role: 'ROLE_ADMIN'
}));
okFn.mockReturnValueOnce(true);
});

it('should render the component children', async () => {
render(<UserProvider>
{<div>test</div>}
</UserProvider>);
await waitFor(() => expect(screen.getByText('test')).toBeInTheDocument());
});

it('should provide the user context', async () => {
render(<UserProvider>
<TestAdmin />
</UserProvider>);

await waitFor(() => expect(screen.getByText('yes')).toBeInTheDocument());
});
});
Loading

0 comments on commit bae0760

Please sign in to comment.