Skip to content
This repository was archived by the owner on May 13, 2024. It is now read-only.
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
flex-direction: column;
gap: rem(1);
border: 1px solid var(--ifm-color-emphasis-400);
border-radius: rem(0.4);
border-radius: rem(2);
padding: rem(1.6);

label {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

type TCustomErrors = {
token_name_exists: boolean;
tokens_limit_reached: boolean;
input_value: string;
};

const CustomErrors = ({ token_name_exists, tokens_limit_reached, input_value }: TCustomErrors) => {
if (token_name_exists) {
return (
<div className='error-message'>
<p>That name is taken. Choose another.</p>
</div>
);
}
if (tokens_limit_reached && input_value !== '') {
return (
<div className='error-message'>
<p>You&apos;ve created the maximum number of tokens.</p>
</div>
);
}

return <></>;
};

export default CustomErrors;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Text, Button } from '@deriv/ui';
import styles from '../api-token.form.module.scss';
import useApiToken from '@site/src/hooks/useApiToken';
import { FieldErrorsImpl, UseFormRegisterReturn } from 'react-hook-form';
import CustomErrors from './CustomErrors';
import TokenCreationDialogSuccess from '../../Dialogs/TokenCreationDialogSuccess';

type TCreateTokenField = {
Expand Down Expand Up @@ -52,9 +53,13 @@ const CreateTokenField = ({
return token_names;
}, [tokens]);

const token_name_exists = getTokenNames.includes(input_value.toLowerCase());
const disable_button = token_name_exists || Object.keys(errors).length > 0 || input_value === '';
const error_border_active = token_name_exists || errors.name;
const tokens_limit_reached = tokens.length === 30 && Object.keys(errors).length === 0;
const token_name_exists =
getTokenNames.includes(input_value.toLowerCase()) && Object.keys(errors).length === 0;
const has_custom_errors = token_name_exists || (tokens_limit_reached && input_value !== '');
const disable_button =
token_name_exists || Object.keys(errors).length > 0 || input_value === '' || has_custom_errors;
const error_border_active = token_name_exists || errors.name || has_custom_errors;

useEffect(() => {
if (error_border_active) {
Expand All @@ -79,7 +84,7 @@ const CreateTokenField = ({
type='text'
name='name'
{...register}
placeholder='Token name'
placeholder=' '
/>
<Button disabled={disable_button} type='submit'>
Create
Expand All @@ -91,11 +96,11 @@ const CreateTokenField = ({
{errors.name.message}
</Text>
)}
{token_name_exists && (
<div className='error-message'>
<p>That name is taken. Choose another.</p>
</div>
)}
<CustomErrors
token_name_exists={token_name_exists}
tokens_limit_reached={tokens_limit_reached}
input_value={input_value}
/>
</React.Fragment>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,13 @@ import userEvent from '@testing-library/user-event';
import ApiTokenForm from '../api-token.form';
import useCreateToken from '../../../hooks/useCreateToken';
import useApiToken from '@site/src/hooks/useApiToken';
import TokenNameRestrictions from '../../TokenNameRestrictions/TokenNameRestrictions';

jest.mock('@site/src/hooks/useApiToken');

const mockUseApiToken = useApiToken as jest.MockedFunction<
() => Partial<ReturnType<typeof useApiToken>>
>;

mockUseApiToken.mockImplementation(() => ({
tokens: [
{
display_name: 'testtoken1',
last_used: '',
scopes: ['read', 'trade', 'payments', 'admin'],
token: 'asdf1234',
valid_for_ip: '',
},
{
display_name: 'testtoken2',
last_used: '',
scopes: ['read', 'trade', 'payments', 'admin'],
token: 'asdf1235',
valid_for_ip: '',
},
],
}));

jest.mock('@site/src/features/dashboard/hooks/useCreateToken');

const mockUseCreateToken = useCreateToken as jest.MockedFunction<typeof useCreateToken>;
Expand Down Expand Up @@ -76,110 +56,156 @@ const scopes = [
label: 'Admin',
},
];
const preventDefault = jest.fn();

describe('Home Page', () => {
beforeEach(() => {
render(<ApiTokenForm />);
});

afterEach(() => {
cleanup();
jest.clearAllMocks();
});
describe('General tests', () => {
beforeEach(() => {
mockUseApiToken.mockImplementation(() => ({
tokens: [
{
display_name: 'testtoken1',
last_used: '',
scopes: ['read', 'trade', 'payments', 'admin'],
token: 'asdf1234',
valid_for_ip: '',
},
{
display_name: 'testtoken2',
last_used: '',
scopes: ['read', 'trade', 'payments', 'admin'],
token: 'asdf1235',
valid_for_ip: '',
},
],
}));

render(<ApiTokenForm />);
});

it('Should render first step title', () => {
const firstStep = screen.getByTestId('first-step-title');
expect(firstStep).toHaveTextContent(/Select scopes based on the access you need./i);
});
afterEach(() => {
cleanup();
jest.clearAllMocks();
});

it('Should render all of scopes checkbox cards', () => {
scopes.forEach((item) => {
const apiTokenCard = screen.getByTestId(`api-token-card-${item.name}`);
expect(apiTokenCard).toBeInTheDocument();
it('Should render first step title', () => {
const firstStep = screen.getByTestId('first-step-title');
expect(firstStep).toHaveTextContent(/Select scopes based on the access you need./i);
});
});

it('Should render second step title', () => {
const secondStep = screen.getByTestId('second-step-title');
expect(secondStep).toHaveTextContent(
/Name your token and click on Create to generate your token./i,
);
});
it('Should render all of scopes checkbox cards', () => {
scopes.forEach((item) => {
const apiTokenCard = screen.getByTestId(`api-token-card-${item.name}`);
expect(apiTokenCard).toBeInTheDocument();
});
});

it('Should check the checkbox when clicked on api token card', async () => {
const adminTokenCard = screen.getByTestId('api-token-card-admin');
const withinAdminTokenCard = within(adminTokenCard);
const adminCheckbox = withinAdminTokenCard.getByRole<HTMLInputElement>('checkbox');
it('Should render second step title', () => {
const secondStep = screen.getByTestId('second-step-title');
expect(secondStep).toHaveTextContent(
/Name your token and click on Create to generate your token./i,
);
});

expect(adminCheckbox.checked).toBeFalsy();
it('Should check the checkbox when clicked on api token card', async () => {
const adminTokenCard = screen.getByTestId('api-token-card-admin');
const withinAdminTokenCard = within(adminTokenCard);
const adminCheckbox = withinAdminTokenCard.getByRole<HTMLInputElement>('checkbox');

await userEvent.click(adminTokenCard);
expect(adminCheckbox.checked).toBeFalsy();

expect(adminCheckbox.checked).toBeTruthy();
});
await userEvent.click(adminTokenCard);

it('Should create token on form submit', async () => {
const nameInput = screen.getByRole('textbox');
expect(adminCheckbox.checked).toBeTruthy();
});

await userEvent.type(nameInput, 'test create token');
it('Should create token on form submit', async () => {
const nameInput = screen.getByRole('textbox');

const submitButton = screen.getByRole('button', { name: /Create/i });
await userEvent.click(submitButton);
await userEvent.type(nameInput, 'test create token');

expect(mockCreateToken).toHaveBeenCalledTimes(1);
expect(mockCreateToken).toHaveBeenCalledWith('test create token', []);
});
const submitButton = screen.getByRole('button', { name: /Create/i });
await userEvent.click(submitButton);

it('Should not be able to create a token if name already exists', async () => {
const nameInput = screen.getByRole('textbox');
expect(mockCreateToken).toHaveBeenCalledTimes(1);
expect(mockCreateToken).toHaveBeenCalledWith('test create token', []);
});

await userEvent.type(nameInput, 'testtoken1');
it('Should not be able to create a token if name already exists', async () => {
const nameInput = screen.getByRole('textbox');

const error = screen.getByText(/That name is taken. Choose another./i);
expect(error).toBeVisible;
});
await userEvent.type(nameInput, 'testtoken1');

it('should hide restrictions if error is present', async () => {
const nameInput = screen.getByRole('textbox');
const restrictions = screen.getByRole('list');
expect(restrictions).toBeVisible();
await userEvent.type(nameInput, 'testtoken1');
expect(restrictions).not.toBeVisible();
});
const error = screen.getByText(/That name is taken. Choose another./i);
expect(error).toBeVisible;
});

it('Should not create token when name input is empty', async () => {
const nameInput = screen.getByRole('textbox');
it('should hide restrictions if error is present', async () => {
const nameInput = screen.getByRole('textbox');
const restrictions = screen.getByRole('list');
expect(restrictions).toBeVisible();
await userEvent.type(nameInput, 'testtoken1');
expect(restrictions).not.toBeVisible();
});

await userEvent.clear(nameInput);
it('Should not create token when name input is empty', async () => {
const nameInput = screen.getByRole('textbox');

await userEvent.click(nameInput);
await userEvent.clear(nameInput);

expect(mockCreateToken).not.toHaveBeenCalled();
});
await userEvent.click(nameInput);

it('Should open success dialog when token is created ', async () => {
const nameInput = screen.getByRole('textbox');
expect(mockCreateToken).not.toHaveBeenCalled();
});
it('Should open success dialog when token is created ', async () => {
const nameInput = screen.getByRole('textbox');

await userEvent.type(nameInput, 'test create token');
await userEvent.type(nameInput, 'test create token');

const submitButton = screen.getByRole('button', { name: /Create/i });
await userEvent.click(submitButton);
const submitButton = screen.getByRole('button', { name: /Create/i });
await userEvent.click(submitButton);

const modal = await screen.getByText('Your API token is ready to be used.');
expect(modal).toBeVisible();
});
const modal = screen.getByText('Your API token is ready to be used.');
expect(modal).toBeVisible();
});

it('Should have create button disabled in case of empty input or error message', async () => {
const submitButton = screen.getByRole('button', { name: /Create/i });
expect(submitButton).toBeDisabled();
it('Should have create button disabled in case of empty input or error message', async () => {
const submitButton = screen.getByRole('button', { name: /Create/i });
expect(submitButton).toBeDisabled();

const nameInput = screen.getByRole('textbox');
const nameInput = screen.getByRole('textbox');

await userEvent.type(nameInput, 'token-text');
expect(submitButton).toBeDisabled();
await userEvent.type(nameInput, 'token-text');
expect(submitButton).toBeDisabled();

await userEvent.clear(nameInput);
expect(submitButton).toBeDisabled();
await userEvent.clear(nameInput);
expect(submitButton).toBeDisabled();
});
});
describe('Token limit', () => {
const createMaxTokens = () => {
const token_array = [];
for (let i = 0; i < 30; i++) {
token_array.push({
display_name: `testtoken${i}`,
last_used: '',
scopes: ['read', 'trade', 'payments', 'admin'],
token: 'asdf1234',
valid_for_ip: '',
});
}
return token_array;
};

it('Should show an error when the user tries to create more than 30 tokens', async () => {
mockUseApiToken.mockImplementation(() => ({ tokens: createMaxTokens() }));
render(<ApiTokenForm />);

const nameInput = screen.getByRole('textbox');

await userEvent.type(nameInput, 'asdf');

const error = screen.getByText(/created the maximum number of tokens/i);
expect(error).toBeVisible();
});
});
});
Loading