mirror of
https://github.com/strapi/strapi.git
synced 2026-01-08 05:04:10 +00:00
Merge pull request #16141 from strapi/fix/input-uid-disabled
InputUID: Hide re-generate button when field is disabled
This commit is contained in:
commit
9713fa429d
@ -1,9 +1,5 @@
|
||||
import styled, { keyframes } from 'styled-components';
|
||||
import { Box, Flex, FieldAction } from '@strapi/design-system';
|
||||
|
||||
export const EndActionWrapper = styled(Box)`
|
||||
position: relative;
|
||||
`;
|
||||
import { Flex, FieldAction } from '@strapi/design-system';
|
||||
|
||||
export const FieldActionWrapper = styled(FieldAction)`
|
||||
svg {
|
||||
@ -22,18 +18,13 @@ export const FieldActionWrapper = styled(FieldAction)`
|
||||
`;
|
||||
|
||||
export const TextValidation = styled(Flex)`
|
||||
position: absolute;
|
||||
right: ${({ theme }) => theme.spaces[6]};
|
||||
width: 100px;
|
||||
pointer-events: none;
|
||||
|
||||
svg {
|
||||
margin-right: ${({ theme }) => theme.spaces[1]};
|
||||
height: ${12 / 16}rem;
|
||||
width: ${12 / 16}rem;
|
||||
|
||||
path {
|
||||
fill: ${({ theme, notAvailable }) =>
|
||||
!notAvailable ? theme.colors.success600 : theme.colors.danger600};
|
||||
fill: ${({ theme, available }) =>
|
||||
available ? theme.colors.success600 : theme.colors.danger600};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useCMEditViewDataManager, useFetchClient } from '@strapi/helper-plugin';
|
||||
import {
|
||||
useCMEditViewDataManager,
|
||||
useFetchClient,
|
||||
useNotification,
|
||||
useAPIErrorHandler,
|
||||
} from '@strapi/helper-plugin';
|
||||
import { useIntl } from 'react-intl';
|
||||
import get from 'lodash/get';
|
||||
import { TextInput, Typography } from '@strapi/design-system';
|
||||
import { Flex, TextInput, Typography } from '@strapi/design-system';
|
||||
import { Refresh, CheckCircle, ExclamationMarkCircle, Loader } from '@strapi/icons';
|
||||
|
||||
import { getRequestUrl } from '../../utils';
|
||||
import useDebounce from './useDebounce';
|
||||
import UID_REGEX from './regex';
|
||||
import {
|
||||
EndActionWrapper,
|
||||
FieldActionWrapper,
|
||||
TextValidation,
|
||||
LoadingWrapper,
|
||||
} from './endActionStyle';
|
||||
import { FieldActionWrapper, TextValidation, LoadingWrapper } from './endActionStyle';
|
||||
|
||||
const InputUID = ({
|
||||
attribute,
|
||||
@ -34,9 +34,11 @@ const InputUID = ({
|
||||
const [availability, setAvailability] = useState(null);
|
||||
const debouncedValue = useDebounce(value, 300);
|
||||
const generateUid = useRef();
|
||||
const toggleNotification = useNotification();
|
||||
const { formatAPIError } = useAPIErrorHandler();
|
||||
const initialValue = initialData[name];
|
||||
const { formatMessage } = useIntl();
|
||||
const createdAtName = get(layout, ['options', 'timestamps', 0]);
|
||||
const createdAtName = layout?.options?.timestamps ?? 0;
|
||||
const isCreation = !initialData[createdAtName];
|
||||
const debouncedTargetFieldValue = useDebounce(modifiedData[attribute.targetField], 300);
|
||||
const [isCustomized, setIsCustomized] = useState(false);
|
||||
@ -59,72 +61,74 @@ const InputUID = ({
|
||||
|
||||
generateUid.current = async (shouldSetInitialValue = false) => {
|
||||
setIsLoading(true);
|
||||
const requestURL = getRequestUrl('uid/generate');
|
||||
|
||||
try {
|
||||
const {
|
||||
data: { data },
|
||||
} = await post(requestURL, {
|
||||
} = await post(getRequestUrl('uid/generate'), {
|
||||
contentTypeUID,
|
||||
field: name,
|
||||
data: modifiedData,
|
||||
});
|
||||
|
||||
onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
|
||||
setIsLoading(false);
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
setIsLoading(false);
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: formatAPIError(error),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const checkAvailability = async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
const requestURL = getRequestUrl('uid/check-availability');
|
||||
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const { data } = await post(requestURL, {
|
||||
const { data } = await post(getRequestUrl('uid/check-availability'), {
|
||||
contentTypeUID,
|
||||
field: name,
|
||||
value: value ? value.trim() : '',
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setAvailability(data);
|
||||
|
||||
setIsLoading(false);
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
setIsLoading(false);
|
||||
toggleNotification({
|
||||
type: 'warning',
|
||||
message: formatAPIError(error),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// // FIXME: we need to find a better way to autofill the input when it is required.
|
||||
// FIXME: we need to find a better way to autofill the input when it is required.
|
||||
useEffect(() => {
|
||||
if (!value && attribute.required) {
|
||||
generateUid.current(true);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [attribute.required, generateUid, value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
debouncedValue &&
|
||||
debouncedValue.trim().match(UID_REGEX) &&
|
||||
debouncedValue !== initialValue
|
||||
) {
|
||||
if (debouncedValue?.trim().match(UID_REGEX) && debouncedValue !== initialValue) {
|
||||
checkAvailability();
|
||||
}
|
||||
|
||||
if (!debouncedValue) {
|
||||
setAvailability(null);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [debouncedValue, initialValue]);
|
||||
}, [initialValue, debouncedValue]);
|
||||
|
||||
useEffect(() => {
|
||||
let timer;
|
||||
|
||||
if (availability && availability.isAvailable) {
|
||||
if (availability?.isAvailable) {
|
||||
timer = setTimeout(() => {
|
||||
setAvailability(null);
|
||||
}, 4000);
|
||||
@ -176,51 +180,70 @@ const InputUID = ({
|
||||
disabled={disabled}
|
||||
error={error}
|
||||
endAction={
|
||||
<EndActionWrapper>
|
||||
{availability && availability.isAvailable && !regenerateLabel && (
|
||||
<TextValidation alignItems="center" justifyContent="flex-end">
|
||||
<CheckCircle />
|
||||
<Typography textColor="success600" variant="pi">
|
||||
{formatMessage({
|
||||
id: 'content-manager.components.uid.available',
|
||||
defaultMessage: 'Available',
|
||||
<Flex position="relative" gap={1}>
|
||||
{availability && !regenerateLabel && (
|
||||
<TextValidation
|
||||
alignItems="center"
|
||||
gap={1}
|
||||
justifyContent="flex-end"
|
||||
available={!!availability?.isAvailable}
|
||||
data-not-here-outer
|
||||
position="absolute"
|
||||
pointerEvents="none"
|
||||
right={6}
|
||||
width="100px"
|
||||
>
|
||||
{availability?.isAvailable ? <CheckCircle /> : <ExclamationMarkCircle />}
|
||||
|
||||
<Typography
|
||||
textColor={availability.isAvailable ? 'success600' : 'danger600'}
|
||||
variant="pi"
|
||||
>
|
||||
{formatMessage(
|
||||
availability.isAvailable
|
||||
? {
|
||||
id: 'content-manager.components.uid.available',
|
||||
defaultMessage: 'Available',
|
||||
}
|
||||
: {
|
||||
id: 'content-manager.components.uid.unavailable',
|
||||
defaultMessage: 'Unavailable',
|
||||
}
|
||||
)}
|
||||
</Typography>
|
||||
</TextValidation>
|
||||
)}
|
||||
|
||||
{!disabled && (
|
||||
<>
|
||||
{regenerateLabel && (
|
||||
<TextValidation alignItems="center" justifyContent="flex-end" gap={1}>
|
||||
<Typography textColor="primary600" variant="pi">
|
||||
{regenerateLabel}
|
||||
</Typography>
|
||||
</TextValidation>
|
||||
)}
|
||||
|
||||
<FieldActionWrapper
|
||||
onClick={() => generateUid.current()}
|
||||
label={formatMessage({
|
||||
id: 'content-manager.components.uid.regenerate',
|
||||
defaultMessage: 'Regenerate',
|
||||
})}
|
||||
</Typography>
|
||||
</TextValidation>
|
||||
onMouseEnter={handleGenerateMouseEnter}
|
||||
onMouseLeave={handleGenerateMouseLeave}
|
||||
>
|
||||
{isLoading ? (
|
||||
<LoadingWrapper data-testid="loading-wrapper">
|
||||
<Loader />
|
||||
</LoadingWrapper>
|
||||
) : (
|
||||
<Refresh />
|
||||
)}
|
||||
</FieldActionWrapper>
|
||||
</>
|
||||
)}
|
||||
{availability && !availability.isAvailable && !regenerateLabel && (
|
||||
<TextValidation notAvailable alignItems="center" justifyContent="flex-end">
|
||||
<ExclamationMarkCircle />
|
||||
<Typography textColor="danger600" variant="pi">
|
||||
{formatMessage({
|
||||
id: 'content-manager.components.uid.unavailable',
|
||||
defaultMessage: 'Unavailable',
|
||||
})}
|
||||
</Typography>
|
||||
</TextValidation>
|
||||
)}
|
||||
{regenerateLabel && (
|
||||
<TextValidation alignItems="center" justifyContent="flex-end">
|
||||
<Typography textColor="primary600" variant="pi">
|
||||
{regenerateLabel}
|
||||
</Typography>
|
||||
</TextValidation>
|
||||
)}
|
||||
<FieldActionWrapper
|
||||
onClick={() => generateUid.current()}
|
||||
label="regenerate"
|
||||
onMouseEnter={handleGenerateMouseEnter}
|
||||
onMouseLeave={handleGenerateMouseLeave}
|
||||
>
|
||||
{isLoading ? (
|
||||
<LoadingWrapper>
|
||||
<Loader />
|
||||
</LoadingWrapper>
|
||||
) : (
|
||||
<Refresh />
|
||||
)}
|
||||
</FieldActionWrapper>
|
||||
</EndActionWrapper>
|
||||
</Flex>
|
||||
}
|
||||
hint={hint}
|
||||
label={label}
|
||||
|
||||
@ -1,313 +1,240 @@
|
||||
/**
|
||||
*
|
||||
* Tests for InputIUD
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { act, fireEvent, render, waitFor } from '@testing-library/react';
|
||||
import { ThemeProvider, lightTheme } from '@strapi/design-system';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
|
||||
import InputUID from '../index';
|
||||
|
||||
jest.mock('@strapi/helper-plugin', () => ({
|
||||
...jest.requireActual('@strapi/helper-plugin'),
|
||||
useCMEditViewDataManager: jest.fn(() => ({
|
||||
modifiedData: {},
|
||||
initialData: {},
|
||||
modifiedData: {
|
||||
target: 'source-string',
|
||||
},
|
||||
initialData: {
|
||||
name: 'initial-data',
|
||||
},
|
||||
})),
|
||||
useNotification: jest.fn().mockReturnValue(() => {}),
|
||||
}));
|
||||
|
||||
describe('<InputUID />', () => {
|
||||
const props = {
|
||||
attribute: {
|
||||
required: false,
|
||||
},
|
||||
contentTypeUID: 'api::test.test',
|
||||
intlLabel: {
|
||||
id: 'test',
|
||||
defaultMessage: 'test',
|
||||
},
|
||||
name: 'test',
|
||||
onChange: jest.fn(),
|
||||
value: 'michka',
|
||||
};
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
it('renders and matches the snapshot', async () => {
|
||||
const { container, getByText } = render(
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<IntlProvider locale="en" messages={{}} defaultLocale="en">
|
||||
<InputUID {...props} />
|
||||
</IntlProvider>
|
||||
</ThemeProvider>
|
||||
const server = setupServer(
|
||||
rest.post('*/uid/generate', async (req, res, ctx) => {
|
||||
const body = await req.json();
|
||||
|
||||
return res(
|
||||
ctx.json({
|
||||
data: body?.data?.target ?? 'regenerated',
|
||||
})
|
||||
);
|
||||
}),
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('test')).toBeInTheDocument();
|
||||
rest.post('*/uid/check-availability', async (req, res, ctx) => {
|
||||
const body = await req.json();
|
||||
|
||||
return res(
|
||||
ctx.json({
|
||||
isAvailable: body?.value === 'available',
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
const ComponentFixture = (props) => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<InputUID
|
||||
attribute={{ targetField: 'target', required: true }}
|
||||
contentTypeUID="api::test.test"
|
||||
intlLabel={{
|
||||
id: 'test',
|
||||
defaultMessage: 'Label',
|
||||
}}
|
||||
name="name"
|
||||
onChange={jest.fn()}
|
||||
{...props}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
function setup(props) {
|
||||
return new Promise((resolve) => {
|
||||
act(() => {
|
||||
resolve(render(<ComponentFixture {...props} />));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Content-Manager | <InputUID />', () => {
|
||||
beforeAll(() => {
|
||||
server.listen();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
test('renders', async () => {
|
||||
const { getByText, getByRole } = await setup({
|
||||
hint: 'hint',
|
||||
value: 'test',
|
||||
required: true,
|
||||
labelAction: <>action</>,
|
||||
});
|
||||
|
||||
expect(container.firstChild).toMatchInlineSnapshot(`
|
||||
.c6 {
|
||||
padding-right: 12px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
expect(getByText('Label')).toBeInTheDocument();
|
||||
expect(getByText('*')).toBeInTheDocument();
|
||||
expect(getByText('action')).toBeInTheDocument();
|
||||
expect(getByText('hint')).toBeInTheDocument();
|
||||
expect(getByRole('textbox')).toHaveValue('test');
|
||||
});
|
||||
|
||||
.c8 {
|
||||
background: transparent;
|
||||
border-style: none;
|
||||
}
|
||||
test('renders an error', async () => {
|
||||
const { getByText } = await setup({
|
||||
error: 'error',
|
||||
});
|
||||
|
||||
.c0 {
|
||||
-webkit-align-items: stretch;
|
||||
-webkit-box-align: stretch;
|
||||
-ms-flex-align: stretch;
|
||||
align-items: stretch;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
expect(getByText('error')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
.c3 {
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
test('Hides the regenerate label when disabled', async () => {
|
||||
const { queryByRole } = await setup({ disabled: true, value: 'test' });
|
||||
|
||||
.c9 {
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-box-pack: unset;
|
||||
-webkit-justify-content: unset;
|
||||
-ms-flex-pack: unset;
|
||||
justify-content: unset;
|
||||
}
|
||||
expect(queryByRole('button', { name: /regenerate/i })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
.c13 {
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
}
|
||||
test('Calls onChange handler', async () => {
|
||||
const spy = jest.fn();
|
||||
const { getByRole } = await setup({ value: 'test', onChange: spy });
|
||||
|
||||
.c1 {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.33;
|
||||
font-weight: 600;
|
||||
color: #32324d;
|
||||
}
|
||||
fireEvent.change(getByRole('textbox'), { target: { value: 'test-new' } });
|
||||
|
||||
.c12 {
|
||||
border: 0;
|
||||
-webkit-clip: rect(0 0 0 0);
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
.c2 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
test('Regenerates the value based on the target field', async () => {
|
||||
const user = userEvent.setup();
|
||||
const spy = jest.fn();
|
||||
const { getByRole, queryByTestId } = await setup({ onChange: spy, value: '' });
|
||||
|
||||
.c5 {
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding-bottom: 0.65625rem;
|
||||
padding-left: 16px;
|
||||
padding-right: 0;
|
||||
padding-top: 0.65625rem;
|
||||
color: #32324d;
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
display: block;
|
||||
width: 100%;
|
||||
background: inherit;
|
||||
}
|
||||
await act(async () => {
|
||||
await user.click(getByRole('button', { name: /regenerate/i }));
|
||||
});
|
||||
|
||||
.c5::-webkit-input-placeholder {
|
||||
color: #8e8ea9;
|
||||
opacity: 1;
|
||||
}
|
||||
await waitFor(() => expect(queryByTestId('loading-wrapper')).not.toBeInTheDocument());
|
||||
|
||||
.c5::-moz-placeholder {
|
||||
color: #8e8ea9;
|
||||
opacity: 1;
|
||||
}
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
{
|
||||
target: {
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
value: 'source-string',
|
||||
},
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
.c5:-ms-input-placeholder {
|
||||
color: #8e8ea9;
|
||||
opacity: 1;
|
||||
}
|
||||
test('If the field is required and the value is empty it should automatically fill it', async () => {
|
||||
const spy = jest.fn();
|
||||
|
||||
.c5::placeholder {
|
||||
color: #8e8ea9;
|
||||
opacity: 1;
|
||||
}
|
||||
const { queryByTestId } = await setup({
|
||||
value: '',
|
||||
required: true,
|
||||
onChange: spy,
|
||||
});
|
||||
|
||||
.c5[aria-disabled='true'] {
|
||||
color: inherit;
|
||||
}
|
||||
await waitFor(() => expect(queryByTestId('loading-wrapper')).not.toBeInTheDocument());
|
||||
|
||||
.c5:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
{
|
||||
target: {
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
value: 'source-string',
|
||||
},
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
.c4 {
|
||||
border: 1px solid #dcdce4;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
outline: none;
|
||||
box-shadow: 0;
|
||||
-webkit-transition-property: border-color,box-shadow,fill;
|
||||
transition-property: border-color,box-shadow,fill;
|
||||
-webkit-transition-duration: 0.2s;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
test('If the field is required and the value is not empty it should not automatically fill it', async () => {
|
||||
const spy = jest.fn();
|
||||
|
||||
.c4:focus-within {
|
||||
border: 1px solid #4945ff;
|
||||
box-shadow: #4945ff 0px 0px 0px 2px;
|
||||
}
|
||||
const { queryByTestId } = await setup({
|
||||
value: 'test',
|
||||
required: true,
|
||||
onChange: spy,
|
||||
});
|
||||
|
||||
.c10 {
|
||||
font-size: 1.6rem;
|
||||
padding: 0;
|
||||
}
|
||||
await waitFor(() => expect(queryByTestId('loading-wrapper')).not.toBeInTheDocument());
|
||||
|
||||
.c7 {
|
||||
position: relative;
|
||||
}
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
.c11 svg {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
}
|
||||
test('Checks the initial availability (isAvailable)', async () => {
|
||||
const spy = jest.fn();
|
||||
|
||||
.c11 svg path {
|
||||
fill: #a5a5ba;
|
||||
}
|
||||
const { getByText, queryByText, queryByTestId } = await setup({
|
||||
value: 'available',
|
||||
required: true,
|
||||
onChange: spy,
|
||||
});
|
||||
|
||||
.c11 svg:hover path {
|
||||
fill: #4945ff;
|
||||
}
|
||||
await waitFor(() => expect(queryByTestId('loading-wrapper')).not.toBeInTheDocument());
|
||||
|
||||
.c14 {
|
||||
-webkit-animation: gzYjWD 2s infinite linear;
|
||||
animation: gzYjWD 2s infinite linear;
|
||||
}
|
||||
expect(getByText('Available')).toBeInTheDocument();
|
||||
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="c0"
|
||||
>
|
||||
<label
|
||||
class="c1 c2"
|
||||
for="1"
|
||||
>
|
||||
test
|
||||
</label>
|
||||
<div
|
||||
class="c3 c4"
|
||||
>
|
||||
<input
|
||||
aria-disabled="false"
|
||||
aria-invalid="false"
|
||||
aria-required="false"
|
||||
class="c5"
|
||||
id="1"
|
||||
name="test"
|
||||
placeholder=""
|
||||
value="michka"
|
||||
/>
|
||||
<div
|
||||
class="c6"
|
||||
>
|
||||
<div
|
||||
class="c7"
|
||||
>
|
||||
<button
|
||||
class="c8 c9 c10 c11"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="c12"
|
||||
>
|
||||
regenerate
|
||||
</span>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="c13 c14"
|
||||
focusable="false"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="1rem"
|
||||
viewBox="0 0 24 24"
|
||||
width="1rem"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M12.057 18c.552 0 1 .451 1 .997v4.006a1 1 0 0 1-.941.995l-.059.002c-.552 0-1-.451-1-.997v-4.006a1 1 0 0 1 .941-.995l.06-.002Zm-3.06-.736.055.03c.478.276.64.89.367 1.364l-2.002 3.468a1 1 0 0 1-1.31.394l-.055-.03a1.002 1.002 0 0 1-.368-1.363l2.003-3.469a1 1 0 0 1 1.31-.394Zm7.42.394 2.002 3.468a1 1 0 0 1-.314 1.331l-.053.033a1.002 1.002 0 0 1-1.365-.363l-2.003-3.469a1 1 0 0 1 .314-1.33l.054-.034a1.002 1.002 0 0 1 1.364.364Zm-9.548-2.66.033.054c.276.478.11 1.091-.364 1.364L3.07 18.42a1 1 0 0 1-1.331-.314l-.033-.053a1.001 1.001 0 0 1 .364-1.365l3.468-2.003a1 1 0 0 1 1.33.314Zm11.79-.313 3.468 2.002a1 1 0 0 1 .393 1.31l-.03.055c-.276.478-.89.64-1.363.367l-3.469-2.003a1 1 0 0 1-.394-1.309l.03-.055c.276-.479.89-.64 1.364-.367Zm4.344-3.628a1 1 0 0 1 .995.941l.002.06c0 .551-.451 1-.997 1h-4.006a1 1 0 0 1-.995-.942L18 12.057c0-.552.451-1 .997-1h4.006Zm-18 0a1 1 0 0 1 .995.941l.002.06c0 .551-.451 1-.998 1H.998a1 1 0 0 1-.996-.942L0 12.057c0-.552.451-1 .998-1h4.004Zm17.454-5.059.033.054c.277.478.11 1.091-.363 1.365l-3.469 2.002a1 1 0 0 1-1.33-.314l-.034-.053a1.002 1.002 0 0 1 .364-1.365l3.468-2.003a1 1 0 0 1 1.331.314ZM3.07 5.684l3.468 2.003a1 1 0 0 1 .394 1.31l-.03.055c-.276.478-.89.64-1.364.367L2.07 7.417a1 1 0 0 1-.394-1.31l.03-.055c.276-.479.89-.64 1.364-.368Zm14.926-4.008.056.03c.478.276.64.89.367 1.364l-2.003 3.468a1 1 0 0 1-1.309.394l-.055-.03a1.002 1.002 0 0 1-.367-1.364l2.002-3.468a1 1 0 0 1 1.31-.394Zm-10.58.394L9.42 5.538a1 1 0 0 1-.314 1.33l-.053.034a1.002 1.002 0 0 1-1.365-.364L5.684 3.07a1 1 0 0 1 .314-1.331l.054-.033a1.002 1.002 0 0 1 1.365.364ZM12.058 0c.552 0 1 .451 1 .998v4.004a1 1 0 0 1-.941.996L12.057 6c-.552 0-1-.451-1-.998V.998a1 1 0 0 1 .941-.996l.06-.002Z"
|
||||
fill="#212134"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
await sleep(4500);
|
||||
|
||||
expect(queryByText('Available')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Checks the initial availability (!isAvailable)', async () => {
|
||||
const spy = jest.fn();
|
||||
|
||||
const { getByText, queryByTestId, queryByText } = await setup({
|
||||
value: 'not-available',
|
||||
required: true,
|
||||
onChange: spy,
|
||||
});
|
||||
|
||||
await waitFor(() => expect(queryByTestId('loading-wrapper')).not.toBeInTheDocument());
|
||||
|
||||
expect(getByText('Unavailable')).toBeInTheDocument();
|
||||
|
||||
await sleep(4500);
|
||||
|
||||
expect(queryByText('Available')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Does not check the initial availability without a value', async () => {
|
||||
const spy = jest.fn();
|
||||
|
||||
const { queryByText, queryByTestId } = await setup({
|
||||
value: '',
|
||||
required: true,
|
||||
onChange: spy,
|
||||
});
|
||||
|
||||
await waitFor(() => expect(queryByTestId('loading-wrapper')).not.toBeInTheDocument());
|
||||
|
||||
expect(queryByText('Available')).not.toBeInTheDocument();
|
||||
expect(queryByText('Unavailable')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user