Files
superset2/superset-frontend/src/SqlLab/components/SqlEditorTopBar/useDatabaseSelector.test.ts
Mehmet Salih Yavuz 41a22d7918 chore: Upgrade to React 18 (#38563)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-05-04 19:19:36 +03:00

321 lines
7.6 KiB
TypeScript

/**
* 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 configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { renderHook, act } from '@testing-library/react';
import { createWrapper } from 'spec/helpers/testing-library';
import { initialState, defaultQueryEditor } from 'src/SqlLab/fixtures';
import * as localStorageHelpers from 'src/utils/localStorageHelpers';
import useDatabaseSelector from './useDatabaseSelector';
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
const mockDatabase = {
id: 1,
database_name: 'main',
backend: 'mysql',
};
const mockDatabases = {
[mockDatabase.id]: mockDatabase,
};
const createInitialState = (overrides = {}) => ({
...initialState,
sqlLab: {
...initialState.sqlLab,
databases: mockDatabases,
...overrides,
},
});
beforeEach(() => {
jest.spyOn(localStorageHelpers, 'getItem').mockReturnValue(null);
jest.spyOn(localStorageHelpers, 'setItem').mockImplementation(() => {});
});
afterEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});
test('returns initial values from query editor', () => {
const store = mockStore(createInitialState());
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
expect(result.current.catalog).toBe(defaultQueryEditor.catalog);
expect(result.current.schema).toBe(defaultQueryEditor.schema);
expect(typeof result.current.onDbChange).toBe('function');
expect(typeof result.current.onCatalogChange).toBe('function');
expect(typeof result.current.onSchemaChange).toBe('function');
expect(typeof result.current.getDbList).toBe('function');
expect(typeof result.current.handleError).toBe('function');
});
test('returns database when dbId exists in store', () => {
const store = mockStore(
createInitialState({
unsavedQueryEditor: {
id: defaultQueryEditor.id,
dbId: mockDatabase.id,
},
}),
);
const { result, rerender } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
// Trigger effect by rerendering
rerender();
expect(result.current.db).toEqual(mockDatabase);
});
test('dispatches QUERY_EDITOR_SETDB action on onDbChange', () => {
const store = mockStore(createInitialState());
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
act(() => {
result.current.onDbChange({ id: 2 });
});
const actions = store.getActions();
expect(actions).toContainEqual(
expect.objectContaining({
type: 'QUERY_EDITOR_SETDB',
dbId: 2,
}),
);
});
test('dispatches queryEditorSetCatalog action on onCatalogChange', () => {
const store = mockStore(createInitialState());
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
act(() => {
result.current.onCatalogChange('new_catalog');
});
const actions = store.getActions();
expect(actions).toContainEqual(
expect.objectContaining({
type: 'QUERY_EDITOR_SET_CATALOG',
}),
);
});
test('dispatches queryEditorSetSchema action on onSchemaChange', () => {
const store = mockStore(createInitialState());
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
act(() => {
result.current.onSchemaChange('new_schema');
});
const actions = store.getActions();
expect(actions).toContainEqual(
expect.objectContaining({
type: 'QUERY_EDITOR_SET_SCHEMA',
}),
);
});
test('dispatches setDatabases action on getDbList', () => {
const store = mockStore(createInitialState());
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
const newDatabase = {
id: 3,
database_name: 'test_db',
backend: 'postgresql',
};
act(() => {
result.current.getDbList(newDatabase as any);
});
const actions = store.getActions();
expect(actions).toContainEqual(
expect.objectContaining({
type: 'SET_DATABASES',
}),
);
});
test('dispatches addDangerToast action on handleError', () => {
const store = mockStore(createInitialState());
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
act(() => {
result.current.handleError('Test error message');
});
const actions = store.getActions();
expect(actions).toContainEqual(
expect.objectContaining({
type: 'ADD_TOAST',
payload: expect.objectContaining({
toastType: 'DANGER_TOAST',
text: 'Test error message',
}),
}),
);
});
test('reads database from localStorage when URL has db param', () => {
const localStorageDb = {
id: 5,
database_name: 'local_storage_db',
backend: 'sqlite',
};
jest.spyOn(localStorageHelpers, 'getItem').mockReturnValue(localStorageDb);
const originalLocation = window.location;
Object.defineProperty(window, 'location', {
value: { search: '?db=true' },
writable: true,
});
const store = mockStore(createInitialState());
const { result, rerender } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
rerender();
expect(result.current.db).toEqual(localStorageDb);
expect(localStorageHelpers.setItem).toHaveBeenCalledWith(
localStorageHelpers.LocalStorageKeys.Database,
null,
);
Object.defineProperty(window, 'location', {
value: originalLocation,
writable: true,
});
});
test('returns null db when dbId does not exist in databases', () => {
const store = mockStore(
createInitialState({
databases: {},
}),
);
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
expect(result.current.db).toBeNull();
});
test('handles null catalog change', () => {
const store = mockStore(createInitialState());
const { result } = renderHook(
() => useDatabaseSelector(defaultQueryEditor.id),
{
wrapper: createWrapper({
useRedux: true,
store,
}),
},
);
act(() => {
result.current.onCatalogChange(null);
});
const actions = store.getActions();
expect(actions).toContainEqual(
expect.objectContaining({
type: 'QUERY_EDITOR_SET_CATALOG',
}),
);
});