blob: 4045c4b85ccaf5eaec38b13a7066225b5686bd97 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { render, screen, within, waitFor } from 'spec/helpers/testing-library';
import userEvent from '@testing-library/user-event';
import { QueryParamProvider } from 'use-query-params';
import thunk from 'redux-thunk';
import configureStore from 'redux-mock-store';
import fetchMock from 'fetch-mock';
// Only import components that are directly referenced in tests
import { ListView } from './ListView';
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
function makeMockLocation(query) {
const queryStr = encodeURIComponent(query);
return {
protocol: 'http:',
host: 'localhost',
pathname: '/',
search: queryStr.length ? `?${queryStr}` : '',
};
}
const fetchSelectsMock = jest.fn(() => []);
const mockedProps = {
title: 'Data Table',
columns: [
{
accessor: 'id',
Header: 'ID',
sortable: true,
id: 'id',
},
{
accessor: 'age',
Header: 'Age',
id: 'age',
},
{
accessor: 'name',
Header: 'Name',
id: 'name',
},
{
accessor: 'time',
Header: 'Time',
id: 'time',
},
],
filters: [
{
Header: 'ID',
id: 'id',
input: 'select',
selects: [{ label: 'foo', value: 'bar' }],
operator: 'eq',
},
{
Header: 'Name',
id: 'name',
input: 'search',
operator: 'ct',
},
{
Header: 'Age',
id: 'age',
input: 'select',
fetchSelects: fetchSelectsMock,
paginate: true,
operator: 'eq',
},
{
Header: 'Time',
id: 'time',
input: 'datetime_range',
operator: 'between',
},
],
data: [
{ id: 1, name: 'data 1', age: 10, time: '2020-11-18T07:53:45.354Z' },
{ id: 2, name: 'data 2', age: 1, time: '2020-11-18T07:53:45.354Z' },
],
count: 2,
pageSize: 1,
fetchData: jest.fn(() => []),
loading: false,
bulkSelectEnabled: true,
disableBulkSelect: jest.fn(),
bulkActions: [
{
key: 'something',
name: 'do something',
style: 'danger',
onSelect: jest.fn(),
},
],
cardSortSelectOptions: [
{
desc: false,
id: 'something',
label: 'Alphabetical',
value: 'alphabetical',
},
],
};
const factory = (props = mockedProps) =>
render(
<QueryParamProvider location={makeMockLocation()}>
<ListView {...props} />
</QueryParamProvider>,
{ store: mockStore() },
);
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ListView', () => {
beforeEach(() => {
fetchMock.reset();
jest.clearAllMocks();
factory();
});
afterEach(() => {
fetchMock.reset();
mockedProps.fetchData.mockClear();
mockedProps.bulkActions.forEach(ba => {
ba.onSelect.mockClear();
});
});
// Example of converted test:
test('calls fetchData on mount', () => {
expect(mockedProps.fetchData).toHaveBeenCalledWith({
filters: [],
pageIndex: 0,
pageSize: 1,
sortBy: [],
});
});
test('calls fetchData on sort', async () => {
const sortHeader = screen.getAllByTestId('sort-header')[1];
await userEvent.click(sortHeader);
expect(mockedProps.fetchData).toHaveBeenCalledWith({
filters: [],
pageIndex: 0,
pageSize: 1,
sortBy: [
{
desc: false,
id: 'id',
},
],
});
});
// Update pagination control tests for Ant Design pagination
test('renders pagination controls', () => {
const paginationList = screen.getByRole('list');
expect(paginationList).toBeInTheDocument();
const pageOneItem = screen.getByRole('listitem', { name: '1' });
expect(pageOneItem).toBeInTheDocument();
});
test('calls fetchData on page change', async () => {
const pageTwoItem = screen.getByRole('listitem', { name: '2' });
await userEvent.click(pageTwoItem);
await waitFor(() => {
const { calls } = mockedProps.fetchData.mock;
const pageChangeCall = calls.find(
call =>
call[0].pageIndex === 1 &&
call[0].filters.length === 0 &&
call[0].pageSize === 1,
);
expect(pageChangeCall).toBeDefined();
});
});
test('handles bulk actions on 1 row', async () => {
const checkboxes = screen.getAllByRole('checkbox');
await userEvent.click(checkboxes[1]); // Index 1 is the first row checkbox
const bulkActionButton = within(
screen.getByTestId('bulk-select-controls'),
).getByTestId('bulk-select-action');
await userEvent.click(bulkActionButton);
expect(mockedProps.bulkActions[0].onSelect).toHaveBeenCalledWith([
{
age: 10,
id: 1,
name: 'data 1',
time: '2020-11-18T07:53:45.354Z',
},
]);
});
// Update UI filters test to use more specific selector
test('renders UI filters', () => {
const filterControls = screen.getAllByRole('combobox');
expect(filterControls).toHaveLength(2);
});
test('calls fetchData on filter', async () => {
// Handle select filter
const selectFilter = screen.getAllByRole('combobox')[0];
await userEvent.click(selectFilter);
const option = screen.getByText('foo');
await userEvent.click(option);
// Handle search filter
const searchFilter = screen.getByPlaceholderText('Type a value');
await userEvent.type(searchFilter, 'something');
await userEvent.tab();
expect(mockedProps.fetchData).toHaveBeenCalledWith(
expect.objectContaining({
filters: [
{
id: 'id',
operator: 'eq',
value: { label: 'foo', value: 'bar' },
},
{
id: 'name',
operator: 'ct',
value: 'something',
},
],
}),
);
});
test('calls fetchData on card view sort', async () => {
factory({
...mockedProps,
renderCard: jest.fn(),
initialSort: [{ id: 'something' }],
});
const sortSelect = screen.getByTestId('card-sort-select');
await userEvent.click(sortSelect);
const sortOption = screen.getByText('Alphabetical');
await userEvent.click(sortOption);
expect(mockedProps.fetchData).toHaveBeenCalled();
});
});