debian-image-builder-frontend/src/test/Components/Blueprints/Blueprints.test.tsx
regexowl eb2cfe9a2f test: Move @testing-library/jest-dom import to test setup file
This removes `@testing-library/jest-dom` from single test files and adds it to the shared setup.ts file.
2024-07-22 15:49:18 +02:00

326 lines
9.8 KiB
TypeScript

import React from 'react';
import { screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import CreateImageWizard from '../../../Components/CreateImageWizard';
import LandingPage from '../../../Components/LandingPage/LandingPage';
import { IMAGE_BUILDER_API } from '../../../constants';
import { emptyGetBlueprints } from '../../fixtures/blueprints';
import { server } from '../../mocks/server';
import {
renderCustomRoutesWithReduxRouter,
renderWithReduxRouter,
} from '../../testUtils';
vi.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
useChrome: () => ({
isBeta: () => true,
isProd: () => true,
getEnvironment: () => 'prod',
}),
}));
vi.mock('@unleash/proxy-client-react', () => ({
useUnleashContext: () => vi.fn(),
useFlag: vi.fn((flag) =>
flag === 'image-builder.new-wizard.enabled' ? true : false
),
}));
const selectBlueprintById = async (bpId: string) => {
const user = userEvent.setup();
const blueprint = await screen.findByTestId(bpId);
await waitFor(() => user.click(blueprint));
return blueprint;
};
describe('Blueprints', () => {
beforeEach(() => {
vi.clearAllMocks();
});
const user = userEvent.setup();
const blueprintNameWithComposes = 'Dark Chocolate';
const blueprintIdWithComposes = '677b010b-e95e-4694-9813-d11d847f1bfc';
const blueprintIdWithMultipleTargets = 'c1cfa347-4c37-49b5-8e73-6aa1d1746cfa';
const blueprintNameEmptyComposes = 'Milk Chocolate';
const blueprintIdEmptyComposes = '193482e4-4bd0-4898-a8bc-dc8c33ed669f';
const blueprintIdOutOfSync = '51243667-8d87-4aef-8dd1-84fc58261b05';
const blueprintIdCentos8 = 'b1f10309-a250-4db8-ab64-c110176e3eb7';
test('renders blueprints page', async () => {
renderWithReduxRouter('', {});
await screen.findByText(blueprintNameWithComposes);
await screen.findByText(blueprintNameEmptyComposes);
});
test('renders blueprint empty state', async () => {
server.use(
http.get(`${IMAGE_BUILDER_API}/blueprints`, () => {
return HttpResponse.json(emptyGetBlueprints);
})
);
const { router } = await renderWithReduxRouter('', {});
await screen.findByText('No blueprints yet');
const emptyStateAction = screen.getByRole('link', {
name: /Add blueprint/i,
});
expect(emptyStateAction).toBeInTheDocument();
user.click(emptyStateAction);
await waitFor(() =>
expect(router.state.location.pathname).toBe(
'/insights/image-builder/imagewizard'
)
);
});
test('renders blueprint composes', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdWithComposes);
const table = await screen.findByTestId('images-table');
const { findAllByText } = within(table);
const images = await findAllByText('dark-chocolate-aws');
expect(images).toHaveLength(2);
});
test('renders blueprint composes empty state', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdEmptyComposes);
const table = await screen.findByTestId('images-table');
const { findByText } = within(table);
await findByText('No images');
});
test('click build image button', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdWithComposes);
const buildImageBtn = await screen.findByRole('button', {
name: /Build image/i,
});
expect(buildImageBtn).toBeEnabled();
});
test('uncheck Target option and check that build image button is Disable', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdWithComposes);
const buildImageBtn = await screen.findByRole('button', {
name: /Build image/i,
});
expect(buildImageBtn).toBeEnabled();
const buildImageDropDown = screen.getByTestId('blueprint-build-image-menu');
user.click(buildImageDropDown);
const awsCheckbox = await screen.findByRole('checkbox', {
name: /amazon web services/i,
});
expect(awsCheckbox).toBeChecked();
user.click(awsCheckbox);
await waitFor(() => expect(awsCheckbox).not.toBeChecked());
const buildSelectedBtn = await screen.findByRole('button', {
name: /Build selected/i,
});
expect(buildSelectedBtn).toBeDisabled();
});
test('uncheck one Target option and check that you can build an image', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdWithMultipleTargets);
const buildImageBtn = await screen.findByRole('button', {
name: /Build image/i,
});
expect(buildImageBtn).toBeEnabled();
const buildImageDropDown = screen.getByTestId('blueprint-build-image-menu');
user.click(buildImageDropDown);
const awsCheckbox = await screen.findByRole('checkbox', {
name: /amazon web services/i,
});
expect(awsCheckbox).toBeChecked();
user.click(awsCheckbox);
await waitFor(() => expect(awsCheckbox).not.toBeChecked());
const buildSelectedBtn = await screen.findByRole('button', {
name: /Build selected/i,
});
expect(buildSelectedBtn).toBeEnabled();
});
test('blueprint is out of sync', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdOutOfSync);
await screen.findByText(
'The selected blueprint is at version 2, the latest images are at version 1. Build images to synchronize with the latest version.'
);
await selectBlueprintById(blueprintIdWithComposes);
expect(
screen.queryByText(
'The selected blueprint is at version 2, the latest images are at version 1. Build images to synchronize with the latest version.'
)
).not.toBeInTheDocument();
});
test('CentOS 8 Stream renders', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdCentos8);
await screen.findByText(
'CentOS Stream 8 is no longer supported, building images from this blueprint will fail.'
);
await selectBlueprintById(blueprintIdWithComposes);
expect(
screen.queryByText(
'CentOS Stream 8 is no longer supported, building images from this blueprint will fail.'
)
).not.toBeInTheDocument();
});
describe('edit blueprint', () => {
beforeEach(() => {
vi.clearAllMocks();
});
const editedBlueprintName = 'Dark Chocolate';
const routes = [
{
path: 'insights/image-builder/*',
element: <LandingPage />,
},
{
path: 'insights/image-builder/imagewizard/:composeId?',
element: <CreateImageWizard />,
},
];
test('open blueprint wizard in editing mode', async () => {
await renderCustomRoutesWithReduxRouter(
'imagewizard/677b010b-e95e-4694-9813-d11d847f1bfc',
{},
routes
);
const blueprintDetails = await screen.findByTestId(
'image-details-expandable'
);
user.click(blueprintDetails);
await screen.findByText(editedBlueprintName);
});
test('redirect to index page when blueprint is invalid', async () => {
server.use(
http.get(`${IMAGE_BUILDER_API}/blueprints/invalid-compose-id`, () => {
return new HttpResponse(null, { status: 404 });
})
);
await renderCustomRoutesWithReduxRouter(
'imagewizard/invalid-compose-id',
{},
routes
);
await screen.findByRole('heading', { name: /Images/i, level: 1 });
});
});
describe('filtering', () => {
beforeEach(() => {
vi.clearAllMocks();
});
test('filter blueprints', async () => {
renderWithReduxRouter('', {});
const searchInput = await screen.findByPlaceholderText(
'Search by name or description'
);
searchInput.focus();
user.keyboard('Milk');
// wait for debounce
await waitFor(
() => {
expect(
screen.getByTestId(blueprintIdEmptyComposes)
).toBeInTheDocument();
},
{
timeout: 1500,
}
);
});
});
describe('pagination', () => {
beforeEach(() => {
vi.clearAllMocks();
});
test('paging of blueprints', async () => {
renderWithReduxRouter('', {});
expect(await screen.findAllByRole('checkbox')).toHaveLength(10);
const option = await screen.findByTestId('blueprints-pagination-bottom');
const prevButton = within(option).getByRole('button', {
name: /Go to previous page/i,
});
const button = within(option).getByRole('button', {
name: /Go to next page/i,
});
expect(prevButton).toBeInTheDocument();
expect(prevButton).toBeVisible();
expect(prevButton).toBeDisabled();
expect(button).toBeInTheDocument();
expect(button).toBeVisible();
await waitFor(() => {
expect(button).toBeEnabled();
});
user.click(button);
user.click(button);
await waitFor(() => {
expect(screen.getAllByRole('checkbox')).toHaveLength(8);
});
});
});
describe('composes filtering', () => {
beforeEach(() => {
vi.clearAllMocks();
});
test('filter composes by blueprint version', async () => {
renderWithReduxRouter('', {});
await selectBlueprintById(blueprintIdWithComposes);
// Wait for the filter appear (right now it's hidden unless a blueprint is selected)
const composesVersionFilter = await screen.findByRole('button', {
name: /All Versions/i,
});
expect(
within(screen.getByTestId('images-table')).getAllByRole('row')
).toHaveLength(4);
user.click(composesVersionFilter);
const option = await screen.findByRole('menuitem', { name: 'Newest' });
user.click(option);
await waitFor(() =>
expect(
within(screen.getByTestId('images-table')).getAllByRole('row')
).toHaveLength(2)
);
});
});
});