import React from 'react';
import { act } from 'react-test-renderer';
import { renderWithRedux, patientlyWaitFor, within, fireEvent } from 'react-testing-lib-wrapper';
import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
import { ModuleStreamsTab } from '../ModuleStreamsTab/ModuleStreamsTab.js';
import mockModuleStreams from './moduleStreams.fixtures.json';
import mockBookmarkData from './bookmarks.fixtures.json';
import { MODULE_STREAMS_KEY } from '../../../../../scenes/ModuleStreams/ModuleStreamsConstants';
import { foremanApi } from '../../../../../services/api';
jest.mock('../../hostDetailsHelpers', () => ({
...jest.requireActual('../../hostDetailsHelpers'),
userPermissionsFromHostDetails: () => ({
create_job_invocations: true,
}),
}));
const moduleBookmarks = foremanApi.getApiUrl('/bookmarks?search=controller%3Dkatello_host_available_module_streams');
const contentFacetAttributes = {
id: 11,
uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e',
content_view_default: false,
lifecycle_environment_library: false,
};
const renderOptions = (facetAttributes = contentFacetAttributes) => ({
apiNamespace: MODULE_STREAMS_KEY,
initialState: {
API: {
HOST_DETAILS: {
response: {
id: 1,
name: 'test-host',
content_facet_attributes: { ...facetAttributes },
},
status: 'RESOLVED',
},
},
},
});
const hostModuleStreams = foremanApi.getApiUrl('/hosts/1/module_streams');
const autocompleteUrl = '/hosts/1/module_streams/auto_complete_search';
let firstModuleStreams;
let searchDelayScope;
let autoSearchScope;
let bookmarkScope;
beforeEach(() => {
const { results } = mockModuleStreams;
[firstModuleStreams] = results;
bookmarkScope = nockInstance.get(moduleBookmarks).reply(200, mockBookmarkData);
searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
});
afterEach(() => {
assertNockRequest(searchDelayScope);
assertNockRequest(autoSearchScope);
assertNockRequest(bookmarkScope);
});
beforeEach(() => {
const { results } = mockModuleStreams;
[firstModuleStreams] = results;
searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
});
afterEach(() => {
assertNockRequest(searchDelayScope);
assertNockRequest(autoSearchScope);
});
test('Can call API for Module streams and show on screen on page load', async (done) => {
// Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(hostModuleStreams)
.query(true)
.reply(200, mockModuleStreams);
const { getAllByText } = renderWithRedux(, renderOptions());
// Assert that the Module streams are now showing on the screen, but wait for them to appear.
await patientlyWaitFor(() =>
expect(getAllByText(firstModuleStreams.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
act(done);
});
test('Can handle no Module streams 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(hostModuleStreams)
.query(true)
.reply(200, noResults);
const { queryByText } = renderWithRedux(, renderOptions());
// Assert that there are not any Module streams showing on the screen.
await patientlyWaitFor(() => expect(queryByText('This host does not have any Module streams.')).toBeInTheDocument());
// Assert request was made and completed, see helper function
assertNockRequest(autocompleteScope);
assertNockRequest(scope, done); // Pass jest callback to confirm test is done
act(done);
});
test('Can filter results based on status', async (done) => {
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(hostModuleStreams)
.query(true)
.reply(200, mockModuleStreams);
const scope2 = nockInstance
.get(hostModuleStreams)
.query(true)
.reply(200, mockModuleStreams);
const {
queryByLabelText,
getByRole,
getAllByText,
} = renderWithRedux(, renderOptions());
// Assert that the Module streams are now showing on the screen, but wait for them to appear.
await patientlyWaitFor(() =>
expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
const typeContainer = queryByLabelText('select Status container', { ignore: 'th' });
const typeDropdown = within(typeContainer).queryByText('Status');
expect(typeDropdown).toBeInTheDocument();
fireEvent.click(typeDropdown);
const installed = getByRole('option', { name: 'select Installed' });
fireEvent.click(installed);
assertNockRequest(autocompleteScope);
assertNockRequest(scope);
assertNockRequest(scope2, done);
act(done);
});
test('Can filter results based on Installation status', async (done) => {
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(hostModuleStreams)
.query(true)
.reply(200, mockModuleStreams);
const scope2 = nockInstance
.get(hostModuleStreams)
.query(true)
.reply(200, mockModuleStreams);
const {
queryByLabelText,
getByRole,
getAllByText,
} = renderWithRedux(, renderOptions());
// Assert that the Module streams are now showing on the screen, but wait for them to appear.
await patientlyWaitFor(() =>
expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
const typeContainer = queryByLabelText('select Installation status container', { ignore: 'th' });
const typeDropdown = within(typeContainer).queryByText('Installation status');
expect(typeDropdown).toBeInTheDocument();
fireEvent.click(typeDropdown);
const installed = getByRole('option', { name: 'select Upgradable' });
fireEvent.click(installed);
assertNockRequest(autocompleteScope);
assertNockRequest(scope);
assertNockRequest(scope2, done);
act(done);
});
test('Can provide dropdown actions with redirects on Module Streams with customized Rex', async (done) => {
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(hostModuleStreams)
.query(true)
.reply(200, mockModuleStreams);
const {
queryByLabelText,
getByText,
getAllByText,
getByLabelText,
} = renderWithRedux(, renderOptions());
// Assert that the Module streams are now showing on the screen, but wait for them to appear.
await patientlyWaitFor(() =>
expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
expect(queryByLabelText('kebab-dropdown-3')).toBeInTheDocument();
fireEvent.click(queryByLabelText('kebab-dropdown-3'));
await patientlyWaitFor(() => expect(getByLabelText('customize-checkbox-3')).toBeInTheDocument());
fireEvent.click(getByLabelText('customize-checkbox-3'));
await patientlyWaitFor(() => expect(getByText('Enable')).toBeInTheDocument());
expect(getByText('Enable')).toHaveAttribute('href', '/job_invocations/new?feature=katello_module_stream_action&host_ids=name%20%5E%20(test-host)&inputs%5Baction%5D=enable&inputs%5Bmodule_spec%5D=walrus:2.4');
expect(getByText('Install')).toHaveAttribute('href', '/job_invocations/new?feature=katello_module_stream_action&host_ids=name%20%5E%20(test-host)&inputs%5Baction%5D=install&inputs%5Bmodule_spec%5D=walrus:2.4');
assertNockRequest(autocompleteScope);
assertNockRequest(scope, done);
act(done);
});
test('Can perform actions on Module Streams', async (done) => {
const jobInvocationURL = foremanApi.getApiUrl('/job_invocations');
const exampleRemoveAction = {
job_invocation:
{
feature: 'katello_module_stream_action',
inputs: {
action: 'remove',
module_spec: 'walrus:2.4',
},
search_query: 'name ^ (test-host)',
},
};
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(hostModuleStreams)
.query(true)
.reply(200, mockModuleStreams);
const jobScope = nockInstance
.post(jobInvocationURL, exampleRemoveAction)
.reply(200, { id: 'dummy_id', description: 'Remove action dummy response' });
const {
queryByLabelText,
getByText,
getAllByText,
getByLabelText,
} = renderWithRedux(, renderOptions());
// Assert that the Module streams are now showing on the screen, but wait for them to appear.
await patientlyWaitFor(() =>
expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
expect(queryByLabelText('kebab-dropdown-3')).toBeInTheDocument();
fireEvent.click(queryByLabelText('kebab-dropdown-3'));
await patientlyWaitFor(() => expect(getByText('Enable')).toBeInTheDocument());
fireEvent.click(getByText('Remove'));
expect(getByLabelText('confirm-module-action')).toBeInTheDocument();
fireEvent.click(getByLabelText('confirm-module-action'));
assertNockRequest(autocompleteScope);
assertNockRequest(scope);
assertNockRequest(jobScope, done);
act(done);
});