import React from 'react'; import { isEqual } from 'lodash'; import { renderWithRedux, patientlyWaitFor, within, fireEvent } from 'react-testing-lib-wrapper'; import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper'; import { foremanApi } from '../../../../../services/api'; import { HOST_ERRATA_KEY, ERRATA_SEARCH_QUERY } from '../ErrataTab/HostErrataConstants'; import { REX_FEATURES } from '../RemoteExecutionConstants'; import { ErrataTab } from '../ErrataTab/ErrataTab.js'; import mockErrataData from './errata.fixtures.json'; import mockResolveErrataTask from './resolveErrata.fixtures.json'; const contentFacetAttributes = { id: 11, uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e', content_view_default: false, lifecycle_environment_library: false, }; const hostName = 'foo.example.com'; const renderOptions = (facetAttributes = contentFacetAttributes) => ({ apiNamespace: HOST_ERRATA_KEY, initialState: { API: { HOST_DETAILS: { response: { id: 1, name: hostName, content_facet_attributes: { ...facetAttributes }, }, status: 'RESOLVED', }, }, }, }); const makeMockErrata = ({ pageSize = 20, total = 100, page = 1 }) => { const mockErrataResults = []; for (let i = (page * 1000); i < (page * 1000) + pageSize; i += 1) { mockErrataResults.push({ id: i, severity: 'Important', title: `Errata${i}`, type: (i % 2 === 0) ? 'security' : 'enhancement', host_id: 1, errata_id: `Errata${i}`, bugs: [], cves: [], packages: [], module_streams: [], installable: true, }); } return { total, subtotal: total, selectable: total, page, per_page: pageSize, error: null, search: null, results: mockErrataResults, }; }; const hostErrata = foremanApi.getApiUrl('/hosts/1/errata'); const autocompleteUrl = '/hosts/1/errata/auto_complete_search'; const defaultQueryWithoutSearch = { include_applicable: false, per_page: 20, page: 1, }; const defaultQuery = { ...defaultQueryWithoutSearch, search: '' }; const page2Query = { ...defaultQueryWithoutSearch, page: 2 }; const jobInvocations = foremanApi.getApiUrl('/job_invocations'); const applyByKatelloAgentUrl = foremanApi.getApiUrl('/hosts/1/errata/apply'); let firstErrata; let thirdErrata; let searchDelayScope; let autoSearchScope; beforeEach(() => { const { results } = mockErrataData; [firstErrata, , thirdErrata] = results; searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0); autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing'); }); afterEach(() => { assertNockRequest(searchDelayScope); assertNockRequest(autoSearchScope); }); test('Can call API for errata and show on screen on page load', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); // return tracedata results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrataData); const { getAllByText } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText(firstErrata.severity)[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 errata being present', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const noResults = { total: 0, subtotal: 0, page: 1, per_page: 20, results: [], }; const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, noResults); const { queryByText } = renderWithRedux(, renderOptions()); // Assert that there are not any errata showing on the screen. await patientlyWaitFor(() => expect(queryByText('This host does not have any installable errata.')).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 display expanded errata details', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); // return tracedata results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrataData); const { getByText, queryByText, getAllByText, getAllByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText(firstErrata.severity)[0]).toBeInTheDocument()); const firstExpansion = getAllByLabelText('Details')[0]; firstExpansion.click(); expect(getAllByText('CVEs').length).toBeGreaterThan(0); // the errata details should now be visible expect(getByText(firstErrata.summary)).toBeVisible(); const cveTreeItem = getAllByText('CVEs')[0]; expect(cveTreeItem).toBeVisible(); cveTreeItem.click(); // the CVE should now be visible expect(getByText(firstErrata.cves[0].cve_id)).toBeInTheDocument(); cveTreeItem.click(); // the CVE should now have disappeared expect(queryByText(firstErrata.cves[0].cve_id)).not.toBeInTheDocument(); firstExpansion.click(); // the errata details should now be hidden expect(getByText(firstErrata.summary)).not.toBeVisible(); // Assert request was made and completed, see helper function assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Can select one errata', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrataData); const { queryByText, getAllByText, getByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText(firstErrata.severity)[0]).toBeInTheDocument()); expect(queryByText('1 selected')).not.toBeInTheDocument(); const firstCheckBox = getByLabelText('Select row 0'); firstCheckBox.click(); const selectAllCheckbox = getByLabelText('Select all'); expect(selectAllCheckbox.checked).toEqual(false); expect(queryByText('1 selected')).toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Can select all errata across pages through checkbox', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({ page: 1 }); // return errata data results when we look for errata // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const scope2 = nockInstance .get(hostErrata) .query(page2Query) .reply(200, makeMockErrata({ page: 2 })); const { queryByText, getAllByText, getByLabelText, getAllByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectAllCheckbox = getByLabelText('Select all'); selectAllCheckbox.click(); expect(queryByText(`${mockErrata.total} selected`)).toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(true); getAllByLabelText('Go to next page')[0].click(); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(getByLabelText('Select row 0').checked).toEqual(true); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); assertNockRequest(scope2, done); // Pass jest callback to confirm test is done }); test('Can deselect all errata across pages through checkbox', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({ page: 1 }); // return errata data results when we look for errata // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const scope2 = nockInstance .get(hostErrata) .query(page2Query) .reply(200, makeMockErrata({ page: 2 })); const { queryByText, getAllByText, getByLabelText, getAllByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectAllCheckbox = getByLabelText('Select all'); selectAllCheckbox.click(); expect(queryByText(`${mockErrata.total} selected`)).toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(true); selectAllCheckbox.click(); expect(queryByText(`${mockErrata.total} selected`)).not.toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(false); getAllByLabelText('Go to next page')[0].click(); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(getByLabelText('Select row 0').checked).toEqual(false); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done assertNockRequest(scope2, done); }); test('Can select & deselect errata across pages', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, makeMockErrata({ page: 1 })); const scope2 = nockInstance .get(hostErrata) .query(page2Query) .reply(200, makeMockErrata({ page: 2 })); const { queryByText, getAllByText, getByLabelText, getAllByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); getByLabelText('Select row 0').click(); getByLabelText('Select row 1').click(); getAllByLabelText('Go to next page')[0].click(); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); getByLabelText('Select row 0').click(); getByLabelText('Select row 1').click(); expect(queryByText('4 selected')).toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done assertNockRequest(scope2, done); }); test('Can select & de-select all errata through selectDropDown', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { getByText, queryByText, getAllByText, getByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectDropDown = getByLabelText('Select'); selectDropDown.click(); const selectAll = getByText(`Select all (${mockErrata.total})`); expect(selectAll).toBeInTheDocument(); selectAll.click(); expect(queryByText(`${mockErrata.total} selected`)).toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(true); selectDropDown.click(); const selectNone = getByText('Select none (0)'); selectNone.click(); expect(queryByText(`${mockErrata.total} selected`)).not.toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(false); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Can de-select items in select all mode across pages', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({ page: 1 }); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const scope2 = nockInstance .get(hostErrata) .query({ ...defaultQueryWithoutSearch, page: 1 }) .reply(200, makeMockErrata({ page: 2 })); const scope3 = nockInstance .get(hostErrata) .query(page2Query) .reply(200, makeMockErrata({ page: 2 })); const { queryByText, getAllByText, getByLabelText, getAllByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectAllCheckbox = getByLabelText('Select all'); selectAllCheckbox.click(); expect(queryByText(`${mockErrata.total} selected`)).toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(true); getByLabelText('Select row 0').click(); // de select expect(queryByText(`${mockErrata.total - 1} selected`)).toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(false); // goto next page getAllByLabelText('Go to next page')[0].click(); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(getByLabelText('Select row 0').checked).toEqual(true); getByLabelText('Select row 0').click(); // de select expect(queryByText(`${mockErrata.total - 2} selected`)).toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(false); // goto previous page getAllByLabelText('Go to previous page')[0].click(); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(getByLabelText('Select row 0').checked).toEqual(false); expect(getByLabelText('Select row 1').checked).toEqual(true); getByLabelText('Select row 1').click(); // de select expect(queryByText(`${mockErrata.total - 3} selected`)).toBeInTheDocument(); expect(getByLabelText('Select row 1').checked).toEqual(false); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done assertNockRequest(scope2, done); assertNockRequest(scope3, done); }); test('Can select page and select only items on the page', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { getByText, queryByText, getAllByText, getByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectDropDown = getByLabelText('Select'); selectDropDown.click(); const selectPage = getByText('Select page (20)'); expect(selectPage).toBeInTheDocument(); selectPage.click(); expect(queryByText('20 selected')).toBeInTheDocument(); expect(getByLabelText('Select row 0').checked).toEqual(true); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Select all is disabled if all rows are selected', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { getByText, queryByText, getAllByText, getByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectDropDown = getByLabelText('Select'); selectDropDown.click(); const selectAll = getByText(`Select all (${mockErrata.total})`); expect(selectAll).toBeInTheDocument(); expect(selectAll).toHaveAttribute('aria-disabled', 'false'); selectAll.click(); expect(queryByText(`${mockErrata.total} selected`)).toBeInTheDocument(); // click the dropdown again and make sure select all is disabled selectDropDown.click(); expect(getByText(`Select all (${mockErrata.total})`)).toHaveAttribute('aria-disabled', 'true'); expect(getByText('Select page (20)')).toHaveAttribute('aria-disabled', 'true'); expect(getByText('Select none (0)')).toHaveAttribute('aria-disabled', 'false'); // Select none getByText('Select none (0)').click(); selectDropDown.click(); expect(getByText(`Select all (${mockErrata.total})`)).toHaveAttribute('aria-disabled', 'false'); expect(getByText('Select page (20)')).toHaveAttribute('aria-disabled', 'false'); expect(getByText('Select none (0)')).toHaveAttribute('aria-disabled', 'true'); // Select page getByText('Select page (20)').click(); selectDropDown.click(); expect(getByText(`Select all (${mockErrata.total})`)).toHaveAttribute('aria-disabled', 'false'); expect(getByText('Select page (20)')).toHaveAttribute('aria-disabled', 'true'); expect(getByText('Select none (0)')).toHaveAttribute('aria-disabled', 'false'); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Toggle Group shows if it\'s not the default content view or library enviroment', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { queryByLabelText, getAllByText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(queryByLabelText('Installable Errata')).toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Toggle Group shows if it\'s the default content view but non-library environment', async (done) => { const options = renderOptions({ ...contentFacetAttributes, content_view_default: true, }); // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { queryByLabelText, getAllByText, } = renderWithRedux(, options); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(queryByLabelText('Installable Errata')).toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Toggle Group shows if it\'s the library environment but non-default content view', async (done) => { const options = renderOptions({ ...contentFacetAttributes, lifecycle_environment_library: true, }); // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { queryByLabelText, getAllByText, } = renderWithRedux(, options); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(queryByLabelText('Installable Errata')).toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Toggle Group does not show if it\'s the default content view and library environment', async (done) => { const options = renderOptions({ ...contentFacetAttributes, content_view_default: true, lifecycle_environment_library: true, }); // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { queryByLabelText, getAllByText, } = renderWithRedux(, options); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(queryByLabelText('Installable Errata')).not.toBeInTheDocument(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Selection is disabled for errata which are applicable but not installable', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); firstErrata.installable = false; // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrataData); const { getAllByText, getByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText(firstErrata.severity)[0]).toBeInTheDocument()); expect(getByLabelText('Select row 0')).toBeDisabled(); expect(getByLabelText('Select row 1')).not.toBeDisabled(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Can select only installable errata across pages through checkbox', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({ page: 1 }); const first = mockErrata.results[0]; first.installable = false; mockErrata.selectable = mockErrata.total - 1; // return errata data results when we look for errata // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const scope2 = nockInstance .get(hostErrata) .query(page2Query) .reply(200, makeMockErrata({ page: 2 })); const { queryByText, getAllByText, getByLabelText, getAllByLabelText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectAllCheckbox = getByLabelText('Select all'); selectAllCheckbox.click(); expect(queryByText(`${mockErrata.selectable} selected`)).toBeInTheDocument(); expect(queryByText(`${mockErrata.total} selected`)).not.toBeInTheDocument(); expect(getByLabelText('Select row 0')).toBeDisabled(); getAllByLabelText('Go to next page')[0].click(); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(getByLabelText('Select row 0').checked).toEqual(true); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); assertNockRequest(scope2, done); // Pass jest callback to confirm test is done }); test('Can toggle with the Toggle Group ', async (done) => { // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); // return errata data results when we look for errata const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { queryByLabelText, getAllByText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); expect(queryByLabelText('Installable Errata')).toBeInTheDocument(); expect(queryByLabelText('Show Installable')).toHaveAttribute('aria-pressed', 'true'); expect(queryByLabelText('Show All')).toHaveAttribute('aria-pressed', 'false'); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); // Pass jest callback to confirm test is done }); test('Can filter by errata type', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrataData); const scope2 = nockInstance .get(hostErrata) .query({ ...defaultQuery, type: 'security' }) .reply(200, { ...mockErrataData, results: [firstErrata] }); const { queryByText, getByRole, getAllByText, getByText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); // the Bugfix text in the table is just a text node, while the dropdown is a button expect(getByText('Bugfix', { ignore: ['button', 'title'] })).toBeInTheDocument(); expect(getByText('Enhancement', { ignore: ['button', 'title'] })).toBeInTheDocument(); const typeDropdown = queryByText('Type', { ignore: 'th' }); expect(typeDropdown).toBeInTheDocument(); fireEvent.click(typeDropdown); const security = getByRole('option', { name: 'select Security' }); fireEvent.click(security); await patientlyWaitFor(() => { expect(queryByText('Bugfix')).not.toBeInTheDocument(); expect(queryByText('Enhancement')).not.toBeInTheDocument(); }); assertNockRequest(autocompleteScope); assertNockRequest(scope); assertNockRequest(searchDelayScope); assertNockRequest(autoSearchScope); assertNockRequest(scope2, done); // Pass jest callback to confirm test is done }); test('Can filter by severity', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrataData); const scope2 = nockInstance .get(hostErrata) .query({ ...defaultQuery, severity: 'Important' }) .reply(200, { ...mockErrataData, results: [thirdErrata] }); const { queryByText, getByRole, getAllByText, getByText, } = renderWithRedux(, renderOptions()); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); // the Bugfix text in the table is just a text node, while the dropdown is a button expect(getByText('Moderate', { ignore: ['button', 'title'] })).toBeInTheDocument(); expect(getByText('Important', { ignore: ['.pf-c-select__toggle-text', 'title'] })).toBeInTheDocument(); expect(getByText('Critical', { ignore: ['button', 'title'] })).toBeInTheDocument(); const severityDropdown = queryByText('Severity', { ignore: 'th' }); expect(severityDropdown).toBeInTheDocument(); fireEvent.click(severityDropdown); const important = getByRole('option', { name: 'select Important' }); fireEvent.click(important); await patientlyWaitFor(() => { expect(queryByText('Moderate', { ignore: ['.pf-c-select__toggle-text'] })).not.toBeInTheDocument(); expect(queryByText('Critical', { ignore: ['.pf-c-select__toggle-text'] })).not.toBeInTheDocument(); }); await patientlyWaitFor(() => { expect(getByText('Important', { ignore: ['.pf-c-select__toggle-text', 'title'] })).toBeInTheDocument(); }); assertNockRequest(autocompleteScope); assertNockRequest(scope); assertNockRequest(searchDelayScope); assertNockRequest(autoSearchScope); assertNockRequest(scope2, done); // Pass jest callback to confirm test is done }); test('apply button chooses katello agent if enabled', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const options = renderOptions({ ...contentFacetAttributes, katelloAgentInstalled: true, katelloAgentEnabled: true, }); const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const resolveErrataScope = nockInstance .put(applyByKatelloAgentUrl) .reply(201, mockResolveErrataTask); const { getAllByText, getByLabelText, queryByText } = renderWithRedux( , options, ); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); getByLabelText('Select row 0').click(); getByLabelText('Select row 1').click(); const viaAction = queryByText('Apply'); expect(viaAction).toBeInTheDocument(); viaAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope, done); }); test('Can bulk apply via katello agent', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const options = renderOptions({ ...contentFacetAttributes, katelloAgentInstalled: true, katelloAgentEnabled: true, }); const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const postBody = ({ search }) => { const [firstResult, secondResult] = results; return isEqual(search, `errata_id ^ (${firstResult.errata_id},${secondResult.errata_id})`); }; const resolveErrataScope = nockInstance .put(applyByKatelloAgentUrl, postBody) .reply(201, mockResolveErrataTask); const { getAllByText, getByLabelText, queryByText } = renderWithRedux( , options, ); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); getByLabelText('Select row 0').click(); getByLabelText('Select row 1').click(); const actionMenu = getByLabelText('bulk_actions'); actionMenu.click(); const viaAction = queryByText('Apply via Katello agent'); expect(viaAction).toBeInTheDocument(); viaAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope, done); }); test('Can select all, exclude and bulk apply via katello agent', async (done) => { // This is the same test as above, // but using the table action bar instead of the Apply button const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const options = renderOptions({ ...contentFacetAttributes, katelloAgentInstalled: true, katelloAgentEnabled: true, }); const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const postBody = ({ search }) => { const [firstResult] = results; return isEqual(search, `errata_id !^ (${firstResult.errata_id})`); }; const resolveErrataScope = nockInstance .put(applyByKatelloAgentUrl, postBody) .reply(201, mockResolveErrataTask); const { getAllByText, getByLabelText, queryByText } = renderWithRedux( , options, ); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectAllCheckbox = getByLabelText('Select all'); selectAllCheckbox.click(); getByLabelText('Select row 0').click(); // deselect const actionMenu = getByLabelText('bulk_actions'); actionMenu.click(); const viaAction = queryByText('Apply via Katello agent'); expect(viaAction).toBeInTheDocument(); viaAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope, done); }); test('Apply button chooses remote execution', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const options = renderOptions({ ...contentFacetAttributes, katelloAgentInstalled: true, katelloAgentEnabled: true, remoteExecutionByDefault: true, }); const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const scope1 = nockInstance .get(hostErrata) .query(defaultQueryWithoutSearch) .reply(200, mockErrata); const resolveErrataScope = nockInstance .post(jobInvocations) .reply(201, mockResolveErrataTask); const { getAllByText, getByLabelText, queryByText } = renderWithRedux( , options, ); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); getByLabelText('Select row 0').click(); getByLabelText('Select row 1').click(); const viaAction = queryByText('Apply'); expect(viaAction).toBeInTheDocument(); viaAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope1); assertNockRequest(scope, done); }); test('Can bulk apply via remote execution', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const scope1 = nockInstance .get(hostErrata) .query(defaultQueryWithoutSearch) .reply(200, mockErrata); // eslint-disable-next-line camelcase const jobInvocationBody = ({ job_invocation: { inputs, feature, search_query } }) => inputs[ERRATA_SEARCH_QUERY] === `errata_id ^ (${results[0].errata_id},${results[1].errata_id})` && feature === REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH && // eslint-disable-next-line camelcase search_query === `name ^ (${hostName})`; const resolveErrataScope = nockInstance .post(jobInvocations, jobInvocationBody) .reply(201, mockResolveErrataTask); const { getAllByText, getByLabelText, queryByText } = renderWithRedux( , renderOptions(), ); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); getByLabelText('Select row 0').click(); getByLabelText('Select row 1').click(); const actionMenu = getByLabelText('bulk_actions'); actionMenu.click(); const viaRexAction = queryByText('Apply via remote execution'); expect(viaRexAction).toBeInTheDocument(); viaRexAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope1); assertNockRequest(scope, done); }); test('Can select all, exclude and bulk apply via remote execution', async (done) => { // This is the same test as above, // but using the table action bar instead of the Restart app button const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const scope1 = nockInstance .get(hostErrata) .query(defaultQueryWithoutSearch) .reply(200, mockErrata); const jobInvocationBody = ({ job_invocation: { inputs } }) => inputs[ERRATA_SEARCH_QUERY] === `errata_id !^ (${results[0].errata_id})`; const resolveErrataScope = nockInstance .post(jobInvocations, jobInvocationBody) .reply(201, mockResolveErrataTask); const { getAllByText, getByLabelText, queryByText } = renderWithRedux( , renderOptions(), ); // Assert that the errata are now showing on the screen, but wait for them to appear. await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const selectAllCheckbox = getByLabelText('Select all'); selectAllCheckbox.click(); getByLabelText('Select row 0').click(); // de select const actionMenu = getByLabelText('bulk_actions'); actionMenu.click(); const viaRexAction = queryByText('Apply via remote execution'); expect(viaRexAction).toBeInTheDocument(); viaRexAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope1); assertNockRequest(scope, done); }); test('Can apply errata in bulk via customized remote execution', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { getAllByText, getByLabelText, queryByText } = renderWithRedux( , renderOptions(), ); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); getByLabelText('Select row 0').click(); getByLabelText('Select row 1').click(); const errata = `${results[0].errata_id},${results[1].errata_id}`; const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH; const actionMenu = getByLabelText('bulk_actions'); actionMenu.click(); const viaRexAction = queryByText('Apply via customized remote execution'); expect(viaRexAction).toBeInTheDocument(); expect(viaRexAction).toHaveAttribute( 'href', `/job_invocations/new?feature=${feature}&host_ids=name%20%5E%20(${hostName})&inputs%5BErrata%20search%20query%5D=errata_id%20%5E%20(${errata})`, ); viaRexAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); }); test('Can apply a single erratum to the host via katello agent', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const options = renderOptions({ ...contentFacetAttributes, katelloAgentInstalled: true, katelloAgentEnabled: true, }); const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const postBody = ({ errata_ids: errataIds }) => isEqual(errataIds, [results[0].errata_id]); const resolveErrataScope = nockInstance .put(applyByKatelloAgentUrl, postBody) .reply(201, mockResolveErrataTask); const { getAllByText, getByLabelText, getByText } = renderWithRedux( , options, ); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const erratumActionMenu = within(getByLabelText('Select row 0').closest('tr')).getByLabelText('Actions'); expect(erratumActionMenu).toHaveAttribute('aria-label', 'Actions'); erratumActionMenu.click(); let viaAction; await patientlyWaitFor(() => { viaAction = getByText('Apply via Katello agent'); expect(viaAction).toBeInTheDocument(); }); viaAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope, done); }); test('Can apply a single erratum to the host via remote execution', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const jobInvocationBody = ({ job_invocation: { inputs } }) => inputs[ERRATA_SEARCH_QUERY] === `errata_id = ${results[0].errata_id}`; const resolveErrataScope = nockInstance .post(jobInvocations, jobInvocationBody) .reply(201, mockResolveErrataTask); const { getByText, getAllByText, getByLabelText } = renderWithRedux( , renderOptions(), ); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const erratumActionMenu = within(getByLabelText('Select row 0').closest('tr')).getByLabelText('Actions'); expect(erratumActionMenu).toHaveAttribute('aria-label', 'Actions'); erratumActionMenu.click(); let viaRexAction; await patientlyWaitFor(() => { viaRexAction = getByText('Apply via remote execution'); expect(viaRexAction).toBeInTheDocument(); }); viaRexAction.click(); assertNockRequest(autocompleteScope); assertNockRequest(resolveErrataScope); assertNockRequest(scope, done); }); test('Can apply a single erratum to the host via customized remote execution', async (done) => { const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl); const mockErrata = makeMockErrata({}); const { results } = mockErrata; const { errata_id: errataId } = results[0]; const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH; const scope = nockInstance .get(hostErrata) .query(defaultQuery) .reply(200, mockErrata); const { getByText, getAllByText, getByLabelText } = renderWithRedux( , renderOptions(), ); await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument()); const erratumActionMenu = within(getByLabelText('Select row 0').closest('tr')).getByLabelText('Actions'); expect(erratumActionMenu).toHaveAttribute('aria-label', 'Actions'); erratumActionMenu.click(); let viaRexAction; await patientlyWaitFor(() => { viaRexAction = getByText('Apply via customized remote execution'); expect(viaRexAction).toBeInTheDocument(); }); viaRexAction.click(); expect(viaRexAction).toHaveAttribute( 'href', `/job_invocations/new?feature=${feature}&host_ids=name%20%5E%20(${hostName})&inputs%5BErrata%20search%20query%5D=errata_id%20=%20${errataId}`, ); assertNockRequest(autocompleteScope); assertNockRequest(scope, done); });