Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Refactor auth and enable static file serving #577

Merged
merged 20 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ The types of changes are:
* Restart Graph from Failure [#578](https://github.com/ethyca/fidesops/pull/578)
* Redis SSL Support [#611](https://github.com/ethyca/fidesops/pull/611)

### Changed

* Refactor auth and enable static file serving [#577](https://github.com/ethyca/fidesops/pull/577)

## [1.5.2](https://github.com/ethyca/fidesops/compare/1.5.1...1.5.2)

### Added
Expand Down
29 changes: 29 additions & 0 deletions clients/admin-ui/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module.exports = {
extends: [
'airbnb',
'airbnb-typescript/base',
'prettier',
'next/core-web-vitals',
],
plugins: ['simple-import-sort'],
root: true,
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
rules: {
// causes bug in re-exporting default exports, see
// https://github.com/eslint/eslint/issues/15617
'no-restricted-exports': [0],
'react/function-component-definition': [
2,
{
namedComponents: 'arrow-function',
},
],
'react/jsx-filename-extension': [1, { extensions: ['.tsx'] }],
'react/jsx-props-no-spreading': [0],
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
},
};
28 changes: 0 additions & 28 deletions clients/admin-ui/.eslintrc.json

This file was deleted.

1 change: 1 addition & 0 deletions clients/admin-ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ typings/

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
Expand Down
10 changes: 3 additions & 7 deletions clients/admin-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ Admin UI for managing FidesOps privacy requests. A web application built in Next
5. Submit a privacy request through the Privacy Request center.
6. View that request in the Admin UI and either approve or deny it.

## Authentication
## Unit test locations

To enable stable authentication you must supply a `NEXTAUTH_SECRET` environment
variable. The best way to do this is by creating a `.env.local` file, which Next
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the .env.local file no longer needed for auth to work properly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. This was an artifact of the previous library, which we're no longer using.

will automatically pick up:
Unless otherwise specified below, all unit tests should be colocated in the directory with the file(s) they are testing, in a `__tests__` subfolder.

```bash
echo NEXTAUTH_SECRET=`openssl rand -base64 32` >> .env.local
```
The sole exception to this is the `pages` directory. Tests for Next.js pages live in the root `__tests__/pages` directory. Otherwise, Next.js attempts to include them in final build output, which breaks the build.
19 changes: 11 additions & 8 deletions clients/admin-ui/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
// __tests__/index.test.tsx
import { SessionProvider } from 'next-auth/react';

import Home from '../src/pages/index';
import { render, screen } from './test-utils';

describe('Home', () => {
it('renders the Subject Requests page by default', () => {
render(
<SessionProvider>
<Home />
</SessionProvider>
);
it('renders the Subject Requests page by default when logged in', () => {
render(<Home />, {
preloadedState: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoa this is very cool 🤩

auth: {
user: {
username: 'Test',
},
token: 'valid-token',
},
},
});

const message = screen.getAllByText('Subject Requests')[0];
expect(message).toBeInTheDocument();
Expand Down
85 changes: 85 additions & 0 deletions clients/admin-ui/__tests__/pages/login.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { rest } from 'msw';
import { setupServer } from 'msw/node';

import LoginPage from '../../src/pages/login';
import { act, fireEvent, render, screen, waitFor } from '../test-utils';

const useRouter = jest.spyOn(require('next/router'), 'useRouter');

afterAll(() => {
useRouter.mockRestore();
});

describe('/login', () => {
it('Should redirect when the user logs in successfully', async () => {
const server = setupServer(
rest.post(`/login`, (req, res, ctx) =>
res(
ctx.json({
user_data: {
username: 'Test',
},
token_data: {
access_token: 'test-access-token',
},
})
)
)
);

server.listen();

const push = jest.fn();
useRouter.mockImplementation(() => ({
push,
}));

await act(async () => {
render(<LoginPage />);
});

expect(push).toBeCalledTimes(0);

const email = screen.getByRole('textbox', { name: /email/i });
const passwordInput = screen.getByLabelText(/password/i);
const loginButton = screen.getByRole('button');

await act(async () => {
await fireEvent.change(email, { target: { value: 'test-user' } });
await fireEvent.change(passwordInput, {
target: { value: 'test-user-password' },
});
await fireEvent.submit(loginButton);
});

await waitFor(() => expect(push).toHaveBeenCalledTimes(1));
expect(push).toHaveBeenCalledWith('/');

server.close();
});

it('Should redirect to "/" when the user is already logged in', async () => {
await act(async () => {
const push = jest.fn();
useRouter.mockImplementation(() => ({
push,
}));

await act(async () => {
render(<LoginPage />, {
preloadedState: {
auth: {
user: {
username: 'Test User',
},
token: 'valid-token',
},
},
});
});

expect(push).toHaveBeenCalledWith('/');
expect(push).toHaveBeenCalledTimes(1);
});
});
});
12 changes: 7 additions & 5 deletions clients/admin-ui/__tests__/test-utils.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
// test-utils.jsx
import { Store } from '@reduxjs/toolkit';
import { render as rtlRender, RenderOptions } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';

import { AppState, AppStore, makeStore } from '../src/app/store';
import { makeStore, RootState } from '../src/app/store';

type CustomRenderOptions = {
preloadedState?: AppState;
store?: AppStore;
preloadedState?: Partial<RootState>;
customStore?: Store;
} & RenderOptions;

function render(
ui: React.ReactElement<any, string | React.JSXElementConstructor<any>>,
{
preloadedState,
store = makeStore(preloadedState),
customStore = makeStore(preloadedState),
...renderOptions
}: CustomRenderOptions = {}
) {
const Wrapper: React.FC = ({ children }) => (
<Provider store={store}>{children}</Provider>
<Provider store={customStore}>{children}</Provider>
);
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
}

// re-export everything
export * from '@testing-library/react';

// override render method
export { render };
3 changes: 3 additions & 0 deletions clients/admin-ui/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const nextConfig = {

return config;
},
images: {
loader: 'custom',
},
};

module.exports = withBundleAnalyzer(nextConfig);
Loading