/** * 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 configureStore from 'redux-mock-store'; import { mount } from 'enzyme'; import { act } from 'react-dom/test-utils'; import sinon from 'sinon'; import fetchMock from 'fetch-mock'; import thunk from 'redux-thunk'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; import DatabaseSelector from 'src/components/DatabaseSelector'; import TableSelector from 'src/components/TableSelector'; import { initialState, tables } from '../sqllab/fixtures'; const mockStore = configureStore([thunk]); const store = mockStore(initialState); const FETCH_SCHEMAS_ENDPOINT = 'glob:*/api/v1/database/*/schemas/*'; const GET_TABLE_ENDPOINT = 'glob:*/superset/tables/1/*/*'; const GET_TABLE_NAMES_ENDPOINT = 'glob:*/superset/tables/1/main/*'; const mockedProps = { clearable: false, database: { id: 1, database_name: 'main' }, dbId: 1, formMode: false, getDbList: sinon.stub(), handleError: sinon.stub(), horizontal: false, onChange: sinon.stub(), onDbChange: sinon.stub(), onSchemaChange: sinon.stub(), onTableChange: sinon.stub(), sqlLabMode: true, tableName: '', tableNameSticky: true, }; const schemaOptions = { result: ['main', 'erf', 'superset'], }; const selectedSchema = { label: 'main', title: 'main', value: 'main' }; const selectedTable = { extra: null, label: 'birth_names', schema: 'main', title: 'birth_names', type: undefined, value: 'birth_names', }; async function mountAndWait(props = mockedProps) { const mounted = mount(, { context: { store }, wrappingComponent: ThemeProvider, wrappingComponentProps: { theme: supersetTheme }, }); await waitForComponentToPaint(mounted); return mounted; } describe('TableSelector', () => { let wrapper; beforeEach(async () => { fetchMock.reset(); wrapper = await mountAndWait(); }); it('renders', () => { expect(wrapper.find(TableSelector)).toExist(); expect(wrapper.find(DatabaseSelector)).toExist(); }); describe('change database', () => { afterEach(fetchMock.resetHistory); afterAll(fetchMock.reset); it('should fetch schemas', async () => { fetchMock.get(FETCH_SCHEMAS_ENDPOINT, { overwriteRoutes: true }); act(() => { wrapper.find('[data-test="select-database"]').first().props().onChange({ id: 1, database_name: 'main', }); }); await waitForComponentToPaint(wrapper); expect(fetchMock.calls(FETCH_SCHEMAS_ENDPOINT)).toHaveLength(1); }); it('should fetch schema options', async () => { fetchMock.get(FETCH_SCHEMAS_ENDPOINT, schemaOptions, { overwriteRoutes: true, }); act(() => { wrapper.find('[data-test="select-database"]').first().props().onChange({ id: 1, database_name: 'main', }); }); await waitForComponentToPaint(wrapper); wrapper.update(); expect(fetchMock.calls(FETCH_SCHEMAS_ENDPOINT)).toHaveLength(1); expect( wrapper.find('[name="select-schema"]').first().props().options, ).toEqual([ { value: 'main', label: 'main', title: 'main' }, { value: 'erf', label: 'erf', title: 'erf' }, { value: 'superset', label: 'superset', title: 'superset' }, ]); }); it('should clear table options', async () => { act(() => { wrapper.find('[data-test="select-database"]').first().props().onChange({ id: 1, database_name: 'main', }); }); await waitForComponentToPaint(wrapper); const props = wrapper.find('[name="async-select-table"]').first().props(); expect(props.isDisabled).toBe(true); expect(props.value).toEqual(undefined); }); }); describe('change schema', () => { beforeEach(async () => { fetchMock.get(FETCH_SCHEMAS_ENDPOINT, schemaOptions, { overwriteRoutes: true, }); }); afterEach(fetchMock.resetHistory); afterAll(fetchMock.reset); it('should fetch table', async () => { fetchMock.get(GET_TABLE_NAMES_ENDPOINT, { overwriteRoutes: true }); act(() => { wrapper.find('[data-test="select-database"]').first().props().onChange({ id: 1, database_name: 'main', }); }); await waitForComponentToPaint(wrapper); act(() => { wrapper .find('[name="select-schema"]') .first() .props() .onChange(selectedSchema); }); await waitForComponentToPaint(wrapper); expect(fetchMock.calls(GET_TABLE_NAMES_ENDPOINT)).toHaveLength(1); }); it('should fetch table options', async () => { fetchMock.get(GET_TABLE_NAMES_ENDPOINT, tables, { overwriteRoutes: true, }); act(() => { wrapper.find('[data-test="select-database"]').first().props().onChange({ id: 1, database_name: 'main', }); }); await waitForComponentToPaint(wrapper); act(() => { wrapper .find('[name="select-schema"]') .first() .props() .onChange(selectedSchema); }); await waitForComponentToPaint(wrapper); expect( wrapper.find('[name="select-schema"]').first().props().value[0], ).toEqual(selectedSchema); expect(fetchMock.calls(GET_TABLE_NAMES_ENDPOINT)).toHaveLength(1); const { options } = wrapper.find('[name="select-table"]').first().props(); expect({ options }).toEqual(tables); }); }); describe('change table', () => { beforeEach(async () => { fetchMock.get(GET_TABLE_NAMES_ENDPOINT, tables, { overwriteRoutes: true, }); }); it('should change table value', async () => { act(() => { wrapper .find('[name="select-schema"]') .first() .props() .onChange(selectedSchema); }); await waitForComponentToPaint(wrapper); act(() => { wrapper .find('[name="select-table"]') .first() .props() .onChange(selectedTable); }); await waitForComponentToPaint(wrapper); expect( wrapper.find('[name="select-table"]').first().props().value, ).toEqual('birth_names'); }); it('should call onTableChange with schema from table object', async () => { act(() => { wrapper .find('[name="select-schema"]') .first() .props() .onChange(selectedSchema); }); await waitForComponentToPaint(wrapper); act(() => { wrapper .find('[name="select-table"]') .first() .props() .onChange(selectedTable); }); await waitForComponentToPaint(wrapper); expect(mockedProps.onTableChange.getCall(0).args[0]).toBe('birth_names'); expect(mockedProps.onTableChange.getCall(0).args[1]).toBe('main'); }); }); describe('getTableNamesBySubStr', () => { afterEach(fetchMock.resetHistory); afterAll(fetchMock.reset); it('should handle empty', async () => { act(() => { wrapper .find('[name="async-select-table"]') .first() .props() .loadOptions(); }); await waitForComponentToPaint(wrapper); const props = wrapper.find('[name="async-select-table"]').first().props(); expect(props.isDisabled).toBe(true); expect(props.value).toEqual(''); }); it('should handle table name', async () => { wrapper.setProps({ schema: 'main' }); fetchMock.get(GET_TABLE_ENDPOINT, tables, { overwriteRoutes: true, }); act(() => { wrapper .find('[name="async-select-table"]') .first() .props() .loadOptions(); }); await waitForComponentToPaint(wrapper); expect(fetchMock.calls(GET_TABLE_ENDPOINT)).toHaveLength(1); }); }); });