debian-image-builder-frontend/src/test/Components/CreateImageWizard/steps/Registration/Registration.test.tsx
regexowl 25a5f140d8 ESLint: Add rule to sort imports alphabetically
The `import/order` rule isn't enough to sort import within a single import group alphabetically.

This adds `sort-imports` rule that handles the sorting within groups.
2025-07-15 16:52:45 +00:00

470 lines
14 KiB
TypeScript

import type { Router as RemixRouter } from '@remix-run/router';
import { screen, waitFor, within } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import {
CREATE_BLUEPRINT,
EDIT_BLUEPRINT,
RHEL_10,
RHSM_API,
} from '../../../../../constants';
import {
CreateBlueprintRequest,
ImageRequest,
} from '../../../../../store/imageBuilderApi';
import { mockBlueprintIds } from '../../../../fixtures/blueprints';
import {
CERTIFICATE,
SATELLITE_COMMAND,
SATELLITE_COMMAND_EXPIRED_TOKEN,
SATELLITE_COMMAND_NO_EXPIRATION,
} from '../../../../fixtures/customizations';
import { registrationCreateBlueprintRequest } from '../../../../fixtures/editMode';
import { server } from '../../../../mocks/server';
import {
clickBack,
clickNext,
clickRegisterLater,
clickRegisterSatellite,
clickReviewAndFinish,
enterBlueprintName,
getNextButton,
goToRegistrationStep,
interceptBlueprintRequest,
interceptEditBlueprintRequest,
openAndDismissSaveAndBuildModal,
renderCreateMode,
renderEditMode,
verifyCancelButton,
} from '../../wizardTestUtils';
const localStorageMock = (() => {
let store: { [key: string]: string } = {};
return {
getItem: (key: string) => store[key] || null,
setItem: (key: string, value: string) => {
store[key] = value.toString();
},
clear: () => (store = {}),
};
})();
Object.defineProperty(window, 'localStorage', {
value: localStorageMock,
});
// Initiliaze the router
const router: RemixRouter | undefined = undefined;
const clickShowAdditionalConnectionOptions = async () => {
const user = userEvent.setup();
const link = await screen.findByText('Show additional connection options');
await waitFor(() => user.click(link));
};
const deselectEnableRemoteRemediations = async () => {
const user = userEvent.setup();
const checkBox = await screen.findByRole('checkbox', {
name: 'Enable remote remediations and system management with automation',
});
await waitFor(() => user.click(checkBox));
};
const deselectPredictiveAnalytics = async () => {
const user = userEvent.setup();
const checkBox = await screen.findByRole('checkbox', {
name: 'Enable predictive analytics and management capabilities',
});
await waitFor(() => user.click(checkBox));
};
const openActivationKeyDropdown = async () => {
const user = userEvent.setup();
const activationKeyDropdown = await screen.findByPlaceholderText(
'Select activation key'
);
user.click(activationKeyDropdown);
};
const selectActivationKey = async (key: string) => {
const user = userEvent.setup();
const activationKey = await screen.findByRole('option', {
name: key,
});
user.click(activationKey);
await screen.findByDisplayValue(key);
};
const addSatelliteRegistrationCommandViaKeyDown = async (command: string) => {
const user = userEvent.setup({ delay: null });
const satelliteRegistrationCommand = await screen.findByPlaceholderText(
/registration command/i
);
await waitFor(() => user.clear(satelliteRegistrationCommand));
await waitFor(() => user.type(satelliteRegistrationCommand, command));
await waitFor(() => satelliteRegistrationCommand.blur());
};
const uploadFile = async (scriptName: string): Promise<void> => {
const user = userEvent.setup();
const fileInput: HTMLElement | null =
// eslint-disable-next-line testing-library/no-node-access
document.querySelector('input[type="file"]');
if (fileInput) {
const file = new File([scriptName], 'certificate.pem', {
type: 'application/x-pem-file',
});
await waitFor(() => user.upload(fileInput, file));
}
};
const goToReviewStep = async () => {
await clickNext(); // Registration
await clickNext(); // OpenSCAP
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
await clickNext(); // Users
await clickNext(); // Timezone
await clickNext(); // Locale
await clickNext(); // Hostname
await clickNext(); // Kernel
await clickNext(); // Firewall
await clickNext(); // Services
await clickNext(); // Details
await enterBlueprintName();
await clickNext(); // Review
};
const clickRevisitButton = async () => {
const user = userEvent.setup();
const expandable = await screen.findByTestId('registration-expandable');
const revisitButton = await within(expandable).findByTestId(
'revisit-registration'
);
await waitFor(() => user.click(revisitButton));
};
describe('Step Registration', () => {
beforeEach(() => {
vi.clearAllMocks();
});
test('clicking Next leads to OpenSCAP step', async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickRegisterLater();
await clickNext();
await screen.findByRole('heading', {
name: 'OpenSCAP profile',
});
});
test('clicking Back leads to Image output step', async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickBack();
await screen.findByRole('heading', {
name: 'Image output',
});
});
test('clicking Cancel loads landing page', async () => {
await renderCreateMode();
await goToRegistrationStep();
await verifyCancelButton(router);
});
test('clicking Review and finish leads to Review', async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickReviewAndFinish();
await screen.findByRole('heading', {
name: /Review/i,
});
});
test('button Review and finish is disabled for invalid state', async () => {
server.use(
http.get(`${RHSM_API}/activation_keys`, () => {
return new HttpResponse(null, { status: 404 });
})
);
await renderCreateMode();
await goToRegistrationStep();
expect(
await screen.findByRole('button', { name: /Review and finish/ })
).toBeDisabled();
});
test('default registration includes rhsm, rhc and insights', async () => {
await renderCreateMode();
await goToRegistrationStep();
await openActivationKeyDropdown();
await selectActivationKey('name0');
await goToReviewStep();
const review = await screen.findByTestId('review-registration');
expect(review).toHaveTextContent(
'Register with Red Hat Subscription Manager (RHSM)'
);
expect(review).toHaveTextContent('Connect to Red Hat Insights');
expect(review).toHaveTextContent(
'Use remote host configuration (rhc) utility'
);
});
test('should disable dropdown when clicking Register the system later', async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickRegisterLater();
await waitFor(() =>
expect(
screen.queryByTestId('selected-activation-key')
).not.toBeInTheDocument()
);
await waitFor(async () =>
expect(await screen.findByTestId('activation-key-select')).toHaveClass(
'pf-m-disabled'
)
);
await goToReviewStep();
await screen.findByText('Register the system later');
});
test('revisit step button on Review works', async () => {
await renderCreateMode();
await goToRegistrationStep();
await openActivationKeyDropdown();
await selectActivationKey('name0');
await goToReviewStep();
await clickRevisitButton();
await screen.findByRole('heading', {
name: /Register systems using this image/,
});
});
});
describe('Registration request generated correctly', () => {
beforeEach(() => {
vi.clearAllMocks();
});
const imageRequest: ImageRequest = {
architecture: 'x86_64',
image_type: 'guest-image',
upload_request: {
options: {},
type: 'aws.s3',
},
};
const blueprintRequest: CreateBlueprintRequest = {
name: 'Red Velvet',
description: '',
distribution: RHEL_10,
image_requests: [imageRequest],
customizations: {},
};
test('register + insights + rhc', async () => {
await renderCreateMode();
await goToRegistrationStep();
await goToReviewStep();
// informational modal pops up in the first test only as it's tied
// to a 'imageBuilder.saveAndBuildModalSeen' variable in localStorage
await openAndDismissSaveAndBuildModal();
const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);
const expectedSubscription = {
'activation-key': 'name0',
insights: true,
rhc: true,
organization: 5,
'server-url': 'subscription.rhsm.redhat.com',
'base-url': 'https://cdn.redhat.com/',
};
const expectedRequest = {
...blueprintRequest,
customizations: { subscription: expectedSubscription },
};
expect(receivedRequest).toEqual(expectedRequest);
});
test('register + insights', async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickShowAdditionalConnectionOptions();
await deselectEnableRemoteRemediations();
await goToReviewStep();
const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);
const expectedSubscription = {
'activation-key': 'name0',
insights: true,
rhc: false,
organization: 5,
'server-url': 'subscription.rhsm.redhat.com',
'base-url': 'https://cdn.redhat.com/',
};
const expectedRequest = {
...blueprintRequest,
customizations: { subscription: expectedSubscription },
};
expect(receivedRequest).toEqual(expectedRequest);
});
test('register now', async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickShowAdditionalConnectionOptions();
await deselectPredictiveAnalytics();
await goToReviewStep();
// informational modal pops up in the first test only as it's tied
// to a 'imageBuilder.saveAndBuildModalSeen' variable in localStorage
const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);
const expectedSubscription = {
'activation-key': 'name0',
insights: false,
rhc: false,
organization: 5,
'server-url': 'subscription.rhsm.redhat.com',
'base-url': 'https://cdn.redhat.com/',
};
const expectedRequest = {
...blueprintRequest,
customizations: { subscription: expectedSubscription },
};
await waitFor(() => {
expect(receivedRequest).toEqual(expectedRequest);
});
});
test('register later', async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickRegisterLater();
await goToReviewStep();
const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);
const expectedRequest = {
...blueprintRequest,
customizations: {},
};
await waitFor(() => {
expect(receivedRequest).toEqual(expectedRequest);
});
});
test('register with no key in local storage', async () => {
await renderCreateMode();
await goToRegistrationStep();
await screen.findByDisplayValue('name0');
await goToReviewStep();
const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);
const expectedSubscription = {
'activation-key': 'name0',
insights: true,
rhc: true,
organization: 5,
'server-url': 'subscription.rhsm.redhat.com',
'base-url': 'https://cdn.redhat.com/',
};
const expectedRequest = {
...blueprintRequest,
customizations: { subscription: expectedSubscription },
};
await waitFor(() => {
expect(receivedRequest).toEqual(expectedRequest);
});
});
test('register with a key in local storage', async () => {
await renderCreateMode();
localStorage.setItem('imageBuilder.recentActivationKey', 'name1');
await goToRegistrationStep();
await screen.findByDisplayValue('name1');
await goToReviewStep();
const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);
const expectedSubscription = {
'activation-key': 'name1',
insights: true,
rhc: true,
organization: 5,
'server-url': 'subscription.rhsm.redhat.com',
'base-url': 'https://cdn.redhat.com/',
};
const expectedRequest = {
...blueprintRequest,
customizations: { subscription: expectedSubscription },
};
await waitFor(() => {
expect(receivedRequest).toEqual(expectedRequest);
});
// clear mocked values in localStorage so they don't affect following tests
localStorage.clear();
});
test('register with satellite', { timeout: 20000 }, async () => {
await renderCreateMode();
await goToRegistrationStep();
await clickRegisterSatellite();
const nextButton = await getNextButton();
expect(nextButton).toBeDisabled();
await uploadFile(CERTIFICATE);
expect(nextButton).toBeDisabled();
await addSatelliteRegistrationCommandViaKeyDown(
SATELLITE_COMMAND_EXPIRED_TOKEN
);
const expiredTokenHelper = await screen.findByText(
/The token is already expired or will expire by next day./i
);
await waitFor(() => expect(expiredTokenHelper).toBeInTheDocument());
await addSatelliteRegistrationCommandViaKeyDown(SATELLITE_COMMAND);
expect(nextButton).toBeEnabled();
await addSatelliteRegistrationCommandViaKeyDown(
SATELLITE_COMMAND_NO_EXPIRATION
);
expect(nextButton).toBeEnabled();
});
});
describe('Registration edit mode', () => {
beforeEach(() => {
vi.clearAllMocks();
});
test('edit mode works', async () => {
const id = mockBlueprintIds['registration'];
await renderEditMode(id);
// starts on review step
const receivedRequest = await interceptEditBlueprintRequest(
`${EDIT_BLUEPRINT}/${id}`
);
const expectedRequest = registrationCreateBlueprintRequest;
expect(receivedRequest).toEqual(expectedRequest);
});
});