diff --git a/superset-frontend/spec/fixtures/mockStore.js b/superset-frontend/spec/fixtures/mockStore.js index f4aad15b4930b..2b34ff390ea31 100644 --- a/superset-frontend/spec/fixtures/mockStore.js +++ b/superset-frontend/spec/fixtures/mockStore.js @@ -30,6 +30,9 @@ import { sliceId } from './mockChartQueries'; import { dashboardFilters } from './mockDashboardFilters'; import { nativeFilters } from './mockNativeFilters'; +export const storeWithState = state => + createStore(rootReducer, state, compose(applyMiddleware(thunk))); + export const getMockStore = overrideState => createStore( rootReducer, diff --git a/superset-frontend/src/components/TableLoader/TableLoader.test.tsx b/superset-frontend/src/components/TableLoader/TableLoader.test.tsx new file mode 100644 index 0000000000000..c0c46878f9df3 --- /dev/null +++ b/superset-frontend/src/components/TableLoader/TableLoader.test.tsx @@ -0,0 +1,94 @@ +/** + * 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 React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import { Provider } from 'react-redux'; +import fetchMock from 'fetch-mock'; +import { storeWithState } from 'spec/fixtures/mockStore'; +import ToastPresenter from 'src/messageToasts/containers/ToastPresenter'; +import TableLoader, { TableLoaderProps } from '.'; + +fetchMock.get('glob:*/api/v1/mock', [ + { id: 1, name: 'John Doe' }, + { id: 2, name: 'Jane Doe' }, +]); + +const defaultProps: TableLoaderProps = { + dataEndpoint: '/api/v1/mock', + addDangerToast: jest.fn(), +}; + +function renderWithProps(props: TableLoaderProps = defaultProps) { + return render( + + + + , + ); +} + +test('renders loading and table', async () => { + renderWithProps(); + + expect(screen.getByRole('status')).toBeInTheDocument(); + expect(await screen.findByRole('table')).toBeInTheDocument(); +}); + +test('renders with column names', async () => { + renderWithProps({ + ...defaultProps, + columns: ['id_modified', 'name_modified'], + }); + + const columnHeaders = await screen.findAllByRole('columnheader'); + + expect(columnHeaders[0]).toHaveTextContent('id_modified'); + expect(columnHeaders[1]).toHaveTextContent('name_modified'); +}); + +test('renders without mutator', async () => { + renderWithProps(); + + expect(await screen.findAllByRole('row')).toHaveLength(3); + expect(await screen.findAllByRole('columnheader')).toHaveLength(2); + expect(await screen.findAllByRole('cell')).toHaveLength(4); +}); + +test('renders with mutator', async () => { + const mutator = function (data: { id: number; name: string }[]) { + return data.map(row => ({ + id: row.id, + name:

{row.name}

, + })); + }; + + renderWithProps({ ...defaultProps, mutator }); + + expect(await screen.findAllByRole('heading', { level: 4 })).toHaveLength(2); +}); + +test('renders error message', async () => { + fetchMock.mock('glob:*/api/v1/mock', 500, { + overwriteRoutes: true, + }); + + renderWithProps(); + + expect(await screen.findByRole('alert')).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/components/TableLoader.tsx b/superset-frontend/src/components/TableLoader/index.tsx similarity index 78% rename from superset-frontend/src/components/TableLoader.tsx rename to superset-frontend/src/components/TableLoader/index.tsx index aa46a259f7364..c6224499d38b7 100644 --- a/superset-frontend/src/components/TableLoader.tsx +++ b/superset-frontend/src/components/TableLoader/index.tsx @@ -17,25 +17,13 @@ * under the License. */ import React, { useState, useEffect, useMemo } from 'react'; -import PropTypes from 'prop-types'; import { t, SupersetClient, JsonObject } from '@superset-ui/core'; -import TableView from 'src/components/TableView'; -import withToasts from '../messageToasts/enhancers/withToasts'; -import Loading from './Loading'; -import '../../stylesheets/reactable-pagination.less'; -import { EmptyWrapperType } from './TableView/TableView'; +import TableView, { EmptyWrapperType } from 'src/components/TableView'; +import withToasts from 'src/messageToasts/enhancers/withToasts'; +import Loading from 'src/components/Loading'; +import 'stylesheets/reactable-pagination.less'; -const propTypes = { - dataEndpoint: PropTypes.string.isRequired, - mutator: PropTypes.func, - columns: PropTypes.arrayOf(PropTypes.string), - addDangerToast: PropTypes.func.isRequired, - addInfoToast: PropTypes.func.isRequired, - addSuccessToast: PropTypes.func.isRequired, - addWarningToast: PropTypes.func.isRequired, -}; - -interface TableLoaderProps { +export interface TableLoaderProps { dataEndpoint?: string; mutator?: (data: JsonObject) => any[]; columns?: string[]; @@ -96,6 +84,4 @@ const TableLoader = (props: TableLoaderProps) => { ); }; -TableLoader.propTypes = propTypes; - export default withToasts(TableLoader); diff --git a/superset-frontend/src/profile/App.tsx b/superset-frontend/src/profile/App.tsx index 8774d63aeb5a5..d3c5e43c99461 100644 --- a/superset-frontend/src/profile/App.tsx +++ b/superset-frontend/src/profile/App.tsx @@ -22,12 +22,13 @@ import thunk from 'redux-thunk'; import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; import { Provider } from 'react-redux'; import { ThemeProvider } from '@superset-ui/core'; -import App from './components/App'; -import messageToastReducer from '../messageToasts/reducers'; -import { initEnhancer } from '../reduxUtils'; -import setupApp from '../setup/setupApp'; +import App from 'src/profile/components/App'; +import messageToastReducer from 'src/messageToasts/reducers'; +import { initEnhancer } from 'src/reduxUtils'; +import setupApp from 'src/setup/setupApp'; import './main.less'; -import { theme } from '../preamble'; +import { theme } from 'src/preamble'; +import ToastPresenter from 'src/messageToasts/containers/ToastPresenter'; setupApp(); @@ -48,6 +49,7 @@ const Application = () => ( + );