/* eslint-disable no-useless-escape */
import React from 'react';
import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
import CONTENT_VIEWS_KEY from '../ContentViewsConstants';
import ContentViewsPage from '../../ContentViews';
import api from '../../../services/api';
import nock, {
nockInstance, assertNockRequest, mockAutocomplete, mockSetting,
} from '../../../test-utils/nockWrapper';
import createBasicCVs from './basicContentViews.fixtures';
const cvIndexData = require('./contentViewList.fixtures.json');
const cvIndexPath = api.getApiUrl('/content_views');
const autocompleteUrl = '/content_views/auto_complete_search';
const renderOptions = { apiNamespace: CONTENT_VIEWS_KEY };
let firstCV;
let searchDelayScope;
let autoSearchScope;
beforeEach(() => {
const { results } = cvIndexData;
[firstCV] = results;
searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500);
autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true);
});
afterEach(() => {
nock.cleanAll();
assertNockRequest(searchDelayScope);
assertNockRequest(autoSearchScope);
});
test('Can call API for CVs and show on screen on page load', async (done) => {
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
// Mocking API call with nock so it returns the fixture data
const scope = nockInstance
.get(cvIndexPath)
.query(true)
.reply(200, cvIndexData);
// Using a custom rendering function that sets up both redux and react-router.
// This allows us to use the component as it is normally used
const { queryByText } = renderWithRedux(, renderOptions);
// query* functions will return the element or null if it cannot be found
// get* functions will return the element or throw an error if it cannot be found
// Assert that the CV is not showing yet by searching by name and the query returning null
expect(queryByText(firstCV.name)).toBeNull();
// Assert that the CV name is now showing on the screen, but wait for it to appear.
await patientlyWaitFor(() => expect(queryByText(firstCV.name)).toBeTruthy());
// 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 Content Views being present', async (done) => {
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
const noResults = {
total: 0,
subtotal: 0,
page: 1,
per_page: 20,
results: [],
};
const scope = nockInstance
.get(cvIndexPath)
.query(true)
.reply(200, noResults);
const { queryByText } = renderWithRedux(, renderOptions);
expect(queryByText(firstCV.name)).toBeNull();
await patientlyWaitFor(() => expect(queryByText(/don't have any Content Views/i)).toBeTruthy());
assertNockRequest(autocompleteScope);
assertNockRequest(scope, done);
});
test('Can handle errored response', async (done) => {
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(cvIndexPath)
.query(true)
.reply(500);
const { queryByText } = renderWithRedux(, renderOptions);
expect(queryByText(firstCV.name)).toBeNull();
await patientlyWaitFor(() => expect(queryByText(/unable to connect/i)).toBeTruthy());
assertNockRequest(autocompleteScope);
assertNockRequest(scope, done);
});
test('Can handle loading state while request is being made', async (done) => {
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(cvIndexPath)
.delay(2000) // Delay the response so we can check loading state properly
.query(true)
.reply(200);
const { queryByText } = renderWithRedux(, renderOptions);
expect(queryByText('Loading')).toBeTruthy();
assertNockRequest(autocompleteScope);
assertNockRequest(scope, done);
});
test('Can handle unpublished Content Views', async (done) => {
const { results } = cvIndexData;
const unpublishedCVs = results.map(cv => ({ ...cv, last_published: null }));
const unpublishedCVData = { ...cvIndexData, results: unpublishedCVs };
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
const scope = nockInstance
.get(cvIndexPath)
.query(true)
.reply(200, unpublishedCVData);
const { getAllByText } = renderWithRedux(, renderOptions);
await patientlyWaitFor(() => expect(getAllByText(/not yet published/i).length).toBeGreaterThan(0));
assertNockRequest(autocompleteScope);
assertNockRequest(scope, done);
});
test('Can handle pagination', async (done) => {
const cvIndexLarge = createBasicCVs(100);
const { results } = cvIndexLarge;
const cvIndexFirstPage = { ...cvIndexLarge, ...{ results: results.slice(0, 20) } };
const cvIndexSecondPage = { ...cvIndexLarge, page: 2, results: results.slice(20, 40) };
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
// Match first page API request
const firstPageScope = nockInstance
.get(cvIndexPath)
// Using a custom query params matcher because parameters can be strings
.query(actualQueryObject => parseInt(actualQueryObject.page, 10) === 1)
.reply(200, cvIndexFirstPage);
// Match second page API request
const secondPageScope = nockInstance
.get(cvIndexPath)
// Using a custom query params matcher because parameters can be strings
.query(actualQueryObject => parseInt(actualQueryObject.page, 10) === 2)
.reply(200, cvIndexSecondPage);
const { queryByText, getByLabelText } = renderWithRedux(, renderOptions);
// Wait for first paginated page to load and assert only the first page of results are present
await patientlyWaitFor(() => {
expect(queryByText(results[0].name)).toBeInTheDocument();
expect(queryByText(results[19].name)).toBeInTheDocument();
expect(queryByText(results[21].name)).not.toBeInTheDocument();
});
// Label comes from patternfly, if this test fails, check if patternfly updated the label.
expect(getByLabelText('Go to next page')).toBeTruthy();
getByLabelText('Go to next page').click();
// Wait for second paginated page to load and assert only the second page of results are present
await patientlyWaitFor(() => {
expect(queryByText(results[20].name)).toBeInTheDocument();
expect(queryByText(results[39].name)).toBeInTheDocument();
expect(queryByText(results[41].name)).not.toBeInTheDocument();
});
assertNockRequest(autocompleteScope);
assertNockRequest(firstPageScope);
assertNockRequest(secondPageScope, done); // Only pass jest callback to the last API request
});
test('Can search for specific Content View', async (done) => {
const cvname = 'composite one';
const { results } = cvIndexData;
const matchQuery = actualParams => actualParams?.search?.includes(cvname);
const searchResults = {
...cvIndexData,
...{ total: 1, subtotal: 1, results: results.slice(-1) },
};
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
const withSearchScope = mockAutocomplete(nockInstance, autocompleteUrl, matchQuery);
const initialScope = nockInstance
.get(cvIndexPath)
.query(true)
.reply(200, cvIndexData);
const searchResultScope = nockInstance
.get(cvIndexPath)
.query(matchQuery)
.reply(200, searchResults);
const {
getByLabelText,
getByText,
queryByText,
} = renderWithRedux(, renderOptions);
await patientlyWaitFor(() => expect(getByText(firstCV.name)).toBeInTheDocument());
const searchInput = getByLabelText(/text input for search/i);
expect(searchInput).toBeInTheDocument();
fireEvent.change(searchInput, { target: { value: `name = \"${cvname}\"` } });
await patientlyWaitFor(() => {
expect(getByText(cvname)).toBeInTheDocument();
expect(queryByText(firstCV.name)).not.toBeInTheDocument();
});
assertNockRequest(autocompleteScope);
assertNockRequest(initialScope);
assertNockRequest(withSearchScope);
assertNockRequest(searchResultScope, done);
});
test('No results message is shown for empty search', async (done) => {
const cvname = 'notanactualname';
const query = `name = \"${cvname}\"`;
const matchQuery = actualParams => actualParams?.search?.includes(cvname);
const emptyResults = {
total: 1, subtotal: 1, page: 1, per_page: 20, search: query, results: [],
};
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
const withSearchScope = mockAutocomplete(nockInstance, autocompleteUrl, matchQuery);
const initialScope = nockInstance
.get(cvIndexPath)
.query(true)
.reply(200, cvIndexData);
const searchResultScope = nockInstance
.get(cvIndexPath)
.query(matchQuery)
.reply(200, emptyResults);
const { getByLabelText, getByText } = renderWithRedux(, renderOptions);
await patientlyWaitFor(() => expect(getByText(firstCV.name)).toBeInTheDocument());
fireEvent.change(getByLabelText(/text input for search/i), { target: { value: query } });
await patientlyWaitFor(() => expect(getByText(/No matching Content Views found/i)).toBeInTheDocument());
assertNockRequest(autocompleteScope);
assertNockRequest(initialScope);
assertNockRequest(withSearchScope);
assertNockRequest(searchResultScope, done);
});
/* eslint-enable no-useless-escape */