From b9e6ed3a8aefd9d62b0cc2043213cd96ad02b54b Mon Sep 17 00:00:00 2001 From: Kristina Date: Wed, 6 Apr 2022 10:26:33 -0500 Subject: [PATCH] Convert Rich History tests to RTL (#47220) * Migrate enzyme tests to RTL * Convert rich history card tests * Fix Lint errors * Fix tests based on feedback * Fix second await --- .betterer.results | 12 - .../explore/RichHistory/RichHistory.test.tsx | 36 ++- .../RichHistory/RichHistoryCard.test.tsx | 214 ++++++++++++------ .../RichHistoryQueriesTab.test.tsx | 59 ----- .../RichHistory/RichHistorySettings.test.tsx | 23 +- 5 files changed, 166 insertions(+), 178 deletions(-) delete mode 100644 public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx diff --git a/.betterer.results b/.betterer.results index 03900ca860c..57cc3ad8dce 100644 --- a/.betterer.results +++ b/.betterer.results @@ -230,18 +230,6 @@ exports[`no enzyme tests`] = { "public/app/features/explore/LiveLogs.test.tsx:1667605379": [ [2, 17, 13, "RegExp match", "2409514259"] ], - "public/app/features/explore/RichHistory/RichHistory.test.tsx:409631018": [ - [1, 17, 13, "RegExp match", "2409514259"] - ], - "public/app/features/explore/RichHistory/RichHistoryCard.test.tsx:689438177": [ - [1, 19, 13, "RegExp match", "2409514259"] - ], - "public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx:3436519226": [ - [1, 17, 13, "RegExp match", "2409514259"] - ], - "public/app/features/explore/RichHistory/RichHistorySettings.test.tsx:538589654": [ - [1, 17, 13, "RegExp match", "2409514259"] - ], "public/app/features/explore/RichHistory/RichHistoryStarredTab.test.tsx:3948011811": [ [1, 17, 13, "RegExp match", "2409514259"] ], diff --git a/public/app/features/explore/RichHistory/RichHistory.test.tsx b/public/app/features/explore/RichHistory/RichHistory.test.tsx index 92ea6b49539..b49c35b06e2 100644 --- a/public/app/features/explore/RichHistory/RichHistory.test.tsx +++ b/public/app/features/explore/RichHistory/RichHistory.test.tsx @@ -1,9 +1,8 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { GrafanaTheme } from '@grafana/data'; import { ExploreId } from '../../../types/explore'; import { RichHistory, RichHistoryProps, Tabs } from './RichHistory'; -import { Tab } from '@grafana/ui'; jest.mock('../state/selectors', () => ({ getExploreDatasources: jest.fn() })); @@ -21,30 +20,23 @@ const setup = (propOverrides?: Partial) => { Object.assign(props, propOverrides); - const wrapper = mount(); - return wrapper; + render(); }; describe('RichHistory', () => { - it('should render all tabs in tab bar', () => { - const wrapper = setup(); - expect(wrapper.find(Tab)).toHaveLength(3); + it('should render tabs as defined', () => { + setup(); + const tabs = screen.getAllByLabelText(/Tab*/); + expect(tabs).toHaveLength(3); + expect(tabs[0]).toHaveTextContent('Query history'); + expect(tabs[1]).toHaveTextContent('Starred'); + expect(tabs[2]).toHaveTextContent('Settings'); }); - it('should render correct lebels of tabs in tab bar', () => { - const wrapper = setup(); - expect(wrapper.find(Tab).at(0).text()).toEqual('Query history'); - expect(wrapper.find(Tab).at(1).text()).toEqual('Starred'); - expect(wrapper.find(Tab).at(2).text()).toEqual('Settings'); - }); - - it('should correctly render query history tab as active tab', () => { - const wrapper = setup(); - expect(wrapper.find('RichHistoryQueriesTab')).toHaveLength(1); - }); - - it('should correctly render starred tab as active tab', () => { - const wrapper = setup({ firstTab: Tabs.Starred }); - expect(wrapper.find('RichHistoryStarredTab')).toHaveLength(1); + it('should render defined default', () => { + setup(); + const tabs = screen.getAllByLabelText(/Tab*/); + expect(tabs[0].className).toMatch(/-*activeTabStyle/); + expect(tabs[1].className).not.toMatch(/-*activeTabStyle/); }); }); diff --git a/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx b/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx index 004d5983c62..6b2a36efb64 100644 --- a/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx +++ b/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx @@ -1,10 +1,34 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { render, screen, fireEvent, getByText } from '@testing-library/react'; import { RichHistoryCard, Props } from './RichHistoryCard'; -import { ExploreId, RichHistoryQuery } from '../../../types/explore'; +import { ExploreId, RichHistoryQuery } from 'app/types/explore'; import { DataSourceApi, DataQuery } from '@grafana/data'; +import { mockDataSource } from 'app/features/alerting/unified/mocks'; +import { DataSourceType } from 'app/features/alerting/unified/utils/datasource'; +import { ShowConfirmModalEvent } from 'app/types/events'; +import appEvents from 'app/core/app_events'; const starRichHistoryMock = jest.fn(); +const deleteRichHistoryMock = jest.fn(); + +const mockDS = mockDataSource({ + name: 'CloudManager', + type: DataSourceType.Alertmanager, +}); + +jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => { + return { + getDataSourceSrv: () => ({ + get: () => Promise.resolve(mockDS), + getList: () => [mockDS], + getInstanceSettings: () => mockDS, + }), + }; +}); + +jest.mock('app/core/app_events', () => ({ + publish: jest.fn(), +})); interface MockQuery extends DataQuery { query: string; @@ -29,8 +53,8 @@ const setup = (propOverrides?: Partial>) => { isRemoved: false, changeDatasource: jest.fn(), starHistoryItem: starRichHistoryMock, + deleteHistoryItem: deleteRichHistoryMock, commentHistoryItem: jest.fn(), - deleteHistoryItem: jest.fn(), setQueries: jest.fn(), exploreId: ExploreId.left, datasourceInstance: { name: 'Datasource' } as DataSourceApi, @@ -38,8 +62,7 @@ const setup = (propOverrides?: Partial>) => { Object.assign(props, propOverrides); - const wrapper = shallow(); - return wrapper; + render(); }; const starredQueryWithComment: RichHistoryQuery = { @@ -56,93 +79,140 @@ const starredQueryWithComment: RichHistoryQuery = { ], }; +afterEach(() => { + jest.clearAllMocks(); +}); + describe('RichHistoryCard', () => { - it('should render all queries', () => { - const wrapper = setup(); - expect(wrapper.find({ 'aria-label': 'Query text' })).toHaveLength(3); - expect(wrapper.find({ 'aria-label': 'Query text' }).at(0).text()).toEqual('{"query":"query1"}'); - expect(wrapper.find({ 'aria-label': 'Query text' }).at(1).text()).toEqual('{"query":"query2"}'); - expect(wrapper.find({ 'aria-label': 'Query text' }).at(2).text()).toEqual('{"query":"query3"}'); + it('should render all queries', async () => { + setup(); + const queries = await screen.findAllByLabelText('Query text'); + expect(queries).toHaveLength(3); + expect(queries[0]).toHaveTextContent('query1'); + expect(queries[1]).toHaveTextContent('query2'); + expect(queries[2]).toHaveTextContent('query3'); }); - it('should render data source icon', () => { - const wrapper = setup(); - expect(wrapper.find({ 'aria-label': 'Data source icon' })).toHaveLength(1); + it('should render data source icon and name', async () => { + setup(); + const datasourceIcon = await screen.findByLabelText('Data source icon'); + const datasourceName = screen.getByLabelText('Data source name'); + expect(datasourceIcon).toBeInTheDocument(); + expect(datasourceName).toBeInTheDocument(); }); - it('should render data source name', () => { - const wrapper = setup(); - expect(wrapper.find({ 'aria-label': 'Data source name' }).text()).toEqual('Test datasource'); - }); - it('should render "Data source does not exist anymore" if removed data source', () => { - const wrapper = setup({ isRemoved: true }); - expect(wrapper.find({ 'aria-label': 'Data source name' }).text()).toEqual('Data source does not exist anymore'); + it('should render "Data source does not exist anymore" if removed data source', async () => { + setup({ isRemoved: true }); + const datasourceName = await screen.findByLabelText('Data source name'); + expect(datasourceName).toHaveTextContent('Data source does not exist anymore'); }); describe('commenting', () => { - it('should render comment, if comment present', () => { - const wrapper = setup({ query: starredQueryWithComment }); - expect(wrapper.find({ 'aria-label': 'Query comment' })).toHaveLength(1); - expect(wrapper.find({ 'aria-label': 'Query comment' }).text()).toEqual('test comment'); + it('should render comment, if comment present', async () => { + setup({ query: starredQueryWithComment }); + const queryComment = await screen.findByLabelText('Query comment'); + expect(queryComment).toBeInTheDocument(); + expect(queryComment).toHaveTextContent('test comment'); }); - it('should have title "Edit comment" at comment icon, if comment present', () => { - const wrapper = setup({ query: starredQueryWithComment }); - expect(wrapper.find({ title: 'Edit comment' })).toHaveLength(1); - expect(wrapper.find({ title: 'Add comment' })).toHaveLength(0); + it('should have title "Edit comment" at comment icon, if comment present', async () => { + setup({ query: starredQueryWithComment }); + const editComment = await screen.findByTitle('Edit comment'); + const addComment = screen.queryByTitle('Add comment'); + expect(editComment).toBeInTheDocument(); + expect(addComment).not.toBeInTheDocument(); }); - it('should have title "Add comment" at comment icon, if no comment present', () => { - const wrapper = setup(); - expect(wrapper.find({ title: 'Add comment' })).toHaveLength(1); - expect(wrapper.find({ title: 'Edit comment' })).toHaveLength(0); + it('should have title "Add comment" at comment icon, if no comment present', async () => { + setup(); + const addComment = await screen.findByTitle('Add comment'); + const editComment = await screen.queryByTitle('Edit comment'); + expect(addComment).toBeInTheDocument(); + expect(editComment).not.toBeInTheDocument(); }); - it('should open update comment form when edit comment button clicked', () => { - const wrapper = setup({ query: starredQueryWithComment }); - const editCommentButton = wrapper.find({ title: 'Edit comment' }); - editCommentButton.simulate('click'); - expect(wrapper.find({ 'aria-label': 'Update comment form' })).toHaveLength(1); + it('should open update comment form when edit comment button clicked', async () => { + setup({ query: starredQueryWithComment }); + const editComment = await screen.findByTitle('Edit comment'); + fireEvent.click(editComment); + const updateCommentForm = await screen.findByLabelText('Update comment form'); + expect(updateCommentForm).toBeInTheDocument(); }); - it('should close update comment form when escape key pressed', () => { - const wrapper = setup({ query: starredQueryWithComment }); - const editCommentButton = wrapper.find({ title: 'Edit comment' }); - editCommentButton.simulate('click'); - wrapper.simulate('keydown', { key: 'Escape' }); - expect(wrapper.find({ 'aria-label': 'Update comment form' })).toHaveLength(0); + it('should close update comment form when escape key pressed', async () => { + setup({ query: starredQueryWithComment }); + const editComment = await screen.findByTitle('Edit comment'); + fireEvent.click(editComment); + const updateCommentForm = await screen.findByLabelText('Update comment form'); + fireEvent.keyDown(getByText(updateCommentForm, starredQueryWithComment.comment), { + key: 'Escape', + }); + const findCommentForm = screen.queryByLabelText('Update comment form'); + expect(findCommentForm).not.toBeInTheDocument(); }); - it('should close update comment form when enter and shift keys pressed', () => { - const wrapper = setup({ query: starredQueryWithComment }); - const editCommentButton = wrapper.find({ title: 'Edit comment' }); - editCommentButton.simulate('click'); - wrapper.simulate('keydown', { key: 'Enter', shiftKey: true }); - expect(wrapper.find({ 'aria-label': 'Update comment form' })).toHaveLength(0); + it('should close update comment form when enter and shift keys pressed', async () => { + setup({ query: starredQueryWithComment }); + const editComment = await screen.findByTitle('Edit comment'); + fireEvent.click(editComment); + const updateCommentForm = await screen.findByLabelText('Update comment form'); + fireEvent.keyDown(getByText(updateCommentForm, starredQueryWithComment.comment), { + key: 'Enter', + shiftKey: true, + }); + const findCommentForm = screen.queryByLabelText('Update comment form'); + expect(findCommentForm).not.toBeInTheDocument(); }); - it('should close update comment form when enter and ctrl keys pressed', () => { - const wrapper = setup({ query: starredQueryWithComment }); - const editCommentButton = wrapper.find({ title: 'Edit comment' }); - editCommentButton.simulate('click'); - wrapper.simulate('keydown', { key: 'Enter', ctrlKey: true }); - expect(wrapper.find({ 'aria-label': 'Update comment form' })).toHaveLength(0); + it('should close update comment form when enter and ctrl keys pressed', async () => { + setup({ query: starredQueryWithComment }); + const editComment = await screen.findByTitle('Edit comment'); + fireEvent.click(editComment); + const updateCommentForm = await screen.findByLabelText('Update comment form'); + fireEvent.keyDown(getByText(updateCommentForm, starredQueryWithComment.comment), { + key: 'Enter', + ctrlKey: true, + }); + const findCommentForm = screen.queryByLabelText('Update comment form'); + expect(findCommentForm).not.toBeInTheDocument(); }); - it('should not close update comment form when enter key pressed', () => { - const wrapper = setup({ query: starredQueryWithComment }); - const editCommentButton = wrapper.find({ title: 'Edit comment' }); - editCommentButton.simulate('click'); - wrapper.simulate('keydown', { key: 'Enter', shiftKey: false }); - expect(wrapper.find({ 'aria-label': 'Update comment form' })).toHaveLength(1); + it('should not close update comment form when enter key pressed', async () => { + setup({ query: starredQueryWithComment }); + const editComment = await screen.findByTitle('Edit comment'); + fireEvent.click(editComment); + const updateCommentForm = await screen.findByLabelText('Update comment form'); + fireEvent.keyDown(getByText(updateCommentForm, starredQueryWithComment.comment), { + key: 'Enter', + shiftKey: false, + }); + const findCommentForm = screen.queryByLabelText('Update comment form'); + expect(findCommentForm).toBeInTheDocument(); }); }); describe('starring', () => { - it('should have title "Star query", if not starred', () => { - const wrapper = setup(); - const starButton = wrapper.find({ title: 'Star query' }); - expect(starButton).toHaveLength(1); - starButton.simulate('click'); + it('should have title "Star query", if not starred', async () => { + setup(); + const starButton = await screen.findByTitle('Star query'); + expect(starButton).toBeInTheDocument(); + fireEvent.click(starButton); expect(starRichHistoryMock).toBeCalledWith(starredQueryWithComment.id, true); }); - it('should have title "Unstar query", if not starred', () => { - const wrapper = setup({ query: starredQueryWithComment }); - const starButton = wrapper.find({ title: 'Unstar query' }); - expect(starButton).toHaveLength(1); - starButton.simulate('click'); + it('should have title "Unstar query", if not starred', async () => { + setup({ query: starredQueryWithComment }); + const unstarButton = await screen.findByTitle('Unstar query'); + expect(unstarButton).toBeInTheDocument(); + fireEvent.click(unstarButton); expect(starRichHistoryMock).toBeCalledWith(starredQueryWithComment.id, false); }); }); + + describe('deleting', () => { + it('should delete if not starred', async () => { + setup(); + const deleteButton = await screen.findByTitle('Delete query'); + expect(deleteButton).toBeInTheDocument(); + fireEvent.click(deleteButton); + expect(deleteRichHistoryMock).toBeCalledWith(starredQueryWithComment.id); + }); + it('should display modal before deleting if starred', async () => { + setup({ query: starredQueryWithComment }); + const deleteButton = await screen.findByTitle('Delete query'); + fireEvent.click(deleteButton); + expect(deleteRichHistoryMock).not.toBeCalled(); + expect(appEvents.publish).toHaveBeenCalledWith(new ShowConfirmModalEvent(expect.anything())); + }); + }); }); diff --git a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx deleted file mode 100644 index 03debfddf6d..00000000000 --- a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import { ExploreId } from '../../../types/explore'; -import { SortOrder } from 'app/core/utils/richHistory'; -import { RichHistoryQueriesTab, Props } from './RichHistoryQueriesTab'; -import { RangeSlider } from '@grafana/ui'; - -jest.mock('../state/selectors', () => ({ getExploreDatasources: jest.fn() })); - -const setup = (propOverrides?: Partial) => { - const props: Props = { - queries: [], - sortOrder: SortOrder.Ascending, - activeDatasourceOnly: false, - datasourceFilters: [], - retentionPeriod: 14, - height: 100, - exploreId: ExploreId.left, - onChangeSortOrder: jest.fn(), - onSelectDatasourceFilters: jest.fn(), - }; - - Object.assign(props, propOverrides); - - const wrapper = mount(); - return wrapper; -}; - -describe('RichHistoryQueriesTab', () => { - describe('slider', () => { - it('should render slider', () => { - const wrapper = setup(); - expect(wrapper.find(RangeSlider)).toHaveLength(1); - }); - it('should render slider with correct timerange', () => { - const wrapper = setup(); - expect(wrapper.find('.label-slider').at(1).text()).toEqual('today'); - expect(wrapper.find('.label-slider').at(2).text()).toEqual('two weeks ago'); - }); - }); - - describe('sort options', () => { - it('should render sorter', () => { - const wrapper = setup(); - expect(wrapper.find({ 'aria-label': 'Sort queries' })).toHaveLength(1); - }); - }); - - describe('select datasource', () => { - it('should render select datasource if activeDatasourceOnly is false', () => { - const wrapper = setup(); - expect(wrapper.find({ 'aria-label': 'Filter datasources' })).toHaveLength(1); - }); - it('should not render select datasource if activeDatasourceOnly is true', () => { - const wrapper = setup({ activeDatasourceOnly: true }); - expect(wrapper.find({ 'aria-label': 'Filter datasources' })).toHaveLength(0); - }); - }); -}); diff --git a/public/app/features/explore/RichHistory/RichHistorySettings.test.tsx b/public/app/features/explore/RichHistory/RichHistorySettings.test.tsx index 9b205049c5e..16f80c5a81b 100644 --- a/public/app/features/explore/RichHistory/RichHistorySettings.test.tsx +++ b/public/app/features/explore/RichHistory/RichHistorySettings.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { RichHistorySettings, RichHistorySettingsProps } from './RichHistorySettings'; -import { Select, Switch } from '@grafana/ui'; const setup = (propOverrides?: Partial) => { const props: RichHistorySettingsProps = { @@ -16,21 +15,19 @@ const setup = (propOverrides?: Partial) => { Object.assign(props, propOverrides); - const wrapper = mount(); - return wrapper; + return render(); }; describe('RichHistorySettings', () => { it('should render component with correct retention period', () => { - const wrapper = setup(); - expect(wrapper.find(Select).text()).toEqual('2 weeks'); + setup(); + expect(screen.queryByText('2 weeks')).toBeInTheDocument(); }); - it('should render component with correctly checked starredTabAsFirstTab settings', () => { - const wrapper = setup(); - expect(wrapper.find(Switch).at(0).prop('value')).toBe(true); - }); - it('should render component with correctly not checked toggleactiveDatasourceOnly settings', () => { - const wrapper = setup(); - expect(wrapper.find(Switch).at(1).prop('value')).toBe(false); + it('should render component with correctly checked starredTabAsFirstTab and uncheched toggleActiveDatasourceOnly settings', () => { + setup(); + const checkboxes = screen.getAllByRole('checkbox'); + expect(checkboxes.length).toBe(2); + expect(checkboxes[0]).toHaveAttribute('checked'); + expect(checkboxes[1]).not.toHaveAttribute('checked'); }); });