diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.jsx b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.jsx
index eec45618e7150..7b8d822cbcae5 100644
--- a/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.jsx
+++ b/superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.test.jsx
@@ -18,13 +18,23 @@
*/
import React from 'react';
import fetchMock from 'fetch-mock';
-// import userEvent from '@testing-library/user-event';
-import { render, screen } from 'spec/helpers/testing-library';
+import userEvent from '@testing-library/user-event';
+import {
+ render,
+ screen,
+ within,
+ cleanup,
+ act,
+} from 'spec/helpers/testing-library';
+/* -- These imports are used for the mock functions that currently don't work
+import {
+ testDatabaseConnection,
+ useSingleViewResource,
+} from 'src/views/CRUD/hooks'; */
import DatabaseModal from './index';
const dbProps = {
show: true,
- databaseId: 10,
database_name: 'my database',
sqlalchemy_uri: 'postgres://superset:superset@something:1234/superset',
};
@@ -46,276 +56,959 @@ fetchMock.get(DATABASE_FETCH_ENDPOINT, {
fetchMock.mock(AVAILABLE_DB_ENDPOINT, {
databases: [
{
+ available_drivers: ['psycopg2'],
+ default_driver: 'psycopg2',
+ engine: 'postgresql',
+ name: 'PostgreSQL',
+ parameters: {
+ properties: {
+ database: {
+ description: 'Database name',
+ type: 'string',
+ },
+ encryption: {
+ description: 'Use an encrypted connection to the database',
+ type: 'boolean',
+ },
+ host: {
+ description: 'Hostname or IP address',
+ type: 'string',
+ },
+ password: {
+ description: 'Password',
+ nullable: true,
+ type: 'string',
+ },
+ port: {
+ description: 'Database port',
+ format: 'int32',
+ maximum: 65536,
+ minimum: 0,
+ type: 'integer',
+ },
+ query: {
+ additionalProperties: {},
+ description: 'Additional parameters',
+ type: 'object',
+ },
+ username: {
+ description: 'Username',
+ nullable: true,
+ type: 'string',
+ },
+ },
+ required: ['database', 'host', 'port', 'username'],
+ type: 'object',
+ },
+ preferred: true,
+ sqlalchemy_uri_placeholder:
+ 'postgresql://user:password@host:port/dbname[?key=value&key=value...]',
+ },
+ {
+ available_drivers: ['rest'],
+ engine: 'presto',
+ name: 'Presto',
+ preferred: true,
+ },
+ {
+ available_drivers: ['mysqldb'],
+ default_driver: 'mysqldb',
engine: 'mysql',
name: 'MySQL',
+ parameters: {
+ properties: {
+ database: {
+ description: 'Database name',
+ type: 'string',
+ },
+ encryption: {
+ description: 'Use an encrypted connection to the database',
+ type: 'boolean',
+ },
+ host: {
+ description: 'Hostname or IP address',
+ type: 'string',
+ },
+ password: {
+ description: 'Password',
+ nullable: true,
+ type: 'string',
+ },
+ port: {
+ description: 'Database port',
+ format: 'int32',
+ maximum: 65536,
+ minimum: 0,
+ type: 'integer',
+ },
+ query: {
+ additionalProperties: {},
+ description: 'Additional parameters',
+ type: 'object',
+ },
+ username: {
+ description: 'Username',
+ nullable: true,
+ type: 'string',
+ },
+ },
+ required: ['database', 'host', 'port', 'username'],
+ type: 'object',
+ },
+ preferred: true,
+ sqlalchemy_uri_placeholder:
+ 'mysql://user:password@host:port/dbname[?key=value&key=value...]',
+ },
+ {
+ available_drivers: ['pysqlite'],
+ engine: 'sqlite',
+ name: 'SQLite',
+ preferred: true,
+ },
+ {
+ available_drivers: ['rest'],
+ engine: 'druid',
+ name: 'Apache Druid',
+ preferred: false,
+ },
+ {
+ available_drivers: ['bigquery'],
+ default_driver: 'bigquery',
+ engine: 'bigquery',
+ name: 'Google BigQuery',
+ parameters: {
+ properties: {
+ credentials_info: {
+ description: 'Contents of BigQuery JSON credentials.',
+ type: 'string',
+ 'x-encrypted-extra': true,
+ },
+ query: {
+ type: 'object',
+ },
+ },
+ type: 'object',
+ },
preferred: false,
+ sqlalchemy_uri_placeholder: 'bigquery://{project_id}',
},
],
});
describe('DatabaseModal', () => {
- afterEach(fetchMock.restore);
- // describe('initial load', () => {
- // it('hides the forms from the db when not selected', () => {
- // render(, { useRedux: true });
- // // Select Advanced tab
- // const advancedTab = screen.getByRole('tab', {
- // name: /advanced/i,
- // });
- // userEvent.click(advancedTab);
- // // Select SQL Lab tab
- // const sqlLabSettingsTab = screen.getByRole('tab', {
- // name: /sql lab/i,
- // });
- // userEvent.click(sqlLabSettingsTab);
-
- // const exposeInSqlLab = screen.getByText('Expose in SQL Lab');
- // const exposeChoicesForm = exposeInSqlLab.parentElement.nextSibling;
- // const schemaField = screen.getByText('CTAS & CVAS SCHEMA').parentElement;
- // expect(exposeChoicesForm).not.toHaveClass('open');
- // expect(schemaField).not.toHaveClass('open');
- // });
- // });
- // it('renders all settings when "Expose in SQL Lab" is checked', () => {
- // render(, { useRedux: true });
-
- // // Select Advanced tab
- // const advancedTab = screen.getByRole('tab', {
- // name: /advanced/i,
- // });
- // userEvent.click(advancedTab);
-
- // // Select SQL Lab tab
- // const sqlLabSettingsTab = screen.getByRole('tab', {
- // name: /sql lab/i,
- // });
-
- // userEvent.click(sqlLabSettingsTab);
-
- // // Grab all SQL Lab settings by their labels
- // // const exposeInSqlLab = screen.getByText('Expose in SQL Lab');
- // const exposeInSqlLab = screen.getByRole('checkbox', {
- // name: /expose in sql lab/i,
- // });
-
- // expect(exposeInSqlLab).not.toBeChecked();
- // userEvent.click(exposeInSqlLab);
-
- // // While checked make sure all checkboxes are showing
- // expect(exposeInSqlLab).toBeChecked();
- // const checkboxes = screen
- // .getAllByRole('checkbox')
- // .filter(checkbox => !checkbox.checked);
-
- // expect(checkboxes.length).toEqual(4);
- // });
-
- // it('renders the schema field when allowCTAS is checked', () => {
- // render(, { useRedux: true });
-
- // // Select Advanced tab
- // const advancedTab = screen.getByRole('tab', {
- // name: /advanced/i,
- // });
- // userEvent.click(advancedTab);
-
- // // Select SQL Lab tab
- // const sqlLabSettingsTab = screen.getByRole('tab', {
- // name: /sql lab/i,
- // });
- // userEvent.click(sqlLabSettingsTab);
- // // Grab CTAS & schema field by their labels
- // const allowCTAS = screen.getByLabelText('Allow CREATE TABLE AS');
- // const schemaField = screen.getByText('CTAS & CVAS SCHEMA').parentElement;
-
- // // While CTAS & CVAS are unchecked, schema field is not visible
- // expect(schemaField).not.toHaveClass('open');
-
- // // Check "Allow CTAS" to reveal schema field
- // userEvent.click(allowCTAS);
- // expect(schemaField).toHaveClass('open');
-
- // // Uncheck "Allow CTAS" to hide schema field again
- // userEvent.click(allowCTAS);
- // expect(schemaField).not.toHaveClass('open');
- // });
-
- // it('renders the schema field when allowCVAS is checked', () => {
- // render(, { useRedux: true });
-
- // // Select Advanced tab
- // const advancedTab = screen.getByRole('tab', {
- // name: /advanced/i,
- // });
- // userEvent.click(advancedTab);
-
- // // Select SQL Lab tab
- // const sqlLabSettingsTab = screen.getByRole('tab', {
- // name: /sql lab/i,
- // });
- // userEvent.click(sqlLabSettingsTab);
- // // Grab CVAS by it's label & schema field
- // const allowCVAS = screen.getByText('Allow CREATE VIEW AS');
- // const schemaField = screen.getByText('CTAS & CVAS SCHEMA').parentElement;
-
- // // While CTAS & CVAS are unchecked, schema field is not visible
- // expect(schemaField).not.toHaveClass('open');
-
- // // Check "Allow CVAS" to reveal schema field
- // userEvent.click(allowCVAS);
- // expect(schemaField).toHaveClass('open');
-
- // // Uncheck "Allow CVAS" to hide schema field again
- // userEvent.click(allowCVAS);
- // expect(schemaField).not.toHaveClass('open');
- // });
-
- // it('renders the schema field when both allowCTAS and allowCVAS are checked', () => {
- // render(, { useRedux: true });
-
- // // Select Advanced tab
- // const advancedTab = screen.getByRole('tab', {
- // name: /advanced/i,
- // });
- // userEvent.click(advancedTab);
-
- // // Select SQL Lab tab
- // const sqlLabSettingsTab = screen.getByRole('tab', {
- // name: /sql lab/i,
- // });
- // userEvent.click(sqlLabSettingsTab);
- // // Grab CTAS and CVAS by their labels, & schema field
- // const allowCTAS = screen.getByText('Allow CREATE TABLE AS');
- // const allowCVAS = screen.getByText('Allow CREATE VIEW AS');
- // const schemaField = screen.getByText('CTAS & CVAS SCHEMA').parentElement;
-
- // // While CTAS & CVAS are unchecked, schema field is not visible
- // expect(schemaField).not.toHaveClass('open');
-
- // // Check both "Allow CTAS" and "Allow CVAS" to reveal schema field
- // userEvent.click(allowCTAS);
- // userEvent.click(allowCVAS);
- // expect(schemaField).toHaveClass('open');
- // // Uncheck both "Allow CTAS" and "Allow CVAS" to hide schema field again
- // userEvent.click(allowCTAS);
- // userEvent.click(allowCVAS);
-
- // // Both checkboxes go unchecked, so the field should no longer render
- // expect(schemaField).not.toHaveClass('open');
- // });
- // TODO: rewrite when Modal is complete
- // describe('create database', () => {
- // beforeEach(() => {
- // fetchMock.post(DATABASE_POST_ENDPOINT, {
- // id: 10,
- // });
- // fetchMock.mock(AVAILABLE_DB_ENDPOINT, {
- // databases: [
- // {
- // engine: 'mysql',
- // name: 'MySQL',
- // preferred: false,
- // },
- // ],
- // });
- // });
- // const props = {
- // ...dbProps,
- // databaseId: null,
- // database_name: null,
- // sqlalchemy_uri: null,
- // };
- // it('should show a form when dynamic_form is selected', async () => {
- // render(, { useRedux: true });
- // // it should have the correct header text
- // const headerText = screen.getByText(/connect a database/i);
- // expect(headerText).toBeVisible();
-
- // await screen.findByText(/display name/i);
-
- // // it does not fetch any databases if no id is passed in
- // expect(fetchMock.calls(DATABASE_FETCH_ENDPOINT).length).toEqual(0);
-
- // // todo we haven't hooked this up to load dynamically yet so
- // // we can't currently test it
- // });
- // it('should close the modal on save if using the sqlalchemy form', async () => {
- // const onHideMock = jest.fn();
- // render(, {
- // useRedux: true,
- // });
- // // button should be disabled by default
- // const submitButton = screen.getByTestId('modal-confirm-button');
- // expect(submitButton).toBeDisabled();
-
- // const displayName = screen.getByTestId('database-name-input');
- // userEvent.type(displayName, 'MyTestDB');
- // expect(displayName.value).toBe('MyTestDB');
- // const sqlalchemyInput = screen.getByTestId('sqlalchemy-uri-input');
- // userEvent.type(sqlalchemyInput, 'some_url');
- // expect(sqlalchemyInput.value).toBe('some_url');
-
- // // button should not be disabled now
- // expect(submitButton).toBeEnabled();
-
- // await waitFor(() => {
- // userEvent.click(submitButton);
- // });
- // expect(fetchMock.calls(DATABASE_POST_ENDPOINT)).toHaveLength(1);
- // expect(onHideMock).toHaveBeenCalled();
- // });
- // });
-
- describe('edit database', () => {
- beforeEach(() => {
- fetchMock.mock(AVAILABLE_DB_ENDPOINT, {
- databases: [
- {
- engine: 'mysql',
- name: 'MySQL',
- preferred: false,
- },
- ],
+ const renderAndWait = async () => {
+ const mounted = act(async () => {
+ render(, {
+ useRedux: true,
+ });
+ });
+
+ return mounted;
+ };
+
+ beforeEach(async () => {
+ await renderAndWait();
+ });
+
+ afterEach(cleanup);
+
+ describe('Visual: New database connection', () => {
+ it('renders the initial load of Step 1 correctly', async () => {
+ // ---------- Components ----------
+ // - AntD header
+ const closeButton = screen.getByRole('button', { name: /close/i });
+ const step1Header = screen.getByRole('heading', {
+ name: /connect a database/i,
+ });
+ // - Connection header
+ const step1Helper = screen.getByText(/step 1 of 3/i);
+ const selectDbHeader = screen.getByRole('heading', {
+ name: /select a database to connect/i,
+ });
+ // - Preferred database buttons
+ const preferredDbButtonPostgreSQL = screen.getByRole('button', {
+ name: /default-database postgresql/i,
+ });
+ const preferredDbTextPostgreSQL = within(
+ preferredDbButtonPostgreSQL,
+ ).getByText(/postgresql/i);
+ const preferredDbButtonPresto = screen.getByRole('button', {
+ name: /default-database presto/i,
+ });
+ const preferredDbTextPresto = within(preferredDbButtonPresto).getByText(
+ /presto/i,
+ );
+ const preferredDbButtonMySQL = screen.getByRole('button', {
+ name: /default-database mysql/i,
+ });
+ const preferredDbTextMySQL = within(preferredDbButtonMySQL).getByText(
+ /mysql/i,
+ );
+ const preferredDbButtonSQLite = screen.getByRole('button', {
+ name: /default-database sqlite/i,
+ });
+ const preferredDbTextSQLite = within(preferredDbButtonSQLite).getByText(
+ /sqlite/i,
+ );
+ // All dbs render with this icon in this testing environment,
+ // The Icon count should equal the count of databases rendered
+ const preferredDbIcon = screen.getAllByRole('img', {
+ name: /default-database/i,
+ });
+ // renderAvailableSelector() =>