mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
chore: fix "key" prop issues in front end tests (#8459)
Fixes all warnings about the "key" prop. The majority of the fixes fall into one of the following categories: - Extracting "key" props in tables (you're not allowed to just spread them in) - Adding "key" props to autocomplete options and chips - fixing test data that didn't contain ids
This commit is contained in:
parent
c580e762b3
commit
fe09ae214f
@ -1,4 +1,4 @@
|
||||
import { Fragment, useState, type ChangeEvent, type VFC } from 'react';
|
||||
import { type FC, Fragment, useState, type ChangeEvent } from 'react';
|
||||
import {
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
@ -6,6 +6,7 @@ import {
|
||||
Box,
|
||||
Paper,
|
||||
styled,
|
||||
Chip,
|
||||
} from '@mui/material';
|
||||
import { Autocomplete } from '@mui/material';
|
||||
|
||||
@ -39,7 +40,7 @@ export interface ISelectProjectInputProps {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export const SelectProjectInput: VFC<ISelectProjectInputProps> = ({
|
||||
export const SelectProjectInput: FC<ISelectProjectInputProps> = ({
|
||||
options,
|
||||
defaultValue = [ALL_PROJECTS],
|
||||
onChange,
|
||||
@ -80,19 +81,22 @@ export const SelectProjectInput: VFC<ISelectProjectInputProps> = ({
|
||||
};
|
||||
|
||||
const renderOption = (
|
||||
props: object,
|
||||
props: object & { key?: string },
|
||||
option: IAutocompleteBoxOption,
|
||||
{ selected }: AutocompleteRenderOptionState,
|
||||
) => (
|
||||
<li {...props}>
|
||||
<SelectOptionCheckbox
|
||||
icon={<CheckBoxOutlineBlankIcon fontSize='small' />}
|
||||
checkedIcon={<CheckBoxIcon fontSize='small' />}
|
||||
checked={selected}
|
||||
/>
|
||||
{option.label}
|
||||
</li>
|
||||
);
|
||||
) => {
|
||||
const { key, ...rest } = props;
|
||||
return (
|
||||
<li key={key} {...rest}>
|
||||
<SelectOptionCheckbox
|
||||
icon={<CheckBoxOutlineBlankIcon fontSize='small' />}
|
||||
checkedIcon={<CheckBoxIcon fontSize='small' />}
|
||||
checked={selected}
|
||||
/>
|
||||
{option.label}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
const renderGroup = ({ key, children }: AutocompleteRenderGroupParams) => (
|
||||
<Fragment key={key}>
|
||||
@ -149,6 +153,19 @@ export const SelectProjectInput: VFC<ISelectProjectInputProps> = ({
|
||||
fullWidth
|
||||
PaperComponent={CustomPaper}
|
||||
renderOption={renderOption}
|
||||
renderTags={(value, getTagProps) => {
|
||||
return value.map((option, index) => {
|
||||
const { key, ...props } = getTagProps({ index });
|
||||
return (
|
||||
<Chip
|
||||
size='small'
|
||||
key={key}
|
||||
{...props}
|
||||
label={option.label}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}}
|
||||
renderInput={renderInput}
|
||||
value={
|
||||
isWildcardSelected || disabled
|
||||
|
@ -42,13 +42,18 @@ export const ConnectedInstancesTable = ({
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<TableRow hover {...row.getRowProps()}>
|
||||
{row.cells.map((cell) => (
|
||||
<TableCell {...cell.getCellProps()}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableRow hover key={key} {...rowProps}>
|
||||
{row.cells.map((cell) => {
|
||||
const { key, ...cellProps } =
|
||||
cell.getCellProps();
|
||||
return (
|
||||
<TableCell key={key} {...cellProps}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
|
@ -199,13 +199,19 @@ const ContextList: VFC = () => {
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<TableRow hover {...row.getRowProps()}>
|
||||
{row.cells.map((cell) => (
|
||||
<TableCell {...cell.getCellProps()}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableRow hover key={key} {...rowProps}>
|
||||
{row.cells.map((cell) => {
|
||||
const { key, ...cellProps } =
|
||||
cell.getCellProps();
|
||||
|
||||
return (
|
||||
<TableCell key={key} {...cellProps}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
|
@ -3,6 +3,7 @@ import { render } from 'utils/testRenderer';
|
||||
import { testServerRoute, testServerSetup } from 'utils/testServer';
|
||||
import { FeatureStrategyConstraintAccordionList } from './FeatureStrategyConstraintAccordionList';
|
||||
import type { IConstraint } from 'interfaces/strategy';
|
||||
import { constraintId } from 'component/common/ConstraintAccordion/ConstraintAccordionList/createEmptyConstraint';
|
||||
|
||||
const server = testServerSetup();
|
||||
|
||||
@ -18,7 +19,11 @@ const setupApi = () => {
|
||||
};
|
||||
|
||||
const constraints = (limit: number): IConstraint[] =>
|
||||
Array.from(Array(limit).keys()).map(() => ({
|
||||
// @ts-expect-error: we access the id field using `Symbol(id)`,
|
||||
// so just calling the property `id` doesn't work. Instead, we
|
||||
// need to use the `constraintId` symbol.
|
||||
Array.from(Array(limit).keys()).map((_, index) => ({
|
||||
[constraintId]: index,
|
||||
contextName: 'test',
|
||||
operator: 'IN',
|
||||
}));
|
||||
|
@ -18,6 +18,7 @@ export const setupSegmentsEndpoint = () => {
|
||||
testServerRoute(server, '/api/admin/segments', {
|
||||
segments: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'test',
|
||||
constraints: [],
|
||||
},
|
||||
|
@ -65,13 +65,18 @@ export const FeatureMetricsTable = ({
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<TableRow hover {...row.getRowProps()}>
|
||||
{row.cells.map((cell) => (
|
||||
<TableCell {...cell.getCellProps()}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableRow hover key={key} {...rowProps}>
|
||||
{row.cells.map((cell) => {
|
||||
const { key, ...cellProps } =
|
||||
cell.getCellProps();
|
||||
return (
|
||||
<TableCell key={key} {...cellProps}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
|
@ -11,8 +11,8 @@ export const VariantsTooltip: FC<{
|
||||
<TooltipLink
|
||||
tooltip={
|
||||
<>
|
||||
{variants.map((child) => (
|
||||
<div>{child}</div>
|
||||
{variants.map((child, i) => (
|
||||
<div key={i}>{child}</div>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
|
@ -151,13 +151,18 @@ export const EnvironmentVariantsTable = ({
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<TableRow hover {...row.getRowProps()}>
|
||||
{row.cells.map((cell) => (
|
||||
<TableCell {...cell.getCellProps()}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableRow hover {...rowProps} key={key}>
|
||||
{row.cells.map((cell) => {
|
||||
const { key, ...cellProps } =
|
||||
cell.getCellProps();
|
||||
return (
|
||||
<TableCell key={key} {...cellProps}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
type VFC,
|
||||
type FC,
|
||||
} from 'react';
|
||||
import {
|
||||
Alert,
|
||||
@ -74,7 +74,7 @@ type IntegrationFormProps = {
|
||||
addon: AddonSchema | Omit<AddonSchema, 'id'>;
|
||||
};
|
||||
|
||||
export const IntegrationForm: VFC<IntegrationFormProps> = ({
|
||||
export const IntegrationForm: FC<IntegrationFormProps> = ({
|
||||
editMode,
|
||||
provider,
|
||||
addon: initialValues,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { VFC } from 'react';
|
||||
import type { FC } from 'react';
|
||||
import type { IAutocompleteBoxOption } from '../../../common/AutocompleteBox/AutocompleteBox';
|
||||
import type {
|
||||
AutocompleteRenderInputParams,
|
||||
@ -35,7 +35,7 @@ const StyledCheckbox = styled(Checkbox)(() => ({
|
||||
|
||||
const CustomPaper = ({ ...props }) => <Paper elevation={8} {...props} />;
|
||||
|
||||
export const IntegrationMultiSelector: VFC<IIntegrationMultiSelectorProps> = ({
|
||||
export const IntegrationMultiSelector: FC<IIntegrationMultiSelectorProps> = ({
|
||||
options,
|
||||
selectedItems,
|
||||
onChange,
|
||||
@ -67,12 +67,13 @@ export const IntegrationMultiSelector: VFC<IIntegrationMultiSelectorProps> = ({
|
||||
);
|
||||
|
||||
const renderOption = (
|
||||
props: object,
|
||||
props: object & { key?: string },
|
||||
option: IAutocompleteBoxOption,
|
||||
{ selected }: AutocompleteRenderOptionState,
|
||||
) => {
|
||||
const { key, ...rest } = props;
|
||||
return (
|
||||
<li {...props}>
|
||||
<li key={key} {...rest}>
|
||||
<StyledCheckbox
|
||||
icon={<CheckBoxOutlineBlankIcon fontSize='small' />}
|
||||
checkedIcon={<CheckBoxIcon fontSize='small' />}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { ComponentProps, Dispatch, FC, SetStateAction } from 'react';
|
||||
import { Autocomplete, TextField } from '@mui/material';
|
||||
import { Autocomplete, Chip, TextField } from '@mui/material';
|
||||
import { renderOption } from '../../renderOption';
|
||||
|
||||
interface IEnvironmentsFieldProps {
|
||||
@ -59,6 +59,19 @@ export const EnvironmentsField: FC<IEnvironmentsFieldProps> = ({
|
||||
<TextField {...params} label='Environments' />
|
||||
)}
|
||||
renderOption={renderOption}
|
||||
renderTags={(value, getTagProps) => {
|
||||
return value.map((option, index) => {
|
||||
const { key, ...props } = getTagProps({ index });
|
||||
return (
|
||||
<Chip
|
||||
size='small'
|
||||
key={key}
|
||||
{...props}
|
||||
label={option.label}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}}
|
||||
getOptionLabel={({ label }) => label}
|
||||
disableCloseOnSelect={false}
|
||||
size='small'
|
||||
|
@ -7,16 +7,19 @@ const SelectOptionCheckbox = styled(Checkbox)(({ theme }) => ({
|
||||
}));
|
||||
|
||||
export const renderOption = (
|
||||
props: object,
|
||||
props: object & { key?: string },
|
||||
option: { label: string },
|
||||
{ selected }: { selected: boolean },
|
||||
) => (
|
||||
<li {...props}>
|
||||
<SelectOptionCheckbox
|
||||
icon={<CheckBoxOutlineBlankIcon fontSize='small' />}
|
||||
checkedIcon={<CheckBoxIcon fontSize='small' />}
|
||||
checked={selected}
|
||||
/>
|
||||
{option.label}
|
||||
</li>
|
||||
);
|
||||
) => {
|
||||
const { key, ...rest } = props;
|
||||
return (
|
||||
<li key={key} {...rest}>
|
||||
<SelectOptionCheckbox
|
||||
icon={<CheckBoxOutlineBlankIcon fontSize='small' />}
|
||||
checkedIcon={<CheckBoxIcon fontSize='small' />}
|
||||
checked={selected}
|
||||
/>
|
||||
{option.label}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
@ -12,6 +12,7 @@ const testCases = [
|
||||
result: true,
|
||||
data: [
|
||||
{
|
||||
id: 'f17532c8-4b36-4406-a23f-3db75e0adc82',
|
||||
name: 'default',
|
||||
parameters: {},
|
||||
result: { enabled: true, evaluationStatus: 'complete' },
|
||||
@ -31,6 +32,7 @@ const testCases = [
|
||||
result: true,
|
||||
data: [
|
||||
{
|
||||
id: 'f17532c8-4b36-4406-a23f-3db75e0adc83',
|
||||
name: 'default',
|
||||
parameters: {},
|
||||
result: { enabled: true, evaluationStatus: 'complete' },
|
||||
@ -50,6 +52,7 @@ const testCases = [
|
||||
result: true,
|
||||
data: [
|
||||
{
|
||||
id: 'f17532c8-4b36-4406-a23f-3db75e0adc77',
|
||||
name: 'default',
|
||||
parameters: {},
|
||||
result: { enabled: true, evaluationStatus: 'complete' },
|
||||
@ -69,11 +72,13 @@ const testCases = [
|
||||
result: true,
|
||||
data: [
|
||||
{
|
||||
id: 'f17532c8-4b36-4406-a23f-3db75e0adc78',
|
||||
name: 'default',
|
||||
parameters: {},
|
||||
result: { enabled: true, evaluationStatus: 'complete' },
|
||||
},
|
||||
{
|
||||
id: 'f17532c8-4b36-4406-a23f-3db75e0adc79',
|
||||
name: 'default',
|
||||
parameters: {},
|
||||
disabled: true,
|
||||
@ -97,11 +102,13 @@ const testCases = [
|
||||
result: true,
|
||||
data: [
|
||||
{
|
||||
id: 'f17532c8-4b36-4406-a23f-3db75e0adc80',
|
||||
name: 'default',
|
||||
parameters: {},
|
||||
result: { enabled: true, evaluationStatus: 'complete' },
|
||||
},
|
||||
{
|
||||
id: 'f17532c8-4b36-4406-a23f-3db75e0adc81',
|
||||
name: 'default',
|
||||
parameters: {},
|
||||
disabled: true,
|
||||
|
@ -229,13 +229,18 @@ export const LeadTimeForChanges = ({
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<TableRow hover {...row.getRowProps()}>
|
||||
{row.cells.map((cell) => (
|
||||
<TableCell {...cell.getCellProps()}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableRow hover key={key} {...rowProps}>
|
||||
{row.cells.map((cell) => {
|
||||
const { key, ...cellProps } =
|
||||
cell.getCellProps();
|
||||
return (
|
||||
<TableCell key={key} {...cellProps}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
|
@ -15,7 +15,7 @@ const setupApi = () => {
|
||||
});
|
||||
|
||||
testServerRoute(server, '/api/admin/projects', {
|
||||
projects: [{ name: 'existing' }],
|
||||
projects: [{ name: 'existing', id: '1' }],
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -210,13 +210,18 @@ export const TagTypeList = () => {
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<TableRow hover {...row.getRowProps()}>
|
||||
{row.cells.map((cell) => (
|
||||
<TableCell {...cell.getCellProps()}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableRow hover key={key} {...rowProps}>
|
||||
{row.cells.map((cell) => {
|
||||
const { key, ...cellProps } =
|
||||
cell.getCellProps();
|
||||
return (
|
||||
<TableCell key={key} {...cellProps}>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
|
@ -16,8 +16,8 @@ const RouteNameRender: FC<{}> = () => {
|
||||
return (
|
||||
<div>
|
||||
<RecentlyVisitedRecorder />
|
||||
{lastVisited.map((visited) => (
|
||||
<div>{visited.pathName}</div>
|
||||
{lastVisited.map((visited, index) => (
|
||||
<div key={index}>{visited.pathName}</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user