Skip to content

Commit

Permalink
chore(fe): migrate 6 Enzyme-based unit tests to RTL (#31819)
Browse files Browse the repository at this point in the history
Signed-off-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: JUST.in DO IT <justin.park@airbnb.com>
  • Loading branch information
hainenber and justinpark authored Jan 22, 2025
1 parent 7383e43 commit b74da79
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -43,15 +41,15 @@ test('renders a proper table', () => {
user,
});

const wrapper = mount(
const { container } = render(
<Provider store={store}>
<QueryTable {...mockedProps} />
</Provider>,
);
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);
});
Original file line number Diff line number Diff line change
Expand Up @@ -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' });
Expand All @@ -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(<ImageLoader {...props} />);
return render(<ImageLoader {...props} />);
};

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',
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export default function ImageLoader({

return (
<ImageContainer
data-test="image-loader"
src={isLoading ? fallback : imgSrc}
{...rest}
position={position}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
import { styledMount as mount } from 'spec/helpers/theming';
import fetchMock from 'fetch-mock';

import ListViewCard from 'src/components/ListViewCard';
import ImageLoader from 'src/components/ListViewCard/ImageLoader';
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
import { render, screen } from 'spec/helpers/testing-library';

global.URL.createObjectURL = jest.fn(() => '/local_url');
fetchMock.get('/thumbnail', { body: new Blob(), sendAsJson: false });
Expand All @@ -44,25 +42,22 @@ describe('ListViewCard', () => {
),
};

let wrapper;
const factory = (extraProps = {}) => {
const props = { ...defaultProps, ...extraProps };
return mount(<ListViewCard {...props} />);
};
beforeEach(async () => {
wrapper = factory();
await waitForComponentToPaint(wrapper);
beforeEach(() => {
const props = { ...defaultProps };
render(<ListViewCard {...props} />);
});

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();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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(
<DndProvider backend={HTML5Backend}>
<Divider {...props} {...overrideProps} />
</DndProvider>,
{
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);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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(<ViewportControl {...defaultProps} />);
inst = wrapper.instance();
render(<ViewportControl {...defaultProps} />);
});

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();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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 '.';

Expand Down Expand Up @@ -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(
<MemoryRouter>
<Provider store={store}>
<RowLevelSecurityList {...mockedProps} user={mockUser} />
</Provider>
</MemoryRouter>,
);

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 () => {
Expand All @@ -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,
Expand Down

0 comments on commit b74da79

Please sign in to comment.