feat(ui): write tests [EE-6685] (#11081)
parent
2d25bf4afa
commit
4bf18b1d65
|
@ -29,15 +29,15 @@ test('submit button should be disabled when name or image is missing', async ()
|
||||||
expect(button).toBeDisabled();
|
expect(button).toBeDisabled();
|
||||||
|
|
||||||
const nameInput = getByLabelText(/name/i);
|
const nameInput = getByLabelText(/name/i);
|
||||||
userEvent.type(nameInput, 'name');
|
await userEvent.type(nameInput, 'name');
|
||||||
|
|
||||||
const imageInput = getByLabelText(/image/i);
|
const imageInput = getByLabelText(/image/i);
|
||||||
userEvent.type(imageInput, 'image');
|
await userEvent.type(imageInput, 'image');
|
||||||
|
|
||||||
await expect(findByText(/Deploy the container/)).resolves.toBeEnabled();
|
await expect(findByText(/Deploy the container/)).resolves.toBeEnabled();
|
||||||
|
|
||||||
expect(nameInput).toHaveValue('name');
|
expect(nameInput).toHaveValue('name');
|
||||||
userEvent.clear(nameInput);
|
await userEvent.clear(nameInput);
|
||||||
|
|
||||||
await expect(findByText(/Deploy the container/)).resolves.toBeDisabled();
|
await expect(findByText(/Deploy the container/)).resolves.toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { render } from '@/react-tools/test-utils';
|
||||||
|
|
||||||
|
import { Badge } from './Badge';
|
||||||
|
|
||||||
|
test('should render a Badge component with default type', () => {
|
||||||
|
const { getByText } = render(<Badge>Default Badge</Badge>);
|
||||||
|
const badgeElement = getByText('Default Badge');
|
||||||
|
expect(badgeElement).toBeInTheDocument();
|
||||||
|
expect(badgeElement).toHaveClass('text-blue-9 bg-blue-2');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render a Badge component with custom type', () => {
|
||||||
|
const { getByText } = render(<Badge type="success">Success Badge</Badge>);
|
||||||
|
const badgeElement = getByText('Success Badge');
|
||||||
|
expect(badgeElement).toBeInTheDocument();
|
||||||
|
expect(badgeElement).toHaveClass('text-success-9 bg-success-2');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render a Badge component with custom className', () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<Badge className="custom-class">Custom Badge</Badge>
|
||||||
|
);
|
||||||
|
const badgeElement = getByText('Custom Badge');
|
||||||
|
expect(badgeElement).toBeInTheDocument();
|
||||||
|
expect(badgeElement).toHaveClass('custom-class');
|
||||||
|
});
|
|
@ -0,0 +1,90 @@
|
||||||
|
import { FormikErrors } from 'formik';
|
||||||
|
import { ComponentProps } from 'react';
|
||||||
|
import { HttpResponse } from 'msw';
|
||||||
|
|
||||||
|
import { renderWithQueryClient, fireEvent } from '@/react-tools/test-utils';
|
||||||
|
import { http, server } from '@/setup-tests/server';
|
||||||
|
|
||||||
|
import { ImageConfigFieldset } from './ImageConfigFieldset';
|
||||||
|
import { Values } from './types';
|
||||||
|
|
||||||
|
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
|
||||||
|
...(await importOriginal()),
|
||||||
|
useCurrentStateAndParams: vi.fn(() => ({
|
||||||
|
params: { endpointId: 1 },
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should render SimpleForm when useRegistry is true', () => {
|
||||||
|
const { getByText } = render({ values: { useRegistry: true } });
|
||||||
|
|
||||||
|
expect(getByText('Advanced mode')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render AdvancedForm when useRegistry is false', () => {
|
||||||
|
const { getByText } = render({ values: { useRegistry: false } });
|
||||||
|
|
||||||
|
expect(getByText('Simple mode')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call setFieldValue with useRegistry set to false when "Advanced mode" button is clicked', () => {
|
||||||
|
const setFieldValue = vi.fn();
|
||||||
|
const { getByText } = render({
|
||||||
|
values: { useRegistry: true },
|
||||||
|
setFieldValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(getByText('Advanced mode'));
|
||||||
|
|
||||||
|
expect(setFieldValue).toHaveBeenCalledWith('useRegistry', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call setFieldValue with useRegistry set to true when "Simple mode" button is clicked', () => {
|
||||||
|
const setFieldValue = vi.fn();
|
||||||
|
const { getByText } = render({
|
||||||
|
values: { useRegistry: false },
|
||||||
|
setFieldValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(getByText('Simple mode'));
|
||||||
|
|
||||||
|
expect(setFieldValue).toHaveBeenCalledWith('useRegistry', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
function render({
|
||||||
|
values = {
|
||||||
|
useRegistry: true,
|
||||||
|
registryId: 123,
|
||||||
|
image: '',
|
||||||
|
},
|
||||||
|
errors = {},
|
||||||
|
setFieldValue = vi.fn(),
|
||||||
|
onChangeImage = vi.fn(),
|
||||||
|
onRateLimit = vi.fn(),
|
||||||
|
}: {
|
||||||
|
values?: Partial<Values>;
|
||||||
|
errors?: FormikErrors<Values>;
|
||||||
|
setFieldValue?: ComponentProps<typeof ImageConfigFieldset>['setFieldValue'];
|
||||||
|
onChangeImage?: ComponentProps<typeof ImageConfigFieldset>['onChangeImage'];
|
||||||
|
onRateLimit?: ComponentProps<typeof ImageConfigFieldset>['onRateLimit'];
|
||||||
|
} = {}) {
|
||||||
|
server.use(
|
||||||
|
http.get('/api/registries/:id', () => HttpResponse.json({})),
|
||||||
|
http.get('/api/endpoints/:id', () => HttpResponse.json({}))
|
||||||
|
);
|
||||||
|
|
||||||
|
return renderWithQueryClient(
|
||||||
|
<ImageConfigFieldset
|
||||||
|
values={{
|
||||||
|
useRegistry: true,
|
||||||
|
registryId: 123,
|
||||||
|
image: '',
|
||||||
|
...values,
|
||||||
|
}}
|
||||||
|
errors={errors}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
onChangeImage={onChangeImage}
|
||||||
|
onRateLimit={onRateLimit}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ test('should call onSelect when clicked with id', async () => {
|
||||||
const { findByText } = renderComponent(options, options[1].id, onSelect);
|
const { findByText } = renderComponent(options, options[1].id, onSelect);
|
||||||
|
|
||||||
const heading = await findByText(options[0].label);
|
const heading = await findByText(options[0].label);
|
||||||
userEvent.click(heading);
|
await userEvent.click(heading);
|
||||||
|
|
||||||
expect(onSelect).toHaveBeenCalledWith(options[0].id);
|
expect(onSelect).toHaveBeenCalledWith(options[0].id);
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,14 +17,14 @@ test('the button is disabled when all fields are blank and enabled when all fiel
|
||||||
const descriptionField = getByLabelText(/Description/);
|
const descriptionField = getByLabelText(/Description/);
|
||||||
const passwordField = getByLabelText(/Current password/);
|
const passwordField = getByLabelText(/Current password/);
|
||||||
|
|
||||||
userEvent.type(passwordField, 'password');
|
await userEvent.type(passwordField, 'password');
|
||||||
userEvent.type(descriptionField, 'description');
|
await userEvent.type(descriptionField, 'description');
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(button).toBeEnabled();
|
expect(button).toBeEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
userEvent.clear(descriptionField);
|
await userEvent.clear(descriptionField);
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(button).toBeDisabled();
|
expect(button).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
import { render } from '@/react-tools/test-utils';
|
||||||
|
|
||||||
|
import { AppTemplatesListItem } from './AppTemplatesListItem';
|
||||||
|
import { TemplateViewModel } from './view-model';
|
||||||
|
import { TemplateType } from './types';
|
||||||
|
|
||||||
|
test('should render AppTemplatesListItem component', () => {
|
||||||
|
const template: TemplateViewModel = {
|
||||||
|
Title: 'Test Template',
|
||||||
|
// provide necessary properties for the template object
|
||||||
|
} as TemplateViewModel;
|
||||||
|
|
||||||
|
const onSelect = vi.fn();
|
||||||
|
const isSelected = false;
|
||||||
|
|
||||||
|
const { getByText } = render(
|
||||||
|
<AppTemplatesListItem
|
||||||
|
template={template}
|
||||||
|
onSelect={onSelect}
|
||||||
|
isSelected={isSelected}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getByText(template.Title, { exact: false })).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const copyAsCustomTestCases = [
|
||||||
|
{
|
||||||
|
type: TemplateType.Container,
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: TemplateType.ComposeStack,
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: TemplateType.SwarmStack,
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// TODO - remove after fixing workaround for UISref
|
||||||
|
vi.mock('@uirouter/react', async (importOriginal: () => Promise<object>) => ({
|
||||||
|
...(await importOriginal()),
|
||||||
|
UISref: ({ children }: PropsWithChildren<unknown>) => children, // Mocking UISref to render its children directly
|
||||||
|
}));
|
||||||
|
|
||||||
|
copyAsCustomTestCases.forEach(({ type, expected }) => {
|
||||||
|
test(`copy as custom button should ${
|
||||||
|
expected ? '' : 'not '
|
||||||
|
}be rendered for type ${type}`, () => {
|
||||||
|
const onSelect = vi.fn();
|
||||||
|
const isSelected = false;
|
||||||
|
|
||||||
|
const { queryByText, unmount } = render(
|
||||||
|
<AppTemplatesListItem
|
||||||
|
template={
|
||||||
|
{
|
||||||
|
Type: type,
|
||||||
|
} as TemplateViewModel
|
||||||
|
}
|
||||||
|
onSelect={onSelect}
|
||||||
|
isSelected={isSelected}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (expected) {
|
||||||
|
expect(queryByText('Copy as Custom')).toBeVisible();
|
||||||
|
} else {
|
||||||
|
expect(queryByText('Copy as Custom')).toBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call onSelect when clicked', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
const template: TemplateViewModel = {
|
||||||
|
Title: 'Test Template',
|
||||||
|
// provide necessary properties for the template object
|
||||||
|
} as TemplateViewModel;
|
||||||
|
|
||||||
|
const onSelect = vi.fn();
|
||||||
|
const isSelected = false;
|
||||||
|
|
||||||
|
const { getByLabelText } = render(
|
||||||
|
<AppTemplatesListItem
|
||||||
|
template={template}
|
||||||
|
onSelect={onSelect}
|
||||||
|
isSelected={isSelected}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const button = getByLabelText(template.Title);
|
||||||
|
await user.click(button);
|
||||||
|
|
||||||
|
expect(onSelect).toHaveBeenCalledWith(template);
|
||||||
|
});
|
|
@ -45,6 +45,7 @@ export function TemplateItem({
|
||||||
as={linkParams ? Link : undefined}
|
as={linkParams ? Link : undefined}
|
||||||
to={linkParams?.to}
|
to={linkParams?.to}
|
||||||
params={linkParams?.params}
|
params={linkParams?.params}
|
||||||
|
aria-label={template.Title}
|
||||||
>
|
>
|
||||||
<div className="vertical-center min-w-[56px] justify-center">
|
<div className="vertical-center min-w-[56px] justify-center">
|
||||||
<FallbackImage
|
<FallbackImage
|
||||||
|
|
|
@ -19,7 +19,7 @@ test('filling the name should make the submit button clickable and emptying it s
|
||||||
expect(button).toBeDisabled();
|
expect(button).toBeDisabled();
|
||||||
|
|
||||||
const newValue = 'name';
|
const newValue = 'name';
|
||||||
userEvent.type(nameField, newValue);
|
await userEvent.type(nameField, newValue);
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(nameField).toHaveDisplayValue(newValue);
|
expect(nameField).toHaveDisplayValue(newValue);
|
||||||
|
|
|
@ -142,7 +142,7 @@
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"@testing-library/dom": "^9.3.4",
|
"@testing-library/dom": "^9.3.4",
|
||||||
"@testing-library/react": "^12",
|
"@testing-library/react": "^12",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
"@types/angular": "^1.8.3",
|
"@types/angular": "^1.8.3",
|
||||||
"@types/file-saver": "^2.0.4",
|
"@types/file-saver": "^2.0.4",
|
||||||
"@types/filesize-parser": "^1.5.1",
|
"@types/filesize-parser": "^1.5.1",
|
||||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -5624,12 +5624,10 @@
|
||||||
"@testing-library/dom" "^8.0.0"
|
"@testing-library/dom" "^8.0.0"
|
||||||
"@types/react-dom" "<18.0.0"
|
"@types/react-dom" "<18.0.0"
|
||||||
|
|
||||||
"@testing-library/user-event@^13.5.0":
|
"@testing-library/user-event@^14.5.2":
|
||||||
version "13.5.0"
|
version "14.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295"
|
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd"
|
||||||
integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==
|
integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.12.5"
|
|
||||||
|
|
||||||
"@tippyjs/react@^4.2.6":
|
"@tippyjs/react@^4.2.6":
|
||||||
version "4.2.6"
|
version "4.2.6"
|
||||||
|
|
Loading…
Reference in New Issue