Testing: Use React Testing Library (#27072)

* Add RTL

* Add setupTests.ts

* Refactor DashboardSearch tests
This commit is contained in:
Alex Khomenko 2020-08-20 16:21:42 +03:00 committed by GitHub
parent 3504009914
commit 6b2d44416d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 190 additions and 66 deletions

View File

@ -12,6 +12,7 @@ module.exports = {
testRegex: '(\\.|/)(test)\\.(jsx?|tsx?)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
setupFiles: ['jest-canvas-mock', './public/test/jest-shim.ts', './public/test/jest-setup.ts'],
setupFilesAfterEnv: ['./public/test/setupTests.ts'],
snapshotSerializers: ['enzyme-to-json/serializer'],
globals: { 'ts-jest': { isolatedModules: true } },
moduleNameMapper: {

View File

@ -75,6 +75,8 @@
"@grafana/eslint-config": "2.0.0",
"@microsoft/api-extractor": "7.8.2-pr1796.0",
"@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1",
"@testing-library/jest-dom": "^5.11.3",
"@testing-library/react": "^10.4.8",
"@testing-library/react-hooks": "^3.2.1",
"@types/angular": "1.6.56",
"@types/angular-route": "1.7.0",
@ -112,6 +114,7 @@
"@types/slate": "0.47.1",
"@types/slate-plain-serializer": "0.6.1",
"@types/slate-react": "0.22.5",
"@types/testing-library__jest-dom": "^5.9.2",
"@types/testing-library__react-hooks": "^3.2.0",
"@types/tinycolor2": "1.4.2",
"@typescript-eslint/eslint-plugin": "3.6.0",

View File

@ -93,7 +93,7 @@ export const TagFilter: FC<Props> = ({
};
return (
<div className={styles.tagFilter}>
<div className={styles.tagFilter} aria-label="Tag filter">
{isClearable && tags.length > 0 && (
<span className={styles.clear} onClick={() => onTagChange([])}>
Clear tags

View File

@ -1,6 +1,5 @@
import React from 'react';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
import { render, fireEvent, screen, waitFor, act } from '@testing-library/react';
import { mockSearch } from './mocks';
import { DashboardSearch, Props } from './DashboardSearch';
import { searchResults } from '../testData';
@ -15,18 +14,13 @@ afterEach(() => {
jest.useRealTimers();
});
const setup = async (testProps?: Partial<Props>): Promise<any> => {
const setup = (testProps?: Partial<Props>) => {
const props: any = {
onCloseSearch: () => {},
...testProps,
};
let wrapper;
//@ts-ignore
await act(async () => {
wrapper = await mount(<DashboardSearch {...props} />);
jest.runAllTimers();
});
return wrapper;
render(<DashboardSearch {...props} />);
jest.runAllTimers();
};
/**
@ -35,7 +29,9 @@ const setup = async (testProps?: Partial<Props>): Promise<any> => {
*/
describe('DashboardSearch', () => {
it('should call search api with default query when initialised', async () => {
await setup();
setup();
await waitFor(() => screen.getByPlaceholderText('Search dashboards by name'));
expect(mockSearch).toHaveBeenCalledTimes(1);
expect(mockSearch).toHaveBeenCalledWith({
@ -51,19 +47,13 @@ describe('DashboardSearch', () => {
});
it('should call api with updated query on query change', async () => {
let wrapper = await setup();
//@ts-ignore
await act(async () => {
// @ts-ignore
await wrapper
.find({ placeholder: 'Search dashboards by name' })
.hostNodes()
//@ts-ignore
.prop('onChange')({ currentTarget: { value: 'Test' } });
setup();
const input = await screen.findByPlaceholderText('Search dashboards by name');
await act((async () => {
await fireEvent.input(input, { target: { value: 'Test' } });
jest.runAllTimers();
});
}) as any);
expect(mockSearch).toHaveBeenCalledWith({
query: 'Test',
@ -78,58 +68,61 @@ describe('DashboardSearch', () => {
});
it("should render 'No results' message when there are no dashboards", async () => {
let wrapper = await setup();
setup();
wrapper.update();
expect(
wrapper
.findWhere((c: any) => c.type() === 'div' && c.text() === 'No dashboards matching your query were found.')
.exists()
).toBe(true);
const message = await screen.findByText('No dashboards matching your query were found.');
expect(message).toBeInTheDocument();
});
it('should render search results', async () => {
//@ts-ignore
mockSearch.mockImplementation(() => Promise.resolve(searchResults));
let wrapper = await setup();
wrapper.update();
expect(wrapper.find({ 'aria-label': 'Search section' })).toHaveLength(2);
expect(wrapper.find({ 'aria-label': 'Search items' }).children()).toHaveLength(2);
mockSearch.mockResolvedValueOnce(searchResults);
setup();
const section = await screen.findAllByLabelText('Search section');
expect(section).toHaveLength(2);
expect(screen.getAllByLabelText('Search items')).toHaveLength(2);
});
it('should call search with selected tags', async () => {
let wrapper = await setup();
setup();
//@ts-ignore
await act(async () => {
//@ts-ignore
await wrapper.find('TagFilter').prop('onChange')(['TestTag']);
jest.runAllTimers();
});
await waitFor(() => screen.getByLabelText('Tag filter'));
// Get the actual element for the underlying Select component, since Select doesn't accept aria- props
const tagComponent = screen.getByLabelText('Tag filter').querySelector('div') as Node;
fireEvent.keyDown(tagComponent, { keyCode: 40 });
expect(mockSearch).toHaveBeenCalledWith({
query: '',
skipRecent: false,
skipStarred: false,
tag: ['TestTag'],
starred: false,
folderIds: [],
layout: SearchLayout.Folders,
sort: undefined,
});
await waitFor(() => screen.getByText('tag1'));
fireEvent.click(screen.getByText('tag1'));
expect(tagComponent).toBeInTheDocument();
await waitFor(() =>
expect(mockSearch).toHaveBeenCalledWith({
query: '',
skipRecent: false,
skipStarred: false,
tag: ['tag1'],
starred: false,
folderIds: [],
layout: SearchLayout.Folders,
sort: undefined,
})
);
});
it('should call search api with provided search params', async () => {
const params = { query: 'test query', tag: ['tag1'], sort: { value: 'asc' } };
await setup({ params });
setup({ params });
expect(mockSearch).toHaveBeenCalledTimes(1);
expect(mockSearch).toHaveBeenCalledWith(
expect.objectContaining({
query: 'test query',
tag: ['tag1'],
sort: 'asc',
})
);
await waitFor(() => {
expect(mockSearch).toHaveBeenCalledTimes(1);
expect(mockSearch).toHaveBeenCalledWith(
expect.objectContaining({
query: 'test query',
tag: ['tag1'],
sort: 'asc',
})
);
});
});
});

View File

@ -1,12 +1,18 @@
export const mockSearch = jest.fn(() => {
export const mockSearch = jest.fn<any, any>(() => {
return Promise.resolve([]);
});
jest.mock('app/core/services/search_srv', () => {
return {
SearchSrv: jest.fn().mockImplementation(() => {
return {
search: mockSearch,
getDashboardTags: jest.fn(() => Promise.resolve(['Tag1', 'Tag2'])),
getDashboardTags: jest.fn(() =>
Promise.resolve([
{ term: 'tag1', count: 2 },
{ term: 'tag2', count: 10 },
])
),
getSortOptions: jest.fn(() => Promise.resolve({ sortOptions: [{ name: 'test', displayName: 'Test' }] })),
};
}),

View File

@ -0,0 +1 @@
import '@testing-library/jest-dom';

124
yarn.lock
View File

@ -2727,6 +2727,14 @@
pirates "^4.0.0"
source-map-support "^0.5.16"
"@babel/runtime-corejs3@^7.10.2":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.11.2.tgz#02c3029743150188edeb66541195f54600278419"
integrity sha512-qh5IR+8VgFz83VBa6OkaET6uN/mJOhHONuy3m1sgF0CV6mXdPSEBdA7e1eUbVvyNtANjMbg22JUv71BaDXLY6A==
dependencies:
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f"
@ -2741,6 +2749,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.9.2":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.3.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.3.tgz#0811944f73a6c926bb2ad35e918dcc1bfab279f1"
@ -5470,6 +5485,33 @@
"@svgr/plugin-svgo" "^4.3.1"
loader-utils "^1.2.3"
"@testing-library/dom@^7.17.1":
version "7.22.1"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.22.1.tgz#b66861fb7751287bda63a55f5c72ca808c63043c"
integrity sha512-bEszhvj9LcspaRz56mqGV7uc+vJTAYKCKPJcGb5X6U1qBysgTAgCexQXvKZ3BBjWu5S/TANP2NniOVsMWqKXcw==
dependencies:
"@babel/runtime" "^7.10.3"
"@types/aria-query" "^4.2.0"
aria-query "^4.2.2"
dom-accessibility-api "^0.5.0"
pretty-format "^25.5.0"
"@testing-library/jest-dom@^5.11.3":
version "5.11.3"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.3.tgz#3802cb244e9ab50559a20344698a2d41f9bf11ec"
integrity sha512-vP8ABJt4+YIzu9UItbpJ6nM5zN3g9/tpLcp2DJiXyfX9gnwgcmLsa42+YiohNGEtSUTsseb6xB9HAwlgk8WdaQ==
dependencies:
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
aria-query "^4.2.2"
chalk "^3.0.0"
css "^3.0.0"
css.escape "^1.5.1"
jest-diff "^25.1.0"
jest-matcher-utils "^25.1.0"
lodash "^4.17.15"
redent "^3.0.0"
"@testing-library/react-hooks@^3.2.1":
version "3.2.1"
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-3.2.1.tgz#19b6caa048ef15faa69d439c469033873ea01294"
@ -5478,6 +5520,14 @@
"@babel/runtime" "^7.5.4"
"@types/testing-library__react-hooks" "^3.0.0"
"@testing-library/react@^10.4.8":
version "10.4.8"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-10.4.8.tgz#5eb730291b8fd81cdb2d8877770d060b044ae4a4"
integrity sha512-clgpFR6QHiRRcdhFfAKDhH8UXpNASyfkkANhtCsCVBnai+O+mK1rGtMES+Apc7ql5Wyxu7j8dcLiC4pV5VblHA==
dependencies:
"@babel/runtime" "^7.10.3"
"@testing-library/dom" "^7.17.1"
"@torkelo/react-select@3.0.8":
version "3.0.8"
resolved "https://registry.yarnpkg.com/@torkelo/react-select/-/react-select-3.0.8.tgz#04bfc877118af425f97eac2b471b66705484ee4a"
@ -5524,6 +5574,11 @@
resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9"
integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==
"@types/aria-query@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0"
integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==
"@types/babel-types@*", "@types/babel-types@^7.0.0":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3"
@ -6673,6 +6728,13 @@
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370"
integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==
"@types/testing-library__jest-dom@^5.9.1", "@types/testing-library__jest-dom@^5.9.2":
version "5.9.2"
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.2.tgz#59e4771a1cf87d51e89a5cc8195cd3b647cba322"
integrity sha512-K7nUSpH/5i8i0NagTJ+uFUDRueDlnMNhJtMjMwTGPPSqyImbWC/hgKPDCKt6Phu2iMJg2kWqlax+Ucj2DKMwpA==
dependencies:
"@types/jest" "*"
"@types/testing-library__react-hooks@^3.0.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@types/testing-library__react-hooks/-/testing-library__react-hooks-3.1.0.tgz#04d174ce767fbcce3ccb5021d7f156e1b06008a9"
@ -7590,6 +7652,14 @@ argv-tools@^0.1.1:
array-back "^2.0.0"
find-replace "^2.0.1"
aria-query@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
dependencies:
"@babel/runtime" "^7.10.2"
"@babel/runtime-corejs3" "^7.10.2"
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@ -10095,6 +10165,11 @@ core-js-compat@^3.6.2:
browserslist "^4.8.3"
semver "7.0.0"
core-js-pure@^3.0.0:
version "3.6.5"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
core-js-pure@^3.0.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.3.2.tgz#ace92f9744ef1f6129f73ac4df4936b6df9a3cbe"
@ -10467,6 +10542,20 @@ css-what@2.1, css-what@^2.1.2:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
css.escape@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
css@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d"
integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==
dependencies:
inherits "^2.0.4"
source-map "^0.6.1"
source-map-resolve "^0.6.0"
cssdb@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0"
@ -11405,6 +11494,11 @@ doctypes@^1.1.0:
resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9"
integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=
dom-accessibility-api@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.0.tgz#fddffd04e178796e241436c3f21be2f89c91afac"
integrity sha512-eCVf9n4Ni5UQAFc2+fqfMPHdtiX7DA0rLakXgNBZfXNJzEbNo3MQIYd+zdYpFBqAaGYVrkd8leNSLGPrG4ODmA==
dom-align@^1.7.0:
version "1.10.2"
resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.10.2.tgz#540ea1c9e20462bd11b9fc28c561dc8351ece4c6"
@ -14912,7 +15006,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -16015,7 +16109,7 @@ jest-diff@^24.9.0:
jest-get-type "^24.9.0"
pretty-format "^24.9.0"
jest-diff@^25.2.1:
jest-diff@^25.1.0, jest-diff@^25.2.1, jest-diff@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9"
integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==
@ -16252,6 +16346,16 @@ jest-matcher-utils@^24.9.0:
jest-get-type "^24.9.0"
pretty-format "^24.9.0"
jest-matcher-utils@^25.1.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz#fbc98a12d730e5d2453d7f1ed4a4d948e34b7867"
integrity sha512-VWI269+9JS5cpndnpCwm7dy7JtGQT30UHfrnM3mXl22gHGt/b7NkjBqXfbhZ8V4B7ANUsjK18PlSBmG0YH7gjw==
dependencies:
chalk "^3.0.0"
jest-diff "^25.5.0"
jest-get-type "^25.2.6"
pretty-format "^25.5.0"
jest-matcher-utils@^26.0.1:
version "26.0.1"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.0.1.tgz#12e1fc386fe4f14678f4cc8dbd5ba75a58092911"
@ -22506,6 +22610,14 @@ redent@^2.0.0:
indent-string "^3.0.0"
strip-indent "^2.0.0"
redent@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
dependencies:
indent-string "^4.0.0"
strip-indent "^3.0.0"
reduce-flatten@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
@ -24166,6 +24278,14 @@ source-map-resolve@^0.5.3:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-resolve@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2"
integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==
dependencies:
atob "^2.1.2"
decode-uri-component "^0.2.0"
source-map-support@^0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.3.3.tgz#34900977d5ba3f07c7757ee72e73bb1a9b53754f"