* Fixed unhandled rejection in <ImageUploader /> test. * Fixed <FollowUsers /> tests. * Fixed the tests for the <RequestManager /> component. * Fixed unhandled rejection in search utilities. * Added an unhandledRejection listener so tests will fail if a Promise fails. * Added a comment about why you might get an unhandled rejection exception.
271 lines
8.1 KiB
JavaScript
271 lines
8.1 KiB
JavaScript
import fetch from 'jest-fetch-mock';
|
|
import {
|
|
getInitialSearchTerm,
|
|
preloadSearchResults,
|
|
hasInstantClick,
|
|
displaySearchResults,
|
|
fetchSearch,
|
|
createSearchUrl,
|
|
} from '../search';
|
|
import '../../../assets/javascripts/lib/xss';
|
|
|
|
/* global globalThis */
|
|
|
|
describe('Search utilities', () => {
|
|
beforeAll(() => {
|
|
const csrfToken = 'this-is-a-csrf-token';
|
|
|
|
globalThis.fetch = fetch;
|
|
globalThis.getCsrfToken = async () => csrfToken;
|
|
});
|
|
afterAll(() => {
|
|
delete globalThis.fetch;
|
|
delete globalThis.getCsrfToken;
|
|
});
|
|
|
|
describe('getInitialSearchTerm', () => {
|
|
describe(`When the querystring key 'q' has a value`, () => {
|
|
it(`should return the querystring key q's value`, () => {
|
|
const expected = 'hello';
|
|
const querystring = `?q=${expected}`;
|
|
const actual = getInitialSearchTerm(querystring);
|
|
expect(actual).toEqual(expected);
|
|
});
|
|
});
|
|
|
|
describe(`When the querystring key 'q' has a + character representing a space`, () => {
|
|
it(`should return the querystring key q's decoded value with + characters replaced by a space`, () => {
|
|
const expected = `my visual studio setup`;
|
|
const querystring = `?q=my+visual+studio+setup`;
|
|
const actual = getInitialSearchTerm(querystring);
|
|
expect(actual).toEqual(expected);
|
|
});
|
|
});
|
|
|
|
describe(`When the querystring key 'q' has an encoded value with markup`, () => {
|
|
it(`should return the querystring key q's decoded value`, () => {
|
|
const expected = `<script>alert('XSS!');</script>`;
|
|
const querystring = `?q=<script>alert(%27XSS!%27);</script>`;
|
|
const actual = getInitialSearchTerm(querystring);
|
|
expect(actual).toEqual(expected);
|
|
});
|
|
});
|
|
|
|
describe(`When the querystring key 'q' has no value`, () => {
|
|
it(`should return an empty string`, () => {
|
|
const expected = '';
|
|
const querystring = `?q=`;
|
|
const actual = getInitialSearchTerm(querystring);
|
|
expect(actual).toEqual(expected);
|
|
});
|
|
|
|
it(`should return an empty string when the search term is not defined`, () => {
|
|
/* eslint-disable-next-line no-global-assign */
|
|
filterXSS = jest.fn(() => undefined);
|
|
const querystring = `?q=`;
|
|
|
|
const actual = getInitialSearchTerm(querystring);
|
|
expect(actual).toEqual('');
|
|
});
|
|
});
|
|
|
|
describe(`When the querystring key 'q' does not exist`, () => {
|
|
it(`should return an empty string`, () => {
|
|
const expected = '';
|
|
const querystring = '?';
|
|
const actual = getInitialSearchTerm(querystring);
|
|
expect(actual).toEqual(expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('preloadSearchResults', () => {
|
|
beforeEach(() => {
|
|
global.InstantClick = {
|
|
preload: (url) => url,
|
|
};
|
|
jest.spyOn(InstantClick, 'preload');
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
delete global.InstantClick;
|
|
});
|
|
|
|
it('should call InstantClick.preLoad', () => {
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
href: 'http://localhost',
|
|
};
|
|
preloadSearchResults({
|
|
location,
|
|
searchTerm: 'hello',
|
|
});
|
|
|
|
expect(InstantClick.preload).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
describe('When a search term is passed in', () => {
|
|
it('should call InstantClick.preLoad with the search term value in the URL', () => {
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
href: 'http://localhost',
|
|
};
|
|
const searchTerm = 'hello';
|
|
const expected = `${location.origin}/search?q=${searchTerm}`;
|
|
|
|
preloadSearchResults({ searchTerm, location });
|
|
|
|
expect(InstantClick.preload).toBeCalledWith(expected);
|
|
});
|
|
|
|
it('should call InstantClick.preLoad with the encoded value for the search term', () => {
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
href: 'http://localhost',
|
|
};
|
|
|
|
const searchTerm = 'hello+everybody!';
|
|
const expected = `${location.origin}/search?q=hello%2Beverybody%21`;
|
|
|
|
preloadSearchResults({ searchTerm, location });
|
|
|
|
expect(InstantClick.preload).toBeCalledWith(expected);
|
|
});
|
|
|
|
it('should call InstantClick.preLoad if the search term is empty', () => {
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
href: 'http://localhost',
|
|
};
|
|
const searchTerm = '';
|
|
|
|
preloadSearchResults({ searchTerm, location });
|
|
|
|
expect(InstantClick.preload).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('hasInstantClick', () => {
|
|
describe('When instant click exists', () => {
|
|
it('should return true', () => {
|
|
global.instantClick = {};
|
|
expect(hasInstantClick()).toEqual(true);
|
|
delete global.instantClick;
|
|
});
|
|
});
|
|
|
|
describe('When instant click does not exist', () => {
|
|
it('should return false', () => {
|
|
expect(hasInstantClick()).toEqual(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('displaySearchResults', () => {
|
|
beforeEach(() => {
|
|
global.InstantClick = {
|
|
display: (url) => url,
|
|
};
|
|
jest.spyOn(InstantClick, 'display');
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
delete global.InstantClick;
|
|
});
|
|
|
|
it('should call InstantClick.display if search term is empty', () => {
|
|
displaySearchResults({ searchTerm: '', location: { href: '' } });
|
|
|
|
expect(InstantClick.display).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should call InstantClick.display once', () => {
|
|
displaySearchResults({ searchTerm: 'hello', location: { href: '' } });
|
|
|
|
expect(InstantClick.display).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should call InstantClick.display with the correct search URL', () => {
|
|
const searchTerm = 'hello';
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
};
|
|
|
|
displaySearchResults({ searchTerm, location });
|
|
|
|
expect(InstantClick.display).toBeCalledWith(
|
|
`${location.origin}/search?q=${searchTerm}`,
|
|
);
|
|
});
|
|
|
|
it('should call InstantClick.display with an encoded search term', () => {
|
|
const searchTerm = '#hello%';
|
|
const sanitizedSearchTerm = '%23hello%25';
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
};
|
|
|
|
displaySearchResults({ searchTerm, location });
|
|
|
|
expect(InstantClick.display).toBeCalledWith(
|
|
`${location.origin}/search?q=${sanitizedSearchTerm}`,
|
|
);
|
|
});
|
|
|
|
it('should call InstantClick.display with filters, if present', () => {
|
|
const searchTerm = '#hello%';
|
|
const sanitizedSearchTerm = '%23hello%25';
|
|
const filterParameters = 'class_name:Article';
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
href: `http://localhost?filters=${filterParameters}`,
|
|
};
|
|
|
|
displaySearchResults({ searchTerm, location });
|
|
|
|
expect(InstantClick.display).toBeCalledWith(
|
|
`${location.origin}/search?q=${sanitizedSearchTerm}&filters=${filterParameters}`,
|
|
);
|
|
});
|
|
|
|
it('should not call InstantClick.display with filters, if filter querystring key is present, but has no value', () => {
|
|
const searchTerm = '#hello%';
|
|
const sanitizedSearchTerm = '%23hello%25';
|
|
const location = {
|
|
origin: 'http://localhost',
|
|
href: 'http://localhost?filters=',
|
|
};
|
|
|
|
displaySearchResults({ searchTerm, location });
|
|
|
|
expect(InstantClick.display).toBeCalledWith(
|
|
`${location.origin}/search?q=${sanitizedSearchTerm}`,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('fetchSearch', () => {
|
|
it('should return response formatted as JSON', async () => {
|
|
const expected = { results: [] };
|
|
|
|
fetch.mockResponse(JSON.stringify({ results: [] }));
|
|
|
|
const response = await fetchSearch('tags', { name: 'jav' });
|
|
|
|
expect(response).toBeInstanceOf(Object);
|
|
expect(response).toMatchObject(expected);
|
|
});
|
|
});
|
|
|
|
describe('createSearchUrl', () => {
|
|
it('should return a url string', () => {
|
|
const dataHash = { name: 'jav', tags: ['one', 'two'] };
|
|
const responseString = createSearchUrl(dataHash);
|
|
|
|
expect(responseString).toEqual('name=jav&tags%5B%5D=one&tags%5B%5D=two');
|
|
});
|
|
});
|
|
});
|