Skip to content

Commit

Permalink
add back in refactored tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dauglyon committed Dec 6, 2024
1 parent 6a2bcfe commit 0668a0e
Show file tree
Hide file tree
Showing 13 changed files with 731 additions and 80 deletions.
111 changes: 111 additions & 0 deletions src/features/login/EnforcePolicies.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { ThemeProvider } from '@emotion/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { createTestStore } from '../../app/store';
import { theme } from '../../theme';
import { noOp } from '../common';
import { EnforcePolicies } from './EnforcePolicies';

jest.mock('./Policies', () => ({
...jest.requireActual('./Policies'),
kbasePolicies: {
'kbase-user': {
raw: '---\ntitle: KBase Terms and Conditions\nid: kbase-user\nversion: 1\nequivalentVersions: []\n---\nsome content',
markdown: 'some content',
title: 'KBase Terms and Conditions',
id: 'kbase-user',
version: '2',
equivalentVersions: [],
},
'test-policy': {
raw: '---\ntitle: Test Policy\nid: test-policy\nversion: 1\nequivalentVersions: []\n---\ntest content',
markdown: 'test content',
title: 'Test Policy',
id: 'test-policy',
version: '1',
equivalentVersions: [],
},
},
}));

const renderWithProviders = (
ui: React.ReactElement,
{ store = createTestStore() } = {}
) => {
return render(
<Provider store={store}>
<ThemeProvider theme={theme}>
<BrowserRouter>
<main style={{ height: '100vh' }}>{ui}</main>
</BrowserRouter>
</ThemeProvider>
</Provider>
);
};

describe('EnforcePolicies', () => {
it('renders default message', () => {
renderWithProviders(
<EnforcePolicies policyIds={['test-policy']} onAccept={noOp} />
);
expect(
screen.getByText(
'To continue to your account, you must agree to the following KBase use policies.'
)
).toBeInTheDocument();
});

it('renders special v2 policy message', () => {
renderWithProviders(
<EnforcePolicies policyIds={['kbase-user']} onAccept={noOp} />
);
expect(
screen.getByText(
"KBase's recent renewal (Oct '2024) has prompted an update and version 2 release to our Terms and Conditions. Please review and agree to these policies changes to continue using this free resource."
)
).toBeInTheDocument();
});

it('disables accept button until all policies are accepted', async () => {
const mockAccept = jest.fn();
renderWithProviders(
<EnforcePolicies policyIds={['kbase-user']} onAccept={mockAccept} />
);

const acceptButton = screen.getByRole('button', {
name: /agree and continue/i,
});
expect(acceptButton).toBeDisabled();

const checkbox = screen.getByTestId('policy-checkbox');
await userEvent.click(checkbox);

expect(acceptButton).toBeEnabled();
});

it('calls onAccept when accept button clicked', async () => {
const mockAccept = jest.fn();
renderWithProviders(
<EnforcePolicies policyIds={['kbase-user']} onAccept={mockAccept} />
);

const checkbox = screen.getByTestId('policy-checkbox');
await userEvent.click(checkbox);

const acceptButton = screen.getByRole('button', {
name: /agree and continue/i,
});
await userEvent.click(acceptButton);

expect(mockAccept).toHaveBeenCalledWith(['kbase-user.2']);
});
it('throws error when policy does not exist', () => {
expect(() =>
renderWithProviders(
<EnforcePolicies policyIds={['non-existent-policy']} onAccept={noOp} />
)
).toThrow('Required policy "non-existent-policy" cannot be loaded');
});
});
72 changes: 66 additions & 6 deletions src/features/login/EnforcePolicies.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import { faArrowRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Alert, Button, Container, Paper } from '@mui/material';
import {
Alert,
Button,
Container,
Paper,
Box,
Checkbox,
FormControl,
FormControlLabel,
Typography,
} from '@mui/material';
import { Stack } from '@mui/system';
import { useState } from 'react';
import classes from '../signup/SignUp.module.scss';
import { kbasePolicies, PolicyViewer } from './Policies';
import { kbasePolicies } from './Policies';
import createDOMPurify from 'dompurify';
import { marked } from 'marked';

export const EnforcePolicies = ({
policyIds,
Expand All @@ -14,13 +26,17 @@ export const EnforcePolicies = ({
onAccept: (versionedPolicyIds: string[]) => void;
}) => {
// Get policy information
const targetPolicies = policyIds.map((id) => kbasePolicies[id]);
const targetPolicies = policyIds.map((id) => {
if (!kbasePolicies[id])
throw new Error(`Required policy "${id}" cannot be loaded`);
return kbasePolicies[id];
});
const [accepted, setAccepted] = useState<{
[k in typeof targetPolicies[number]['id']]?: boolean;
}>({});
const allAccepted = targetPolicies.every(
(policy) => accepted[policy.id] === true
);
const allAccepted = targetPolicies.every((policy) => {
return accepted[policy.id] === true;
});

// Message to user, uses a special message when agreeing to kbase-user.2
let message =
Expand Down Expand Up @@ -77,3 +93,47 @@ export const EnforcePolicies = ({
</Container>
);
};

const purify = createDOMPurify(window);

export const PolicyViewer = ({
policyId,
setAccept,
accepted = false,
}: {
policyId: string;
setAccept: (accepted: boolean) => void;
accepted?: boolean;
}) => {
const policy = kbasePolicies[policyId];
if (!policy)
throw new Error(`Required policy "${policyId}" cannot be loaded`);
return (
<FormControl>
<Typography fontWeight="bold">{policy.title}</Typography>
<Paper className={classes['policy-panel']} elevation={0}>
<div
dangerouslySetInnerHTML={{
__html: purify.sanitize(marked(policy.markdown)),
}}
/>
</Paper>
<div>
<Box className={classes['agreement-box']}>
<FormControlLabel
control={
<Checkbox
data-testid="policy-checkbox"
checked={accepted}
onChange={(e) => {
setAccept(e.currentTarget.checked);
}}
/>
}
label="I have read and agree to this policy"
/>
</Box>
</div>
</FormControl>
);
};
48 changes: 48 additions & 0 deletions src/features/login/LogInContinue.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,52 @@ describe('Login Continue', () => {
expect(Login).toHaveBeenCalled();
});
});

it('handles new user signup flow', async () => {
// getLoginChoice - return create data instead of login data
fetchMock.mockResponseOnce(
JSON.stringify({
login: [],
create: [
{
id: 'newuserid',
provider: 'google',
username: '[email protected]',
},
],
})
);

const Signup = jest.fn(() => <></>);
const store = createTestStore();
render(
<Provider store={store}>
<ThemeProvider theme={theme}>
<MemoryRouter initialEntries={['/login/continue']}>
<Routes>
<Route path={'/login/continue'} element={<LogInContinue />} />
<Route path={'/signup/2'} Component={Signup} />
</Routes>
</MemoryRouter>
</ThemeProvider>
</Provider>
);

await waitFor(() => {
// Check that login data was set in store
expect(store.getState().signup.loginData).toEqual({
login: [],
create: [
{
id: 'newuserid',
provider: 'google',
username: '[email protected]',
},
],
});
});
await waitFor(() => {
expect(window.location.pathname === '/signup/2');
});
});
});
54 changes: 0 additions & 54 deletions src/features/login/Policies.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
import policyStrings from 'kbase-policies';
import frontmatter from 'front-matter';
import {
Box,
Checkbox,
FormControl,
FormControlLabel,
Paper,
Typography,
} from '@mui/material';
import classes from './PolicyViewer.module.scss';
import createDOMPurify from 'dompurify';
import { marked } from 'marked';

export const ENFORCED_POLICIES = ['kbase-user'];

const purify = createDOMPurify(window);

interface PolicyMeta {
title: string;
id: string;
Expand Down Expand Up @@ -46,44 +33,3 @@ export const kbasePolicies = policyStrings.reduce(
}
>
);

export const PolicyViewer = ({
policyId,
setAccept,
accepted = false,
}: {
policyId: string;
setAccept: (accepted: boolean) => void;
accepted?: boolean;
}) => {
const policy = kbasePolicies[policyId];
if (!policy)
throw new Error(`Required policy "${policyId}" cannot be loaded`);
return (
<FormControl>
<Typography fontWeight="bold">{policy.title}</Typography>
<Paper className={classes['policy-panel']} elevation={0}>
<div
dangerouslySetInnerHTML={{
__html: purify.sanitize(marked(policy.markdown)),
}}
/>
</Paper>
<div>
<Box className={classes['agreement-box']}>
<FormControlLabel
control={
<Checkbox
checked={accepted}
onChange={(e) => {
setAccept(e.currentTarget.checked);
}}
/>
}
label="I have read and agree to this policy"
/>
</Box>
</div>
</FormControl>
);
};
8 changes: 0 additions & 8 deletions src/features/login/PolicyViewer.module.scss

This file was deleted.

Loading

0 comments on commit 0668a0e

Please sign in to comment.