import React from 'react'; import { renderWithRedux, patientlyWaitFor, fireEvent, within } from 'react-testing-lib-wrapper'; import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper'; import katelloApi, { foremanApi } from '../../../../../services/api'; import mockPackagesData from './yumInstallablePackages.fixtures.json'; import PackageInstallModal from '../PackagesTab/PackageInstallModal'; import { HOST_YUM_INSTALLABLE_PACKAGES_KEY, PACKAGE_SEARCH_QUERY } from '../PackagesTab/YumInstallablePackagesConstants'; import { REX_FEATURES } from '../RemoteExecutionConstants'; const contentFacetAttributes = { id: 11, uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e', content_view_default: false, lifecycle_environment_library: false, }; const renderOptions = (facetAttributes = contentFacetAttributes) => ({ apiNamespace: HOST_YUM_INSTALLABLE_PACKAGES_KEY, initialState: { API: { HOST_DETAILS: { response: { id: 1, name: 'test-host', content_facet_attributes: { ...facetAttributes }, }, status: 'RESOLVED', }, }, }, }); const hostYumInstallablePackages = katelloApi.getApiUrl('/packages'); const hostPackages = foremanApi.getApiUrl('/hosts/1/packages/install'); const jobInvocations = foremanApi.getApiUrl('/job_invocations'); const autocompleteUrl = '/hosts/1/packages/auto_complete_search'; const fakeTask = { id: '21c0f9e4-b27b-49aa-8774-6be66126043b' }; const defaultQuery = { packages_restrict_not_installed: true, packages_restrict_applicable: false, packages_restrict_latest: true, host_id: 1, per_page: 20, page: 1, }; let firstPackages; let secondPackages; let searchDelayScope; let autoSearchScope; beforeEach(() => { const { results } = mockPackagesData; [firstPackages, secondPackages] = results; searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500); autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true); }); afterEach(() => { assertNockRequest(searchDelayScope); assertNockRequest(autoSearchScope); }); test('Can call API for installable packages and show on screen on page load', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const { getAllByText } = renderWithRedux(, renderOptions()); // Assert that the packages are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // Assert request was made and completed, see helper function assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Can handle no installable packages being present', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const noResults = { total: 0, subtotal: 0, page: 1, per_page: 20, results: [], }; const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, noResults); const { queryByText } = renderWithRedux(, renderOptions()); // Assert that there are not any packages showing on the screen. await patientlyWaitFor(() => expect(queryByText('No packages available to install')).toBeInTheDocument()); // Assert request was made and completed, see helper function assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Does not show katello-agent option when disabled', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const { getAllByText, getByText, getByRole, queryByText, } = renderWithRedux(, renderOptions()); // Assert that the packages are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // Assert request was made and completed, see helper function // find the first table row's checkbox const checkbox = getByRole('checkbox', { name: 'Select row 0' }); // click the checkbox to make sure the Install dropdown will be enabled fireEvent.click(checkbox); const footer = getByRole('contentinfo'); // find the dropdown to the right of the Install button // (no, the other one! The one that's in the footer.) const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' })); fireEvent.click(dropdown); expect(getByText('Install via remote execution')).toBeInTheDocument(); // Assert that the katello-agent option is not present expect(queryByText('katello-agent')).not.toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Shows the katello-agent option when enabled', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const { getAllByText, getByText, getByRole, } = renderWithRedux(, renderOptions()); // Assert that the packages are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // Assert request was made and completed, see helper function // find the first table row's checkbox const checkbox = getByRole('checkbox', { name: 'Select row 0' }); // click the checkbox to make sure the Install dropdown will be enabled fireEvent.click(checkbox); const footer = getByRole('contentinfo'); const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' })); fireEvent.click(dropdown); expect(getByText('Install via remote execution')).toBeInTheDocument(); expect(getByText('Install via katello-agent')).toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Can install packages via katello-agent', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const installScope = nockInstance .put(hostPackages, { packages: [secondPackages.name, firstPackages.name] }) .reply(202, fakeTask); const { getAllByText, getByText, getByRole, } = renderWithRedux(, renderOptions()); await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // find and select the first two packages const checkbox1 = getByRole('checkbox', { name: 'Select row 0' }); const checkbox2 = getByRole('checkbox', { name: 'Select row 1' }); fireEvent.click(checkbox1); fireEvent.click(checkbox2); // click the Install dropdown const footer = getByRole('contentinfo'); const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' })); fireEvent.click(dropdown); // click the katello-agent option const katelloAgentOption = getByText('Install via katello-agent'); fireEvent.click(katelloAgentOption); assertNockRequest(autocompleteScope); assertNockRequest(scope); assertNockRequest(installScope, done); }); test('Can install a package via remote execution', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const installScope = nockInstance .post(jobInvocations, { job_invocation: { inputs: { [PACKAGE_SEARCH_QUERY]: `id ^ (${firstPackages.id},${secondPackages.id})`, }, search_query: 'name ^ (test-host)', feature: REX_FEATURES.KATELLO_PACKAGE_INSTALL_BY_SEARCH, }, }) .reply(201); const { getAllByText, getByText, getByRole, } = renderWithRedux(, renderOptions()); await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // find and select the first two packages const checkbox1 = getByRole('checkbox', { name: 'Select row 0' }); const checkbox2 = getByRole('checkbox', { name: 'Select row 1' }); fireEvent.click(checkbox1); fireEvent.click(checkbox2); // click the Install dropdown const footer = getByRole('contentinfo'); const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' })); fireEvent.click(dropdown); const rexOption = getByText('Install via remote execution'); fireEvent.click(rexOption); assertNockRequest(autocompleteScope); assertNockRequest(scope); assertNockRequest(installScope, done); }); test('Can install a package via customized remote execution', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const { getAllByText, queryByText, getByRole, } = renderWithRedux(, renderOptions()); await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // find and select the first two packages const checkbox1 = getByRole('checkbox', { name: 'Select row 0' }); const checkbox2 = getByRole('checkbox', { name: 'Select row 1' }); fireEvent.click(checkbox1); fireEvent.click(checkbox2); // click the Install dropdown const footer = getByRole('contentinfo'); const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' })); fireEvent.click(dropdown); const customizedRexOption = queryByText('Install via customized remote execution'); expect(customizedRexOption).toBeInTheDocument(); expect(customizedRexOption).toHaveAttribute( 'href', `/job_invocations/new?feature=${REX_FEATURES.KATELLO_PACKAGE_INSTALL}&host_ids=name%20%5E%20(test-host)&inputs%5Bpackage%5D=duck,cheetah`, ); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); }); test('Uses package_install_by_search_query template when in select all mode', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const { getAllByText, queryByText, getByRole, } = renderWithRedux(, renderOptions()); await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // find and click the select all checkbox const selectAllCheckbox = getByRole('checkbox', { name: 'Select all' }); fireEvent.click(selectAllCheckbox); // find and deselect the first package const checkbox1 = getByRole('checkbox', { name: 'Select row 0' }); fireEvent.click(checkbox1); // click the Install dropdown const footer = getByRole('contentinfo'); const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' })); fireEvent.click(dropdown); const customizedRexOption = queryByText('Install via customized remote execution'); expect(customizedRexOption).toBeInTheDocument(); expect(customizedRexOption).toHaveAttribute( 'href', `/job_invocations/new?feature=${REX_FEATURES.KATELLO_PACKAGE_INSTALL_BY_SEARCH}&host_ids=name%20%5E%20(test-host)&inputs%5BPackage%20search%20query%5D=id%20!%5E%20(32376)`, ); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); }); test('Disables the katello-agent option when in select all mode', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostYumInstallablePackages) .query(defaultQuery) .reply(200, mockPackagesData); const { getAllByText, getByText, getByRole, } = renderWithRedux(, renderOptions()); await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument()); // find and click the select all checkbox const selectAllCheckbox = getByRole('checkbox', { name: 'Select all' }); fireEvent.click(selectAllCheckbox); // find and deselect the first package const checkbox1 = getByRole('checkbox', { name: 'Select row 0' }); fireEvent.click(checkbox1); // click the Install dropdown const footer = getByRole('contentinfo'); const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' })); fireEvent.click(dropdown); const katelloAgentOption = getByText('Install via katello-agent'); // expect the katello-agent option to be disabled expect(katelloAgentOption).toHaveAttribute('aria-disabled', 'true'); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); });