diff --git a/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.tsx b/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.tsx index 4be4c995452c5..d10d926b11131 100644 --- a/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.tsx +++ b/superset-frontend/src/SqlLab/components/QueryTable/QueryTable.test.tsx @@ -19,12 +19,10 @@ import { isValidElement } from 'react'; import thunk from 'redux-thunk'; import configureStore from 'redux-mock-store'; -import { styledMount as mount } from 'spec/helpers/theming'; import QueryTable from 'src/SqlLab/components/QueryTable'; -import TableView from 'src/components/TableView'; -import TableCollection from 'src/components/TableCollection'; import { Provider } from 'react-redux'; import { runningQuery, successfulQuery, user } from 'src/SqlLab/fixtures'; +import { render, screen } from 'spec/helpers/testing-library'; const mockedProps = { queries: [runningQuery, successfulQuery], @@ -43,15 +41,15 @@ test('renders a proper table', () => { user, }); - const wrapper = mount( + const { container } = render( , ); - const tableWrapper = wrapper.find(TableView).find(TableCollection); - expect(wrapper.find(TableView)).toExist(); - expect(tableWrapper.find('table')).toExist(); - expect(tableWrapper.find('table').find('thead').find('tr')).toHaveLength(1); - expect(tableWrapper.find('table').find('tbody').find('tr')).toHaveLength(2); + expect(screen.getByTestId('listview-table')).toBeVisible(); // Presence of TableCollection + expect(screen.getByRole('table')).toBeVisible(); + expect(container.querySelector('.table-condensed')).toBeVisible(); // Presence of TableView signature class + expect(container.querySelectorAll('table > thead > tr')).toHaveLength(1); + expect(container.querySelectorAll('table > tbody > tr')).toHaveLength(2); }); diff --git a/superset-frontend/src/components/ListViewCard/ImageLoader.test.jsx b/superset-frontend/src/components/ListViewCard/ImageLoader.test.tsx similarity index 65% rename from superset-frontend/src/components/ListViewCard/ImageLoader.test.jsx rename to superset-frontend/src/components/ListViewCard/ImageLoader.test.tsx index cdb03caa55288..2449b838f28a0 100644 --- a/superset-frontend/src/components/ListViewCard/ImageLoader.test.jsx +++ b/superset-frontend/src/components/ListViewCard/ImageLoader.test.tsx @@ -16,11 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { styledMount as mount } from 'spec/helpers/theming'; import fetchMock from 'fetch-mock'; -import ImageLoader from 'src/components/ListViewCard/ImageLoader'; -import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; +import ImageLoader, { + BackgroundPosition, +} from 'src/components/ListViewCard/ImageLoader'; +import { render, screen } from 'spec/helpers/testing-library'; global.URL.createObjectURL = jest.fn(() => '/local_url'); const blob = new Blob([], { type: 'image/png' }); @@ -37,36 +38,46 @@ describe('ImageLoader', () => { const defaultProps = { src: '/thumbnail', fallback: '/fallback', + position: 'top' as BackgroundPosition, }; - const factory = (extraProps = {}) => { + const setup = (extraProps = {}) => { const props = { ...defaultProps, ...extraProps }; - return mount(); + return render(); }; - afterEach(fetchMock.resetHistory); + afterEach(() => fetchMock.resetHistory()); it('is a valid element', async () => { - const wrapper = factory(); - await waitForComponentToPaint(wrapper); - expect(wrapper.find(ImageLoader)).toExist(); + setup(); + expect(await screen.findByTestId('image-loader')).toBeVisible(); }); it('fetches loads the image in the background', async () => { - const wrapper = factory(); - expect(wrapper.find('div').props().src).toBe('/fallback'); - await waitForComponentToPaint(wrapper); + setup(); + expect(screen.getByTestId('image-loader')).toHaveAttribute( + 'src', + '/fallback', + ); expect(fetchMock.calls(/thumbnail/)).toHaveLength(1); expect(global.URL.createObjectURL).toHaveBeenCalled(); - expect(wrapper.find('div').props().src).toBe('/local_url'); + expect(await screen.findByTestId('image-loader')).toHaveAttribute( + 'src', + '/local_url', + ); }); it('displays fallback image when response is not an image', async () => { fetchMock.once('/thumbnail2', {}); - const wrapper = factory({ src: '/thumbnail2' }); - expect(wrapper.find('div').props().src).toBe('/fallback'); - await waitForComponentToPaint(wrapper); + setup({ src: '/thumbnail2' }); + expect(screen.getByTestId('image-loader')).toHaveAttribute( + 'src', + '/fallback', + ); expect(fetchMock.calls(/thumbnail2/)).toHaveLength(1); - expect(wrapper.find('div').props().src).toBe('/fallback'); + expect(await screen.findByTestId('image-loader')).toHaveAttribute( + 'src', + '/fallback', + ); }); }); diff --git a/superset-frontend/src/components/ListViewCard/ImageLoader.tsx b/superset-frontend/src/components/ListViewCard/ImageLoader.tsx index 86d115365e16f..ae4c429843129 100644 --- a/superset-frontend/src/components/ListViewCard/ImageLoader.tsx +++ b/superset-frontend/src/components/ListViewCard/ImageLoader.tsx @@ -77,6 +77,7 @@ export default function ImageLoader({ return ( '/local_url'); fetchMock.get('/thumbnail', { body: new Blob(), sendAsJson: false }); @@ -44,25 +42,22 @@ describe('ListViewCard', () => { ), }; - let wrapper; - const factory = (extraProps = {}) => { - const props = { ...defaultProps, ...extraProps }; - return mount(); - }; - beforeEach(async () => { - wrapper = factory(); - await waitForComponentToPaint(wrapper); + beforeEach(() => { + const props = { ...defaultProps }; + render(); }); it('is a valid element', () => { - expect(wrapper.find(ListViewCard)).toExist(); + expect(screen.getByTestId('styled-card')).toBeInTheDocument(); }); it('renders Actions', () => { - expect(wrapper.find(ListViewCard.Actions)).toExist(); + expect(screen.getByTestId('card-actions')).toBeVisible(); + expect(screen.getByText('Action 1')).toBeVisible(); + expect(screen.getByText('Action 2')).toBeVisible(); }); - it('renders and ImageLoader', () => { - expect(wrapper.find(ImageLoader)).toExist(); + it('renders an ImageLoader', () => { + expect(screen.getByTestId('image-loader')).toBeVisible(); }); }); diff --git a/superset-frontend/src/dashboard/components/gridComponents/Divider.test.jsx b/superset-frontend/src/dashboard/components/gridComponents/Divider.test.jsx index 02d55da08aaf9..76bd0dfb7da09 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Divider.test.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Divider.test.jsx @@ -16,20 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -import { styledMount as mount } from 'spec/helpers/theming'; import sinon from 'sinon'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; -import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; -import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; -import { Draggable } from 'src/dashboard/components/dnd/DragDroppable'; import Divider from 'src/dashboard/components/gridComponents/Divider'; import newComponentFactory from 'src/dashboard/util/newComponentFactory'; import { DIVIDER_TYPE, DASHBOARD_GRID_TYPE, } from 'src/dashboard/util/componentTypes'; +import { screen, render } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; describe('Divider', () => { const props = { @@ -44,42 +42,48 @@ describe('Divider', () => { deleteComponent() {}, }; - function setup(overrideProps) { + const setup = overrideProps => // We have to wrap provide DragDropContext for the underlying DragDroppable // otherwise we cannot assert on DragDroppable children - const wrapper = mount( + render( , + { + useDnd: true, + }, ); - return wrapper; - } it('should render a Draggable', () => { - const wrapper = setup(); - expect(wrapper.find(Draggable)).toExist(); + setup(); + expect(screen.getByTestId('dragdroppable-object')).toBeInTheDocument(); }); it('should render a div with class "dashboard-component-divider"', () => { - const wrapper = setup(); - expect(wrapper.find('.dashboard-component-divider')).toExist(); + const { container } = setup(); + expect( + container.querySelector('.dashboard-component-divider'), + ).toBeInTheDocument(); }); it('should render a HoverMenu with DeleteComponentButton in editMode', () => { - let wrapper = setup(); - expect(wrapper.find(HoverMenu)).not.toExist(); - expect(wrapper.find(DeleteComponentButton)).not.toExist(); + setup(); + expect(screen.queryByTestId('hover-menu')).not.toBeInTheDocument(); + expect(screen.queryByRole('button')).not.toBeInTheDocument(); // we cannot set props on the Divider because of the WithDragDropContext wrapper - wrapper = setup({ editMode: true }); - expect(wrapper.find(HoverMenu)).toExist(); - expect(wrapper.find(DeleteComponentButton)).toExist(); + setup({ editMode: true }); + expect(screen.getByTestId('hover-menu')).toBeInTheDocument(); + expect(screen.getByRole('button').firstChild).toHaveAttribute( + 'aria-label', + 'trash', + ); }); it('should call deleteComponent when deleted', () => { const deleteComponent = sinon.spy(); - const wrapper = setup({ editMode: true, deleteComponent }); - wrapper.find(DeleteComponentButton).simulate('click'); + setup({ editMode: true, deleteComponent }); + userEvent.click(screen.getByRole('button')); expect(deleteComponent.callCount).toBe(1); }); }); diff --git a/superset-frontend/src/explore/components/controls/ViewportControl.test.jsx b/superset-frontend/src/explore/components/controls/ViewportControl.test.jsx index 282e39f6b1ec1..b1b958d6dab89 100644 --- a/superset-frontend/src/explore/components/controls/ViewportControl.test.jsx +++ b/superset-frontend/src/explore/components/controls/ViewportControl.test.jsx @@ -16,13 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import { styledMount as mount } from 'spec/helpers/theming'; -import Popover from 'src/components/Popover'; - -import Label from 'src/components/Label'; import ViewportControl from 'src/explore/components/controls/ViewportControl'; -import TextControl from 'src/explore/components/controls/TextControl'; -import ControlHeader from 'src/explore/components/ControlHeader'; +import { render, screen } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; const defaultProps = { value: { @@ -33,29 +29,27 @@ const defaultProps = { pitch: 0, }, name: 'foo', + label: 'bar', }; +const renderedCoordinate = '6° 51\' 8.50" | 31° 13\' 21.56"'; describe('ViewportControl', () => { - let wrapper; - let inst; beforeEach(() => { - wrapper = mount(); - inst = wrapper.instance(); + render(); }); - it('renders a OverlayTrigger', () => { - const controlHeader = wrapper.find(ControlHeader); - expect(controlHeader).toHaveLength(1); - expect(wrapper.find(Popover)).toExist(); + it('renders a OverlayTrigger if clicked', () => { + expect(screen.getByTestId('foo-header')).toBeInTheDocument(); // Presence of ControlHeader + userEvent.click(screen.getByText(renderedCoordinate)); + expect(screen.getByText('Viewport')).toBeInTheDocument(); // Presence of Popover }); - it('renders a Popover with 5 TextControl', () => { - const popOver = mount(inst.renderPopover()); - expect(popOver.find(TextControl)).toHaveLength(5); + it('renders a Popover with 5 TextControl if clicked', () => { + userEvent.click(screen.getByText(renderedCoordinate)); + expect(screen.queryAllByTestId('inline-name')).toHaveLength(5); }); it('renders a summary in the label', () => { - const label = wrapper.find(Label).first(); - expect(label.render().text()).toBe('6° 51\' 8.50" | 31° 13\' 21.56"'); + expect(screen.getByText(renderedCoordinate)).toBeInTheDocument(); }); }); diff --git a/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx b/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx index 0cbf349491797..7565877f40517 100644 --- a/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx +++ b/superset-frontend/src/pages/RowLevelSecurityList/RowLevelSecurityList.test.tsx @@ -21,12 +21,6 @@ import { render, screen, within } from 'spec/helpers/testing-library'; import { act } from 'react-dom/test-utils'; import { MemoryRouter } from 'react-router-dom'; import { QueryParamProvider } from 'use-query-params'; -import { styledMount as mount } from 'spec/helpers/theming'; -import { Provider } from 'react-redux'; -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; -import ListView from 'src/components/ListView/ListView'; import userEvent from '@testing-library/user-event'; import RowLevelSecurityList from '.'; @@ -101,43 +95,6 @@ const mockUser = { userId: 1, }; -const mockedProps = {}; - -const mockStore = configureStore([thunk]); -const store = mockStore({}); - -describe('RulesList Enzyme', () => { - let wrapper: any; - - beforeAll(async () => { - fetchMock.resetHistory(); - wrapper = mount( - - - - - , - ); - - await waitForComponentToPaint(wrapper); - }); - - it('renders', () => { - expect(wrapper.find(RowLevelSecurityList)).toExist(); - }); - it('renders a ListView', () => { - expect(wrapper.find(ListView)).toExist(); - }); - it('fetched data', () => { - // wrapper.update(); - const apiCalls = fetchMock.calls(/rowlevelsecurity\/\?q/); - expect(apiCalls).toHaveLength(1); - expect(apiCalls[0][0]).toMatchInlineSnapshot( - `"http://localhost/api/v1/rowlevelsecurity/?q=(order_column:changed_on_delta_humanized,order_direction:desc,page:0,page_size:25)"`, - ); - }); -}); - describe('RuleList RTL', () => { async function renderAndWait() { const mounted = act(async () => { @@ -154,6 +111,27 @@ describe('RuleList RTL', () => { return mounted; } + it('renders', async () => { + await renderAndWait(); + expect(screen.getByText('Row Level Security')).toBeVisible(); + }); + + it('renders a ListView', async () => { + await renderAndWait(); + expect(screen.getByTestId('rls-list-view')).toBeInTheDocument(); + }); + + it('fetched data', async () => { + fetchMock.resetHistory(); + await renderAndWait(); + const apiCalls = fetchMock.calls(/rowlevelsecurity\/\?q/); + expect(apiCalls).toHaveLength(1); + expect(apiCalls[0][0]).toMatchInlineSnapshot( + `"http://localhost/api/v1/rowlevelsecurity/?q=(order_column:changed_on_delta_humanized,order_direction:desc,page:0,page_size:25)"`, + ); + fetchMock.resetHistory(); + }); + it('renders add rule button on empty state', async () => { fetchMock.get( ruleListEndpoint,