Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(fe): migrate 6 Enzyme-based unit tests to RTL #31819

Merged
merged 6 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading