mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
fix: improve selecting projects
Adds tests to the form for creating API tokens.
This commit is contained in:
parent
b5db7b8326
commit
bb8ceabbaf
@ -3,5 +3,6 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
export const useStyles = makeStyles(theme => ({
|
||||
selectOptionsLink: {
|
||||
cursor: 'pointer',
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
},
|
||||
}));
|
||||
|
@ -15,7 +15,11 @@ export const SelectAllButton: FC<SelectAllButtonProps> = ({
|
||||
|
||||
return (
|
||||
<Box sx={{ ml: 3.5, my: 0.5 }}>
|
||||
<Link onClick={onClick} className={styles.selectOptionsLink}>
|
||||
<Link
|
||||
onClick={onClick}
|
||||
className={styles.selectOptionsLink}
|
||||
component="button"
|
||||
>
|
||||
{isAllSelected ? 'Deselect all' : 'Select all'}
|
||||
</Link>
|
||||
</Box>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { screen, within } from '@testing-library/react';
|
||||
import { screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { render } from 'utils/testRenderer';
|
||||
import {
|
||||
@ -14,6 +14,7 @@ const mockProps: ISelectProjectInputProps = {
|
||||
options: [
|
||||
{ label: 'Project1', value: 'project1' },
|
||||
{ label: 'Project2', value: 'project2' },
|
||||
{ label: 'Project3', value: 'project3' },
|
||||
],
|
||||
defaultValue: ['*'],
|
||||
onChange,
|
||||
@ -59,4 +60,106 @@ describe('SelectProjectInput', () => {
|
||||
|
||||
expect(screen.getByLabelText('Projects')).toBeDisabled();
|
||||
});
|
||||
|
||||
it('renders with autocomplete enabled if default value is not a wildcard', () => {
|
||||
render(
|
||||
<SelectProjectInput {...mockProps} defaultValue={['project1']} />
|
||||
);
|
||||
|
||||
const checkbox = screen.getByLabelText(
|
||||
/all current and future projects/i
|
||||
);
|
||||
expect(checkbox).not.toBeChecked();
|
||||
|
||||
const selectInputContainer = screen.getByTestId('select-input');
|
||||
const input = within(selectInputContainer).getByRole('textbox');
|
||||
expect(input).toBeEnabled();
|
||||
});
|
||||
|
||||
describe('Select/Deselect projects in dropdown', () => {
|
||||
it('selects and deselects all options', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<SelectProjectInput {...mockProps} defaultValue={[]} />);
|
||||
await user.click(screen.getByLabelText('Projects'));
|
||||
|
||||
let button = screen.getByRole('button', {
|
||||
name: /select all/i,
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
await user.click(button);
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith([
|
||||
'project1',
|
||||
'project2',
|
||||
'project3',
|
||||
]);
|
||||
|
||||
button = screen.getByRole('button', {
|
||||
name: /deselect all/i,
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
await user.click(button);
|
||||
expect(onChange).toHaveBeenCalledWith([]);
|
||||
});
|
||||
|
||||
it("doesn't show up for less than 3 options", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<SelectProjectInput
|
||||
{...mockProps}
|
||||
defaultValue={[]}
|
||||
options={[
|
||||
{ label: 'Project1', value: 'project1' },
|
||||
{ label: 'Project2', value: 'project2' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
await user.click(screen.getByLabelText('Projects'));
|
||||
|
||||
const button = screen.queryByRole('button', {
|
||||
name: /select all/i,
|
||||
});
|
||||
expect(button).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('can filter options', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<SelectProjectInput
|
||||
{...mockProps}
|
||||
defaultValue={[]}
|
||||
options={[
|
||||
{ label: 'Alpha', value: 'alpha' },
|
||||
{ label: 'Bravo', value: 'bravo' },
|
||||
{ label: 'Charlie', value: 'charlie' },
|
||||
{ label: 'Alpaca', value: 'alpaca' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
const input = await screen.findByLabelText('Projects');
|
||||
user.type(input, 'alp');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Alpha')).toBeVisible();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Bravo')).not.toBeInTheDocument();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Charlie')).not.toBeInTheDocument();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Alpaca')).toBeVisible();
|
||||
});
|
||||
|
||||
user.clear(input);
|
||||
user.type(input, 'bravo');
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Bravo')).toBeVisible();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Alpha')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -17,6 +17,7 @@ import CheckBoxIcon from '@material-ui/icons/CheckBox';
|
||||
import { IAutocompleteBoxOption } from 'component/common/AutocompleteBox/AutocompleteBox';
|
||||
import { useStyles } from '../ApiTokenForm.styles';
|
||||
import { SelectAllButton } from './SelectAllButton/SelectAllButton';
|
||||
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||
|
||||
const ALL_PROJECTS = '*';
|
||||
|
||||
@ -47,7 +48,10 @@ export const SelectProjectInput: VFC<ISelectProjectInputProps> = ({
|
||||
const [isWildcardSelected, selectWildcard] = useState(
|
||||
typeof defaultValue === 'string' || defaultValue.includes(ALL_PROJECTS)
|
||||
);
|
||||
const isAllSelected = projects.length === options.length;
|
||||
const isAllSelected =
|
||||
projects.length > 0 &&
|
||||
projects.length === options.length &&
|
||||
projects[0] !== ALL_PROJECTS;
|
||||
|
||||
const onAllProjectsChange = (
|
||||
e: ChangeEvent<HTMLInputElement>,
|
||||
@ -62,6 +66,14 @@ export const SelectProjectInput: VFC<ISelectProjectInputProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const onSelectAllClick = () => {
|
||||
const newProjects = isAllSelected
|
||||
? []
|
||||
: options.map(({ value }) => value);
|
||||
setProjects(newProjects);
|
||||
onChange(newProjects);
|
||||
};
|
||||
|
||||
const renderOption = (
|
||||
option: IAutocompleteBoxOption,
|
||||
{ selected }: AutocompleteRenderOptionState
|
||||
@ -79,13 +91,14 @@ export const SelectProjectInput: VFC<ISelectProjectInputProps> = ({
|
||||
|
||||
const renderGroup = ({ key, children }: AutocompleteRenderGroupParams) => (
|
||||
<Fragment key={key}>
|
||||
<SelectAllButton
|
||||
isAllSelected={isAllSelected}
|
||||
onClick={() => {
|
||||
setProjects(
|
||||
isAllSelected ? [] : options.map(({ value }) => value)
|
||||
);
|
||||
}}
|
||||
<ConditionallyRender
|
||||
condition={options.length > 2}
|
||||
show={
|
||||
<SelectAllButton
|
||||
isAllSelected={isAllSelected}
|
||||
onClick={onSelectAllClick}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{children}
|
||||
</Fragment>
|
||||
|
Loading…
Reference in New Issue
Block a user