diff --git a/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx b/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx index e1d672ec0262..3251c83b3e25 100644 --- a/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx +++ b/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx @@ -49,6 +49,7 @@ describe('ExploreResultsButton', () => { database, show: true, query: queries[0], + onClick() {}, }; const mockColumns = { ds: { @@ -90,6 +91,7 @@ describe('ExploreResultsButton', () => { database, show: true, query: queryWithBadColumns, + onClick() {}, }); const badCols = wrapper.instance().getInvalidColumns(); @@ -147,6 +149,7 @@ describe('ExploreResultsButton', () => { show: true, query: longQuery, database, + onClick() {}, }; const longQueryWrapper = shallow( , diff --git a/superset-frontend/spec/javascripts/sqllab/QueryTable_spec.jsx b/superset-frontend/spec/javascripts/sqllab/QueryTable_spec.jsx index 5037b9d24cfb..6c963e22c834 100644 --- a/superset-frontend/spec/javascripts/sqllab/QueryTable_spec.jsx +++ b/superset-frontend/spec/javascripts/sqllab/QueryTable_spec.jsx @@ -26,9 +26,10 @@ import { queries } from './fixtures'; describe('QueryTable', () => { const mockedProps = { queries, + displayLimit: 100, }; it('is valid', () => { - expect(React.isValidElement()).toBe(true); + expect(React.isValidElement()).toBe(true); }); it('is valid with props', () => { expect(React.isValidElement()).toBe(true); diff --git a/superset-frontend/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx b/superset-frontend/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx index c679bf855464..362539472fdf 100644 --- a/superset-frontend/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx +++ b/superset-frontend/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx @@ -23,6 +23,8 @@ import URI from 'urijs'; import { Provider } from 'react-redux'; import { shallow, mount } from 'enzyme'; import sinon from 'sinon'; +import { act } from 'react-dom/test-utils'; +import fetchMock from 'fetch-mock'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import { EditableTabs } from 'src/common/components/Tabs'; import TabbedSqlEditors from 'src/SqlLab/components/TabbedSqlEditors'; @@ -30,6 +32,10 @@ import SqlEditor from 'src/SqlLab/components/SqlEditor'; import { table, initialState } from './fixtures'; +fetchMock.get('glob:*/api/v1/database/*', {}); +fetchMock.get('glob:*/savedqueryviewapi/api/get/*', {}); +fetchMock.get('glob:*/kv/*', {}); + describe('TabbedSqlEditors', () => { const middlewares = [thunk]; const mockStore = configureStore(middlewares); @@ -58,6 +64,7 @@ describe('TabbedSqlEditors', () => { id: 'B1-VQU1zW', sqlEditorId: 'newEditorId', tableName: 'ab_user', + state: 'success', }, }; const mockedProps = { @@ -78,6 +85,19 @@ describe('TabbedSqlEditors', () => { .dive() .dive(); + const mountWithAct = async () => + act(async () => { + mount( + + + , + { + wrappingComponent: ThemeProvider, + wrappingComponentProps: { theme: supersetTheme }, + }, + ); + }); + let wrapper; it('is valid', () => { expect(React.isValidElement()).toBe( @@ -88,64 +108,29 @@ describe('TabbedSqlEditors', () => { let uriStub; beforeEach(() => { sinon.stub(window.history, 'replaceState'); - // sinon.spy(TabbedSqlEditors.prototype, 'componentDidMount'); uriStub = sinon.stub(URI.prototype, 'search'); }); afterEach(() => { window.history.replaceState.restore(); - // TabbedSqlEditors.prototype.componentDidMount.restore(); uriStub.restore(); }); - it('should handle id', () => { + it('should handle id', async () => { uriStub.returns({ id: 1 }); - wrapper = mount( - - - , - { - wrappingComponent: ThemeProvider, - wrappingComponentProps: { theme: supersetTheme }, - }, - ); - /* expect(TabbedSqlEditors.prototype.componentDidMount.calledOnce).toBe( - true, - ); */ + await mountWithAct(); expect(window.history.replaceState.getCall(0).args[2]).toBe( '/superset/sqllab', ); }); - it('should handle savedQueryId', () => { + it('should handle savedQueryId', async () => { uriStub.returns({ savedQueryId: 1 }); - wrapper = mount( - - - , - { - wrappingComponent: ThemeProvider, - wrappingComponentProps: { theme: supersetTheme }, - }, - ); - /* expect(TabbedSqlEditors.prototype.componentDidMount.calledOnce).toBe( - true, - ); */ + await mountWithAct(); expect(window.history.replaceState.getCall(0).args[2]).toBe( '/superset/sqllab', ); }); - it('should handle sql', () => { + it('should handle sql', async () => { uriStub.returns({ sql: 1, dbid: 1 }); - wrapper = mount( - - - , - { - wrappingComponent: ThemeProvider, - wrappingComponentProps: { theme: supersetTheme }, - }, - ); - /* expect(TabbedSqlEditors.prototype.componentDidMount.calledOnce).toBe( - true, - ); */ + await mountWithAct(); expect(window.history.replaceState.getCall(0).args[2]).toBe( '/superset/sqllab', ); diff --git a/superset-frontend/spec/javascripts/sqllab/fixtures.ts b/superset-frontend/spec/javascripts/sqllab/fixtures.ts index d71ffe987dba..13d126d45e08 100644 --- a/superset-frontend/spec/javascripts/sqllab/fixtures.ts +++ b/superset-frontend/spec/javascripts/sqllab/fixtures.ts @@ -478,6 +478,7 @@ export const initialState = { conf: { DEFAULT_SQLLAB_LIMIT: 1000, SQL_MAX_ROW: 100000, + DISPLAY_MAX_ROW: 100, }, }, }; diff --git a/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx index 33f2385dabd5..dfd19b7da3fa 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx @@ -22,7 +22,6 @@ import configureStore from 'redux-mock-store'; import { Provider } from 'react-redux'; import fetchMock from 'fetch-mock'; import * as featureFlags from 'src/featureFlags'; - import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; import { styledMount as mount } from 'spec/helpers/theming'; @@ -38,10 +37,11 @@ const store = mockStore({}); const chartsInfoEndpoint = 'glob:*/api/v1/chart/_info*'; const chartssOwnersEndpoint = 'glob:*/api/v1/chart/related/owners*'; const chartsCreatedByEndpoint = 'glob:*/api/v1/chart/related/created_by*'; -const chartsEndpoint = 'glob:*/api/v1/chart/?*'; +const chartsEndpoint = 'glob:*/api/v1/chart/*'; const chartsVizTypesEndpoint = 'glob:*/api/v1/chart/viz_types'; const chartsDatasourcesEndpoint = 'glob:*/api/v1/chart/datasources'; const chartFavoriteStatusEndpoint = 'glob:*/api/v1/chart/favorite_status*'; +const datasetEndpoint = 'glob:*/api/v1/dataset/*'; const mockCharts = [...new Array(3)].map((_, i) => ({ changed_on: new Date().toISOString(), @@ -86,6 +86,8 @@ fetchMock.get(chartsDatasourcesEndpoint, { count: 0, }); +fetchMock.get(datasetEndpoint, {}); + global.URL.createObjectURL = jest.fn(); fetchMock.get('/thumbnail', { body: new Blob(), sendAsJson: false }); @@ -98,6 +100,7 @@ describe('ChartList', () => { isFeatureEnabledMock.restore(); }); const mockedProps = {}; + const wrapper = mount( @@ -134,19 +137,22 @@ describe('ChartList', () => { expect(wrapper.find(ListViewCard)).toExist(); }); - it('renders a table view', () => { + it('renders a table view', async () => { wrapper.find('[data-test="list-view"]').first().simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find('table')).toExist(); }); - it('edits', () => { + it('edits', async () => { expect(wrapper.find(PropertiesModal)).not.toExist(); wrapper.find('[data-test="edit-alt"]').first().simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find(PropertiesModal)).toExist(); }); - it('delete', () => { + it('delete', async () => { wrapper.find('[data-test="trash"]').first().simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find(ConfirmStatusChange)).toExist(); }); }); diff --git a/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx index 227f97ec3342..2af4dc189945 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx @@ -43,6 +43,7 @@ const dashboardCreatedByEndpoint = const dashboardFavoriteStatusEndpoint = 'glob:*/api/v1/dashboard/favorite_status*'; const dashboardsEndpoint = 'glob:*/api/v1/dashboard/?*'; +const dashboardEndpoint = 'glob:*/api/v1/dashboard/*'; const mockDashboards = [...new Array(3)].map((_, i) => ({ id: i, @@ -54,7 +55,7 @@ const mockDashboards = [...new Array(3)].map((_, i) => ({ published: true, changed_on_utc: new Date().toISOString(), changed_on_delta_humanized: '5 minutes ago', - owners: [{ first_name: 'admin', last_name: 'admin_user' }], + owners: [{ id: 1, first_name: 'admin', last_name: 'admin_user' }], thumbnail_url: '/thumbnail', })); @@ -80,6 +81,10 @@ fetchMock.get(dashboardsEndpoint, { dashboard_count: 3, }); +fetchMock.get(dashboardEndpoint, { + result: mockDashboards[0], +}); + global.URL.createObjectURL = jest.fn(); fetchMock.get('/thumbnail', { body: new Blob(), sendAsJson: false }); @@ -129,35 +134,40 @@ describe('DashboardList', () => { expect(wrapper.find(ListViewCard)).toExist(); }); - it('renders a table view', () => { + it('renders a table view', async () => { wrapper.find('[data-test="list-view"]').first().simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find('table')).toExist(); }); - it('edits', () => { + it('edits', async () => { expect(wrapper.find(PropertiesModal)).not.toExist(); wrapper.find('[data-test="edit-alt"]').first().simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find(PropertiesModal)).toExist(); }); - it('card view edits', () => { + it('card view edits', async () => { wrapper.find('[data-test="edit-alt"]').last().simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find(PropertiesModal)).toExist(); }); - it('delete', () => { + it('delete', async () => { wrapper .find('[data-test="dashboard-list-trash-icon"]') .first() .simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find(ConfirmStatusChange)).toExist(); }); - it('card view delete', () => { + it('card view delete', async () => { wrapper .find('[data-test="dashboard-list-trash-icon"]') .last() .simulate('click'); + await waitForComponentToPaint(wrapper); expect(wrapper.find(ConfirmStatusChange)).toExist(); }); }); diff --git a/superset-frontend/spec/javascripts/views/CRUD/welcome/ChartTable_spec.tsx b/superset-frontend/spec/javascripts/views/CRUD/welcome/ChartTable_spec.tsx index f8154e210c20..3af468a601df 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/welcome/ChartTable_spec.tsx +++ b/superset-frontend/spec/javascripts/views/CRUD/welcome/ChartTable_spec.tsx @@ -24,6 +24,7 @@ import configureStore from 'redux-mock-store'; import { act } from 'react-dom/test-utils'; import ChartTable from 'src/views/CRUD/welcome/ChartTable'; +import { ReactWrapper } from 'enzyme'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; const mockStore = configureStore([thunk]); @@ -31,6 +32,7 @@ const store = mockStore({}); const chartsEndpoint = 'glob:*/api/v1/chart/?*'; const chartsInfoEndpoint = 'glob:*/api/v1/chart/_info*'; +const chartFavoriteStatusEndpoint = 'glob:*/api/v1/chart/favorite_status*'; const mockCharts = [...new Array(3)].map((_, i) => ({ changed_on_utc: new Date().toISOString(), @@ -51,13 +53,26 @@ fetchMock.get(chartsInfoEndpoint, { permissions: ['can_add', 'can_edit', 'can_delete'], }); +fetchMock.get(chartFavoriteStatusEndpoint, { + result: [], +}); + describe('ChartTable', () => { const mockedProps = { user: { userId: '2', }, }; - const wrapper = mount(); + + let wrapper: ReactWrapper; + + beforeEach(async () => { + act(() => { + wrapper = mount(); + }); + await waitForComponentToPaint(wrapper); + }); + it('renders', () => { expect(wrapper.find(ChartTable)).toExist(); }); @@ -74,9 +89,7 @@ describe('ChartTable', () => { expect(wrapper.find('ChartCard')).toExist(); }); - it('display EmptyState if there is no data', () => { - fetchMock.resetHistory(); - const wrapper = mount(); + it('display EmptyState if there is no data', async () => { expect(wrapper.find('EmptyState')).toExist(); }); }); diff --git a/superset-frontend/spec/javascripts/views/CRUD/welcome/DashboardTable_spec.tsx b/superset-frontend/spec/javascripts/views/CRUD/welcome/DashboardTable_spec.tsx index 8fbc75d4fb85..4146ab80f8fd 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/welcome/DashboardTable_spec.tsx +++ b/superset-frontend/spec/javascripts/views/CRUD/welcome/DashboardTable_spec.tsx @@ -59,7 +59,7 @@ describe('DashboardTable', () => { }, mine: mockDashboards, }; - const wrapper = mount(); + let wrapper = mount(); beforeAll(async () => { await waitForComponentToPaint(wrapper); @@ -87,15 +87,18 @@ describe('DashboardTable', () => { expect(wrapper.find(DashboardCard)).toExist(); }); - it('display EmptyState if there is no data', () => { - const wrapper = mount( - , - ); + it('display EmptyState if there is no data', async () => { + await act(async () => { + wrapper = mount( + , + ); + }); + expect(wrapper.find('EmptyState')).toExist(); }); }); diff --git a/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx b/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx index 5900136824a1..8a57b0991f91 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx +++ b/superset-frontend/spec/javascripts/views/CRUD/welcome/SavedQueries_spec.tsx @@ -32,7 +32,7 @@ const mockStore = configureStore([thunk]); const store = mockStore({}); const queriesEndpoint = 'glob:*/api/v1/saved_query/?*'; -const savedQueriesInfo = 'glob:*/api/v1/saved_query/_info'; +const savedQueriesInfo = 'glob:*/api/v1/saved_query/_info*'; const mockqueries = [...new Array(3)].map((_, i) => ({ created_by: { diff --git a/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx index adbb55888ed4..5e5cc1302d2a 100644 --- a/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx +++ b/superset-frontend/src/views/CRUD/welcome/ActivityTable.tsx @@ -158,7 +158,8 @@ export default function ActivityTable({ cover={<>} url={e.sql ? `/superset/sqllab?savedQueryId=${e.id}` : e.url} title={getFilterTitle(e)} - description={`Last Edited: ${moment(e.changed_on_utc).format( + description={`Last Edited: ${moment( + e.changed_on_utc, 'MM/DD/YYYY HH:mm:ss', )}`} avatar={getIconName(e)}