Compare commits

...

9 Commits

Author SHA1 Message Date
Elizabeth Thompson
3d2c332165 Merge remote-tracking branch 'origin/master' into docs/testing-guidelines-test-function 2025-09-29 13:13:49 -07:00
Elizabeth Thompson
572f3392d7 docs(testing): add guidelines for using test() instead of describe()/it()
Added comprehensive testing structure guidelines to LLMS.md that explain why and how to use test() instead of describe() and it(), following the "avoid nesting when testing" principle for better test isolation and readability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 10:25:15 -07:00
Geidō
90f281f585 fix: AceEditor Autocomplete Highlight (#35316) 2025-09-29 13:37:30 +03:00
Evan Rusackas
d62249d13f test(frontend): Migrate from describe/it to flat test() pattern (#35305)
Co-authored-by: Claude <noreply@anthropic.com>
2025-09-28 11:45:33 -07:00
Maxime Beauchemin
ff102aadb3 refactor(llm): rename LLMS.md to AGENTS.md for modern AI tools (#35314)
Co-authored-by: Claude <noreply@anthropic.com>
2025-09-27 12:46:16 +03:00
Elizabeth Thompson
82e2bc6181 fix(DatasourceModal): replace imperative modal updates with declarative state (#35256)
Co-authored-by: Claude <noreply@anthropic.com>
2025-09-26 17:54:17 -07:00
Gabriel Torres Ruiz
784ff82847 fix(sqllab): fix blank bottom section in SQL Lab left panel (#35309) 2025-09-26 20:07:20 +03:00
Mehmet Salih Yavuz
027b25e6b8 fix(DateFilterControl): remove modal overlay style to fix z-index issues (#35292) 2025-09-26 15:42:46 +02:00
SBIN2010
b652fab042 fix(table): New ad-hoc columns retain the name of previous columns (#35274) 2025-09-26 10:34:55 -03:00
272 changed files with 2361 additions and 1664 deletions

View File

@@ -1 +1 @@
../LLMS.md ../AGENTS.md

View File

@@ -82,6 +82,7 @@ intro_header.txt
# for LLMs # for LLMs
llm-context.md llm-context.md
AGENTS.md
LLMS.md LLMS.md
CLAUDE.md CLAUDE.md
CURSOR.md CURSOR.md

View File

@@ -68,7 +68,7 @@ superset/
### Apache License Headers ### Apache License Headers
- **New files require ASF license headers** - When creating new code files, include the standard Apache Software Foundation license header - **New files require ASF license headers** - When creating new code files, include the standard Apache Software Foundation license header
- **LLM instruction files are excluded** - Files like LLMS.md, CLAUDE.md, etc. are in `.rat-excludes` to avoid header token overhead - **LLM instruction files are excluded** - Files like AGENTS.md, CLAUDE.md, etc. are in `.rat-excludes` to avoid header token overhead
### Code Comments ### Code Comments
- **Avoid time-specific language** - Don't use words like "now", "currently", "today" in code comments as they become outdated - **Avoid time-specific language** - Don't use words like "now", "currently", "today" in code comments as they become outdated
@@ -102,6 +102,17 @@ superset/
- **`selectOption()`** - Select component helper - **`selectOption()`** - Select component helper
- **React Testing Library** - NO Enzyme (removed) - **React Testing Library** - NO Enzyme (removed)
### Test Structure Guidelines
- **Use `test()` instead of `describe()` and `it()`** - Follow the [avoid nesting when testing](https://kentcdodds.com/blog/avoid-nesting-when-youre-testing) principle
- **Why**: Reduces unnecessary nesting, improves test isolation, and makes tests more readable
- **Pattern**: Write flat test files with descriptive test names that fully describe what's being tested
- **Example**: Instead of nested `describe('Component', () => { it('should render', ...) })`, use `test('Component renders correctly', ...)`
- **Benefits**:
- Each test stands alone with a clear, searchable name
- Easier to run individual tests
- Forces you to write more descriptive test names
- Reduces cognitive overhead from nested context switching
### Test Database Patterns ### Test Database Patterns
- **Mock patterns**: Use `MagicMock()` for config objects, avoid `AsyncMock` for synchronous code - **Mock patterns**: Use `MagicMock()` for config objects, avoid `AsyncMock` for synchronous code
- **API tests**: Update expected columns when adding new model fields - **API tests**: Update expected columns when adding new model fields

View File

@@ -1 +1 @@
LLMS.md AGENTS.md

View File

@@ -1 +1 @@
LLMS.md AGENTS.md

2
GPT.md
View File

@@ -1 +1 @@
LLMS.md AGENTS.md

View File

@@ -0,0 +1,11 @@
{
"overrides": [
{
"files": ["*.test.ts", "*.test.tsx", "*.test.js", "*.test.jsx"],
"rules": {
"jest/consistent-test-it": ["error", {"fn": "test"}],
"no-restricted-globals": ["error", "describe", "it"]
}
}
]
}

View File

@@ -49,6 +49,7 @@ jest.mock('@superset-ui/core', () => ({
isFeatureEnabled: jest.fn(), isFeatureEnabled: jest.fn(),
})); }));
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('getUpToDateQuery', () => { describe('getUpToDateQuery', () => {
test('should return the up to date query editor state', () => { test('should return the up to date query editor state', () => {
const outOfUpdatedQueryEditor = { const outOfUpdatedQueryEditor = {
@@ -72,6 +73,7 @@ describe('getUpToDateQuery', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('async actions', () => { describe('async actions', () => {
const mockBigNumber = '9223372036854775807'; const mockBigNumber = '9223372036854775807';
const queryEditor = { const queryEditor = {
@@ -100,6 +102,7 @@ describe('async actions', () => {
const runQueryEndpoint = 'glob:*/api/v1/sqllab/execute/'; const runQueryEndpoint = 'glob:*/api/v1/sqllab/execute/';
fetchMock.post(runQueryEndpoint, `{ "data": ${mockBigNumber} }`); fetchMock.post(runQueryEndpoint, `{ "data": ${mockBigNumber} }`);
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('saveQuery', () => { describe('saveQuery', () => {
const saveQueryEndpoint = 'glob:*/api/v1/saved_query/'; const saveQueryEndpoint = 'glob:*/api/v1/saved_query/';
fetchMock.post(saveQueryEndpoint, { results: { json: {} } }); fetchMock.post(saveQueryEndpoint, { results: { json: {} } });
@@ -109,7 +112,7 @@ describe('async actions', () => {
return request(dispatch, () => initialState); return request(dispatch, () => initialState);
}; };
it('posts to the correct url', () => { test('posts to the correct url', () => {
expect.assertions(1); expect.assertions(1);
const store = mockStore(initialState); const store = mockStore(initialState);
@@ -118,7 +121,7 @@ describe('async actions', () => {
}); });
}); });
it('posts the correct query object', () => { test('posts the correct query object', () => {
const store = mockStore(initialState); const store = mockStore(initialState);
return store.dispatch(actions.saveQuery(query, queryId)).then(() => { return store.dispatch(actions.saveQuery(query, queryId)).then(() => {
const call = fetchMock.calls(saveQueryEndpoint)[0]; const call = fetchMock.calls(saveQueryEndpoint)[0];
@@ -131,7 +134,7 @@ describe('async actions', () => {
}); });
}); });
it('calls 3 dispatch actions', () => { test('calls 3 dispatch actions', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -139,7 +142,7 @@ describe('async actions', () => {
}); });
}); });
it('calls QUERY_EDITOR_SAVED after making a request', () => { test('calls QUERY_EDITOR_SAVED after making a request', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -147,7 +150,7 @@ describe('async actions', () => {
}); });
}); });
it('onSave calls QUERY_EDITOR_SAVED and QUERY_EDITOR_SET_TITLE', () => { test('onSave calls QUERY_EDITOR_SAVED and QUERY_EDITOR_SET_TITLE', () => {
expect.assertions(1); expect.assertions(1);
const store = mockStore(initialState); const store = mockStore(initialState);
@@ -163,6 +166,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('formatQuery', () => { describe('formatQuery', () => {
const formatQueryEndpoint = 'glob:*/api/v1/sqllab/format_sql/'; const formatQueryEndpoint = 'glob:*/api/v1/sqllab/format_sql/';
const expectedSql = 'SELECT 1'; const expectedSql = 'SELECT 1';
@@ -179,6 +183,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('fetchQueryResults', () => { describe('fetchQueryResults', () => {
const makeRequest = () => { const makeRequest = () => {
const store = mockStore(initialState); const store = mockStore(initialState);
@@ -186,7 +191,7 @@ describe('async actions', () => {
return request(dispatch, store.getState); return request(dispatch, store.getState);
}; };
it('makes the fetch request', () => { test('makes the fetch request', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -194,7 +199,7 @@ describe('async actions', () => {
}); });
}); });
it('calls requestQueryResults', () => { test('calls requestQueryResults', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -202,7 +207,7 @@ describe('async actions', () => {
}); });
}); });
it.skip('parses large number result without losing precision', () => test.skip('parses large number result without losing precision', () =>
makeRequest().then(() => { makeRequest().then(() => {
expect(fetchMock.calls(fetchQueryEndpoint)).toHaveLength(1); expect(fetchMock.calls(fetchQueryEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(2); expect(dispatch.callCount).toBe(2);
@@ -211,7 +216,7 @@ describe('async actions', () => {
); );
})); }));
it('calls querySuccess on fetch success', () => { test('calls querySuccess on fetch success', () => {
expect.assertions(1); expect.assertions(1);
const store = mockStore({}); const store = mockStore({});
@@ -226,7 +231,7 @@ describe('async actions', () => {
}); });
}); });
it('calls queryFailed on fetch error', () => { test('calls queryFailed on fetch error', () => {
expect.assertions(1); expect.assertions(1);
fetchMock.get( fetchMock.get(
@@ -248,13 +253,14 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('runQuery without query params', () => { describe('runQuery without query params', () => {
const makeRequest = () => { const makeRequest = () => {
const request = actions.runQuery(query); const request = actions.runQuery(query);
return request(dispatch, () => initialState); return request(dispatch, () => initialState);
}; };
it('makes the fetch request', () => { test('makes the fetch request', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -262,7 +268,7 @@ describe('async actions', () => {
}); });
}); });
it('calls startQuery', () => { test('calls startQuery', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -270,7 +276,7 @@ describe('async actions', () => {
}); });
}); });
it.skip('parses large number result without losing precision', () => test.skip('parses large number result without losing precision', () =>
makeRequest().then(() => { makeRequest().then(() => {
expect(fetchMock.calls(runQueryEndpoint)).toHaveLength(1); expect(fetchMock.calls(runQueryEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(2); expect(dispatch.callCount).toBe(2);
@@ -279,7 +285,7 @@ describe('async actions', () => {
); );
})); }));
it('calls querySuccess on fetch success', () => { test('calls querySuccess on fetch success', () => {
expect.assertions(1); expect.assertions(1);
const store = mockStore({}); const store = mockStore({});
@@ -293,7 +299,7 @@ describe('async actions', () => {
}); });
}); });
it('calls queryFailed on fetch error and logs the error details', () => { test('calls queryFailed on fetch error and logs the error details', () => {
expect.assertions(2); expect.assertions(2);
fetchMock.post( fetchMock.post(
@@ -324,6 +330,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('runQuery with query params', () => { describe('runQuery with query params', () => {
const { location } = window; const { location } = window;
@@ -342,7 +349,7 @@ describe('async actions', () => {
return request(dispatch, () => initialState); return request(dispatch, () => initialState);
}; };
it('makes the fetch request', async () => { test('makes the fetch request', async () => {
const runQueryEndpointWithParams = const runQueryEndpointWithParams =
'glob:*/api/v1/sqllab/execute/?foo=bar'; 'glob:*/api/v1/sqllab/execute/?foo=bar';
fetchMock.post( fetchMock.post(
@@ -355,8 +362,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('reRunQuery', () => { describe('reRunQuery', () => {
it('creates new query with a new id', () => { test('creates new query with a new id', () => {
const id = 'id'; const id = 'id';
const state = { const state = {
sqlLab: { sqlLab: {
@@ -372,6 +380,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('postStopQuery', () => { describe('postStopQuery', () => {
const stopQueryEndpoint = 'glob:*/api/v1/query/stop'; const stopQueryEndpoint = 'glob:*/api/v1/query/stop';
fetchMock.post(stopQueryEndpoint, {}); fetchMock.post(stopQueryEndpoint, {});
@@ -385,7 +394,7 @@ describe('async actions', () => {
return request(dispatch); return request(dispatch);
}; };
it('makes the fetch request', () => { test('makes the fetch request', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -393,7 +402,7 @@ describe('async actions', () => {
}); });
}); });
it('calls stopQuery', () => { test('calls stopQuery', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -401,7 +410,7 @@ describe('async actions', () => {
}); });
}); });
it('sends the correct data', () => { test('sends the correct data', () => {
expect.assertions(1); expect.assertions(1);
return makeRequest().then(() => { return makeRequest().then(() => {
@@ -412,8 +421,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('cloneQueryToNewTab', () => { describe('cloneQueryToNewTab', () => {
it('creates new query editor', () => { test('creates new query editor', () => {
expect.assertions(1); expect.assertions(1);
const id = 'id'; const id = 'id';
@@ -455,6 +465,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('popSavedQuery', () => { describe('popSavedQuery', () => {
const supersetClientGetSpy = jest.spyOn(SupersetClient, 'get'); const supersetClientGetSpy = jest.spyOn(SupersetClient, 'get');
const store = mockStore({}); const store = mockStore({});
@@ -508,7 +519,7 @@ describe('async actions', () => {
supersetClientGetSpy.mockRestore(); supersetClientGetSpy.mockRestore();
}); });
it('calls API endpint with correct params', async () => { test('calls API endpint with correct params', async () => {
supersetClientGetSpy.mockResolvedValue({ supersetClientGetSpy.mockResolvedValue({
json: { result: mockSavedQueryApiResponse }, json: { result: mockSavedQueryApiResponse },
}); });
@@ -520,7 +531,7 @@ describe('async actions', () => {
}); });
}); });
it('dispatches addQueryEditor with correct params on successful API call', async () => { test('dispatches addQueryEditor with correct params on successful API call', async () => {
supersetClientGetSpy.mockResolvedValue({ supersetClientGetSpy.mockResolvedValue({
json: { result: mockSavedQueryApiResponse }, json: { result: mockSavedQueryApiResponse },
}); });
@@ -547,7 +558,7 @@ describe('async actions', () => {
); );
}); });
it('should dispatch addDangerToast on API error', async () => { test('should dispatch addDangerToast on API error', async () => {
supersetClientGetSpy.mockResolvedValue(new Error()); supersetClientGetSpy.mockResolvedValue(new Error());
await makeRequest(1); await makeRequest(1);
@@ -561,8 +572,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('addQueryEditor', () => { describe('addQueryEditor', () => {
it('creates new query editor', () => { test('creates new query editor', () => {
expect.assertions(1); expect.assertions(1);
const store = mockStore(initialState); const store = mockStore(initialState);
@@ -582,8 +594,9 @@ describe('async actions', () => {
expect(store.getActions()).toEqual(expectedActions); expect(store.getActions()).toEqual(expectedActions);
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('addNewQueryEditor', () => { describe('addNewQueryEditor', () => {
it('creates new query editor with new tab name', () => { test('creates new query editor with new tab name', () => {
const store = mockStore({ const store = mockStore({
...initialState, ...initialState,
sqlLab: { sqlLab: {
@@ -621,7 +634,7 @@ describe('async actions', () => {
}); });
}); });
it('set current query editor', () => { test('set current query editor', () => {
expect.assertions(1); expect.assertions(1);
const store = mockStore(initialState); const store = mockStore(initialState);
@@ -636,8 +649,9 @@ describe('async actions', () => {
expect(store.getActions()).toEqual(expectedActions); expect(store.getActions()).toEqual(expectedActions);
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('swithQueryEditor', () => { describe('swithQueryEditor', () => {
it('switch to the next tab editor', () => { test('switch to the next tab editor', () => {
const store = mockStore(initialState); const store = mockStore(initialState);
const expectedActions = [ const expectedActions = [
{ {
@@ -650,7 +664,7 @@ describe('async actions', () => {
expect(store.getActions()).toEqual(expectedActions); expect(store.getActions()).toEqual(expectedActions);
}); });
it('switch to the first tab editor once it reaches the rightmost tab', () => { test('switch to the first tab editor once it reaches the rightmost tab', () => {
const store = mockStore({ const store = mockStore({
...initialState, ...initialState,
sqlLab: { sqlLab: {
@@ -673,7 +687,7 @@ describe('async actions', () => {
expect(store.getActions()).toEqual(expectedActions); expect(store.getActions()).toEqual(expectedActions);
}); });
it('switch to the previous tab editor', () => { test('switch to the previous tab editor', () => {
const store = mockStore({ const store = mockStore({
...initialState, ...initialState,
sqlLab: { sqlLab: {
@@ -692,7 +706,7 @@ describe('async actions', () => {
expect(store.getActions()).toEqual(expectedActions); expect(store.getActions()).toEqual(expectedActions);
}); });
it('switch to the last tab editor once it reaches the leftmost tab', () => { test('switch to the last tab editor once it reaches the leftmost tab', () => {
const store = mockStore({ const store = mockStore({
...initialState, ...initialState,
sqlLab: { sqlLab: {
@@ -715,6 +729,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('backend sync', () => { describe('backend sync', () => {
const updateTabStateEndpoint = 'glob:*/tabstateview/*'; const updateTabStateEndpoint = 'glob:*/tabstateview/*';
fetchMock.put(updateTabStateEndpoint, {}); fetchMock.put(updateTabStateEndpoint, {});
@@ -745,8 +760,9 @@ describe('async actions', () => {
afterEach(() => fetchMock.resetHistory()); afterEach(() => fetchMock.resetHistory());
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('addQueryEditor', () => { describe('addQueryEditor', () => {
it('creates the tab state in the local storage', () => { test('creates the tab state in the local storage', () => {
expect.assertions(2); expect.assertions(2);
const store = mockStore({}); const store = mockStore({});
@@ -769,8 +785,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('removeQueryEditor', () => { describe('removeQueryEditor', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const store = mockStore({}); const store = mockStore({});
@@ -785,8 +802,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetDb', () => { describe('queryEditorSetDb', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const dbId = 42; const dbId = 42;
@@ -803,8 +821,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetCatalog', () => { describe('queryEditorSetCatalog', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const catalog = 'public'; const catalog = 'public';
@@ -821,8 +840,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetSchema', () => { describe('queryEditorSetSchema', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const schema = 'schema'; const schema = 'schema';
@@ -839,8 +859,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetAutorun', () => { describe('queryEditorSetAutorun', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const autorun = true; const autorun = true;
@@ -857,8 +878,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetTitle', () => { describe('queryEditorSetTitle', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const name = 'name'; const name = 'name';
@@ -877,6 +899,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetAndSaveSql', () => { describe('queryEditorSetAndSaveSql', () => {
const sql = 'SELECT * '; const sql = 'SELECT * ';
const expectedActions = [ const expectedActions = [
@@ -886,8 +909,9 @@ describe('async actions', () => {
sql, sql,
}, },
]; ];
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('with backend persistence flag on', () => { describe('with backend persistence flag on', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(2); expect.assertions(2);
const store = mockStore({ const store = mockStore({
@@ -904,8 +928,9 @@ describe('async actions', () => {
}); });
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('with backend persistence flag off', () => { describe('with backend persistence flag off', () => {
it('does not update the tab state in the backend', () => { test('does not update the tab state in the backend', () => {
isFeatureEnabled.mockImplementation( isFeatureEnabled.mockImplementation(
feature => !(feature === 'SQLLAB_BACKEND_PERSISTENCE'), feature => !(feature === 'SQLLAB_BACKEND_PERSISTENCE'),
); );
@@ -927,8 +952,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetQueryLimit', () => { describe('queryEditorSetQueryLimit', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const queryLimit = 10; const queryLimit = 10;
@@ -947,8 +973,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('queryEditorSetTemplateParams', () => { describe('queryEditorSetTemplateParams', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(1); expect.assertions(1);
const templateParams = '{"foo": "bar"}'; const templateParams = '{"foo": "bar"}';
@@ -968,8 +995,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('addTable', () => { describe('addTable', () => {
it('dispatches table state from unsaved change', () => { test('dispatches table state from unsaved change', () => {
const tableName = 'table'; const tableName = 'table';
const catalogName = null; const catalogName = null;
const schemaName = 'schema'; const schemaName = 'schema';
@@ -1003,7 +1031,7 @@ describe('async actions', () => {
); );
}); });
it('uses tabViewId when available', () => { test('uses tabViewId when available', () => {
const tableName = 'table'; const tableName = 'table';
const catalogName = null; const catalogName = null;
const schemaName = 'schema'; const schemaName = 'schema';
@@ -1043,7 +1071,7 @@ describe('async actions', () => {
); );
}); });
it('falls back to id when tabViewId is not available', () => { test('falls back to id when tabViewId is not available', () => {
const tableName = 'table'; const tableName = 'table';
const catalogName = null; const catalogName = null;
const schemaName = 'schema'; const schemaName = 'schema';
@@ -1083,8 +1111,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('syncTable', () => { describe('syncTable', () => {
it('updates the table schema state in the backend', () => { test('updates the table schema state in the backend', () => {
expect.assertions(4); expect.assertions(4);
const tableName = 'table'; const tableName = 'table';
@@ -1107,6 +1136,7 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('runTablePreviewQuery', () => { describe('runTablePreviewQuery', () => {
const results = { const results = {
data: mockBigNumber, data: mockBigNumber,
@@ -1137,7 +1167,7 @@ describe('async actions', () => {
fetchMock.resetHistory(); fetchMock.resetHistory();
}); });
it('updates and runs data preview query when configured', () => { test('updates and runs data preview query when configured', () => {
expect.assertions(3); expect.assertions(3);
const expectedActionTypes = [ const expectedActionTypes = [
@@ -1161,7 +1191,7 @@ describe('async actions', () => {
}); });
}); });
it('runs data preview query only', () => { test('runs data preview query only', () => {
const expectedActionTypes = [ const expectedActionTypes = [
actions.START_QUERY, // runQuery (data preview) actions.START_QUERY, // runQuery (data preview)
actions.QUERY_SUCCESS, // querySuccess actions.QUERY_SUCCESS, // querySuccess
@@ -1186,8 +1216,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('expandTable', () => { describe('expandTable', () => {
it('updates the table schema state in the backend', () => { test('updates the table schema state in the backend', () => {
expect.assertions(2); expect.assertions(2);
const table = { id: 1 }; const table = { id: 1 };
@@ -1205,8 +1236,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('collapseTable', () => { describe('collapseTable', () => {
it('updates the table schema state in the backend', () => { test('updates the table schema state in the backend', () => {
expect.assertions(2); expect.assertions(2);
const table = { id: 1 }; const table = { id: 1 };
@@ -1224,8 +1256,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('removeTables', () => { describe('removeTables', () => {
it('updates the table schema state in the backend', () => { test('updates the table schema state in the backend', () => {
expect.assertions(2); expect.assertions(2);
const table = { id: 1, initialized: true }; const table = { id: 1, initialized: true };
@@ -1242,7 +1275,7 @@ describe('async actions', () => {
}); });
}); });
it('deletes multiple tables and updates the table schema state in the backend', () => { test('deletes multiple tables and updates the table schema state in the backend', () => {
expect.assertions(2); expect.assertions(2);
const tables = [ const tables = [
@@ -1262,7 +1295,7 @@ describe('async actions', () => {
}); });
}); });
it('only updates the initialized table schema state in the backend', () => { test('only updates the initialized table schema state in the backend', () => {
expect.assertions(2); expect.assertions(2);
const tables = [{ id: 1 }, { id: 2, initialized: true }]; const tables = [{ id: 1 }, { id: 2, initialized: true }];
@@ -1280,8 +1313,9 @@ describe('async actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('syncQueryEditor', () => { describe('syncQueryEditor', () => {
it('updates the tab state in the backend', () => { test('updates the tab state in the backend', () => {
expect.assertions(3); expect.assertions(3);
const results = { const results = {

View File

@@ -68,12 +68,13 @@ const setup = (queryEditor: QueryEditor, store?: Store) =>
}, },
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('AceEditorWrapper', () => { describe('AceEditorWrapper', () => {
beforeEach(() => { beforeEach(() => {
(FullSQLEditor as any as jest.Mock).mockClear(); (FullSQLEditor as any as jest.Mock).mockClear();
}); });
it('renders ace editor including sql value', async () => { test('renders ace editor including sql value', async () => {
const store = createStore(initialState, reducerIndex); const store = createStore(initialState, reducerIndex);
const { getByTestId } = setup(defaultQueryEditor, store); const { getByTestId } = setup(defaultQueryEditor, store);
await waitFor(() => expect(getByTestId('react-ace')).toBeInTheDocument()); await waitFor(() => expect(getByTestId('react-ace')).toBeInTheDocument());
@@ -83,7 +84,7 @@ describe('AceEditorWrapper', () => {
); );
}); });
it('renders current sql for unrelated unsaved changes', () => { test('renders current sql for unrelated unsaved changes', () => {
const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE'; const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE';
const store = createStore( const store = createStore(
{ {
@@ -108,7 +109,7 @@ describe('AceEditorWrapper', () => {
); );
}); });
it('skips rerendering for updating cursor position', () => { test('skips rerendering for updating cursor position', () => {
const store = createStore(initialState, reducerIndex); const store = createStore(initialState, reducerIndex);
setup(defaultQueryEditor, store); setup(defaultQueryEditor, store);

View File

@@ -193,6 +193,11 @@ const AceEditorWrapper = ({
width: ${theme.sizeUnit * 130}px !important; width: ${theme.sizeUnit * 130}px !important;
} }
.ace_completion-highlight {
color: ${theme.colorPrimaryText} !important;
background-color: ${theme.colorPrimaryBgHover};
}
.ace_tooltip { .ace_tooltip {
max-width: ${SQL_EDITOR_LEFTBAR_WIDTH}px; max-width: ${SQL_EDITOR_LEFTBAR_WIDTH}px;
} }

View File

@@ -47,6 +47,7 @@ const sqlLabReducer = combineReducers({
}); });
const mockAction = {} as AnyAction; const mockAction = {} as AnyAction;
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SqlLab App', () => { describe('SqlLab App', () => {
const middlewares = [thunk]; const middlewares = [thunk];
const mockStore = configureStore(middlewares); const mockStore = configureStore(middlewares);
@@ -60,23 +61,23 @@ describe('SqlLab App', () => {
jest.useRealTimers(); jest.useRealTimers();
}); });
it('is valid', () => { test('is valid', () => {
expect(isValidElement(<App />)).toBe(true); expect(isValidElement(<App />)).toBe(true);
}); });
it('should render', () => { test('should render', () => {
const { getByTestId } = render(<App />, { useRedux: true, store }); const { getByTestId } = render(<App />, { useRedux: true, store });
expect(getByTestId('SqlLabApp')).toBeInTheDocument(); expect(getByTestId('SqlLabApp')).toBeInTheDocument();
expect(getByTestId('mock-tabbed-sql-editors')).toBeInTheDocument(); expect(getByTestId('mock-tabbed-sql-editors')).toBeInTheDocument();
}); });
it('reset hotkey events on unmount', () => { test('reset hotkey events on unmount', () => {
const { unmount } = render(<App />, { useRedux: true, store }); const { unmount } = render(<App />, { useRedux: true, store });
unmount(); unmount();
expect(Mousetrap.reset).toHaveBeenCalled(); expect(Mousetrap.reset).toHaveBeenCalled();
}); });
it('logs current usage warning', () => { test('logs current usage warning', () => {
const localStorageUsageInKilobytes = LOCALSTORAGE_MAX_USAGE_KB + 10; const localStorageUsageInKilobytes = LOCALSTORAGE_MAX_USAGE_KB + 10;
const initialState = { const initialState = {
localStorageUsageInKilobytes, localStorageUsageInKilobytes,
@@ -100,7 +101,7 @@ describe('SqlLab App', () => {
); );
}); });
it('logs current local storage usage', async () => { test('logs current local storage usage', async () => {
const localStorageUsageInKilobytes = LOCALSTORAGE_MAX_USAGE_KB - 10; const localStorageUsageInKilobytes = LOCALSTORAGE_MAX_USAGE_KB - 10;
const storeExceedLocalStorage = mockStore( const storeExceedLocalStorage = mockStore(
sqlLabReducer( sqlLabReducer(

View File

@@ -21,22 +21,23 @@ import { render } from 'spec/helpers/testing-library';
import ColumnElement from 'src/SqlLab/components/ColumnElement'; import ColumnElement from 'src/SqlLab/components/ColumnElement';
import { mockedActions, table } from 'src/SqlLab/fixtures'; import { mockedActions, table } from 'src/SqlLab/fixtures';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ColumnElement', () => { describe('ColumnElement', () => {
const mockedProps = { const mockedProps = {
actions: mockedActions, actions: mockedActions,
column: table.columns[0], column: table.columns[0],
}; };
it('is valid with props', () => { test('is valid with props', () => {
expect(isValidElement(<ColumnElement {...mockedProps} />)).toBe(true); expect(isValidElement(<ColumnElement {...mockedProps} />)).toBe(true);
}); });
it('renders a proper primary key', () => { test('renders a proper primary key', () => {
const { container } = render(<ColumnElement column={table.columns[0]} />); const { container } = render(<ColumnElement column={table.columns[0]} />);
expect(container.querySelector('i.fa-key')).toBeInTheDocument(); expect(container.querySelector('i.fa-key')).toBeInTheDocument();
expect( expect(
container.querySelector('[data-test="col-name"]')?.firstChild, container.querySelector('[data-test="col-name"]')?.firstChild,
).toHaveTextContent('id'); ).toHaveTextContent('id');
}); });
it('renders a multi-key column', () => { test('renders a multi-key column', () => {
const { container } = render(<ColumnElement column={table.columns[1]} />); const { container } = render(<ColumnElement column={table.columns[1]} />);
expect(container.querySelector('i.fa-link')).toBeInTheDocument(); expect(container.querySelector('i.fa-link')).toBeInTheDocument();
expect(container.querySelector('i.fa-bookmark')).toBeInTheDocument(); expect(container.querySelector('i.fa-bookmark')).toBeInTheDocument();
@@ -44,7 +45,7 @@ describe('ColumnElement', () => {
container.querySelector('[data-test="col-name"]')?.firstChild, container.querySelector('[data-test="col-name"]')?.firstChild,
).toHaveTextContent('first_name'); ).toHaveTextContent('first_name');
}); });
it('renders a column with no keys', () => { test('renders a column with no keys', () => {
const { container } = render(<ColumnElement column={table.columns[2]} />); const { container } = render(<ColumnElement column={table.columns[2]} />);
expect(container.querySelector('i')).not.toBeInTheDocument(); expect(container.querySelector('i')).not.toBeInTheDocument();
expect( expect(

View File

@@ -53,14 +53,15 @@ const setup = (props: Partial<EstimateQueryCostButtonProps>, store?: Store) =>
}, },
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('EstimateQueryCostButton', () => { describe('EstimateQueryCostButton', () => {
it('renders EstimateQueryCostButton', async () => { test('renders EstimateQueryCostButton', async () => {
const { queryByText } = setup({}, mockStore(initialState)); const { queryByText } = setup({}, mockStore(initialState));
expect(queryByText('Estimate cost')).toBeInTheDocument(); expect(queryByText('Estimate cost')).toBeInTheDocument();
}); });
it('renders label for selected query', async () => { test('renders label for selected query', async () => {
const { queryByText } = setup( const { queryByText } = setup(
{ queryEditorId: extraQueryEditor1.id }, { queryEditorId: extraQueryEditor1.id },
mockStore(initialState), mockStore(initialState),
@@ -69,7 +70,7 @@ describe('EstimateQueryCostButton', () => {
expect(queryByText('Estimate selected query cost')).toBeInTheDocument(); expect(queryByText('Estimate selected query cost')).toBeInTheDocument();
}); });
it('renders label for selected query from unsaved', async () => { test('renders label for selected query from unsaved', async () => {
const { queryByText } = setup( const { queryByText } = setup(
{}, {},
mockStore({ mockStore({
@@ -87,7 +88,7 @@ describe('EstimateQueryCostButton', () => {
expect(queryByText('Estimate selected query cost')).toBeInTheDocument(); expect(queryByText('Estimate selected query cost')).toBeInTheDocument();
}); });
it('renders estimation error result', async () => { test('renders estimation error result', async () => {
const { queryByText, getByText } = setup( const { queryByText, getByText } = setup(
{}, {},
mockStore({ mockStore({
@@ -109,7 +110,7 @@ describe('EstimateQueryCostButton', () => {
expect(queryByText('Estimate error')).toBeInTheDocument(); expect(queryByText('Estimate error')).toBeInTheDocument();
}); });
it('renders estimation success result', async () => { test('renders estimation success result', async () => {
const { queryByText, getByText } = setup( const { queryByText, getByText } = setup(
{}, {},
mockStore({ mockStore({

View File

@@ -47,17 +47,18 @@ const setup = (props: Partial<ExploreCtasResultsButtonProps>, store?: Store) =>
}, },
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ExploreCtasResultsButton', () => { describe('ExploreCtasResultsButton', () => {
const postFormSpy = jest.spyOn(SupersetClientClass.prototype, 'postForm'); const postFormSpy = jest.spyOn(SupersetClientClass.prototype, 'postForm');
postFormSpy.mockImplementation(jest.fn()); postFormSpy.mockImplementation(jest.fn());
it('renders', async () => { test('renders', async () => {
const { queryByText } = setup({}, mockStore(initialState)); const { queryByText } = setup({}, mockStore(initialState));
expect(queryByText('Explore')).toBeInTheDocument(); expect(queryByText('Explore')).toBeInTheDocument();
}); });
it('visualize results', async () => { test('visualize results', async () => {
const { getByText } = setup({}, mockStore(initialState)); const { getByText } = setup({}, mockStore(initialState));
postFormSpy.mockClear(); postFormSpy.mockClear();
@@ -75,7 +76,7 @@ describe('ExploreCtasResultsButton', () => {
}); });
}); });
it('visualize results fails', async () => { test('visualize results fails', async () => {
const { getByText } = setup({}, mockStore(initialState)); const { getByText } = setup({}, mockStore(initialState));
postFormSpy.mockClear(); postFormSpy.mockClear();

View File

@@ -31,8 +31,9 @@ const setup = (
useRedux: true, useRedux: true,
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ExploreResultsButton', () => { describe('ExploreResultsButton', () => {
it('renders', async () => { test('renders', async () => {
const { queryByText } = setup(jest.fn(), { const { queryByText } = setup(jest.fn(), {
database: { allows_subquery: true }, database: { allows_subquery: true },
}); });
@@ -41,7 +42,7 @@ describe('ExploreResultsButton', () => {
expect(screen.getByRole('button', { name: /Create chart/i })).toBeEnabled(); expect(screen.getByRole('button', { name: /Create chart/i })).toBeEnabled();
}); });
it('renders disabled if subquery not allowed', async () => { test('renders disabled if subquery not allowed', async () => {
const { queryByText } = setup(jest.fn()); const { queryByText } = setup(jest.fn());
expect(queryByText('Create chart')).toBeInTheDocument(); expect(queryByText('Create chart')).toBeInTheDocument();
// Updated line to match the actual button name that includes the icon // Updated line to match the actual button name that includes the icon

View File

@@ -43,6 +43,7 @@ const mockState = {
databases: mockDatabases, databases: mockDatabases,
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('QueryAutoRefresh', () => { describe('QueryAutoRefresh', () => {
const runningQueries: QueryDictionary = { [runningQuery.id]: runningQuery }; const runningQueries: QueryDictionary = { [runningQuery.id]: runningQuery };
const successfulQueries: QueryDictionary = { const successfulQueries: QueryDictionary = {
@@ -62,15 +63,15 @@ describe('QueryAutoRefresh', () => {
jest.useRealTimers(); jest.useRealTimers();
}); });
it('isQueryRunning returns true for valid running query', () => { test('isQueryRunning returns true for valid running query', () => {
expect(isQueryRunning(runningQuery)).toBe(true); expect(isQueryRunning(runningQuery)).toBe(true);
}); });
it('isQueryRunning returns false for valid not-running query', () => { test('isQueryRunning returns false for valid not-running query', () => {
expect(isQueryRunning(successfulQuery)).toBe(false); expect(isQueryRunning(successfulQuery)).toBe(false);
}); });
it('isQueryRunning returns false for invalid query', () => { test('isQueryRunning returns false for invalid query', () => {
// @ts-ignore // @ts-ignore
expect(isQueryRunning(null)).toBe(false); expect(isQueryRunning(null)).toBe(false);
// @ts-ignore // @ts-ignore
@@ -81,15 +82,15 @@ describe('QueryAutoRefresh', () => {
expect(isQueryRunning({ state: { badFormat: true } })).toBe(false); expect(isQueryRunning({ state: { badFormat: true } })).toBe(false);
}); });
it('shouldCheckForQueries is true for valid running query', () => { test('shouldCheckForQueries is true for valid running query', () => {
expect(shouldCheckForQueries(runningQueries)).toBe(true); expect(shouldCheckForQueries(runningQueries)).toBe(true);
}); });
it('shouldCheckForQueries is false for valid completed query', () => { test('shouldCheckForQueries is false for valid completed query', () => {
expect(shouldCheckForQueries(successfulQueries)).toBe(false); expect(shouldCheckForQueries(successfulQueries)).toBe(false);
}); });
it('shouldCheckForQueries is false for invalid inputs', () => { test('shouldCheckForQueries is false for invalid inputs', () => {
// @ts-ignore // @ts-ignore
expect(shouldCheckForQueries(null)).toBe(false); expect(shouldCheckForQueries(null)).toBe(false);
// @ts-ignore // @ts-ignore
@@ -109,7 +110,7 @@ describe('QueryAutoRefresh', () => {
).toBe(false); ).toBe(false);
}); });
it('Attempts to refresh when given pending query', async () => { test('Attempts to refresh when given pending query', async () => {
const store = mockStore({ sqlLab: { ...mockState } }); const store = mockStore({ sqlLab: { ...mockState } });
fetchMock.get(refreshApi, { fetchMock.get(refreshApi, {
@@ -135,7 +136,7 @@ describe('QueryAutoRefresh', () => {
); );
}); });
it('Attempts to clear inactive queries when updated queries are empty', async () => { test('Attempts to clear inactive queries when updated queries are empty', async () => {
const store = mockStore({ sqlLab: { ...mockState } }); const store = mockStore({ sqlLab: { ...mockState } });
fetchMock.get(refreshApi, { result: [] }); fetchMock.get(refreshApi, { result: [] });
@@ -164,7 +165,7 @@ describe('QueryAutoRefresh', () => {
expect(fetchMock.calls(refreshApi)).toHaveLength(1); expect(fetchMock.calls(refreshApi)).toHaveLength(1);
}); });
it('Does not fail and attempts to refresh with mixed valid/invalid queries', async () => { test('Does not fail and attempts to refresh with mixed valid/invalid queries', async () => {
const store = mockStore({ sqlLab: { ...mockState } }); const store = mockStore({ sqlLab: { ...mockState } });
fetchMock.get(refreshApi, { fetchMock.get(refreshApi, {
@@ -191,7 +192,7 @@ describe('QueryAutoRefresh', () => {
); );
}); });
it('Does NOT Attempt to refresh when given only completed queries', async () => { test('Does NOT Attempt to refresh when given only completed queries', async () => {
const store = mockStore({ sqlLab: { ...mockState } }); const store = mockStore({ sqlLab: { ...mockState } });
fetchMock.get(refreshApi, { fetchMock.get(refreshApi, {
@@ -219,7 +220,7 @@ describe('QueryAutoRefresh', () => {
expect(fetchMock.calls(refreshApi)).toHaveLength(0); expect(fetchMock.calls(refreshApi)).toHaveLength(0);
}); });
it('logs the failed error for async queries', async () => { test('logs the failed error for async queries', async () => {
const store = mockStore({ sqlLab: { ...mockState } }); const store = mockStore({ sqlLab: { ...mockState } });
fetchMock.get(refreshApi, { fetchMock.get(refreshApi, {

View File

@@ -58,8 +58,9 @@ const setup = (props?: Partial<QueryLimitSelectProps>, store?: Store) =>
}, },
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('QueryLimitSelect', () => { describe('QueryLimitSelect', () => {
it('renders current query limit size', () => { test('renders current query limit size', () => {
const queryLimit = 10; const queryLimit = 10;
const { getByText } = setup( const { getByText } = setup(
{ {
@@ -81,12 +82,12 @@ describe('QueryLimitSelect', () => {
expect(getByText(queryLimit)).toBeInTheDocument(); expect(getByText(queryLimit)).toBeInTheDocument();
}); });
it('renders default query limit for initial queryEditor', () => { test('renders default query limit for initial queryEditor', () => {
const { getByText } = setup({}, mockStore(initialState)); const { getByText } = setup({}, mockStore(initialState));
expect(getByText(defaultQueryLimit)).toBeInTheDocument(); expect(getByText(defaultQueryLimit)).toBeInTheDocument();
}); });
it('renders queryLimit from unsavedQueryEditor', () => { test('renders queryLimit from unsavedQueryEditor', () => {
const queryLimit = 10000; const queryLimit = 10000;
const { getByText } = setup( const { getByText } = setup(
{}, {},
@@ -104,7 +105,7 @@ describe('QueryLimitSelect', () => {
expect(getByText(convertToNumWithSpaces(queryLimit))).toBeInTheDocument(); expect(getByText(convertToNumWithSpaces(queryLimit))).toBeInTheDocument();
}); });
it('renders dropdown select', async () => { test('renders dropdown select', async () => {
const { baseElement, getAllByRole, getByRole } = setup( const { baseElement, getAllByRole, getByRole } = setup(
{ maxRow: 50000 }, { maxRow: 50000 },
mockStore(initialState), mockStore(initialState),
@@ -126,7 +127,7 @@ describe('QueryLimitSelect', () => {
expect(actualLabels).toEqual(expectedLabels); expect(actualLabels).toEqual(expectedLabels);
}); });
it('renders dropdown select correctly when maxRow is less than 10', async () => { test('renders dropdown select correctly when maxRow is less than 10', async () => {
const { baseElement, getAllByRole, getByRole } = setup( const { baseElement, getAllByRole, getByRole } = setup(
{ maxRow: 5 }, { maxRow: 5 },
mockStore(initialState), mockStore(initialState),
@@ -146,7 +147,7 @@ describe('QueryLimitSelect', () => {
expect(actualLabels).toEqual(expectedLabels); expect(actualLabels).toEqual(expectedLabels);
}); });
it('renders dropdown select correctly when maxRow is a multiple of 10', async () => { test('renders dropdown select correctly when maxRow is a multiple of 10', async () => {
const { baseElement, getAllByRole, getByRole } = setup( const { baseElement, getAllByRole, getByRole } = setup(
{ maxRow: 10000 }, { maxRow: 10000 },
mockStore(initialState), mockStore(initialState),
@@ -168,7 +169,7 @@ describe('QueryLimitSelect', () => {
expect(actualLabels).toEqual(expectedLabels); expect(actualLabels).toEqual(expectedLabels);
}); });
it('dispatches QUERY_EDITOR_SET_QUERY_LIMIT action on dropdown menu click', async () => { test('dispatches QUERY_EDITOR_SET_QUERY_LIMIT action on dropdown menu click', async () => {
const store = mockStore(initialState); const store = mockStore(initialState);
const expectedIndex = 1; const expectedIndex = 1;
const { baseElement, getAllByRole, getByRole } = setup({}, store); const { baseElement, getAllByRole, getByRole } = setup({}, store);

View File

@@ -29,6 +29,7 @@ const mockedProps = {
latestQueryId: 'ryhMUZCGb', latestQueryId: 'ryhMUZCGb',
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('QueryTable', () => { describe('QueryTable', () => {
test('is valid', () => { test('is valid', () => {
expect(isValidElement(<QueryTable displayLimit={100} />)).toBe(true); expect(isValidElement(<QueryTable displayLimit={100} />)).toBe(true);

View File

@@ -150,6 +150,7 @@ const setup = (props?: any, store?: Store) =>
...(store && { store }), ...(store && { store }),
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ResultSet', () => { describe('ResultSet', () => {
beforeAll(() => { beforeAll(() => {
setupAGGridModules(); setupAGGridModules();

View File

@@ -53,17 +53,17 @@ const setup = (props?: Partial<RunQueryActionButtonProps>, store?: Store) =>
...(store && { store }), ...(store && { store }),
}); });
it('renders a single Button', () => { test('renders a single Button', () => {
const { getByRole } = setup({}, mockStore(initialState)); const { getByRole } = setup({}, mockStore(initialState));
expect(getByRole('button')).toBeInTheDocument(); expect(getByRole('button')).toBeInTheDocument();
}); });
it('renders a label for Run Query', () => { test('renders a label for Run Query', () => {
const { getByText } = setup({}, mockStore(initialState)); const { getByText } = setup({}, mockStore(initialState));
expect(getByText('Run')).toBeInTheDocument(); expect(getByText('Run')).toBeInTheDocument();
}); });
it('renders a label for Selected Query', () => { test('renders a label for Selected Query', () => {
const { getByText } = setup( const { getByText } = setup(
{}, {},
mockStore({ mockStore({
@@ -80,7 +80,7 @@ it('renders a label for Selected Query', () => {
expect(getByText('Run selection')).toBeInTheDocument(); expect(getByText('Run selection')).toBeInTheDocument();
}); });
it('disable button when sql from unsaved changes is empty', () => { test('disable button when sql from unsaved changes is empty', () => {
const { getByRole } = setup( const { getByRole } = setup(
{}, {},
mockStore({ mockStore({
@@ -98,7 +98,7 @@ it('disable button when sql from unsaved changes is empty', () => {
expect(button).toBeDisabled(); expect(button).toBeDisabled();
}); });
it('disable button when selectedText only contains blank contents', () => { test('disable button when selectedText only contains blank contents', () => {
const { getByRole } = setup( const { getByRole } = setup(
{}, {},
mockStore({ mockStore({
@@ -116,7 +116,7 @@ it('disable button when selectedText only contains blank contents', () => {
expect(button).toBeDisabled(); expect(button).toBeDisabled();
}); });
it('enable default button for unrelated unsaved changes', () => { test('enable default button for unrelated unsaved changes', () => {
const { getByRole } = setup( const { getByRole } = setup(
{}, {},
mockStore({ mockStore({
@@ -134,7 +134,7 @@ it('enable default button for unrelated unsaved changes', () => {
expect(button).toBeEnabled(); expect(button).toBeEnabled();
}); });
it('dispatch runQuery on click', async () => { test('dispatch runQuery on click', async () => {
const runQuery = jest.fn(); const runQuery = jest.fn();
const { getByRole } = setup({ runQuery }, mockStore(initialState)); const { getByRole } = setup({ runQuery }, mockStore(initialState));
const button = getByRole('button'); const button = getByRole('button');
@@ -143,7 +143,7 @@ it('dispatch runQuery on click', async () => {
await waitFor(() => expect(runQuery).toHaveBeenCalledTimes(1)); await waitFor(() => expect(runQuery).toHaveBeenCalledTimes(1));
}); });
it('dispatch stopQuery on click while running state', async () => { test('dispatch stopQuery on click while running state', async () => {
const stopQuery = jest.fn(); const stopQuery = jest.fn();
const { getByRole } = setup( const { getByRole } = setup(
{ queryState: 'running', stopQuery }, { queryState: 'running', stopQuery },

View File

@@ -24,6 +24,7 @@ const overlayMenu = (
<Menu items={[{ label: 'Save dataset', key: 'save-dataset' }]} /> <Menu items={[{ label: 'Save dataset', key: 'save-dataset' }]} />
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SaveDatasetActionButton', () => { describe('SaveDatasetActionButton', () => {
test('renders a split save button', async () => { test('renders a split save button', async () => {
render( render(

View File

@@ -62,8 +62,9 @@ jest.mock('src/explore/exploreUtils/formData', () => ({
postFormData: jest.fn(), postFormData: jest.fn(),
})); }));
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SaveDatasetModal', () => { describe('SaveDatasetModal', () => {
it('renders a "Save as new" field', () => { test('renders a "Save as new" field', () => {
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
const saveRadioBtn = screen.getByRole('radio', { const saveRadioBtn = screen.getByRole('radio', {
@@ -80,7 +81,7 @@ describe('SaveDatasetModal', () => {
expect(inputFieldText).toBeInTheDocument(); expect(inputFieldText).toBeInTheDocument();
}); });
it('renders an "Overwrite existing" field', () => { test('renders an "Overwrite existing" field', () => {
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
const overwriteRadioBtn = screen.getByRole('radio', { const overwriteRadioBtn = screen.getByRole('radio', {
@@ -96,20 +97,20 @@ describe('SaveDatasetModal', () => {
expect(placeholderText).toBeInTheDocument(); expect(placeholderText).toBeInTheDocument();
}); });
it('renders a close button', () => { test('renders a close button', () => {
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
expect(screen.getByRole('button', { name: /close/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /close/i })).toBeInTheDocument();
}); });
it('renders a save button when "Save as new" is selected', () => { test('renders a save button when "Save as new" is selected', () => {
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
// "Save as new" is selected when the modal opens by default // "Save as new" is selected when the modal opens by default
expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument();
}); });
it('renders an overwrite button when "Overwrite existing" is selected', () => { test('renders an overwrite button when "Overwrite existing" is selected', () => {
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
// Click the overwrite radio button to reveal the overwrite confirmation and back buttons // Click the overwrite radio button to reveal the overwrite confirmation and back buttons
@@ -123,7 +124,7 @@ describe('SaveDatasetModal', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('renders the overwrite button as disabled until an existing dataset is selected', async () => { test('renders the overwrite button as disabled until an existing dataset is selected', async () => {
useSelectorMock.mockReturnValue({ ...user }); useSelectorMock.mockReturnValue({ ...user });
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
@@ -155,7 +156,7 @@ describe('SaveDatasetModal', () => {
expect(overwriteConfirmationBtn).toBeEnabled(); expect(overwriteConfirmationBtn).toBeEnabled();
}); });
it('renders a confirm overwrite screen when overwrite is clicked', async () => { test('renders a confirm overwrite screen when overwrite is clicked', async () => {
useSelectorMock.mockReturnValue({ ...user }); useSelectorMock.mockReturnValue({ ...user });
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
@@ -196,7 +197,7 @@ describe('SaveDatasetModal', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('sends the schema when creating the dataset', async () => { test('sends the schema when creating the dataset', async () => {
const dummyDispatch = jest.fn().mockResolvedValue({}); const dummyDispatch = jest.fn().mockResolvedValue({});
useDispatchMock.mockReturnValue(dummyDispatch); useDispatchMock.mockReturnValue(dummyDispatch);
useSelectorMock.mockReturnValue({ ...user }); useSelectorMock.mockReturnValue({ ...user });
@@ -221,7 +222,7 @@ describe('SaveDatasetModal', () => {
}); });
}); });
it('sends the catalog when creating the dataset', async () => { test('sends the catalog when creating the dataset', async () => {
const dummyDispatch = jest.fn().mockResolvedValue({}); const dummyDispatch = jest.fn().mockResolvedValue({});
useDispatchMock.mockReturnValue(dummyDispatch); useDispatchMock.mockReturnValue(dummyDispatch);
useSelectorMock.mockReturnValue({ ...user }); useSelectorMock.mockReturnValue({ ...user });
@@ -252,12 +253,12 @@ describe('SaveDatasetModal', () => {
}); });
}); });
it('does not renders a checkbox button when template processing is disabled', () => { test('does not renders a checkbox button when template processing is disabled', () => {
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true }); render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument(); expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
}); });
it('renders a checkbox button when template processing is enabled', () => { test('renders a checkbox button when template processing is enabled', () => {
// @ts-ignore // @ts-ignore
global.featureFlags = { global.featureFlags = {
[FeatureFlag.EnableTemplateProcessing]: true, [FeatureFlag.EnableTemplateProcessing]: true,
@@ -266,7 +267,7 @@ describe('SaveDatasetModal', () => {
expect(screen.getByRole('checkbox')).toBeInTheDocument(); expect(screen.getByRole('checkbox')).toBeInTheDocument();
}); });
it('correctly includes template parameters when template processing is enabled', () => { test('correctly includes template parameters when template processing is enabled', () => {
// @ts-ignore // @ts-ignore
global.featureFlags = { global.featureFlags = {
[FeatureFlag.EnableTemplateProcessing]: true, [FeatureFlag.EnableTemplateProcessing]: true,
@@ -301,7 +302,7 @@ describe('SaveDatasetModal', () => {
}); });
}); });
it('correctly excludes template parameters when template processing is enabled', () => { test('correctly excludes template parameters when template processing is enabled', () => {
// @ts-ignore // @ts-ignore
global.featureFlags = { global.featureFlags = {
[FeatureFlag.EnableTemplateProcessing]: true, [FeatureFlag.EnableTemplateProcessing]: true,

View File

@@ -64,8 +64,9 @@ const splitSaveBtnProps = {
const middlewares = [thunk]; const middlewares = [thunk];
const mockStore = configureStore(middlewares); const mockStore = configureStore(middlewares);
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SavedQuery', () => { describe('SavedQuery', () => {
it('doesnt render save button when allows_virtual_table_explore is undefined', async () => { test('doesnt render save button when allows_virtual_table_explore is undefined', async () => {
const noRenderProps = { const noRenderProps = {
...mockedProps, ...mockedProps,
database: { database: {
@@ -84,7 +85,7 @@ describe('SavedQuery', () => {
); );
}); });
it('renders a non-split save button when allows_virtual_table_explore is not enabled', () => { test('renders a non-split save button when allows_virtual_table_explore is not enabled', () => {
render(<SaveQuery {...mockedProps} />, { render(<SaveQuery {...mockedProps} />, {
useRedux: true, useRedux: true,
store: mockStore(mockState), store: mockStore(mockState),
@@ -95,7 +96,7 @@ describe('SavedQuery', () => {
expect(saveBtn).toBeVisible(); expect(saveBtn).toBeVisible();
}); });
it('renders a save query modal when user clicks save button', () => { test('renders a save query modal when user clicks save button', () => {
render(<SaveQuery {...mockedProps} />, { render(<SaveQuery {...mockedProps} />, {
useRedux: true, useRedux: true,
store: mockStore(mockState), store: mockStore(mockState),
@@ -111,7 +112,7 @@ describe('SavedQuery', () => {
expect(saveQueryModalHeader).toBeInTheDocument(); expect(saveQueryModalHeader).toBeInTheDocument();
}); });
it('renders the save query modal UI', () => { test('renders the save query modal UI', () => {
render(<SaveQuery {...mockedProps} />, { render(<SaveQuery {...mockedProps} />, {
useRedux: true, useRedux: true,
store: mockStore(mockState), store: mockStore(mockState),
@@ -146,7 +147,7 @@ describe('SavedQuery', () => {
expect(cancelBtn).toBeInTheDocument(); expect(cancelBtn).toBeInTheDocument();
}); });
it('renders a "save as new" and "update" button if query already exists', () => { test('renders a "save as new" and "update" button if query already exists', () => {
render(<SaveQuery {...mockedProps} />, { render(<SaveQuery {...mockedProps} />, {
useRedux: true, useRedux: true,
store: mockStore({ store: mockStore({
@@ -171,7 +172,7 @@ describe('SavedQuery', () => {
expect(updateBtn).toBeInTheDocument(); expect(updateBtn).toBeInTheDocument();
}); });
it('renders a split save button when allows_virtual_table_explore is enabled', async () => { test('renders a split save button when allows_virtual_table_explore is enabled', async () => {
render(<SaveQuery {...splitSaveBtnProps} />, { render(<SaveQuery {...splitSaveBtnProps} />, {
useRedux: true, useRedux: true,
store: mockStore(mockState), store: mockStore(mockState),
@@ -186,7 +187,7 @@ describe('SavedQuery', () => {
}); });
}); });
it('renders a save dataset modal when user clicks "save dataset" menu item', async () => { test('renders a save dataset modal when user clicks "save dataset" menu item', async () => {
render(<SaveQuery {...splitSaveBtnProps} />, { render(<SaveQuery {...splitSaveBtnProps} />, {
useRedux: true, useRedux: true,
store: mockStore(mockState), store: mockStore(mockState),
@@ -205,7 +206,7 @@ describe('SavedQuery', () => {
expect(saveDatasetHeader).toBeInTheDocument(); expect(saveDatasetHeader).toBeInTheDocument();
}); });
it('renders the save dataset modal UI', async () => { test('renders the save dataset modal UI', async () => {
render(<SaveQuery {...splitSaveBtnProps} />, { render(<SaveQuery {...splitSaveBtnProps} />, {
useRedux: true, useRedux: true,
store: mockStore(mockState), store: mockStore(mockState),
@@ -246,7 +247,7 @@ describe('SavedQuery', () => {
expect(overwritePlaceholderText).toBeInTheDocument(); expect(overwritePlaceholderText).toBeInTheDocument();
}); });
it('modal stays open while save is in progress and closes after completion', async () => { test('modal stays open while save is in progress and closes after completion', async () => {
let resolveSave: () => void; let resolveSave: () => void;
const savePromise = new Promise<void>(resolve => { const savePromise = new Promise<void>(resolve => {
resolveSave = resolve; resolveSave = resolve;
@@ -290,7 +291,7 @@ describe('SavedQuery', () => {
expect(mockOnSave).toHaveBeenCalledTimes(1); expect(mockOnSave).toHaveBeenCalledTimes(1);
}); });
it('handles save with a new tab that has no changes', async () => { test('handles save with a new tab that has no changes', async () => {
const mockOnSave = jest.fn().mockResolvedValue(undefined); const mockOnSave = jest.fn().mockResolvedValue(undefined);
// Mock state for a new tab with default SQL // Mock state for a new tab with default SQL

View File

@@ -76,6 +76,7 @@ const unsavedQueryEditor = {
templateParams: '{ "my_value": "foo" }', templateParams: '{ "my_value": "foo" }',
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ShareSqlLabQuery', () => { describe('ShareSqlLabQuery', () => {
const storeQueryUrl = 'glob:*/api/v1/sqllab/permalink'; const storeQueryUrl = 'glob:*/api/v1/sqllab/permalink';
const storeQueryMockId = 'ci39c3'; const storeQueryMockId = 'ci39c3';
@@ -94,6 +95,7 @@ describe('ShareSqlLabQuery', () => {
afterAll(() => fetchMock.reset()); afterAll(() => fetchMock.reset());
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('via permalink api', () => { describe('via permalink api', () => {
beforeAll(() => { beforeAll(() => {
mockedIsFeatureEnabled.mockImplementation(() => true); mockedIsFeatureEnabled.mockImplementation(() => true);
@@ -103,7 +105,7 @@ describe('ShareSqlLabQuery', () => {
mockedIsFeatureEnabled.mockReset(); mockedIsFeatureEnabled.mockReset();
}); });
it('calls storeQuery() with the query when getCopyUrl() is called', async () => { test('calls storeQuery() with the query when getCopyUrl() is called', async () => {
await act(async () => { await act(async () => {
render(<ShareSqlLabQuery {...defaultProps} />, { render(<ShareSqlLabQuery {...defaultProps} />, {
useRedux: true, useRedux: true,
@@ -121,7 +123,7 @@ describe('ShareSqlLabQuery', () => {
).toEqual(expected); ).toEqual(expected);
}); });
it('calls storeQuery() with unsaved changes', async () => { test('calls storeQuery() with unsaved changes', async () => {
await act(async () => { await act(async () => {
render(<ShareSqlLabQuery {...defaultProps} />, { render(<ShareSqlLabQuery {...defaultProps} />, {
useRedux: true, useRedux: true,

View File

@@ -149,6 +149,7 @@ const createStore = (initState: object) =>
getDefaultMiddleware().concat(api.middleware, logAction), getDefaultMiddleware().concat(api.middleware, logAction),
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SqlEditor', () => { describe('SqlEditor', () => {
beforeAll(() => { beforeAll(() => {
jest.setTimeout(30000); jest.setTimeout(30000);
@@ -192,7 +193,7 @@ describe('SqlEditor', () => {
}); });
}); });
it('does not render SqlEditor if no db selected', async () => { test('does not render SqlEditor if no db selected', async () => {
const queryEditor = initialState.sqlLab.queryEditors[2]; const queryEditor = initialState.sqlLab.queryEditors[2];
const { findByText } = setup({ ...mockedProps, queryEditor }, store); const { findByText } = setup({ ...mockedProps, queryEditor }, store);
expect( expect(
@@ -200,7 +201,7 @@ describe('SqlEditor', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('renders db unavailable message', async () => { test('renders db unavailable message', async () => {
const queryEditor = initialState.sqlLab.queryEditors[1]; const queryEditor = initialState.sqlLab.queryEditors[1];
const { findByText } = setup({ ...mockedProps, queryEditor }, store); const { findByText } = setup({ ...mockedProps, queryEditor }, store);
expect( expect(
@@ -210,7 +211,7 @@ describe('SqlEditor', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('render a SqlEditorLeftBar', async () => { test('render a SqlEditorLeftBar', async () => {
const { getByTestId, unmount } = setup(mockedProps, store); const { getByTestId, unmount } = setup(mockedProps, store);
await waitFor( await waitFor(
@@ -222,7 +223,7 @@ describe('SqlEditor', () => {
}, 15000); }, 15000);
// Update other similar tests with timeouts // Update other similar tests with timeouts
it('render an AceEditorWrapper', async () => { test('render an AceEditorWrapper', async () => {
const { findByTestId, unmount } = setup(mockedProps, store); const { findByTestId, unmount } = setup(mockedProps, store);
await waitFor( await waitFor(
@@ -233,7 +234,7 @@ describe('SqlEditor', () => {
unmount(); unmount();
}, 15000); }, 15000);
it('skip rendering an AceEditorWrapper when the current tab is inactive', async () => { test('skip rendering an AceEditorWrapper when the current tab is inactive', async () => {
const { findByTestId, queryByTestId } = setup( const { findByTestId, queryByTestId } = setup(
{ {
...mockedProps, ...mockedProps,
@@ -245,7 +246,7 @@ describe('SqlEditor', () => {
expect(queryByTestId('react-ace')).not.toBeInTheDocument(); expect(queryByTestId('react-ace')).not.toBeInTheDocument();
}); });
it('avoids rerendering EditorLeftBar and ResultSet while typing', async () => { test('avoids rerendering EditorLeftBar and ResultSet while typing', async () => {
const { findByTestId } = setup(mockedProps, store); const { findByTestId } = setup(mockedProps, store);
const editor = await findByTestId('react-ace'); const editor = await findByTestId('react-ace');
const sql = 'select *'; const sql = 'select *';
@@ -260,7 +261,7 @@ describe('SqlEditor', () => {
expect(ResultSet).toHaveBeenCalledTimes(renderCountForSouthPane); expect(ResultSet).toHaveBeenCalledTimes(renderCountForSouthPane);
}); });
it('renders sql from unsaved change', async () => { test('renders sql from unsaved change', async () => {
const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE'; const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE';
store = createStore({ store = createStore({
...initialState, ...initialState,
@@ -293,12 +294,12 @@ describe('SqlEditor', () => {
expect(editor).toHaveValue(expectedSql); expect(editor).toHaveValue(expectedSql);
}); });
it('render a SouthPane', async () => { test('render a SouthPane', async () => {
const { findByTestId } = setup(mockedProps, store); const { findByTestId } = setup(mockedProps, store);
expect(await findByTestId('mock-result-set')).toBeInTheDocument(); expect(await findByTestId('mock-result-set')).toBeInTheDocument();
}); });
it('runs query action with ctas false', async () => { test('runs query action with ctas false', async () => {
store = createStore({ store = createStore({
...initialState, ...initialState,
sqlLab: { sqlLab: {
@@ -338,7 +339,7 @@ describe('SqlEditor', () => {
); );
}); });
it('render a Limit Dropdown', async () => { test('render a Limit Dropdown', async () => {
const defaultQueryLimit = 101; const defaultQueryLimit = 101;
const updatedProps = { ...mockedProps, defaultQueryLimit }; const updatedProps = { ...mockedProps, defaultQueryLimit };
const { findByText } = setup(updatedProps, store); const { findByText } = setup(updatedProps, store);
@@ -346,7 +347,7 @@ describe('SqlEditor', () => {
expect(await findByText('10 000')).toBeInTheDocument(); expect(await findByText('10 000')).toBeInTheDocument();
}); });
it('renders an Extension if provided', async () => { test('renders an Extension if provided', async () => {
const extensionsRegistry = getExtensionsRegistry(); const extensionsRegistry = getExtensionsRegistry();
extensionsRegistry.set('sqleditor.extension.form', () => ( extensionsRegistry.set('sqleditor.extension.form', () => (
@@ -360,6 +361,7 @@ describe('SqlEditor', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('with EstimateQueryCost enabled', () => { describe('with EstimateQueryCost enabled', () => {
beforeEach(() => { beforeEach(() => {
mockIsFeatureEnabled.mockImplementation( mockIsFeatureEnabled.mockImplementation(
@@ -370,7 +372,7 @@ describe('SqlEditor', () => {
mockIsFeatureEnabled.mockClear(); mockIsFeatureEnabled.mockClear();
}); });
it('sends the catalog and schema to the endpoint', async () => { test('sends the catalog and schema to the endpoint', async () => {
const estimateApi = 'http://localhost/api/v1/sqllab/estimate/'; const estimateApi = 'http://localhost/api/v1/sqllab/estimate/';
fetchMock.post(estimateApi, {}); fetchMock.post(estimateApi, {});
@@ -436,6 +438,7 @@ describe('SqlEditor', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('with SqllabBackendPersistence enabled', () => { describe('with SqllabBackendPersistence enabled', () => {
beforeEach(() => { beforeEach(() => {
mockIsFeatureEnabled.mockImplementation( mockIsFeatureEnabled.mockImplementation(
@@ -446,7 +449,7 @@ describe('SqlEditor', () => {
mockIsFeatureEnabled.mockClear(); mockIsFeatureEnabled.mockClear();
}); });
it('should render loading state when its Editor is not loaded', async () => { test('should render loading state when its Editor is not loaded', async () => {
const switchTabApi = `glob:*/tabstateview/${defaultQueryEditor.id}/activate`; const switchTabApi = `glob:*/tabstateview/${defaultQueryEditor.id}/activate`;
fetchMock.post(switchTabApi, {}); fetchMock.post(switchTabApi, {});
const { getByTestId } = setup( const { getByTestId } = setup(

View File

@@ -168,6 +168,9 @@ const StyledToolbar = styled.div`
const StyledSidebar = styled.div` const StyledSidebar = styled.div`
padding: ${({ theme }) => theme.sizeUnit * 2.5}px; padding: ${({ theme }) => theme.sizeUnit * 2.5}px;
height: 100%;
display: flex;
flex-direction: column;
`; `;
const StyledSqlEditor = styled.div` const StyledSqlEditor = styled.div`

View File

@@ -47,7 +47,6 @@ import TableElement from '../TableElement';
export interface SqlEditorLeftBarProps { export interface SqlEditorLeftBarProps {
queryEditorId: string; queryEditorId: string;
height?: number;
database?: DatabaseObject; database?: DatabaseObject;
} }
@@ -72,7 +71,6 @@ const LeftBarStyles = styled.div`
const SqlEditorLeftBar = ({ const SqlEditorLeftBar = ({
database, database,
queryEditorId, queryEditorId,
height = 500,
}: SqlEditorLeftBarProps) => { }: SqlEditorLeftBarProps) => {
const allSelectedTables = useSelector<SqlLabRootState, Table[]>( const allSelectedTables = useSelector<SqlLabRootState, Table[]>(
({ sqlLab }) => ({ sqlLab }) =>
@@ -171,7 +169,6 @@ const SqlEditorLeftBar = ({
}; };
const shouldShowReset = window.location.search === '?reset=1'; const shouldShowReset = window.location.search === '?reset=1';
const tableMetaDataHeight = height - 130; // 130 is the height of the selects above
const handleCatalogChange = useCallback( const handleCatalogChange = useCallback(
(catalog: string | null) => { (catalog: string | null) => {
@@ -228,22 +225,16 @@ const SqlEditorLeftBar = ({
/> />
<div className="divider" /> <div className="divider" />
<StyledScrollbarContainer> <StyledScrollbarContainer>
<div {tables.map(table => (
css={css` <TableElement
height: ${tableMetaDataHeight}px; table={table}
`} key={table.id}
> activeKey={tables
{tables.map(table => ( .filter(({ expanded }) => expanded)
<TableElement .map(({ id }) => id)}
table={table} onChange={onToggleTable}
key={table.id} />
activeKey={tables ))}
.filter(({ expanded }) => expanded)
.map(({ id }) => id)}
onChange={onToggleTable}
/>
))}
</div>
</StyledScrollbarContainer> </StyledScrollbarContainer>
{shouldShowReset && ( {shouldShowReset && (
<Button <Button

View File

@@ -56,15 +56,16 @@ const setup = (queryEditor: QueryEditor, store?: Store) =>
...(store && { store }), ...(store && { store }),
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SqlEditorTabHeader', () => { describe('SqlEditorTabHeader', () => {
it('renders name', () => { test('renders name', () => {
const { queryByText } = setup(defaultQueryEditor, mockStore(initialState)); const { queryByText } = setup(defaultQueryEditor, mockStore(initialState));
expect(queryByText(defaultQueryEditor.name)).toBeInTheDocument(); expect(queryByText(defaultQueryEditor.name)).toBeInTheDocument();
expect(queryByText(extraQueryEditor1.name)).not.toBeInTheDocument(); expect(queryByText(extraQueryEditor1.name)).not.toBeInTheDocument();
expect(queryByText(extraQueryEditor2.name)).not.toBeInTheDocument(); expect(queryByText(extraQueryEditor2.name)).not.toBeInTheDocument();
}); });
it('renders name from unsaved changes', () => { test('renders name from unsaved changes', () => {
const expectedTitle = 'updated title'; const expectedTitle = 'updated title';
const { queryByText } = setup( const { queryByText } = setup(
defaultQueryEditor, defaultQueryEditor,
@@ -85,7 +86,7 @@ describe('SqlEditorTabHeader', () => {
expect(queryByText(extraQueryEditor2.name)).not.toBeInTheDocument(); expect(queryByText(extraQueryEditor2.name)).not.toBeInTheDocument();
}); });
it('renders current name for unrelated unsaved changes', () => { test('renders current name for unrelated unsaved changes', () => {
const unrelatedTitle = 'updated title'; const unrelatedTitle = 'updated title';
const { queryByText } = setup( const { queryByText } = setup(
defaultQueryEditor, defaultQueryEditor,
@@ -106,6 +107,7 @@ describe('SqlEditorTabHeader', () => {
expect(queryByText(extraQueryEditor2.name)).not.toBeInTheDocument(); expect(queryByText(extraQueryEditor2.name)).not.toBeInTheDocument();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('with dropdown menus', () => { describe('with dropdown menus', () => {
let store = mockStore(); let store = mockStore();
beforeEach(async () => { beforeEach(async () => {
@@ -116,7 +118,7 @@ describe('SqlEditorTabHeader', () => {
userEvent.click(dropdown); userEvent.click(dropdown);
}); });
it('should dispatch removeQueryEditor action', async () => { test('should dispatch removeQueryEditor action', async () => {
await waitFor(() => await waitFor(() =>
expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(),
); );
@@ -132,7 +134,7 @@ describe('SqlEditorTabHeader', () => {
); );
}); });
it('should dispatch queryEditorSetTitle action', async () => { test('should dispatch queryEditorSetTitle action', async () => {
await waitFor(() => await waitFor(() =>
expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(),
); );
@@ -155,7 +157,7 @@ describe('SqlEditorTabHeader', () => {
mockPrompt.mockClear(); mockPrompt.mockClear();
}); });
it('should dispatch toggleLeftBar action', async () => { test('should dispatch toggleLeftBar action', async () => {
await waitFor(() => await waitFor(() =>
expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(),
); );
@@ -173,7 +175,7 @@ describe('SqlEditorTabHeader', () => {
); );
}); });
it('should dispatch removeAllOtherQueryEditors action', async () => { test('should dispatch removeAllOtherQueryEditors action', async () => {
await waitFor(() => await waitFor(() =>
expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(),
); );
@@ -194,7 +196,7 @@ describe('SqlEditorTabHeader', () => {
); );
}); });
it('should dispatch cloneQueryToNewTab action', async () => { test('should dispatch cloneQueryToNewTab action', async () => {
await waitFor(() => await waitFor(() =>
expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(), expect(screen.getByTestId('close-tab-menu-option')).toBeInTheDocument(),
); );

View File

@@ -56,6 +56,7 @@ afterEach(() => {
pathStub.mockReset(); pathStub.mockReset();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('componentDidMount', () => { describe('componentDidMount', () => {
let uriStub = jest.spyOn(URI.prototype, 'search'); let uriStub = jest.spyOn(URI.prototype, 'search');
let replaceState = jest.spyOn(window.history, 'replaceState'); let replaceState = jest.spyOn(window.history, 'replaceState');

View File

@@ -135,6 +135,7 @@ test('renders preview', async () => {
); );
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('table actions', () => { describe('table actions', () => {
test('refreshes table metadata when triggered', async () => { test('refreshes table metadata when triggered', async () => {
const { getByRole, getByText } = render(<TablePreview {...mockedProps} />, { const { getByRole, getByText } = render(<TablePreview {...mockedProps} />, {

View File

@@ -64,13 +64,14 @@ const setup = (
}, },
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('TemplateParamsEditor', () => { describe('TemplateParamsEditor', () => {
it('should render with a title', () => { test('should render with a title', () => {
const { container } = setup(); const { container } = setup();
expect(container.querySelector('div[role="button"]')).toBeInTheDocument(); expect(container.querySelector('div[role="button"]')).toBeInTheDocument();
}); });
it('should open a modal with the ace editor', async () => { test('should open a modal with the ace editor', async () => {
const { container, getByTestId } = setup(); const { container, getByTestId } = setup();
fireEvent.click(getByText(container, 'Parameters')); fireEvent.click(getByText(container, 'Parameters'));
await waitFor(() => { await waitFor(() => {
@@ -78,7 +79,7 @@ describe('TemplateParamsEditor', () => {
}); });
}); });
it('renders templateParams', async () => { test('renders templateParams', async () => {
const { container, getByTestId } = setup(); const { container, getByTestId } = setup();
fireEvent.click(getByText(container, 'Parameters')); fireEvent.click(getByText(container, 'Parameters'));
await waitFor(() => { await waitFor(() => {
@@ -89,7 +90,7 @@ describe('TemplateParamsEditor', () => {
); );
}); });
it('renders code from unsaved changes', async () => { test('renders code from unsaved changes', async () => {
const expectedCode = 'custom code value'; const expectedCode = 'custom code value';
const { container, getByTestId } = setup( const { container, getByTestId } = setup(
{}, {},

View File

@@ -52,23 +52,25 @@ const apiDataWithTabState = {
latest_query: null, latest_query: null,
}, },
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('getInitialState', () => { describe('getInitialState', () => {
afterEach(() => { afterEach(() => {
localStorage.clear(); localStorage.clear();
}); });
it('should output the user that is passed in', () => { test('should output the user that is passed in', () => {
expect(getInitialState(apiData).user?.userId).toEqual(1); expect(getInitialState(apiData).user?.userId).toEqual(1);
}); });
it('should return undefined instead of null for templateParams', () => { test('should return undefined instead of null for templateParams', () => {
expect( expect(
getInitialState(apiDataWithTabState).sqlLab?.queryEditors?.[0] getInitialState(apiDataWithTabState).sqlLab?.queryEditors?.[0]
?.templateParams, ?.templateParams,
).toBeUndefined(); ).toBeUndefined();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('dedupeTabHistory', () => { describe('dedupeTabHistory', () => {
it('should dedupe the tab history', () => { test('should dedupe the tab history', () => {
[ [
{ value: [], expected: [] }, { value: [], expected: [] },
{ {
@@ -136,8 +138,9 @@ describe('getInitialState', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('dedupe tables schema', () => { describe('dedupe tables schema', () => {
it('should dedupe the table schema', () => { test('should dedupe the table schema', () => {
localStorage.setItem( localStorage.setItem(
'redux', 'redux',
JSON.stringify({ JSON.stringify({
@@ -195,7 +198,7 @@ describe('getInitialState', () => {
expect(initializedTables.map(({ id }) => id)).toEqual([1, 2, 6]); expect(initializedTables.map(({ id }) => id)).toEqual([1, 2, 6]);
}); });
it('should parse the float dttm value', () => { test('should parse the float dttm value', () => {
const startDttmInStr = '1693433503447.166992'; const startDttmInStr = '1693433503447.166992';
const endDttmInStr = '1693433503500.23132'; const endDttmInStr = '1693433503500.23132';
@@ -249,6 +252,7 @@ describe('getInitialState', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('restore unsaved changes for PERSISTENCE mode', () => { describe('restore unsaved changes for PERSISTENCE mode', () => {
const lastUpdatedTime = Date.now(); const lastUpdatedTime = Date.now();
const expectedValue = 'updated editor value'; const expectedValue = 'updated editor value';
@@ -284,7 +288,7 @@ describe('getInitialState', () => {
); );
}); });
it('restore unsaved changes for PERSISTENCE mode', () => { test('restore unsaved changes for PERSISTENCE mode', () => {
const apiDataWithLocalStorage = { const apiDataWithLocalStorage = {
...apiData, ...apiData,
active_tab: { active_tab: {
@@ -321,7 +325,7 @@ describe('getInitialState', () => {
).toEqual(apiDataWithTabState.active_tab.id.toString()); ).toEqual(apiDataWithTabState.active_tab.id.toString());
}); });
it('skip unsaved changes for expired data', () => { test('skip unsaved changes for expired data', () => {
const apiDataWithLocalStorage = { const apiDataWithLocalStorage = {
...apiData, ...apiData,
active_tab: { active_tab: {
@@ -345,7 +349,7 @@ describe('getInitialState', () => {
); );
}); });
it('skip unsaved changes for legacy cache data', () => { test('skip unsaved changes for legacy cache data', () => {
const apiDataWithLocalStorage = { const apiDataWithLocalStorage = {
...apiData, ...apiData,
active_tab: { active_tab: {

View File

@@ -23,7 +23,9 @@ import { table, initialState as mockState } from '../fixtures';
const initialState = mockState.sqlLab; const initialState = mockState.sqlLab;
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('sqlLabReducer', () => { describe('sqlLabReducer', () => {
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Query editors actions', () => { describe('Query editors actions', () => {
let newState; let newState;
let defaultQueryEditor; let defaultQueryEditor;
@@ -38,12 +40,12 @@ describe('sqlLabReducer', () => {
newState = sqlLabReducer(newState, action); newState = sqlLabReducer(newState, action);
qe = newState.queryEditors.find(e => e.id === 'abcd'); qe = newState.queryEditors.find(e => e.id === 'abcd');
}); });
it('should add a query editor', () => { test('should add a query editor', () => {
expect(newState.queryEditors).toHaveLength( expect(newState.queryEditors).toHaveLength(
initialState.queryEditors.length + 1, initialState.queryEditors.length + 1,
); );
}); });
it('should merge the current unsaved changes when adding a query editor', () => { test('should merge the current unsaved changes when adding a query editor', () => {
const expectedTitle = 'new updated title'; const expectedTitle = 'new updated title';
const updateAction = { const updateAction = {
type: actions.QUERY_EDITOR_SET_TITLE, type: actions.QUERY_EDITOR_SET_TITLE,
@@ -62,7 +64,7 @@ describe('sqlLabReducer', () => {
newState.queryEditors[newState.queryEditors.length - 1].id, newState.queryEditors[newState.queryEditors.length - 1].id,
).toEqual('efgh'); ).toEqual('efgh');
}); });
it('should remove a query editor', () => { test('should remove a query editor', () => {
expect(newState.queryEditors).toHaveLength( expect(newState.queryEditors).toHaveLength(
initialState.queryEditors.length + 1, initialState.queryEditors.length + 1,
); );
@@ -75,7 +77,7 @@ describe('sqlLabReducer', () => {
initialState.queryEditors.length, initialState.queryEditors.length,
); );
}); });
it('should select the latest query editor when tabHistory is empty', () => { test('should select the latest query editor when tabHistory is empty', () => {
const currentQE = newState.queryEditors[0]; const currentQE = newState.queryEditors[0];
newState = { newState = {
...initialState, ...initialState,
@@ -94,7 +96,7 @@ describe('sqlLabReducer', () => {
); );
expect(newState.tabHistory).toEqual([initialState.queryEditors[2].id]); expect(newState.tabHistory).toEqual([initialState.queryEditors[2].id]);
}); });
it('should remove a query editor including unsaved changes', () => { test('should remove a query editor including unsaved changes', () => {
expect(newState.queryEditors).toHaveLength( expect(newState.queryEditors).toHaveLength(
initialState.queryEditors.length + 1, initialState.queryEditors.length + 1,
); );
@@ -116,7 +118,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.dbId).toBeUndefined(); expect(newState.unsavedQueryEditor.dbId).toBeUndefined();
expect(newState.unsavedQueryEditor.id).toBeUndefined(); expect(newState.unsavedQueryEditor.id).toBeUndefined();
}); });
it('should set q query editor active', () => { test('should set q query editor active', () => {
const expectedTitle = 'new updated title'; const expectedTitle = 'new updated title';
const addQueryEditorAction = { const addQueryEditorAction = {
type: actions.ADD_QUERY_EDITOR, type: actions.ADD_QUERY_EDITOR,
@@ -139,7 +141,7 @@ describe('sqlLabReducer', () => {
); );
expect(newState.queryEditors[1].name).toEqual(expectedTitle); expect(newState.queryEditors[1].name).toEqual(expectedTitle);
}); });
it('should not fail while setting DB', () => { test('should not fail while setting DB', () => {
const dbId = 9; const dbId = 9;
const action = { const action = {
type: actions.QUERY_EDITOR_SETDB, type: actions.QUERY_EDITOR_SETDB,
@@ -150,7 +152,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.dbId).toBe(dbId); expect(newState.unsavedQueryEditor.dbId).toBe(dbId);
expect(newState.unsavedQueryEditor.id).toBe(qe.id); expect(newState.unsavedQueryEditor.id).toBe(qe.id);
}); });
it('should not fail while setting schema', () => { test('should not fail while setting schema', () => {
const schema = 'foo'; const schema = 'foo';
const action = { const action = {
type: actions.QUERY_EDITOR_SET_SCHEMA, type: actions.QUERY_EDITOR_SET_SCHEMA,
@@ -161,7 +163,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.schema).toBe(schema); expect(newState.unsavedQueryEditor.schema).toBe(schema);
expect(newState.unsavedQueryEditor.id).toBe(qe.id); expect(newState.unsavedQueryEditor.id).toBe(qe.id);
}); });
it('should not fail while setting autorun', () => { test('should not fail while setting autorun', () => {
const action = { const action = {
type: actions.QUERY_EDITOR_SET_AUTORUN, type: actions.QUERY_EDITOR_SET_AUTORUN,
queryEditor: qe, queryEditor: qe,
@@ -173,7 +175,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.autorun).toBe(true); expect(newState.unsavedQueryEditor.autorun).toBe(true);
expect(newState.unsavedQueryEditor.id).toBe(qe.id); expect(newState.unsavedQueryEditor.id).toBe(qe.id);
}); });
it('should not fail while setting title', () => { test('should not fail while setting title', () => {
const title = 'Untitled Query 1'; const title = 'Untitled Query 1';
const action = { const action = {
type: actions.QUERY_EDITOR_SET_TITLE, type: actions.QUERY_EDITOR_SET_TITLE,
@@ -184,7 +186,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.name).toBe(title); expect(newState.unsavedQueryEditor.name).toBe(title);
expect(newState.unsavedQueryEditor.id).toBe(qe.id); expect(newState.unsavedQueryEditor.id).toBe(qe.id);
}); });
it('should not fail while setting Sql', () => { test('should not fail while setting Sql', () => {
const sql = 'SELECT nothing from dev_null'; const sql = 'SELECT nothing from dev_null';
const action = { const action = {
type: actions.QUERY_EDITOR_SET_SQL, type: actions.QUERY_EDITOR_SET_SQL,
@@ -195,7 +197,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.sql).toBe(sql); expect(newState.unsavedQueryEditor.sql).toBe(sql);
expect(newState.unsavedQueryEditor.id).toBe(qe.id); expect(newState.unsavedQueryEditor.id).toBe(qe.id);
}); });
it('should not fail while setting queryLimit', () => { test('should not fail while setting queryLimit', () => {
const queryLimit = 101; const queryLimit = 101;
const action = { const action = {
type: actions.QUERY_EDITOR_SET_QUERY_LIMIT, type: actions.QUERY_EDITOR_SET_QUERY_LIMIT,
@@ -206,7 +208,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.queryLimit).toBe(queryLimit); expect(newState.unsavedQueryEditor.queryLimit).toBe(queryLimit);
expect(newState.unsavedQueryEditor.id).toBe(qe.id); expect(newState.unsavedQueryEditor.id).toBe(qe.id);
}); });
it('should set selectedText', () => { test('should set selectedText', () => {
const selectedText = 'TEST'; const selectedText = 'TEST';
const action = { const action = {
type: actions.QUERY_EDITOR_SET_SELECTED_TEXT, type: actions.QUERY_EDITOR_SET_SELECTED_TEXT,
@@ -218,7 +220,7 @@ describe('sqlLabReducer', () => {
expect(newState.unsavedQueryEditor.selectedText).toBe(selectedText); expect(newState.unsavedQueryEditor.selectedText).toBe(selectedText);
expect(newState.unsavedQueryEditor.id).toBe(qe.id); expect(newState.unsavedQueryEditor.id).toBe(qe.id);
}); });
it('should not wiped out unsaved changes while delayed async call intercepted', () => { test('should not wiped out unsaved changes while delayed async call intercepted', () => {
const expectedSql = 'Updated SQL WORKING IN PROGRESS--'; const expectedSql = 'Updated SQL WORKING IN PROGRESS--';
const action = { const action = {
type: actions.QUERY_EDITOR_SET_SQL, type: actions.QUERY_EDITOR_SET_SQL,
@@ -239,7 +241,7 @@ describe('sqlLabReducer', () => {
interceptedAction.northPercent, interceptedAction.northPercent,
); );
}); });
it('should migrate query editor by new query editor id', () => { test('should migrate query editor by new query editor id', () => {
const { length } = newState.queryEditors; const { length } = newState.queryEditors;
const index = newState.queryEditors.findIndex(({ id }) => id === qe.id); const index = newState.queryEditors.findIndex(({ id }) => id === qe.id);
const newQueryEditor = { const newQueryEditor = {
@@ -267,7 +269,7 @@ describe('sqlLabReducer', () => {
newQueryEditor.tabViewId, newQueryEditor.tabViewId,
); );
}); });
it('should clear the destroyed query editors', () => { test('should clear the destroyed query editors', () => {
const expectedQEId = '1233289'; const expectedQEId = '1233289';
const action = { const action = {
type: actions.CLEAR_DESTROYED_QUERY_EDITOR, type: actions.CLEAR_DESTROYED_QUERY_EDITOR,
@@ -285,6 +287,7 @@ describe('sqlLabReducer', () => {
expect(newState.destroyedQueryEditors).toEqual({}); expect(newState.destroyedQueryEditors).toEqual({});
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Tables', () => { describe('Tables', () => {
let newState; let newState;
let newTable; let newTable;
@@ -297,12 +300,12 @@ describe('sqlLabReducer', () => {
newState = sqlLabReducer(initialState, action); newState = sqlLabReducer(initialState, action);
newTable = newState.tables[0]; newTable = newState.tables[0];
}); });
it('should add a table', () => { test('should add a table', () => {
// Testing that beforeEach actually added the table // Testing that beforeEach actually added the table
expect(newState.tables).toHaveLength(1); expect(newState.tables).toHaveLength(1);
expect(newState.tables[0].expanded).toBe(true); expect(newState.tables[0].expanded).toBe(true);
}); });
it('should merge the table attributes', () => { test('should merge the table attributes', () => {
// Merging the extra attribute // Merging the extra attribute
newTable.extra = true; newTable.extra = true;
const action = { const action = {
@@ -313,7 +316,7 @@ describe('sqlLabReducer', () => {
expect(newState.tables).toHaveLength(1); expect(newState.tables).toHaveLength(1);
expect(newState.tables[0].extra).toBe(true); expect(newState.tables[0].extra).toBe(true);
}); });
it('should overwrite table ID be ignored when the existing table is already initialized', () => { test('should overwrite table ID be ignored when the existing table is already initialized', () => {
const action = { const action = {
type: actions.MERGE_TABLE, type: actions.MERGE_TABLE,
table: newTable, table: newTable,
@@ -345,7 +348,7 @@ describe('sqlLabReducer', () => {
expect(newState.tables).toHaveLength(1); expect(newState.tables).toHaveLength(1);
expect(newState.tables[0].id).toBe(remoteId); expect(newState.tables[0].id).toBe(remoteId);
}); });
it('should expand and collapse a table', () => { test('should expand and collapse a table', () => {
const collapseTableAction = { const collapseTableAction = {
type: actions.COLLAPSE_TABLE, type: actions.COLLAPSE_TABLE,
table: newTable, table: newTable,
@@ -359,7 +362,7 @@ describe('sqlLabReducer', () => {
newState = sqlLabReducer(newState, expandTableAction); newState = sqlLabReducer(newState, expandTableAction);
expect(newState.tables[0].expanded).toBe(true); expect(newState.tables[0].expanded).toBe(true);
}); });
it('should remove a table', () => { test('should remove a table', () => {
const action = { const action = {
type: actions.REMOVE_TABLES, type: actions.REMOVE_TABLES,
tables: [newTable], tables: [newTable],
@@ -368,6 +371,7 @@ describe('sqlLabReducer', () => {
expect(newState.tables).toHaveLength(0); expect(newState.tables).toHaveLength(0);
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Run Query', () => { describe('Run Query', () => {
const DENORMALIZED_CHANGED_ON = '2023-06-26T07:53:05.439'; const DENORMALIZED_CHANGED_ON = '2023-06-26T07:53:05.439';
const CHANGED_ON_TIMESTAMP = 1687765985439; const CHANGED_ON_TIMESTAMP = 1687765985439;
@@ -385,7 +389,7 @@ describe('sqlLabReducer', () => {
sqlEditorId: 'dfsadfs', sqlEditorId: 'dfsadfs',
}; };
}); });
it('should start a query', () => { test('should start a query', () => {
const action = { const action = {
type: actions.START_QUERY, type: actions.START_QUERY,
query: { query: {
@@ -401,7 +405,7 @@ describe('sqlLabReducer', () => {
newState = sqlLabReducer(newState, action); newState = sqlLabReducer(newState, action);
expect(Object.keys(newState.queries)).toHaveLength(1); expect(Object.keys(newState.queries)).toHaveLength(1);
}); });
it('should stop the query', () => { test('should stop the query', () => {
const startQueryAction = { const startQueryAction = {
type: actions.START_QUERY, type: actions.START_QUERY,
query, query,
@@ -415,7 +419,7 @@ describe('sqlLabReducer', () => {
const q = newState.queries[Object.keys(newState.queries)[0]]; const q = newState.queries[Object.keys(newState.queries)[0]];
expect(q.state).toBe('stopped'); expect(q.state).toBe('stopped');
}); });
it('should remove a query', () => { test('should remove a query', () => {
const startQueryAction = { const startQueryAction = {
type: actions.START_QUERY, type: actions.START_QUERY,
query, query,
@@ -428,7 +432,7 @@ describe('sqlLabReducer', () => {
newState = sqlLabReducer(newState, removeQueryAction); newState = sqlLabReducer(newState, removeQueryAction);
expect(Object.keys(newState.queries)).toHaveLength(0); expect(Object.keys(newState.queries)).toHaveLength(0);
}); });
it('should refresh queries when polling returns new results', () => { test('should refresh queries when polling returns new results', () => {
const startDttmInStr = '1693433503447.166992'; const startDttmInStr = '1693433503447.166992';
const endDttmInStr = '1693433503500.23132'; const endDttmInStr = '1693433503500.23132';
newState = sqlLabReducer( newState = sqlLabReducer(
@@ -449,7 +453,7 @@ describe('sqlLabReducer', () => {
expect(newState.queries.abcd.endDttm).toBe(Number(endDttmInStr)); expect(newState.queries.abcd.endDttm).toBe(Number(endDttmInStr));
expect(newState.queriesLastUpdate).toBe(CHANGED_ON_TIMESTAMP); expect(newState.queriesLastUpdate).toBe(CHANGED_ON_TIMESTAMP);
}); });
it('should skip refreshing queries when polling contains existing results', () => { test('should skip refreshing queries when polling contains existing results', () => {
const completedQuery = { const completedQuery = {
...query, ...query,
extra: { extra: {
@@ -478,10 +482,11 @@ describe('sqlLabReducer', () => {
expect(newState.queries.abcd).toBe(query); expect(newState.queries.abcd).toBe(query);
expect(newState.queries.def).toBe(completedQuery); expect(newState.queries.def).toBe(completedQuery);
}); });
it('should refresh queries when polling returns empty', () => { test('should refresh queries when polling returns empty', () => {
newState = sqlLabReducer(newState, actions.refreshQueries({})); newState = sqlLabReducer(newState, actions.refreshQueries({}));
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('CLEAR_INACTIVE_QUERIES', () => { describe('CLEAR_INACTIVE_QUERIES', () => {
let newState; let newState;
let query; let query;
@@ -496,7 +501,7 @@ describe('sqlLabReducer', () => {
cached: false, cached: false,
}; };
}); });
it('updates queries that have already been completed', () => { test('updates queries that have already been completed', () => {
newState = sqlLabReducer( newState = sqlLabReducer(
{ {
...newState, ...newState,

View File

@@ -29,6 +29,7 @@ import {
} from 'src/SqlLab/constants'; } from 'src/SqlLab/constants';
import { queries, defaultQueryEditor } from '../fixtures'; import { queries, defaultQueryEditor } from '../fixtures';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('reduxStateToLocalStorageHelper', () => { describe('reduxStateToLocalStorageHelper', () => {
const queriesObj: Record<string, any> = {}; const queriesObj: Record<string, any> = {};
beforeEach(() => { beforeEach(() => {
@@ -37,7 +38,7 @@ describe('reduxStateToLocalStorageHelper', () => {
}); });
}); });
it('should empty query.results if query.startDttm is > LOCALSTORAGE_MAX_QUERY_AGE_MS', () => { test('should empty query.results if query.startDttm is > LOCALSTORAGE_MAX_QUERY_AGE_MS', () => {
// make sure sample data contains old query // make sure sample data contains old query
const oldQuery = queries[0]; const oldQuery = queries[0];
const { id, startDttm } = oldQuery; const { id, startDttm } = oldQuery;
@@ -51,7 +52,7 @@ describe('reduxStateToLocalStorageHelper', () => {
expect(emptiedQuery[id].results).toEqual({}); expect(emptiedQuery[id].results).toEqual({});
}); });
it('should empty query.results if query,.results size is greater than LOCALSTORAGE_MAX_QUERY_RESULTS_KB', () => { test('should empty query.results if query,.results size is greater than LOCALSTORAGE_MAX_QUERY_RESULTS_KB', () => {
const reasonableSizeQuery = { const reasonableSizeQuery = {
...queries[0], ...queries[0],
startDttm: Date.now(), startDttm: Date.now(),
@@ -83,7 +84,7 @@ describe('reduxStateToLocalStorageHelper', () => {
); );
}); });
it('should only return selected keys for query editor', () => { test('should only return selected keys for query editor', () => {
const queryEditors = [{ ...defaultQueryEditor, dummy: 'value' }]; const queryEditors = [{ ...defaultQueryEditor, dummy: 'value' }];
expect(Object.keys(queryEditors[0])).toContain('dummy'); expect(Object.keys(queryEditors[0])).toContain('dummy');

View File

@@ -29,13 +29,14 @@ const emptyEditor = {
remoteId: null, remoteId: null,
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('newQueryTabName', () => { describe('newQueryTabName', () => {
it("should return default title if queryEditor's length is 0", () => { test("should return default title if queryEditor's length is 0", () => {
const defaultTitle = 'default title'; const defaultTitle = 'default title';
const title = newQueryTabName([], defaultTitle); const title = newQueryTabName([], defaultTitle);
expect(title).toEqual(defaultTitle); expect(title).toEqual(defaultTitle);
}); });
it('should return next available number if there are unsaved editors', () => { test('should return next available number if there are unsaved editors', () => {
const untitledQueryText = 'Untitled Query'; const untitledQueryText = 'Untitled Query';
const unsavedEditors = [ const unsavedEditors = [
{ ...emptyEditor, name: `${untitledQueryText} 1` }, { ...emptyEditor, name: `${untitledQueryText} 1` },

View File

@@ -20,38 +20,40 @@
import { alterForComparison, formatValueHandler, getRowsFromDiffs } from '.'; import { alterForComparison, formatValueHandler, getRowsFromDiffs } from '.';
import { RowType } from '../types'; import { RowType } from '../types';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('alterForComparison', () => { describe('alterForComparison', () => {
it('returns null for undefined value', () => { test('returns null for undefined value', () => {
expect(alterForComparison(undefined)).toBeNull(); expect(alterForComparison(undefined)).toBeNull();
}); });
it('returns null for null value', () => { test('returns null for null value', () => {
expect(alterForComparison(null)).toBeNull(); expect(alterForComparison(null)).toBeNull();
}); });
it('returns null for empty string value', () => { test('returns null for empty string value', () => {
expect(alterForComparison('')).toBeNull(); expect(alterForComparison('')).toBeNull();
}); });
it('returns null for empty array value', () => { test('returns null for empty array value', () => {
expect(alterForComparison([])).toBeNull(); expect(alterForComparison([])).toBeNull();
}); });
it('returns null for empty object value', () => { test('returns null for empty object value', () => {
expect(alterForComparison({})).toBeNull(); expect(alterForComparison({})).toBeNull();
}); });
it('returns value for non-empty array', () => { test('returns value for non-empty array', () => {
const value = [1, 2, 3]; const value = [1, 2, 3];
expect(alterForComparison(value)).toEqual(value); expect(alterForComparison(value)).toEqual(value);
}); });
it('returns value for non-empty object', () => { test('returns value for non-empty object', () => {
const value = { key: 'value' }; const value = { key: 'value' };
expect(alterForComparison(value)).toEqual(value); expect(alterForComparison(value)).toEqual(value);
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('formatValueHandler', () => { describe('formatValueHandler', () => {
const controlsMap = { const controlsMap = {
b: { type: 'BoundsControl', label: 'Bounds' }, b: { type: 'BoundsControl', label: 'Bounds' },
@@ -61,7 +63,7 @@ describe('formatValueHandler', () => {
other_control: { type: 'OtherControl', label: 'Other' }, other_control: { type: 'OtherControl', label: 'Other' },
}; };
it('handles undefined value', () => { test('handles undefined value', () => {
const value = undefined; const value = undefined;
const key = 'b'; const key = 'b';
@@ -74,7 +76,7 @@ describe('formatValueHandler', () => {
expect(formattedValue).toBe('N/A'); expect(formattedValue).toBe('N/A');
}); });
it('handles null value', () => { test('handles null value', () => {
const value = null; const value = null;
const key = 'b'; const key = 'b';
@@ -87,7 +89,7 @@ describe('formatValueHandler', () => {
expect(formattedValue).toBe('null'); expect(formattedValue).toBe('null');
}); });
it('returns "[]" for empty filters', () => { test('returns "[]" for empty filters', () => {
const value: unknown[] = []; const value: unknown[] = [];
const key = 'adhoc_filters'; const key = 'adhoc_filters';
@@ -100,7 +102,7 @@ describe('formatValueHandler', () => {
expect(formattedValue).toBe('[]'); expect(formattedValue).toBe('[]');
}); });
it('formats filters with array values', () => { test('formats filters with array values', () => {
const filters = [ const filters = [
{ {
clause: 'WHERE', clause: 'WHERE',
@@ -129,7 +131,7 @@ describe('formatValueHandler', () => {
expect(formattedValue).toBe(expected); expect(formattedValue).toBe(expected);
}); });
it('formats filters with string values', () => { test('formats filters with string values', () => {
const filters = [ const filters = [
{ {
clause: 'WHERE', clause: 'WHERE',
@@ -158,7 +160,7 @@ describe('formatValueHandler', () => {
expect(formattedValue).toBe(expected); expect(formattedValue).toBe(expected);
}); });
it('formats "Min" and "Max" for BoundsControl', () => { test('formats "Min" and "Max" for BoundsControl', () => {
const value: number[] = [1, 2]; const value: number[] = [1, 2];
const key = 'b'; const key = 'b';
@@ -167,7 +169,7 @@ describe('formatValueHandler', () => {
expect(result).toEqual('Min: 1, Max: 2'); expect(result).toEqual('Min: 1, Max: 2');
}); });
it('formats stringified objects for CollectionControl', () => { test('formats stringified objects for CollectionControl', () => {
const value = [{ a: 1 }, { b: 2 }]; const value = [{ a: 1 }, { b: 2 }];
const key = 'column_collection'; const key = 'column_collection';
@@ -178,7 +180,7 @@ describe('formatValueHandler', () => {
); );
}); });
it('formats MetricsControl values correctly', () => { test('formats MetricsControl values correctly', () => {
const value = [{ label: 'SUM(Sales)' }, { label: 'Metric2' }]; const value = [{ label: 'SUM(Sales)' }, { label: 'Metric2' }];
const key = 'metrics'; const key = 'metrics';
@@ -187,7 +189,7 @@ describe('formatValueHandler', () => {
expect(result).toEqual('SUM(Sales), Metric2'); expect(result).toEqual('SUM(Sales), Metric2');
}); });
it('formats boolean values as string', () => { test('formats boolean values as string', () => {
const value1 = true; const value1 = true;
const value2 = false; const value2 = false;
const key = 'b'; const key = 'b';
@@ -207,7 +209,7 @@ describe('formatValueHandler', () => {
expect(formattedValue2).toBe('false'); expect(formattedValue2).toBe('false');
}); });
it('formats array values correctly', () => { test('formats array values correctly', () => {
const value = [ const value = [
{ label: 'Label1' }, { label: 'Label1' },
{ label: 'Label2' }, { label: 'Label2' },
@@ -229,7 +231,7 @@ describe('formatValueHandler', () => {
expect(result).toEqual(expected); expect(result).toEqual(expected);
}); });
it('formats string values correctly', () => { test('formats string values correctly', () => {
const value = 'test'; const value = 'test';
const key = 'other_control'; const key = 'other_control';
@@ -238,7 +240,7 @@ describe('formatValueHandler', () => {
expect(result).toEqual('test'); expect(result).toEqual('test');
}); });
it('formats number values correctly', () => { test('formats number values correctly', () => {
const value = 123; const value = 123;
const key = 'other_control'; const key = 'other_control';
@@ -247,7 +249,7 @@ describe('formatValueHandler', () => {
expect(result).toEqual(123); expect(result).toEqual(123);
}); });
it('formats object values correctly', () => { test('formats object values correctly', () => {
const value = { 1: 2, alpha: 'bravo' }; const value = { 1: 2, alpha: 'bravo' };
const key = 'other_control'; const key = 'other_control';
const expected = '{"1":2,"alpha":"bravo"}'; const expected = '{"1":2,"alpha":"bravo"}';
@@ -258,8 +260,9 @@ describe('formatValueHandler', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('getRowsFromDiffs', () => { describe('getRowsFromDiffs', () => {
it('returns formatted rows for diffs', () => { test('returns formatted rows for diffs', () => {
const diffs = { const diffs = {
metric: { before: [{ label: 'old' }], after: [{ label: 'new' }] }, metric: { before: [{ label: 'old' }], after: [{ label: 'new' }] },
limit: { before: 10, after: 20 }, limit: { before: 10, after: 20 },
@@ -278,7 +281,7 @@ describe('getRowsFromDiffs', () => {
]); ]);
}); });
it('falls back to key if label is missing', () => { test('falls back to key if label is missing', () => {
const diffs = { const diffs = {
unknown: { before: 'a', after: 'b' }, unknown: { before: 'a', after: 'b' },
}; };

View File

@@ -42,6 +42,7 @@ const ERROR_MESSAGE_COMPONENT = (props: ErrorMessageComponentProps) => (
</> </>
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ChartErrorMessage', () => { describe('ChartErrorMessage', () => {
const defaultProps = { const defaultProps = {
chartId: 1, chartId: 1,
@@ -49,7 +50,7 @@ describe('ChartErrorMessage', () => {
source: 'test_source' as ChartSource, source: 'test_source' as ChartSource,
}; };
it('renders the default error message when error is null', () => { test('renders the default error message when error is null', () => {
mockUseChartOwnerNames.mockReturnValue({ mockUseChartOwnerNames.mockReturnValue({
result: null, result: null,
status: ResourceStatus.Loading, status: ResourceStatus.Loading,
@@ -61,7 +62,7 @@ describe('ChartErrorMessage', () => {
expect(screen.getByText('Test subtitle')).toBeInTheDocument(); expect(screen.getByText('Test subtitle')).toBeInTheDocument();
}); });
it('renders the error message that is passed in from the error', () => { test('renders the error message that is passed in from the error', () => {
getErrorMessageComponentRegistry().registerValue( getErrorMessageComponentRegistry().registerValue(
'VALID_KEY', 'VALID_KEY',
ERROR_MESSAGE_COMPONENT, ERROR_MESSAGE_COMPONENT,

View File

@@ -281,6 +281,7 @@ test('should render "Edit chart" enabled with can_explore permission', async ()
expect(screen.getByRole('button', { name: 'Edit chart' })).toBeEnabled(); expect(screen.getByRole('button', { name: 'Edit chart' })).toBeEnabled();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Embedded mode behavior', () => { describe('Embedded mode behavior', () => {
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
const { isEmbedded } = require('src/dashboard/util/isEmbedded'); const { isEmbedded } = require('src/dashboard/util/isEmbedded');
@@ -357,6 +358,7 @@ describe('Embedded mode behavior', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Table view with pagination', () => { describe('Table view with pagination', () => {
beforeEach(() => { beforeEach(() => {
// Mock a large dataset response for pagination testing // Mock a large dataset response for pagination testing

View File

@@ -59,6 +59,7 @@ jest.mock('@superset-ui/core', () => ({
getChartBuildQueryRegistry: jest.fn(), getChartBuildQueryRegistry: jest.fn(),
})); }));
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('chart actions', () => { describe('chart actions', () => {
const MOCK_URL = '/mockURL'; const MOCK_URL = '/mockURL';
let dispatch; let dispatch;
@@ -121,12 +122,13 @@ describe('chart actions', () => {
}; };
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('v1 API', () => { describe('v1 API', () => {
beforeEach(() => { beforeEach(() => {
fakeMetadata = { viz_type: 'my_viz', useLegacyApi: false }; fakeMetadata = { viz_type: 'my_viz', useLegacyApi: false };
}); });
it('should query with the built query', async () => { test('should query with the built query', async () => {
const actionThunk = actions.postChartFormData({}, null); const actionThunk = actions.postChartFormData({}, null);
await actionThunk(dispatch, mockGetState); await actionThunk(dispatch, mockGetState);
@@ -141,7 +143,7 @@ describe('chart actions', () => {
expect(dispatch.args[0][0].type).toBe(actions.CHART_UPDATE_STARTED); expect(dispatch.args[0][0].type).toBe(actions.CHART_UPDATE_STARTED);
}); });
it('should handle the bigint without regression', async () => { test('should handle the bigint without regression', async () => {
getChartDataUriStub.restore(); getChartDataUriStub.restore();
const mockBigIntUrl = '/mock/chart/data/bigint'; const mockBigIntUrl = '/mock/chart/data/bigint';
const expectedBigNumber = '9223372036854775807'; const expectedBigNumber = '9223372036854775807';
@@ -160,7 +162,7 @@ describe('chart actions', () => {
expect(json.value.toString()).toEqual(expectedBigNumber); expect(json.value.toString()).toEqual(expectedBigNumber);
}); });
it('handleChartDataResponse should return result if GlobalAsyncQueries flag is disabled', async () => { test('handleChartDataResponse should return result if GlobalAsyncQueries flag is disabled', async () => {
const result = await handleChartDataResponse( const result = await handleChartDataResponse(
{ status: 200 }, { status: 200 },
{ result: [1, 2, 3] }, { result: [1, 2, 3] },
@@ -168,7 +170,7 @@ describe('chart actions', () => {
expect(result).toEqual([1, 2, 3]); expect(result).toEqual([1, 2, 3]);
}); });
it('handleChartDataResponse should handle responses when GlobalAsyncQueries flag is enabled and results are returned synchronously', async () => { test('handleChartDataResponse should handle responses when GlobalAsyncQueries flag is enabled and results are returned synchronously', async () => {
global.featureFlags = { global.featureFlags = {
[FeatureFlag.GlobalAsyncQueries]: true, [FeatureFlag.GlobalAsyncQueries]: true,
}; };
@@ -179,7 +181,7 @@ describe('chart actions', () => {
expect(result).toEqual([1, 2, 3]); expect(result).toEqual([1, 2, 3]);
}); });
it('handleChartDataResponse should handle responses when GlobalAsyncQueries flag is enabled and query is running asynchronously', async () => { test('handleChartDataResponse should handle responses when GlobalAsyncQueries flag is enabled and query is running asynchronously', async () => {
global.featureFlags = { global.featureFlags = {
[FeatureFlag.GlobalAsyncQueries]: true, [FeatureFlag.GlobalAsyncQueries]: true,
}; };
@@ -191,12 +193,13 @@ describe('chart actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('legacy API', () => { describe('legacy API', () => {
beforeEach(() => { beforeEach(() => {
fakeMetadata = { useLegacyApi: true }; fakeMetadata = { useLegacyApi: true };
}); });
it('should dispatch CHART_UPDATE_STARTED action before the query', () => { test('should dispatch CHART_UPDATE_STARTED action before the query', () => {
const actionThunk = actions.postChartFormData({}); const actionThunk = actions.postChartFormData({});
return actionThunk(dispatch, mockGetState).then(() => { return actionThunk(dispatch, mockGetState).then(() => {
@@ -207,7 +210,7 @@ describe('chart actions', () => {
}); });
}); });
it('should dispatch TRIGGER_QUERY action with the query', () => { test('should dispatch TRIGGER_QUERY action with the query', () => {
const actionThunk = actions.postChartFormData({}); const actionThunk = actions.postChartFormData({});
return actionThunk(dispatch, mockGetState).then(() => { return actionThunk(dispatch, mockGetState).then(() => {
// chart update, trigger query, update form data, success // chart update, trigger query, update form data, success
@@ -217,7 +220,7 @@ describe('chart actions', () => {
}); });
}); });
it('should dispatch UPDATE_QUERY_FORM_DATA action with the query', () => { test('should dispatch UPDATE_QUERY_FORM_DATA action with the query', () => {
const actionThunk = actions.postChartFormData({}); const actionThunk = actions.postChartFormData({});
return actionThunk(dispatch, mockGetState).then(() => { return actionThunk(dispatch, mockGetState).then(() => {
// chart update, trigger query, update form data, success // chart update, trigger query, update form data, success
@@ -227,7 +230,7 @@ describe('chart actions', () => {
}); });
}); });
it('should dispatch logEvent async action', () => { test('should dispatch logEvent async action', () => {
const actionThunk = actions.postChartFormData({}); const actionThunk = actions.postChartFormData({});
return actionThunk(dispatch, mockGetState).then(() => { return actionThunk(dispatch, mockGetState).then(() => {
// chart update, trigger query, update form data, success // chart update, trigger query, update form data, success
@@ -241,7 +244,7 @@ describe('chart actions', () => {
}); });
}); });
it('should dispatch CHART_UPDATE_SUCCEEDED action upon success', () => { test('should dispatch CHART_UPDATE_SUCCEEDED action upon success', () => {
const actionThunk = actions.postChartFormData({}); const actionThunk = actions.postChartFormData({});
return actionThunk(dispatch, mockGetState).then(() => { return actionThunk(dispatch, mockGetState).then(() => {
// chart update, trigger query, update form data, success // chart update, trigger query, update form data, success
@@ -251,7 +254,7 @@ describe('chart actions', () => {
}); });
}); });
it('should dispatch CHART_UPDATE_FAILED action upon query timeout', () => { test('should dispatch CHART_UPDATE_FAILED action upon query timeout', () => {
const unresolvingPromise = new Promise(() => {}); const unresolvingPromise = new Promise(() => {});
fetchMock.post(MOCK_URL, () => unresolvingPromise, { fetchMock.post(MOCK_URL, () => unresolvingPromise, {
overwriteRoutes: true, overwriteRoutes: true,
@@ -269,7 +272,7 @@ describe('chart actions', () => {
}); });
}); });
it('should dispatch CHART_UPDATE_FAILED action upon non-timeout non-abort failure', () => { test('should dispatch CHART_UPDATE_FAILED action upon non-timeout non-abort failure', () => {
fetchMock.post( fetchMock.post(
MOCK_URL, MOCK_URL,
{ throws: { statusText: 'misc error' } }, { throws: { statusText: 'misc error' } },
@@ -290,7 +293,7 @@ describe('chart actions', () => {
}); });
}); });
it('should handle the bigint without regression', async () => { test('should handle the bigint without regression', async () => {
getExploreUrlStub.restore(); getExploreUrlStub.restore();
const mockBigIntUrl = '/mock/chart/data/bigint'; const mockBigIntUrl = '/mock/chart/data/bigint';
const expectedBigNumber = '9223372036854775807'; const expectedBigNumber = '9223372036854775807';
@@ -310,13 +313,14 @@ describe('chart actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('runAnnotationQuery', () => { describe('runAnnotationQuery', () => {
const mockDispatch = jest.fn(); const mockDispatch = jest.fn();
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should dispatch annotationQueryStarted and annotationQuerySuccess on successful query', async () => { test('should dispatch annotationQueryStarted and annotationQuerySuccess on successful query', async () => {
const annotation = { const annotation = {
name: 'Holidays', name: 'Holidays',
annotationType: 'EVENT', annotationType: 'EVENT',
@@ -366,12 +370,13 @@ describe('chart actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('chart actions timeout', () => { describe('chart actions timeout', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should use the timeout from arguments when given', async () => { test('should use the timeout from arguments when given', async () => {
const postSpy = jest.spyOn(SupersetClient, 'post'); const postSpy = jest.spyOn(SupersetClient, 'post');
postSpy.mockImplementation(() => Promise.resolve({ json: { result: [] } })); postSpy.mockImplementation(() => Promise.resolve({ json: { result: [] } }));
const timeout = 10; // Set the timeout value here const timeout = 10; // Set the timeout value here
@@ -403,7 +408,7 @@ describe('chart actions timeout', () => {
expect(postSpy).toHaveBeenCalledWith(expectedPayload); expect(postSpy).toHaveBeenCalledWith(expectedPayload);
}); });
it('should use the timeout from common.conf when not passed as an argument', async () => { test('should use the timeout from common.conf when not passed as an argument', async () => {
const postSpy = jest.spyOn(SupersetClient, 'post'); const postSpy = jest.spyOn(SupersetClient, 'post');
postSpy.mockImplementation(() => Promise.resolve({ json: { result: [] } })); postSpy.mockImplementation(() => Promise.resolve({ json: { result: [] } }));
const formData = { datasource: 'table__1' }; // Set the formData here const formData = { datasource: 'table__1' }; // Set the formData here

View File

@@ -19,6 +19,7 @@
import chartReducer, { chart } from 'src/components/Chart/chartReducer'; import chartReducer, { chart } from 'src/components/Chart/chartReducer';
import * as actions from 'src/components/Chart/chartAction'; import * as actions from 'src/components/Chart/chartAction';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('chart reducers', () => { describe('chart reducers', () => {
const chartKey = 1; const chartKey = 1;
let testChart; let testChart;
@@ -31,13 +32,13 @@ describe('chart reducers', () => {
charts = { [chartKey]: testChart }; charts = { [chartKey]: testChart };
}); });
it('should update endtime on fail', () => { test('should update endtime on fail', () => {
const newState = chartReducer(charts, actions.chartUpdateStopped(chartKey)); const newState = chartReducer(charts, actions.chartUpdateStopped(chartKey));
expect(newState[chartKey].chartUpdateEndTime).toBeGreaterThan(0); expect(newState[chartKey].chartUpdateEndTime).toBeGreaterThan(0);
expect(newState[chartKey].chartStatus).toEqual('stopped'); expect(newState[chartKey].chartStatus).toEqual('stopped');
}); });
it('should update endtime on timeout', () => { test('should update endtime on timeout', () => {
const newState = chartReducer( const newState = chartReducer(
charts, charts,
actions.chartUpdateFailed( actions.chartUpdateFailed(

View File

@@ -73,24 +73,25 @@ beforeEach(() => {
fetchMock.get(GET_DATABASE_ENDPOINT, { result: [] }); fetchMock.get(GET_DATABASE_ENDPOINT, { result: [] });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DatasourceModal', () => { describe('DatasourceModal', () => {
it('renders', async () => { test('renders', async () => {
expect(container).toBeDefined(); expect(container).toBeDefined();
}); });
it('renders the component', () => { test('renders the component', () => {
expect(screen.getByText('Edit Dataset')).toBeInTheDocument(); expect(screen.getByText('Edit Dataset')).toBeInTheDocument();
}); });
it('renders a Modal', async () => { test('renders a Modal', async () => {
expect(screen.getByRole('dialog')).toBeInTheDocument(); expect(screen.getByRole('dialog')).toBeInTheDocument();
}); });
it('renders a DatasourceEditor', async () => { test('renders a DatasourceEditor', async () => {
expect(screen.getByTestId('datasource-editor')).toBeInTheDocument(); expect(screen.getByTestId('datasource-editor')).toBeInTheDocument();
}); });
it('disables the save button when the datasource is managed externally', () => { test('disables the save button when the datasource is managed externally', () => {
// the render is currently in a before operation, so it needs to be cleaned up // the render is currently in a before operation, so it needs to be cleaned up
// we could alternatively move all the renders back into the tests or find a better // we could alternatively move all the renders back into the tests or find a better
// way to automatically render but still allow to pass in props with the tests // way to automatically render but still allow to pass in props with the tests
@@ -104,7 +105,7 @@ describe('DatasourceModal', () => {
expect(saveButton).toBeDisabled(); expect(saveButton).toBeDisabled();
}); });
it('calls the onDatasourceSave function when the save button is clicked', async () => { test('calls the onDatasourceSave function when the save button is clicked', async () => {
cleanup(); cleanup();
const onDatasourceSave = jest.fn(); const onDatasourceSave = jest.fn();
@@ -120,7 +121,7 @@ describe('DatasourceModal', () => {
}); });
}); });
it('should render error dialog', async () => { test('should render error dialog', async () => {
jest jest
.spyOn(SupersetClient, 'put') .spyOn(SupersetClient, 'put')
.mockRejectedValue(new Error('Something went wrong')); .mockRejectedValue(new Error('Something went wrong'));

View File

@@ -0,0 +1,110 @@
/**
* 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 {
render,
screen,
fireEvent,
act,
defaultStore as store,
} from 'spec/helpers/testing-library';
import fetchMock from 'fetch-mock';
import { Modal } from '@superset-ui/core/components';
import mockDatasource from 'spec/fixtures/mockDatasource';
import DatasourceModal from '.';
const mockedProps = {
datasource: mockDatasource['7__table'],
addSuccessToast: jest.fn(),
addDangerToast: jest.fn(),
onChange: jest.fn(),
onHide: jest.fn(),
show: true,
onDatasourceSave: jest.fn(),
};
beforeEach(() => {
fetchMock.reset();
fetchMock.put('glob:*/api/v1/dataset/7?override_columns=*', {});
fetchMock.get('glob:*/api/v1/dataset/7', { result: {} });
fetchMock.get('glob:*/api/v1/database/?q=*', { result: [] });
});
afterEach(() => {
fetchMock.reset();
jest.clearAllMocks();
});
test('DatasourceModal - should use Modal.useModal hook instead of Modal.confirm directly', () => {
const useModalSpy = jest.spyOn(Modal, 'useModal');
const confirmSpy = jest.spyOn(Modal, 'confirm');
render(<DatasourceModal {...mockedProps} />, { store });
// Should use the useModal hook
expect(useModalSpy).toHaveBeenCalled();
// Should not call Modal.confirm during initial render
expect(confirmSpy).not.toHaveBeenCalled();
useModalSpy.mockRestore();
confirmSpy.mockRestore();
});
test('DatasourceModal - should handle sync columns state without imperative modal updates', async () => {
// Test that we can successfully click the save button without DOM errors
// The actual checkbox is only visible when SQL has changed
render(<DatasourceModal {...mockedProps} />, { store });
const saveButton = screen.getByTestId('datasource-modal-save');
// This should not throw any DOM errors
await act(async () => {
fireEvent.click(saveButton);
});
// Should show confirmation modal
expect(screen.getByText('Confirm save')).toBeInTheDocument();
// Should show the confirmation message
expect(
screen.getByText('Are you sure you want to save and apply changes?'),
).toBeInTheDocument();
});
test('DatasourceModal - should not store modal instance in state', () => {
// Mock console.warn to catch any warnings about refs or imperatives
const consoleWarn = jest.spyOn(console, 'warn').mockImplementation();
render(<DatasourceModal {...mockedProps} />, { store });
// No warnings should be generated about improper React patterns
const reactWarnings = consoleWarn.mock.calls.filter(call =>
call.some(
arg =>
typeof arg === 'string' &&
(arg.includes('findDOMNode') ||
arg.includes('ref') ||
arg.includes('instance')),
),
);
expect(reactWarnings).toHaveLength(0);
consoleWarn.mockRestore();
});

View File

@@ -16,13 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import { import { FunctionComponent, useState, useEffect, useCallback } from 'react';
FunctionComponent,
useState,
useRef,
useEffect,
useCallback,
} from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { import {
styled, styled,
@@ -101,8 +95,7 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const [currentDatasource, setCurrentDatasource] = useState(datasource); const [currentDatasource, setCurrentDatasource] = useState(datasource);
const syncColumnsRef = useRef(false); const [syncColumns, setSyncColumns] = useState(false);
const [confirmModal, setConfirmModal] = useState<any>(null);
const currencies = useSelector< const currencies = useSelector<
{ {
common: { common: {
@@ -114,7 +107,6 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
const [errors, setErrors] = useState<any[]>([]); const [errors, setErrors] = useState<any[]>([]);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [isEditing, setIsEditing] = useState<boolean>(false); const [isEditing, setIsEditing] = useState<boolean>(false);
const dialog = useRef<any>(null);
const [modal, contextHolder] = Modal.useModal(); const [modal, contextHolder] = Modal.useModal();
const buildPayload = (datasource: Record<string, any>) => { const buildPayload = (datasource: Record<string, any>) => {
const payload: Record<string, any> = { const payload: Record<string, any> = {
@@ -196,7 +188,7 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
setIsSaving(true); setIsSaving(true);
try { try {
await SupersetClient.put({ await SupersetClient.put({
endpoint: `/api/v1/dataset/${currentDatasource.id}?override_columns=${syncColumnsRef.current}`, endpoint: `/api/v1/dataset/${currentDatasource.id}?override_columns=${syncColumns}`,
jsonPayload: buildPayload(currentDatasource), jsonPayload: buildPayload(currentDatasource),
}); });
@@ -281,14 +273,9 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
impact the column definitions, you might want to skip this step.`)} impact the column definitions, you might want to skip this step.`)}
/> />
<Checkbox <Checkbox
checked={syncColumnsRef.current} checked={syncColumns}
onChange={() => { onChange={() => {
syncColumnsRef.current = !syncColumnsRef.current; setSyncColumns(!syncColumns);
if (confirmModal) {
confirmModal.update({
content: getSaveDialog(),
});
}
}} }}
/> />
<span <span
@@ -303,25 +290,17 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
{t('Are you sure you want to save and apply changes?')} {t('Are you sure you want to save and apply changes?')}
</div> </div>
), ),
[currentDatasource.sql, datasource.sql, confirmModal], [currentDatasource.sql, datasource.sql, syncColumns],
); );
useEffect(() => {
if (confirmModal) {
confirmModal.update({
content: getSaveDialog(),
});
}
}, [confirmModal, getSaveDialog]);
useEffect(() => { useEffect(() => {
if (datasource.sql !== currentDatasource.sql) { if (datasource.sql !== currentDatasource.sql) {
syncColumnsRef.current = true; setSyncColumns(true);
} }
}, [datasource.sql, currentDatasource.sql]); }, [datasource.sql, currentDatasource.sql]);
const onClickSave = () => { const onClickSave = () => {
const modalInstance = modal.confirm({ modal.confirm({
title: t('Confirm save'), title: t('Confirm save'),
content: getSaveDialog(), content: getSaveDialog(),
onOk: onConfirmSave, onOk: onConfirmSave,
@@ -329,8 +308,6 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
okText: t('OK'), okText: t('OK'),
cancelText: t('Cancel'), cancelText: t('Cancel'),
}); });
setConfirmModal(modalInstance);
dialog.current = modalInstance;
}; };
return ( return (

View File

@@ -46,6 +46,7 @@ const setupTest = (dashboards = mockDashboards) =>
}), }),
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DashboardLinksExternal', () => { describe('DashboardLinksExternal', () => {
test('renders empty state when no dashboards provided', () => { test('renders empty state when no dashboards provided', () => {
setupTest([]); setupTest([]);

View File

@@ -63,6 +63,7 @@ export const asyncRender = props =>
}), }),
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DatasourceEditor', () => { describe('DatasourceEditor', () => {
beforeAll(() => { beforeAll(() => {
jest.clearAllMocks(); jest.clearAllMocks();
@@ -80,11 +81,11 @@ describe('DatasourceEditor', () => {
// jest.clearAllMocks(); // jest.clearAllMocks();
}); });
it('renders Tabs', () => { test('renders Tabs', () => {
expect(screen.getByTestId('edit-dataset-tabs')).toBeInTheDocument(); expect(screen.getByTestId('edit-dataset-tabs')).toBeInTheDocument();
}); });
it('can sync columns from source', async () => { test('can sync columns from source', async () => {
const columnsTab = screen.getByTestId('collection-tab-Columns'); const columnsTab = screen.getByTestId('collection-tab-Columns');
userEvent.click(columnsTab); userEvent.click(columnsTab);
@@ -111,7 +112,7 @@ describe('DatasourceEditor', () => {
}); });
// to add, remove and modify columns accordingly // to add, remove and modify columns accordingly
it('can modify columns', async () => { test('can modify columns', async () => {
const columnsTab = screen.getByTestId('collection-tab-Columns'); const columnsTab = screen.getByTestId('collection-tab-Columns');
userEvent.click(columnsTab); userEvent.click(columnsTab);
@@ -138,7 +139,7 @@ describe('DatasourceEditor', () => {
userEvent.type(inputCertDetails, 'test'); userEvent.type(inputCertDetails, 'test');
}, 40000); }, 40000);
it('can delete columns', async () => { test('can delete columns', async () => {
const columnsTab = screen.getByTestId('collection-tab-Columns'); const columnsTab = screen.getByTestId('collection-tab-Columns');
userEvent.click(columnsTab); userEvent.click(columnsTab);
@@ -162,7 +163,7 @@ describe('DatasourceEditor', () => {
}); });
}, 60000); // 60 seconds timeout to avoid timeouts }, 60000); // 60 seconds timeout to avoid timeouts
it('can add new columns', async () => { test('can add new columns', async () => {
const calcColsTab = screen.getByTestId('collection-tab-Calculated columns'); const calcColsTab = screen.getByTestId('collection-tab-Calculated columns');
userEvent.click(calcColsTab); userEvent.click(calcColsTab);
@@ -180,7 +181,7 @@ describe('DatasourceEditor', () => {
}); });
}, 60000); }, 60000);
it('renders isSqla fields', async () => { test('renders isSqla fields', async () => {
const columnsTab = screen.getByRole('tab', { const columnsTab = screen.getByRole('tab', {
name: /settings/i, name: /settings/i,
}); });
@@ -195,6 +196,7 @@ describe('DatasourceEditor', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DatasourceEditor Source Tab', () => { describe('DatasourceEditor Source Tab', () => {
beforeAll(() => { beforeAll(() => {
isFeatureEnabled.mockImplementation(() => false); isFeatureEnabled.mockImplementation(() => false);
@@ -216,7 +218,7 @@ describe('DatasourceEditor Source Tab', () => {
isFeatureEnabled.mockRestore(); isFeatureEnabled.mockRestore();
}); });
it('Source Tab: edit mode', async () => { test('Source Tab: edit mode', async () => {
const getLockBtn = screen.getByRole('img', { name: /lock/i }); const getLockBtn = screen.getByRole('img', { name: /lock/i });
userEvent.click(getLockBtn); userEvent.click(getLockBtn);
@@ -231,7 +233,7 @@ describe('DatasourceEditor Source Tab', () => {
expect(virtualRadioBtn).toBeEnabled(); expect(virtualRadioBtn).toBeEnabled();
}); });
it('Source Tab: readOnly mode', () => { test('Source Tab: readOnly mode', () => {
const getLockBtn = screen.getByRole('img', { name: /lock/i }); const getLockBtn = screen.getByRole('img', { name: /lock/i });
expect(getLockBtn).toBeInTheDocument(); expect(getLockBtn).toBeInTheDocument();
@@ -246,7 +248,7 @@ describe('DatasourceEditor Source Tab', () => {
expect(virtualRadioBtn).toBeDisabled(); expect(virtualRadioBtn).toBeDisabled();
}); });
it('calls onChange with empty SQL when switching to physical dataset', async () => { test('calls onChange with empty SQL when switching to physical dataset', async () => {
// Clean previous render // Clean previous render
cleanup(); cleanup();

View File

@@ -30,6 +30,7 @@ const fastRender = props =>
initialState: { common: { currencies: ['USD', 'GBP', 'EUR'] } }, initialState: { common: { currencies: ['USD', 'GBP', 'EUR'] } },
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DatasourceEditor Currency Tests', () => { describe('DatasourceEditor Currency Tests', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.get(DATASOURCE_ENDPOINT, [], { overwriteRoutes: true }); fetchMock.get(DATASOURCE_ENDPOINT, [], { overwriteRoutes: true });
@@ -40,7 +41,7 @@ describe('DatasourceEditor Currency Tests', () => {
}); });
// The problematic test, now optimized // The problematic test, now optimized
it('renders currency controls', async () => { test('renders currency controls', async () => {
// Setup a metric with currency data // Setup a metric with currency data
const propsWithCurrency = { const propsWithCurrency = {
...props, ...props,

View File

@@ -24,6 +24,7 @@ import {
DATASOURCE_ENDPOINT, DATASOURCE_ENDPOINT,
} from './DatasourceEditor.test'; } from './DatasourceEditor.test';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DatasourceEditor RTL Metrics Tests', () => { describe('DatasourceEditor RTL Metrics Tests', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.get(DATASOURCE_ENDPOINT, [], { overwriteRoutes: true }); fetchMock.get(DATASOURCE_ENDPOINT, [], { overwriteRoutes: true });
@@ -34,7 +35,7 @@ describe('DatasourceEditor RTL Metrics Tests', () => {
fetchMock.restore(); fetchMock.restore();
}); });
it('properly renders the metric information', async () => { test('properly renders the metric information', async () => {
await asyncRender(props); await asyncRender(props);
const metricButton = screen.getByTestId('collection-tab-Metrics'); const metricButton = screen.getByTestId('collection-tab-Metrics');
@@ -52,7 +53,7 @@ describe('DatasourceEditor RTL Metrics Tests', () => {
expect(warningMarkdown.value).toEqual('someone'); expect(warningMarkdown.value).toEqual('someone');
}); });
it('properly updates the metric information', async () => { test('properly updates the metric information', async () => {
await asyncRender(props); await asyncRender(props);
const metricButton = screen.getByTestId('collection-tab-Metrics'); const metricButton = screen.getByTestId('collection-tab-Metrics');
@@ -82,6 +83,7 @@ describe('DatasourceEditor RTL Metrics Tests', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DatasourceEditor RTL Columns Tests', () => { describe('DatasourceEditor RTL Columns Tests', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.get(DATASOURCE_ENDPOINT, [], { overwriteRoutes: true }); fetchMock.get(DATASOURCE_ENDPOINT, [], { overwriteRoutes: true });
@@ -92,7 +94,7 @@ describe('DatasourceEditor RTL Columns Tests', () => {
fetchMock.restore(); fetchMock.restore();
}); });
it('shows the default datetime column', async () => { test('shows the default datetime column', async () => {
await asyncRender(props); await asyncRender(props);
const columnsButton = screen.getByTestId('collection-tab-Columns'); const columnsButton = screen.getByTestId('collection-tab-Columns');
@@ -107,7 +109,7 @@ describe('DatasourceEditor RTL Columns Tests', () => {
expect(genderDefaultDatetimeRadio).not.toBeChecked(); expect(genderDefaultDatetimeRadio).not.toBeChecked();
}); });
it('allows choosing only temporal columns as the default datetime', async () => { test('allows choosing only temporal columns as the default datetime', async () => {
await asyncRender(props); await asyncRender(props);
const columnsButton = screen.getByTestId('collection-tab-Columns'); const columnsButton = screen.getByTestId('collection-tab-Columns');

View File

@@ -20,6 +20,7 @@
import { tn } from '@superset-ui/core'; import { tn } from '@superset-ui/core';
import { updateColumns } from '.'; import { updateColumns } from '.';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('updateColumns', () => { describe('updateColumns', () => {
let addSuccessToast: jest.Mock; let addSuccessToast: jest.Mock;
@@ -27,7 +28,7 @@ describe('updateColumns', () => {
addSuccessToast = jest.fn(); addSuccessToast = jest.fn();
}); });
it('adds new columns when prevCols is empty', () => { test('adds new columns when prevCols is empty', () => {
interface Column { interface Column {
column_name: string; column_name: string;
type: string; type: string;
@@ -56,7 +57,7 @@ describe('updateColumns', () => {
); );
}); });
it('modifies columns when type or is_dttm changes', () => { test('modifies columns when type or is_dttm changes', () => {
const prevCols = [ const prevCols = [
{ column_name: 'col1', type: 'string', is_dttm: false }, { column_name: 'col1', type: 'string', is_dttm: false },
{ column_name: 'col2', type: 'number', is_dttm: false }, { column_name: 'col2', type: 'number', is_dttm: false },
@@ -94,7 +95,7 @@ describe('updateColumns', () => {
); );
}); });
it('removes columns not present in newCols', () => { test('removes columns not present in newCols', () => {
const prevCols = [ const prevCols = [
{ column_name: 'col1', type: 'string', is_dttm: false }, { column_name: 'col1', type: 'string', is_dttm: false },
{ column_name: 'col2', type: 'number', is_dttm: true }, { column_name: 'col2', type: 'number', is_dttm: true },
@@ -121,7 +122,7 @@ describe('updateColumns', () => {
); );
}); });
it('handles combined additions, modifications, and removals', () => { test('handles combined additions, modifications, and removals', () => {
const prevCols = [ const prevCols = [
{ column_name: 'col1', type: 'string', is_dttm: false }, { column_name: 'col1', type: 'string', is_dttm: false },
{ column_name: 'col2', type: 'number', is_dttm: false }, { column_name: 'col2', type: 'number', is_dttm: false },
@@ -170,7 +171,7 @@ describe('updateColumns', () => {
], ],
]); ]);
}); });
it('should not remove columns with expressions', () => { test('should not remove columns with expressions', () => {
const prevCols = [ const prevCols = [
{ column_name: 'col1', type: 'string', is_dttm: false }, { column_name: 'col1', type: 'string', is_dttm: false },
{ column_name: 'col2', type: 'number', is_dttm: false }, { column_name: 'col2', type: 'number', is_dttm: false },

View File

@@ -20,72 +20,71 @@
import { screen, fireEvent, render } from 'spec/helpers/testing-library'; import { screen, fireEvent, render } from 'spec/helpers/testing-library';
import { ErrorAlert } from './ErrorAlert'; import { ErrorAlert } from './ErrorAlert';
describe('ErrorAlert', () => { // ErrorAlert
it('renders the error message correctly', () => { test('ErrorAlert renders the error message correctly', () => {
render( render(
<ErrorAlert <ErrorAlert
errorType="Error" errorType="Error"
message="Something went wrong" message="Something went wrong"
type="error" type="error"
/>, />,
); );
expect(screen.getByText('Error')).toBeInTheDocument(); expect(screen.getByText('Error')).toBeInTheDocument();
expect(screen.getByText('Something went wrong')).toBeInTheDocument(); expect(screen.getByText('Something went wrong')).toBeInTheDocument();
}); });
it('renders the description when provided', () => { test('ErrorAlert renders the description when provided', () => {
const description = 'This is a detailed description'; const description = 'This is a detailed description';
render( render(
<ErrorAlert <ErrorAlert
errorType="Error" errorType="Error"
message="Something went wrong" message="Something went wrong"
type="error" type="error"
description={description} description={description}
/>, />,
); );
expect(screen.getByText(description)).toBeInTheDocument(); expect(screen.getByText(description)).toBeInTheDocument();
}); });
it('toggles description details visibility when show more/less is clicked', () => { test('ErrorAlert toggles description details visibility when show more/less is clicked', () => {
const descriptionDetails = 'Additional details about the error.'; const descriptionDetails = 'Additional details about the error.';
render( render(
<ErrorAlert <ErrorAlert
errorType="Error" errorType="Error"
message="Something went wrong" message="Something went wrong"
type="error" type="error"
descriptionDetails={descriptionDetails} descriptionDetails={descriptionDetails}
descriptionDetailsCollapsed descriptionDetailsCollapsed
/>, />,
); );
const showMoreButton = screen.getByText('See more'); const showMoreButton = screen.getByText('See more');
expect(showMoreButton).toBeInTheDocument(); expect(showMoreButton).toBeInTheDocument();
fireEvent.click(showMoreButton); fireEvent.click(showMoreButton);
expect(screen.getByText(descriptionDetails)).toBeInTheDocument(); expect(screen.getByText(descriptionDetails)).toBeInTheDocument();
const showLessButton = screen.getByText('See less'); const showLessButton = screen.getByText('See less');
fireEvent.click(showLessButton); fireEvent.click(showLessButton);
expect(screen.queryByText(descriptionDetails)).not.toBeInTheDocument(); expect(screen.queryByText(descriptionDetails)).not.toBeInTheDocument();
}); });
it('renders compact mode with a tooltip and modal', () => { test('ErrorAlert renders compact mode with a tooltip and modal', () => {
render( render(
<ErrorAlert <ErrorAlert
errorType="Error" errorType="Error"
message="Compact mode example" message="Compact mode example"
type="error" type="error"
compact compact
descriptionDetails="Detailed description in compact mode." descriptionDetails="Detailed description in compact mode."
/>, />,
); );
const iconTrigger = screen.getByText('Error'); const iconTrigger = screen.getByText('Error');
expect(iconTrigger).toBeInTheDocument(); expect(iconTrigger).toBeInTheDocument();
fireEvent.click(iconTrigger); fireEvent.click(iconTrigger);
expect(screen.getByText('Compact mode example')).toBeInTheDocument(); expect(screen.getByText('Compact mode example')).toBeInTheDocument();
});
}); });

View File

@@ -54,6 +54,7 @@ const missingExtraProps = {
const renderComponent = (overrides = {}) => const renderComponent = (overrides = {}) =>
render(<InvalidSQLErrorMessage {...defaultProps} {...overrides} />); render(<InvalidSQLErrorMessage {...defaultProps} {...overrides} />);
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('InvalidSQLErrorMessage', () => { describe('InvalidSQLErrorMessage', () => {
beforeAll(() => { beforeAll(() => {
jest.setTimeout(30000); jest.setTimeout(30000);
@@ -64,7 +65,7 @@ describe('InvalidSQLErrorMessage', () => {
await new Promise(resolve => setTimeout(resolve, 0)); await new Promise(resolve => setTimeout(resolve, 0));
}); });
it('renders the error message with correct properties', async () => { test('renders the error message with correct properties', async () => {
const { getByText, unmount } = renderComponent(); const { getByText, unmount } = renderComponent();
// Validate main properties // Validate main properties
@@ -75,13 +76,13 @@ describe('InvalidSQLErrorMessage', () => {
unmount(); unmount();
}); });
it('renders the error message with the empty extra properties', () => { test('renders the error message with the empty extra properties', () => {
const { getByText } = renderComponent(missingExtraProps); const { getByText } = renderComponent(missingExtraProps);
expect(getByText('Unable to parse SQL')).toBeInTheDocument(); expect(getByText('Unable to parse SQL')).toBeInTheDocument();
expect(getByText(missingExtraProps.error.message)).toBeInTheDocument(); expect(getByText(missingExtraProps.error.message)).toBeInTheDocument();
}); });
it('displays the SQL error line and column indicator', async () => { test('displays the SQL error line and column indicator', async () => {
const { getByText, container, unmount } = renderComponent(); const { getByText, container, unmount } = renderComponent();
// Validate SQL and caret indicator // Validate SQL and caret indicator
@@ -95,7 +96,7 @@ describe('InvalidSQLErrorMessage', () => {
unmount(); unmount();
}); });
it('handles missing line number gracefully', async () => { test('handles missing line number gracefully', async () => {
const overrides = { const overrides = {
error: { error: {
...defaultProps.error, ...defaultProps.error,
@@ -114,7 +115,7 @@ describe('InvalidSQLErrorMessage', () => {
unmount(); unmount();
}); });
it('handles missing column number gracefully', async () => { test('handles missing column number gracefully', async () => {
const overrides = { const overrides = {
error: { error: {
...defaultProps.error, ...defaultProps.error,

View File

@@ -21,6 +21,7 @@ import { render, screen, fireEvent } from 'spec/helpers/testing-library';
import { ErrorLevel, ErrorTypeEnum } from '@superset-ui/core'; import { ErrorLevel, ErrorTypeEnum } from '@superset-ui/core';
import { MarshmallowErrorMessage } from './MarshmallowErrorMessage'; import { MarshmallowErrorMessage } from './MarshmallowErrorMessage';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('MarshmallowErrorMessage', () => { describe('MarshmallowErrorMessage', () => {
const mockError = { const mockError = {
extra: { extra: {

View File

@@ -99,15 +99,16 @@ const setup = (overrides = {}) => (
</Provider> </Provider>
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('OAuth2RedirectMessage Component', () => { describe('OAuth2RedirectMessage Component', () => {
it('renders without crashing and displays the correct initial UI elements', () => { test('renders without crashing and displays the correct initial UI elements', () => {
const { getByText } = render(setup()); const { getByText } = render(setup());
expect(getByText(/Authorization needed/i)).toBeInTheDocument(); expect(getByText(/Authorization needed/i)).toBeInTheDocument();
expect(getByText(/provide authorization/i)).toBeInTheDocument(); expect(getByText(/provide authorization/i)).toBeInTheDocument();
}); });
it('opens a new window with the correct URL when the link is clicked', () => { test('opens a new window with the correct URL when the link is clicked', () => {
const { getByText } = render(setup()); const { getByText } = render(setup());
const linkElement = getByText(/provide authorization/i); const linkElement = getByText(/provide authorization/i);
@@ -116,7 +117,7 @@ describe('OAuth2RedirectMessage Component', () => {
expect(mockOpen).toHaveBeenCalledWith('https://example.com', '_blank'); expect(mockOpen).toHaveBeenCalledWith('https://example.com', '_blank');
}); });
it('cleans up the message event listener on unmount', () => { test('cleans up the message event listener on unmount', () => {
const { unmount } = render(setup()); const { unmount } = render(setup());
expect(mockAddEventListener).toHaveBeenCalled(); expect(mockAddEventListener).toHaveBeenCalled();
@@ -124,7 +125,7 @@ describe('OAuth2RedirectMessage Component', () => {
expect(mockRemoveEventListener).toHaveBeenCalled(); expect(mockRemoveEventListener).toHaveBeenCalled();
}); });
it('dispatches reRunQuery action when a message with correct tab ID is received for SQL Lab', async () => { test('dispatches reRunQuery action when a message with correct tab ID is received for SQL Lab', async () => {
render(setup()); render(setup());
simulateMessageEvent({ tabId: 'tabId' }, 'https://redirect.example.com'); simulateMessageEvent({ tabId: 'tabId' }, 'https://redirect.example.com');
@@ -134,7 +135,7 @@ describe('OAuth2RedirectMessage Component', () => {
}); });
}); });
it('dispatches triggerQuery action for explore source upon receiving a correct message', async () => { test('dispatches triggerQuery action for explore source upon receiving a correct message', async () => {
render(setup({ source: 'explore' })); render(setup({ source: 'explore' }));
simulateMessageEvent({ tabId: 'tabId' }, 'https://redirect.example.com'); simulateMessageEvent({ tabId: 'tabId' }, 'https://redirect.example.com');
@@ -144,7 +145,7 @@ describe('OAuth2RedirectMessage Component', () => {
}); });
}); });
it('dispatches onRefresh action for dashboard source upon receiving a correct message', async () => { test('dispatches onRefresh action for dashboard source upon receiving a correct message', async () => {
render(setup({ source: 'dashboard' })); render(setup({ source: 'dashboard' }));
simulateMessageEvent({ tabId: 'tabId' }, 'https://redirect.example.com'); simulateMessageEvent({ tabId: 'tabId' }, 'https://redirect.example.com');

View File

@@ -57,15 +57,16 @@ afterEach(() => {
cleanup(); cleanup();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FacePile', () => { describe('FacePile', () => {
it('renders empty state with no users', () => { test('renders empty state with no users', () => {
const { container } = render(<FacePile users={[]} />, { store }); const { container } = render(<FacePile users={[]} />, { store });
expect(container.querySelector('.ant-avatar-group')).toBeInTheDocument(); expect(container.querySelector('.ant-avatar-group')).toBeInTheDocument();
expect(container.querySelectorAll('.ant-avatar')).toHaveLength(0); expect(container.querySelectorAll('.ant-avatar')).toHaveLength(0);
}); });
it('renders single user without truncation', () => { test('renders single user without truncation', () => {
const { container } = render(<FacePile users={users.slice(0, 1)} />, { const { container } = render(<FacePile users={users.slice(0, 1)} />, {
store, store,
}); });
@@ -76,7 +77,7 @@ describe('FacePile', () => {
expect(within(container).queryByText(/\+/)).not.toBeInTheDocument(); expect(within(container).queryByText(/\+/)).not.toBeInTheDocument();
}); });
it('renders multiple users no truncation', () => { test('renders multiple users no truncation', () => {
const { container } = render(<FacePile users={users.slice(0, 4)} />, { const { container } = render(<FacePile users={users.slice(0, 4)} />, {
store, store,
}); });
@@ -90,7 +91,7 @@ describe('FacePile', () => {
expect(within(container).queryByText(/\+/)).not.toBeInTheDocument(); expect(within(container).queryByText(/\+/)).not.toBeInTheDocument();
}); });
it('renders multiple users with truncation', () => { test('renders multiple users with truncation', () => {
const { container } = render(<FacePile users={users} />, { store }); const { container } = render(<FacePile users={users} />, { store });
// Should show 4 avatars + 1 overflow indicator = 5 total elements // Should show 4 avatars + 1 overflow indicator = 5 total elements
@@ -107,7 +108,7 @@ describe('FacePile', () => {
expect(within(container).getByText('+6')).toBeInTheDocument(); expect(within(container).getByText('+6')).toBeInTheDocument();
}); });
it('displays user tooltip on hover', () => { test('displays user tooltip on hover', () => {
const { container } = render(<FacePile users={users.slice(0, 2)} />, { const { container } = render(<FacePile users={users.slice(0, 2)} />, {
store, store,
}); });
@@ -119,7 +120,7 @@ describe('FacePile', () => {
expect(screen.getByRole('tooltip')).toHaveTextContent('user 0'); expect(screen.getByRole('tooltip')).toHaveTextContent('user 0');
}); });
it('displays avatar images when Slack avatars are enabled', () => { test('displays avatar images when Slack avatars are enabled', () => {
// Enable Slack avatars feature flag // Enable Slack avatars feature flag
mockIsFeatureEnabled.mockImplementation( mockIsFeatureEnabled.mockImplementation(
feature => feature === 'SLACK_ENABLE_AVATARS', feature => feature === 'SLACK_ENABLE_AVATARS',
@@ -143,24 +144,26 @@ describe('FacePile', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('utils', () => { describe('utils', () => {
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('getRandomColor', () => { describe('getRandomColor', () => {
const colors = ['color1', 'color2', 'color3']; const colors = ['color1', 'color2', 'color3'];
it('produces the same color for the same input values', () => { test('produces the same color for the same input values', () => {
const name = 'foo'; const name = 'foo';
expect(getRandomColor(name, colors)).toEqual( expect(getRandomColor(name, colors)).toEqual(
getRandomColor(name, colors), getRandomColor(name, colors),
); );
}); });
it('produces a different color for different input values', () => { test('produces a different color for different input values', () => {
expect(getRandomColor('foo', colors)).not.toEqual( expect(getRandomColor('foo', colors)).not.toEqual(
getRandomColor('bar', colors), getRandomColor('bar', colors),
); );
}); });
it('handles non-ascii input values', () => { test('handles non-ascii input values', () => {
expect(getRandomColor('泰', colors)).toMatchInlineSnapshot(`"color1"`); expect(getRandomColor('泰', colors)).toMatchInlineSnapshot(`"color1"`);
expect(getRandomColor('مُحَمَّد‎', colors)).toMatchInlineSnapshot( expect(getRandomColor('مُحَمَّد‎', colors)).toMatchInlineSnapshot(
`"color2"`, `"color2"`,

View File

@@ -26,6 +26,7 @@ import {
import { setupAGGridModules } from '@superset-ui/core/components/ThemedAgGridReact'; import { setupAGGridModules } from '@superset-ui/core/components/ThemedAgGridReact';
import { FilterableTable } from '.'; import { FilterableTable } from '.';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FilterableTable', () => { describe('FilterableTable', () => {
beforeAll(() => { beforeAll(() => {
setupAGGridModules(); setupAGGridModules();
@@ -40,10 +41,10 @@ describe('FilterableTable', () => {
], ],
height: 500, height: 500,
}; };
it('is valid element', () => { test('is valid element', () => {
expect(isValidElement(<FilterableTable {...mockedProps} />)).toBe(true); expect(isValidElement(<FilterableTable {...mockedProps} />)).toBe(true);
}); });
it('renders a grid with 3 Table rows', () => { test('renders a grid with 3 Table rows', () => {
const { getByRole, getByText } = render( const { getByRole, getByText } = render(
<FilterableTable {...mockedProps} />, <FilterableTable {...mockedProps} />,
); );
@@ -52,7 +53,7 @@ describe('FilterableTable', () => {
expect(getByText(columnBContent)).toBeInTheDocument(); expect(getByText(columnBContent)).toBeInTheDocument();
}); });
}); });
it('filters on a string', () => { test('filters on a string', () => {
const props = { const props = {
...mockedProps, ...mockedProps,
filterText: 'b1', filterText: 'b1',
@@ -62,7 +63,7 @@ describe('FilterableTable', () => {
expect(queryByText('b2')).not.toBeInTheDocument(); expect(queryByText('b2')).not.toBeInTheDocument();
expect(queryByText('b3')).not.toBeInTheDocument(); expect(queryByText('b3')).not.toBeInTheDocument();
}); });
it('filters on a number', () => { test('filters on a number', () => {
const props = { const props = {
...mockedProps, ...mockedProps,
filterText: '100', filterText: '100',
@@ -74,12 +75,13 @@ describe('FilterableTable', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FilterableTable sorting - RTL', () => { describe('FilterableTable sorting - RTL', () => {
beforeAll(() => { beforeAll(() => {
setupAGGridModules(); setupAGGridModules();
}); });
it('sorts strings correctly', () => { test('sorts strings correctly', () => {
const stringProps = { const stringProps = {
orderedColumnKeys: ['columnA'], orderedColumnKeys: ['columnA'],
data: [ data: [
@@ -128,7 +130,7 @@ describe('FilterableTable sorting - RTL', () => {
); );
}); });
it('sorts integers correctly', () => { test('sorts integers correctly', () => {
const integerProps = { const integerProps = {
orderedColumnKeys: ['columnB'], orderedColumnKeys: ['columnB'],
data: [{ columnB: 21 }, { columnB: 0 }, { columnB: 623 }], data: [{ columnB: 21 }, { columnB: 0 }, { columnB: 623 }],
@@ -163,7 +165,7 @@ describe('FilterableTable sorting - RTL', () => {
expect(gridCells?.textContent).toEqual(['21', '0', '623'].join('')); expect(gridCells?.textContent).toEqual(['21', '0', '623'].join(''));
}); });
it('sorts floating numbers correctly', () => { test('sorts floating numbers correctly', () => {
const floatProps = { const floatProps = {
orderedColumnKeys: ['columnC'], orderedColumnKeys: ['columnC'],
data: [{ columnC: 45.67 }, { columnC: 1.23 }, { columnC: 89.0000001 }], data: [{ columnC: 45.67 }, { columnC: 1.23 }, { columnC: 89.0000001 }],
@@ -206,7 +208,7 @@ describe('FilterableTable sorting - RTL', () => {
); );
}); });
it('sorts rows properly when floating numbers have mixed types', () => { test('sorts rows properly when floating numbers have mixed types', () => {
const mixedFloatProps = { const mixedFloatProps = {
orderedColumnKeys: ['columnD'], orderedColumnKeys: ['columnD'],
data: [ data: [
@@ -308,7 +310,7 @@ describe('FilterableTable sorting - RTL', () => {
); );
}); });
it('sorts YYYY-MM-DD properly', () => { test('sorts YYYY-MM-DD properly', () => {
const dsProps = { const dsProps = {
orderedColumnKeys: ['columnDS'], orderedColumnKeys: ['columnDS'],
data: [ data: [

View File

@@ -152,6 +152,7 @@ test('renders unhide when invisible column exists', async () => {
expect(mockGridApi.setColumnsVisible).toHaveBeenCalledWith(['column2'], true); expect(mockGridApi.setColumnsVisible).toHaveBeenCalledWith(['column2'], true);
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('for main menu', () => { describe('for main menu', () => {
test('renders Copy to Clipboard', async () => { test('renders Copy to Clipboard', async () => {
const { getByText } = setup({ ...mockedProps, isMain: true }); const { getByText } = setup({ ...mockedProps, isMain: true });

View File

@@ -130,6 +130,7 @@ const factory = (props = mockedProps) =>
{ store: mockStore() }, { store: mockStore() },
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ListView', () => { describe('ListView', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.reset(); fetchMock.reset();
@@ -146,7 +147,7 @@ describe('ListView', () => {
}); });
// Example of converted test: // Example of converted test:
it('calls fetchData on mount', () => { test('calls fetchData on mount', () => {
expect(mockedProps.fetchData).toHaveBeenCalledWith({ expect(mockedProps.fetchData).toHaveBeenCalledWith({
filters: [], filters: [],
pageIndex: 0, pageIndex: 0,
@@ -155,7 +156,7 @@ describe('ListView', () => {
}); });
}); });
it('calls fetchData on sort', async () => { test('calls fetchData on sort', async () => {
const sortHeader = screen.getAllByTestId('sort-header')[1]; const sortHeader = screen.getAllByTestId('sort-header')[1];
await userEvent.click(sortHeader); await userEvent.click(sortHeader);
@@ -173,7 +174,7 @@ describe('ListView', () => {
}); });
// Update pagination control tests for Ant Design pagination // Update pagination control tests for Ant Design pagination
it('renders pagination controls', () => { test('renders pagination controls', () => {
const paginationList = screen.getByRole('list'); const paginationList = screen.getByRole('list');
expect(paginationList).toBeInTheDocument(); expect(paginationList).toBeInTheDocument();
@@ -181,7 +182,7 @@ describe('ListView', () => {
expect(pageOneItem).toBeInTheDocument(); expect(pageOneItem).toBeInTheDocument();
}); });
it('calls fetchData on page change', async () => { test('calls fetchData on page change', async () => {
const pageTwoItem = screen.getByRole('listitem', { name: '2' }); const pageTwoItem = screen.getByRole('listitem', { name: '2' });
await userEvent.click(pageTwoItem); await userEvent.click(pageTwoItem);
@@ -197,7 +198,7 @@ describe('ListView', () => {
}); });
}); });
it('handles bulk actions on 1 row', async () => { test('handles bulk actions on 1 row', async () => {
const checkboxes = screen.getAllByRole('checkbox'); const checkboxes = screen.getAllByRole('checkbox');
await userEvent.click(checkboxes[1]); // Index 1 is the first row checkbox await userEvent.click(checkboxes[1]); // Index 1 is the first row checkbox
@@ -217,12 +218,12 @@ describe('ListView', () => {
}); });
// Update UI filters test to use more specific selector // Update UI filters test to use more specific selector
it('renders UI filters', () => { test('renders UI filters', () => {
const filterControls = screen.getAllByRole('combobox'); const filterControls = screen.getAllByRole('combobox');
expect(filterControls).toHaveLength(2); expect(filterControls).toHaveLength(2);
}); });
it('calls fetchData on filter', async () => { test('calls fetchData on filter', async () => {
// Handle select filter // Handle select filter
const selectFilter = screen.getAllByRole('combobox')[0]; const selectFilter = screen.getAllByRole('combobox')[0];
await userEvent.click(selectFilter); await userEvent.click(selectFilter);
@@ -252,7 +253,7 @@ describe('ListView', () => {
); );
}); });
it('calls fetchData on card view sort', async () => { test('calls fetchData on card view sort', async () => {
factory({ factory({
...mockedProps, ...mockedProps,
renderCard: jest.fn(), renderCard: jest.fn(),

View File

@@ -19,26 +19,25 @@
import { ADD_TOAST, REMOVE_TOAST } from 'src/components/MessageToasts/actions'; import { ADD_TOAST, REMOVE_TOAST } from 'src/components/MessageToasts/actions';
import messageToastsReducer from 'src/components/MessageToasts/reducers'; import messageToastsReducer from 'src/components/MessageToasts/reducers';
describe('messageToasts reducer', () => { // messageToasts reducer
it('should return initial state', () => { test('messageToasts reducer should return initial state', () => {
expect(messageToastsReducer(undefined, {})).toEqual([]); expect(messageToastsReducer(undefined, {})).toEqual([]);
}); });
it('should add a toast', () => { test('messageToasts reducer should add a toast', () => {
expect( expect(
messageToastsReducer([], { messageToastsReducer([], {
type: ADD_TOAST, type: ADD_TOAST,
payload: { text: 'test', id: 'id', type: 'test_type' }, payload: { text: 'test', id: 'id', type: 'test_type' },
}), }),
).toEqual([{ text: 'test', id: 'id', type: 'test_type' }]); ).toEqual([{ text: 'test', id: 'id', type: 'test_type' }]);
}); });
it('should remove a toast', () => { test('messageToasts reducer should remove a toast', () => {
expect( expect(
messageToastsReducer([{ id: 'id' }, { id: 'id2' }], { messageToastsReducer([{ id: 'id' }, { id: 'id2' }], {
type: REMOVE_TOAST, type: REMOVE_TOAST,
payload: { id: 'id' }, payload: { id: 'id' },
}), }),
).toEqual([{ id: 'id2' }]); ).toEqual([{ id: 'id2' }]);
});
}); });

View File

@@ -20,41 +20,40 @@ import { render, screen } from 'spec/helpers/testing-library';
import { Icons } from '@superset-ui/core/components'; import { Icons } from '@superset-ui/core/components';
import { ModalTitleWithIcon } from '.'; import { ModalTitleWithIcon } from '.';
describe('ModalTitleWithIcon', () => { // ModalTitleWithIcon
it('renders the title without icon if none is passed and isEditMode is undefined', () => { test('ModalTitleWithIcon renders the title without icon if none is passed and isEditMode is undefined', () => {
render(<ModalTitleWithIcon title="My Title" />); render(<ModalTitleWithIcon title="My Title" />);
expect(screen.getByText('My Title')).toBeInTheDocument(); expect(screen.getByText('My Title')).toBeInTheDocument();
expect(screen.queryByRole('img')).not.toBeInTheDocument(); expect(screen.queryByRole('img')).not.toBeInTheDocument();
}); });
it('renders Edit icon if isEditMode is true', () => { test('ModalTitleWithIcon renders Edit icon if isEditMode is true', () => {
render(<ModalTitleWithIcon title="Edit Mode" isEditMode />); render(<ModalTitleWithIcon title="Edit Mode" isEditMode />);
expect(screen.getByText('Edit Mode')).toBeInTheDocument(); expect(screen.getByText('Edit Mode')).toBeInTheDocument();
expect(screen.getByRole('img', { name: /edit/i })).toBeInTheDocument(); expect(screen.getByRole('img', { name: /edit/i })).toBeInTheDocument();
}); });
it('renders Plus icon if isEditMode is false', () => { test('ModalTitleWithIcon renders Plus icon if isEditMode is false', () => {
render(<ModalTitleWithIcon title="Add Mode" isEditMode={false} />); render(<ModalTitleWithIcon title="Add Mode" isEditMode={false} />);
expect(screen.getByText('Add Mode')).toBeInTheDocument(); expect(screen.getByText('Add Mode')).toBeInTheDocument();
expect(screen.getByRole('img', { name: /plus/i })).toBeInTheDocument(); expect(screen.getByRole('img', { name: /plus/i })).toBeInTheDocument();
}); });
it('renders custom icon when passed explicitly', () => { test('ModalTitleWithIcon renders custom icon when passed explicitly', () => {
render( render(
<ModalTitleWithIcon <ModalTitleWithIcon
title="Custom Icon" title="Custom Icon"
icon={<Icons.DownOutlined data-test="custom-icon" />} icon={<Icons.DownOutlined data-test="custom-icon" />}
/>, />,
); );
expect(screen.getByText('Custom Icon')).toBeInTheDocument(); expect(screen.getByText('Custom Icon')).toBeInTheDocument();
expect(screen.getByTestId('custom-icon')).toBeInTheDocument(); expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
}); });
it('respects the level prop (e.g., renders h3 for level=3)', () => { test('ModalTitleWithIcon respects the level prop (e.g., renders h3 for level=3)', () => {
const { container } = render( const { container } = render(
<ModalTitleWithIcon title="Header Level 3" level={3} />, <ModalTitleWithIcon title="Header Level 3" level={3} />,
); );
expect(container.querySelector('h3')).toHaveTextContent('Header Level 3'); expect(container.querySelector('h3')).toHaveTextContent('Header Level 3');
});
}); });

View File

@@ -26,6 +26,7 @@ import useStoredSidebarWidth from './useStoredSidebarWidth';
const INITIAL_WIDTH = 300; const INITIAL_WIDTH = 300;
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('useStoredSidebarWidth', () => { describe('useStoredSidebarWidth', () => {
beforeEach(() => { beforeEach(() => {
localStorage.clear(); localStorage.clear();
@@ -35,7 +36,7 @@ describe('useStoredSidebarWidth', () => {
localStorage.clear(); localStorage.clear();
}); });
it('returns a default filterBar width by initialWidth', () => { test('returns a default filterBar width by initialWidth', () => {
const id = '123'; const id = '123';
const { result } = renderHook(() => const { result } = renderHook(() =>
useStoredSidebarWidth(id, INITIAL_WIDTH), useStoredSidebarWidth(id, INITIAL_WIDTH),
@@ -45,7 +46,7 @@ describe('useStoredSidebarWidth', () => {
expect(actualWidth).toEqual(INITIAL_WIDTH); expect(actualWidth).toEqual(INITIAL_WIDTH);
}); });
it('returns a stored filterBar width from localStorage', () => { test('returns a stored filterBar width from localStorage', () => {
const id = '123'; const id = '123';
const expectedWidth = 378; const expectedWidth = 378;
setItem(LocalStorageKeys.CommonResizableSidebarWidths, { setItem(LocalStorageKeys.CommonResizableSidebarWidths, {
@@ -61,7 +62,7 @@ describe('useStoredSidebarWidth', () => {
expect(actualWidth).not.toEqual(250); expect(actualWidth).not.toEqual(250);
}); });
it('returns a setter for filterBar width that stores the state in localStorage together', () => { test('returns a setter for filterBar width that stores the state in localStorage together', () => {
const id = '123'; const id = '123';
const expectedWidth = 378; const expectedWidth = 378;
const otherDashboardId = '456'; const otherDashboardId = '456';

View File

@@ -41,12 +41,13 @@ const defaultProps = {
datasourceType: 'table', datasourceType: 'table',
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SQLEditorWithValidation', () => { describe('SQLEditorWithValidation', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('renders SQLEditor with validation bar when showValidation is true', () => { test('renders SQLEditor with validation bar when showValidation is true', () => {
render(<SQLEditorWithValidation {...defaultProps} />); render(<SQLEditorWithValidation {...defaultProps} />);
expect(screen.getByText('Unverified')).toBeInTheDocument(); expect(screen.getByText('Unverified')).toBeInTheDocument();
@@ -55,7 +56,7 @@ describe('SQLEditorWithValidation', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('does not render validation bar when showValidation is false', () => { test('does not render validation bar when showValidation is false', () => {
render( render(
<SQLEditorWithValidation {...defaultProps} showValidation={false} />, <SQLEditorWithValidation {...defaultProps} showValidation={false} />,
); );
@@ -66,7 +67,7 @@ describe('SQLEditorWithValidation', () => {
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
it('shows primary button style when unverified', () => { test('shows primary button style when unverified', () => {
render(<SQLEditorWithValidation {...defaultProps} />); render(<SQLEditorWithValidation {...defaultProps} />);
const validateButton = screen.getByRole('button', { const validateButton = screen.getByRole('button', {
@@ -76,7 +77,7 @@ describe('SQLEditorWithValidation', () => {
// Button should have primary styling (this would need to check actual class or style) // Button should have primary styling (this would need to check actual class or style)
}); });
it('disables validate button when no value or datasourceId', () => { test('disables validate button when no value or datasourceId', () => {
render( render(
<SQLEditorWithValidation <SQLEditorWithValidation
{...defaultProps} {...defaultProps}
@@ -91,7 +92,7 @@ describe('SQLEditorWithValidation', () => {
expect(validateButton).toBeDisabled(); expect(validateButton).toBeDisabled();
}); });
it('shows validating state when validation is in progress', async () => { test('shows validating state when validation is in progress', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;
@@ -117,7 +118,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('shows success state when validation passes', async () => { test('shows success state when validation passes', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;
@@ -138,7 +139,7 @@ describe('SQLEditorWithValidation', () => {
expect(validateButton).toBeInTheDocument(); expect(validateButton).toBeInTheDocument();
}); });
it('shows error state when validation fails', async () => { test('shows error state when validation fails', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;
@@ -169,7 +170,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('handles API errors gracefully', async () => { test('handles API errors gracefully', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;
@@ -189,7 +190,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('sends correct payload for column expression', async () => { test('sends correct payload for column expression', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;
@@ -221,7 +222,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('sends correct payload for WHERE expression', async () => { test('sends correct payload for WHERE expression', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;
@@ -252,7 +253,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('sends correct payload for HAVING expression', async () => { test('sends correct payload for HAVING expression', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;
@@ -283,7 +284,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('resets validation state when value changes', () => { test('resets validation state when value changes', () => {
const { rerender } = render(<SQLEditorWithValidation {...defaultProps} />); const { rerender } = render(<SQLEditorWithValidation {...defaultProps} />);
// Simulate having a validation result // Simulate having a validation result
@@ -304,7 +305,7 @@ describe('SQLEditorWithValidation', () => {
expect(screen.getByText('Unverified')).toBeInTheDocument(); expect(screen.getByText('Unverified')).toBeInTheDocument();
}); });
it('calls onChange when editor value changes', () => { test('calls onChange when editor value changes', () => {
const onChange = jest.fn(); const onChange = jest.fn();
render(<SQLEditorWithValidation {...defaultProps} onChange={onChange} />); render(<SQLEditorWithValidation {...defaultProps} onChange={onChange} />);
@@ -313,7 +314,7 @@ describe('SQLEditorWithValidation', () => {
expect(onChange).toBeDefined(); expect(onChange).toBeDefined();
}); });
it('calls onValidationComplete callback when provided', async () => { test('calls onValidationComplete callback when provided', async () => {
const onValidationComplete = jest.fn(); const onValidationComplete = jest.fn();
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
@@ -337,7 +338,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('calls onValidationComplete with errors when validation fails', async () => { test('calls onValidationComplete with errors when validation fails', async () => {
const onValidationComplete = jest.fn(); const onValidationComplete = jest.fn();
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
@@ -371,7 +372,7 @@ describe('SQLEditorWithValidation', () => {
}); });
}); });
it('shows tooltip with full error message when error is truncated', async () => { test('shows tooltip with full error message when error is truncated', async () => {
const longErrorMessage = const longErrorMessage =
'This is a very long error message that should be truncated in the display but shown in full in the tooltip when user hovers over it'; 'This is a very long error message that should be truncated in the display but shown in full in the tooltip when user hovers over it';
@@ -410,7 +411,7 @@ describe('SQLEditorWithValidation', () => {
expect(errorElement.parentElement).toBeTruthy(); expect(errorElement.parentElement).toBeTruthy();
}); });
it('handles empty response gracefully', async () => { test('handles empty response gracefully', async () => {
const mockPost = SupersetClient.post as jest.MockedFunction< const mockPost = SupersetClient.post as jest.MockedFunction<
typeof SupersetClient.post typeof SupersetClient.post
>; >;

View File

@@ -20,6 +20,7 @@ import fetchMock from 'fetch-mock';
import rison from 'rison'; import rison from 'rison';
import { tagToSelectOption, loadTags } from 'src/components/Tag/utils'; import { tagToSelectOption, loadTags } from 'src/components/Tag/utils';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('tagToSelectOption', () => { describe('tagToSelectOption', () => {
test('converts a Tag object with table_name to a SelectTagsValue', () => { test('converts a Tag object with table_name to a SelectTagsValue', () => {
const tag = { const tag = {
@@ -38,6 +39,7 @@ describe('tagToSelectOption', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('loadTags', () => { describe('loadTags', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.reset(); fetchMock.reset();

View File

@@ -79,6 +79,7 @@ test('should render 3 elements when maxTags is set to 3', async () => {
expect(tagsListItems[2]).toHaveTextContent('+3...'); expect(tagsListItems[2]).toHaveTextContent('+3...');
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Tag type filtering', () => { describe('Tag type filtering', () => {
test('should render only custom type tags (type: 1)', async () => { test('should render only custom type tags (type: 1)', async () => {
const mixedTypeTags = [ const mixedTypeTags = [

View File

@@ -58,6 +58,7 @@ import {
NEW_ROW_ID, NEW_ROW_ID,
} from 'src/dashboard/util/constants'; } from 'src/dashboard/util/constants';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('dashboardLayout actions', () => { describe('dashboardLayout actions', () => {
const mockState = { const mockState = {
dashboardState: { dashboardState: {
@@ -85,8 +86,9 @@ describe('dashboardLayout actions', () => {
dashboardFilters.updateLayoutComponents.restore(); dashboardFilters.updateLayoutComponents.restore();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('updateComponents', () => { describe('updateComponents', () => {
it('should dispatch an updateLayout action', () => { test('should dispatch an updateLayout action', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const nextComponents = { 1: {} }; const nextComponents = { 1: {} };
const thunk = updateComponents(nextComponents); const thunk = updateComponents(nextComponents);
@@ -101,7 +103,7 @@ describe('dashboardLayout actions', () => {
expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(0); expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(0);
}); });
it('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => { test('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
}); });
@@ -115,8 +117,9 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('deleteComponents', () => { describe('deleteComponents', () => {
it('should dispatch an deleteComponent action', () => { test('should dispatch an deleteComponent action', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const thunk = deleteComponent('id', 'parentId'); const thunk = deleteComponent('id', 'parentId');
thunk(dispatch, getState); thunk(dispatch, getState);
@@ -129,7 +132,7 @@ describe('dashboardLayout actions', () => {
expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1); expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1);
}); });
it('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => { test('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
}); });
@@ -142,8 +145,9 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('updateDashboardTitle', () => { describe('updateDashboardTitle', () => {
it('should dispatch an updateComponent action for the header component', () => { test('should dispatch an updateComponent action for the header component', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const thunk1 = updateDashboardTitle('new text'); const thunk1 = updateDashboardTitle('new text');
thunk1(dispatch, getState); thunk1(dispatch, getState);
@@ -167,8 +171,9 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('createTopLevelTabs', () => { describe('createTopLevelTabs', () => {
it('should dispatch a createTopLevelTabs action', () => { test('should dispatch a createTopLevelTabs action', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const dropResult = {}; const dropResult = {};
const thunk = createTopLevelTabs(dropResult); const thunk = createTopLevelTabs(dropResult);
@@ -182,7 +187,7 @@ describe('dashboardLayout actions', () => {
expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1); expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1);
}); });
it('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => { test('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
}); });
@@ -196,8 +201,9 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('deleteTopLevelTabs', () => { describe('deleteTopLevelTabs', () => {
it('should dispatch a deleteTopLevelTabs action', () => { test('should dispatch a deleteTopLevelTabs action', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const dropResult = {}; const dropResult = {};
const thunk = deleteTopLevelTabs(dropResult); const thunk = deleteTopLevelTabs(dropResult);
@@ -211,7 +217,7 @@ describe('dashboardLayout actions', () => {
expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1); expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1);
}); });
it('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => { test('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
}); });
@@ -225,6 +231,7 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('resizeComponent', () => { describe('resizeComponent', () => {
const dashboardLayout = { const dashboardLayout = {
...mockState.dashboardLayout, ...mockState.dashboardLayout,
@@ -240,7 +247,7 @@ describe('dashboardLayout actions', () => {
}, },
}; };
it('should update the size of the component', () => { test('should update the size of the component', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardLayout, dashboardLayout,
}); });
@@ -271,7 +278,7 @@ describe('dashboardLayout actions', () => {
expect(dispatch.callCount).toBe(2); expect(dispatch.callCount).toBe(2);
}); });
it('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => { test('should dispatch a setUnsavedChanges action if hasUnsavedChanges=false', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
dashboardLayout, dashboardLayout,
@@ -289,8 +296,9 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('handleComponentDrop', () => { describe('handleComponentDrop', () => {
it('should create a component if it is new', () => { test('should create a component if it is new', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const dropResult = { const dropResult = {
source: { id: NEW_COMPONENTS_SOURCE_ID }, source: { id: NEW_COMPONENTS_SOURCE_ID },
@@ -315,7 +323,7 @@ describe('dashboardLayout actions', () => {
expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1); expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1);
}); });
it('should move a component if the component is not new', () => { test('should move a component if the component is not new', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardLayout: { dashboardLayout: {
// if 'dragging' is not only child will dispatch deleteComponent thunk // if 'dragging' is not only child will dispatch deleteComponent thunk
@@ -345,7 +353,7 @@ describe('dashboardLayout actions', () => {
expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1); expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1);
}); });
it('should dispatch a toast if the drop overflows the destination', () => { test('should dispatch a toast if the drop overflows the destination', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardLayout: { dashboardLayout: {
present: { present: {
@@ -374,7 +382,7 @@ describe('dashboardLayout actions', () => {
expect(dispatch.callCount).toBe(1); expect(dispatch.callCount).toBe(1);
}); });
it('should delete a parent Row or Tabs if the moved child was the only child', () => { test('should delete a parent Row or Tabs if the moved child was the only child', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardLayout: { dashboardLayout: {
present: { present: {
@@ -411,7 +419,7 @@ describe('dashboardLayout actions', () => {
}); });
}); });
it('should create top-level tabs if dropped on root', () => { test('should create top-level tabs if dropped on root', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const dropResult = { const dropResult = {
source: { id: NEW_COMPONENTS_SOURCE_ID }, source: { id: NEW_COMPONENTS_SOURCE_ID },
@@ -433,7 +441,7 @@ describe('dashboardLayout actions', () => {
}); });
}); });
it('should dispatch a toast if drop top-level tab into nested tab', () => { test('should dispatch a toast if drop top-level tab into nested tab', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardLayout: { dashboardLayout: {
present: { present: {
@@ -488,8 +496,9 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('undoLayoutAction', () => { describe('undoLayoutAction', () => {
it('should dispatch a redux-undo .undo() action', () => { test('should dispatch a redux-undo .undo() action', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardLayout: { past: ['non-empty'] }, dashboardLayout: { past: ['non-empty'] },
}); });
@@ -500,7 +509,7 @@ describe('dashboardLayout actions', () => {
expect(dispatch.getCall(0).args[0]).toEqual(UndoActionCreators.undo()); expect(dispatch.getCall(0).args[0]).toEqual(UndoActionCreators.undo());
}); });
it('should dispatch a setUnsavedChanges(false) action history length is zero', () => { test('should dispatch a setUnsavedChanges(false) action history length is zero', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardLayout: { past: [] }, dashboardLayout: { past: [] },
}); });
@@ -512,8 +521,9 @@ describe('dashboardLayout actions', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('redoLayoutAction', () => { describe('redoLayoutAction', () => {
it('should dispatch a redux-undo .redo() action', () => { test('should dispatch a redux-undo .redo() action', () => {
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const thunk = redoLayoutAction(); const thunk = redoLayoutAction();
thunk(dispatch, getState); thunk(dispatch, getState);
@@ -524,7 +534,7 @@ describe('dashboardLayout actions', () => {
expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1); expect(dashboardFilters.updateLayoutComponents.callCount).toEqual(1);
}); });
it('should dispatch a setUnsavedChanges(true) action if hasUnsavedChanges=false', () => { test('should dispatch a setUnsavedChanges(true) action if hasUnsavedChanges=false', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
}); });

View File

@@ -43,6 +43,7 @@ jest.mock('@superset-ui/core', () => ({
isFeatureEnabled: jest.fn(), isFeatureEnabled: jest.fn(),
})); }));
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('dashboardState actions', () => { describe('dashboardState actions', () => {
const mockState = { const mockState = {
dashboardState: { dashboardState: {
@@ -101,8 +102,9 @@ describe('dashboardState actions', () => {
return { getState, dispatch, state }; return { getState, dispatch, state };
} }
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('saveDashboardRequest', () => { describe('saveDashboardRequest', () => {
it('should dispatch UPDATE_COMPONENTS_PARENTS_LIST action', () => { test('should dispatch UPDATE_COMPONENTS_PARENTS_LIST action', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
}); });
@@ -115,7 +117,7 @@ describe('dashboardState actions', () => {
expect(dispatch.getCall(1).args[0].type).toBe(SAVE_DASHBOARD_STARTED); expect(dispatch.getCall(1).args[0].type).toBe(SAVE_DASHBOARD_STARTED);
}); });
it('should post dashboard data with updated redux state', () => { test('should post dashboard data with updated redux state', () => {
const { getState, dispatch } = setup({ const { getState, dispatch } = setup({
dashboardState: { hasUnsavedChanges: false }, dashboardState: { hasUnsavedChanges: false },
}); });
@@ -144,6 +146,7 @@ describe('dashboardState actions', () => {
).toStrictEqual(mockParentsList); ).toStrictEqual(mockParentsList);
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FeatureFlag.CONFIRM_DASHBOARD_DIFF', () => { describe('FeatureFlag.CONFIRM_DASHBOARD_DIFF', () => {
beforeEach(() => { beforeEach(() => {
isFeatureEnabled.mockImplementation( isFeatureEnabled.mockImplementation(
@@ -155,7 +158,7 @@ describe('dashboardState actions', () => {
isFeatureEnabled.mockRestore(); isFeatureEnabled.mockRestore();
}); });
it('dispatches SET_OVERRIDE_CONFIRM when an inspect value has diff', async () => { test('dispatches SET_OVERRIDE_CONFIRM when an inspect value has diff', async () => {
const id = 192; const id = 192;
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const thunk = saveDashboardRequest( const thunk = saveDashboardRequest(
@@ -174,7 +177,7 @@ describe('dashboardState actions', () => {
).toBe(id); ).toBe(id);
}); });
it('should post dashboard data with after confirm the overwrite values', async () => { test('should post dashboard data with after confirm the overwrite values', async () => {
const id = 192; const id = 192;
const { getState, dispatch } = setup(); const { getState, dispatch } = setup();
const confirmedDashboardData = { const confirmedDashboardData = {

View File

@@ -19,6 +19,7 @@
import { render, act } from 'spec/helpers/testing-library'; import { render, act } from 'spec/helpers/testing-library';
import AnchorLink from 'src/dashboard/components/AnchorLink'; import AnchorLink from 'src/dashboard/components/AnchorLink';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('AnchorLink', () => { describe('AnchorLink', () => {
const props = { const props = {
id: 'CHART-123', id: 'CHART-123',
@@ -30,7 +31,7 @@ describe('AnchorLink', () => {
window.location = globalLocation; window.location = globalLocation;
}); });
it('should scroll the AnchorLink into view upon mount if id matches hash', async () => { test('should scroll the AnchorLink into view upon mount if id matches hash', async () => {
const callback = jest.fn(); const callback = jest.fn();
jest.spyOn(document, 'getElementById').mockReturnValue({ jest.spyOn(document, 'getElementById').mockReturnValue({
scrollIntoView: callback, scrollIntoView: callback,
@@ -49,7 +50,7 @@ describe('AnchorLink', () => {
expect(callback).toHaveBeenCalledTimes(1); expect(callback).toHaveBeenCalledTimes(1);
}); });
it('should render anchor link without short link button', () => { test('should render anchor link without short link button', () => {
const { container, queryByRole } = render( const { container, queryByRole } = render(
<AnchorLink showShortLinkButton={false} {...props} />, <AnchorLink showShortLinkButton={false} {...props} />,
{ useRedux: true }, { useRedux: true },
@@ -58,7 +59,7 @@ describe('AnchorLink', () => {
expect(queryByRole('button')).not.toBeInTheDocument(); expect(queryByRole('button')).not.toBeInTheDocument();
}); });
it('should render short link button', () => { test('should render short link button', () => {
const { getByRole } = render( const { getByRole } = render(
<AnchorLink {...props} showShortLinkButton />, <AnchorLink {...props} showShortLinkButton />,
{ useRedux: true }, { useRedux: true },

View File

@@ -39,6 +39,7 @@ import { getRelatedCharts } from 'src/dashboard/util/getRelatedCharts';
jest.mock('src/dashboard/util/getRelatedCharts'); jest.mock('src/dashboard/util/getRelatedCharts');
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Dashboard', () => { describe('Dashboard', () => {
const mockAddSlice = jest.fn(); const mockAddSlice = jest.fn();
const mockRemoveSlice = jest.fn(); const mockRemoveSlice = jest.fn();
@@ -91,18 +92,19 @@ describe('Dashboard', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should render the children component', () => { test('should render the children component', () => {
renderDashboard(); renderDashboard();
expect(screen.getByText('Test')).toBeInTheDocument(); expect(screen.getByText('Test')).toBeInTheDocument();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('layout changes', () => { describe('layout changes', () => {
const layoutWithExtraChart = { const layoutWithExtraChart = {
...props.layout, ...props.layout,
1001: newComponentFactory(CHART_TYPE, { chartId: 1001 }), 1001: newComponentFactory(CHART_TYPE, { chartId: 1001 }),
}; };
it('should call addSliceToDashboard if a new slice is added to the layout', () => { test('should call addSliceToDashboard if a new slice is added to the layout', () => {
const { rerender } = renderDashboard(); const { rerender } = renderDashboard();
rerender( rerender(
@@ -116,7 +118,7 @@ describe('Dashboard', () => {
expect(mockAddSlice).toHaveBeenCalled(); expect(mockAddSlice).toHaveBeenCalled();
}); });
it('should call removeSliceFromDashboard if a slice is removed from the layout', () => { test('should call removeSliceFromDashboard if a slice is removed from the layout', () => {
const { rerender } = renderDashboard({ layout: layoutWithExtraChart }); const { rerender } = renderDashboard({ layout: layoutWithExtraChart });
const nextLayout = { ...layoutWithExtraChart }; const nextLayout = { ...layoutWithExtraChart };
@@ -134,8 +136,9 @@ describe('Dashboard', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('filter updates', () => { describe('filter updates', () => {
it('should not call refresh when in editMode', () => { test('should not call refresh when in editMode', () => {
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
rerender( rerender(
@@ -156,7 +159,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).not.toHaveBeenCalled(); expect(mockTriggerQuery).not.toHaveBeenCalled();
}); });
it('should not call refresh when there is no change', () => { test('should not call refresh when there is no change', () => {
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
rerender( rerender(
@@ -170,7 +173,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).not.toHaveBeenCalled(); expect(mockTriggerQuery).not.toHaveBeenCalled();
}); });
it('should call refresh when native filters changed', () => { test('should call refresh when native filters changed', () => {
getRelatedCharts.mockReturnValue([230]); getRelatedCharts.mockReturnValue([230]);
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
@@ -195,7 +198,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).toHaveBeenCalled(); expect(mockTriggerQuery).toHaveBeenCalled();
}); });
it('should call refresh if a filter is added', () => { test('should call refresh if a filter is added', () => {
getRelatedCharts.mockReturnValue([1]); getRelatedCharts.mockReturnValue([1]);
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
@@ -214,7 +217,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).toHaveBeenCalled(); expect(mockTriggerQuery).toHaveBeenCalled();
}); });
it('should call refresh if a filter is removed', () => { test('should call refresh if a filter is removed', () => {
getRelatedCharts.mockReturnValue([1]); // Ensure we return some charts to refresh getRelatedCharts.mockReturnValue([1]); // Ensure we return some charts to refresh
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
@@ -233,7 +236,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).toHaveBeenCalledWith(true, 1); expect(mockTriggerQuery).toHaveBeenCalledWith(true, 1);
}); });
it('should call refresh if a filter is changed', () => { test('should call refresh if a filter is changed', () => {
getRelatedCharts.mockReturnValue([1]); getRelatedCharts.mockReturnValue([1]);
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
@@ -253,7 +256,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).toHaveBeenCalled(); expect(mockTriggerQuery).toHaveBeenCalled();
}); });
it('should call refresh with multiple chart ids', () => { test('should call refresh with multiple chart ids', () => {
getRelatedCharts.mockReturnValue([1, 2]); getRelatedCharts.mockReturnValue([1, 2]);
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
@@ -273,7 +276,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).toHaveBeenCalled(); expect(mockTriggerQuery).toHaveBeenCalled();
}); });
it('should call refresh if a filter scope is changed', () => { test('should call refresh if a filter scope is changed', () => {
getRelatedCharts.mockReturnValue([2]); getRelatedCharts.mockReturnValue([2]);
const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS }); const { rerender } = renderDashboard({ activeFilters: OVERRIDE_FILTERS });
@@ -293,7 +296,7 @@ describe('Dashboard', () => {
expect(mockTriggerQuery).toHaveBeenCalled(); expect(mockTriggerQuery).toHaveBeenCalled();
}); });
it('should call refresh with empty [] if a filter is changed but scope is not applicable', () => { test('should call refresh with empty [] if a filter is changed but scope is not applicable', () => {
getRelatedCharts.mockReturnValue([]); getRelatedCharts.mockReturnValue([]);
const { rerender } = renderDashboard({ const { rerender } = renderDashboard({
activeFilters: OVERRIDE_FILTERS, activeFilters: OVERRIDE_FILTERS,

View File

@@ -83,6 +83,7 @@ jest.mock('src/dashboard/containers/DashboardGrid', () => () => (
<div data-test="mock-dashboard-grid" /> <div data-test="mock-dashboard-grid" />
)); ));
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DashboardBuilder', () => { describe('DashboardBuilder', () => {
let favStarStub: jest.Mock; let favStarStub: jest.Mock;
let activeTabsStub: jest.Mock; let activeTabsStub: jest.Mock;
@@ -120,13 +121,13 @@ describe('DashboardBuilder', () => {
}); });
} }
it('should render a StickyContainer with class "dashboard"', () => { test('should render a StickyContainer with class "dashboard"', () => {
const { getByTestId } = setup(); const { getByTestId } = setup();
const stickyContainer = getByTestId('dashboard-content-wrapper'); const stickyContainer = getByTestId('dashboard-content-wrapper');
expect(stickyContainer).toHaveClass('dashboard'); expect(stickyContainer).toHaveClass('dashboard');
}); });
it('should add the "dashboard--editing" class if editMode=true', () => { test('should add the "dashboard--editing" class if editMode=true', () => {
const { getByTestId } = setup({ const { getByTestId } = setup({
dashboardState: { ...mockState.dashboardState, editMode: true }, dashboardState: { ...mockState.dashboardState, editMode: true },
}); });
@@ -134,13 +135,13 @@ describe('DashboardBuilder', () => {
expect(stickyContainer).toHaveClass('dashboard dashboard--editing'); expect(stickyContainer).toHaveClass('dashboard dashboard--editing');
}); });
it('should render a DragDroppable DashboardHeader', () => { test('should render a DragDroppable DashboardHeader', () => {
const { queryByTestId } = setup(); const { queryByTestId } = setup();
const header = queryByTestId('dashboard-header-container'); const header = queryByTestId('dashboard-header-container');
expect(header).toBeInTheDocument(); expect(header).toBeInTheDocument();
}); });
it('should render a Sticky top-level Tabs if the dashboard has tabs', async () => { test('should render a Sticky top-level Tabs if the dashboard has tabs', async () => {
const { findAllByTestId } = setup({ const { findAllByTestId } = setup({
dashboardLayout: undoableDashboardLayoutWithTabs, dashboardLayout: undoableDashboardLayoutWithTabs,
}); });
@@ -162,7 +163,7 @@ describe('DashboardBuilder', () => {
}); });
}); });
it('should render one Tabs and two TabPane', async () => { test('should render one Tabs and two TabPane', async () => {
const { findAllByRole } = setup({ const { findAllByRole } = setup({
dashboardLayout: undoableDashboardLayoutWithTabs, dashboardLayout: undoableDashboardLayoutWithTabs,
}); });
@@ -172,7 +173,7 @@ describe('DashboardBuilder', () => {
expect(tabPanels.length).toBe(2); expect(tabPanels.length).toBe(2);
}); });
it('should render a TabPane and DashboardGrid for first Tab', async () => { test('should render a TabPane and DashboardGrid for first Tab', async () => {
const { findByTestId } = setup({ const { findByTestId } = setup({
dashboardLayout: undoableDashboardLayoutWithTabs, dashboardLayout: undoableDashboardLayoutWithTabs,
}); });
@@ -188,7 +189,7 @@ describe('DashboardBuilder', () => {
).toBe(1); ).toBe(1);
}); });
it('should render a TabPane and DashboardGrid for second Tab', async () => { test('should render a TabPane and DashboardGrid for second Tab', async () => {
const { findByTestId } = setup({ const { findByTestId } = setup({
dashboardLayout: undoableDashboardLayoutWithTabs, dashboardLayout: undoableDashboardLayoutWithTabs,
dashboardState: { dashboardState: {
@@ -209,13 +210,13 @@ describe('DashboardBuilder', () => {
).toBe(1); ).toBe(1);
}); });
it('should render a BuilderComponentPane if editMode=false and user selects "Insert Components" pane', () => { test('should render a BuilderComponentPane if editMode=false and user selects "Insert Components" pane', () => {
const { queryAllByTestId } = setup(); const { queryAllByTestId } = setup();
const builderComponents = queryAllByTestId('mock-builder-component-pane'); const builderComponents = queryAllByTestId('mock-builder-component-pane');
expect(builderComponents.length).toBe(0); expect(builderComponents.length).toBe(0);
}); });
it('should render a BuilderComponentPane if editMode=true and user selects "Insert Components" pane', () => { test('should render a BuilderComponentPane if editMode=true and user selects "Insert Components" pane', () => {
const { queryAllByTestId } = setup({ const { queryAllByTestId } = setup({
dashboardState: { ...mockState.dashboardState, editMode: true }, dashboardState: { ...mockState.dashboardState, editMode: true },
}); });
@@ -223,7 +224,7 @@ describe('DashboardBuilder', () => {
expect(builderComponents.length).toBeGreaterThanOrEqual(1); expect(builderComponents.length).toBeGreaterThanOrEqual(1);
}); });
it('should change redux state if a top-level Tab is clicked', async () => { test('should change redux state if a top-level Tab is clicked', async () => {
(setDirectPathToChild as jest.Mock).mockImplementation(arg0 => ({ (setDirectPathToChild as jest.Mock).mockImplementation(arg0 => ({
type: 'type', type: 'type',
arg0, arg0,
@@ -243,13 +244,13 @@ describe('DashboardBuilder', () => {
(setDirectPathToChild as jest.Mock).mockReset(); (setDirectPathToChild as jest.Mock).mockReset();
}); });
it('should not display a loading spinner when saving is not in progress', () => { test('should not display a loading spinner when saving is not in progress', () => {
const { queryByTestId } = setup(); const { queryByTestId } = setup();
expect(queryByTestId('loading-indicator')).not.toBeInTheDocument(); expect(queryByTestId('loading-indicator')).not.toBeInTheDocument();
}); });
it('should display a loading spinner when saving is in progress', async () => { test('should display a loading spinner when saving is in progress', async () => {
const { findByTestId } = setup({ const { findByTestId } = setup({
dashboardState: { ...mockState.dashboardState, dashboardIsSaving: true }, dashboardState: { ...mockState.dashboardState, dashboardIsSaving: true },
}); });
@@ -257,7 +258,7 @@ describe('DashboardBuilder', () => {
expect(await findByTestId('loading-indicator')).toBeVisible(); expect(await findByTestId('loading-indicator')).toBeVisible();
}); });
it('should set FilterBar width by useStoredSidebarWidth', () => { test('should set FilterBar width by useStoredSidebarWidth', () => {
const expectedValue = 200; const expectedValue = 200;
const setter = jest.fn(); const setter = jest.fn();
(useStoredSidebarWidth as jest.Mock).mockImplementation(() => [ (useStoredSidebarWidth as jest.Mock).mockImplementation(() => [
@@ -274,7 +275,7 @@ describe('DashboardBuilder', () => {
expect(filterbar).toHaveStyleRule('width', `${expectedValue}px`); expect(filterbar).toHaveStyleRule('width', `${expectedValue}px`);
}); });
it('filter panel state when featureflag is true', () => { test('filter panel state when featureflag is true', () => {
window.featureFlags = { window.featureFlags = {
[FeatureFlag.FilterBarClosedByDefault]: true, [FeatureFlag.FilterBarClosedByDefault]: true,
}; };
@@ -294,7 +295,7 @@ describe('DashboardBuilder', () => {
expect(filterbar).toHaveStyleRule('width', `${CLOSED_FILTER_BAR_WIDTH}px`); expect(filterbar).toHaveStyleRule('width', `${CLOSED_FILTER_BAR_WIDTH}px`);
}); });
it('filter panel state when featureflag is false', () => { test('filter panel state when featureflag is false', () => {
window.featureFlags = { window.featureFlags = {
[FeatureFlag.FilterBarClosedByDefault]: false, [FeatureFlag.FilterBarClosedByDefault]: false,
}; };
@@ -314,7 +315,7 @@ describe('DashboardBuilder', () => {
expect(filterbar).toHaveStyleRule('width', `${OPEN_FILTER_BAR_WIDTH}px`); expect(filterbar).toHaveStyleRule('width', `${OPEN_FILTER_BAR_WIDTH}px`);
}); });
it('should not render the filter bar when nativeFiltersEnabled is false', () => { test('should not render the filter bar when nativeFiltersEnabled is false', () => {
jest.spyOn(useNativeFiltersModule, 'useNativeFilters').mockReturnValue({ jest.spyOn(useNativeFiltersModule, 'useNativeFilters').mockReturnValue({
showDashboard: true, showDashboard: true,
missingInitialFilters: [], missingInitialFilters: [],
@@ -327,7 +328,7 @@ describe('DashboardBuilder', () => {
expect(queryByTestId('dashboard-filters-panel')).not.toBeInTheDocument(); expect(queryByTestId('dashboard-filters-panel')).not.toBeInTheDocument();
}); });
it('should render the filter bar when nativeFiltersEnabled is true and not in edit mode', () => { test('should render the filter bar when nativeFiltersEnabled is true and not in edit mode', () => {
jest.spyOn(useNativeFiltersModule, 'useNativeFilters').mockReturnValue({ jest.spyOn(useNativeFiltersModule, 'useNativeFilters').mockReturnValue({
showDashboard: true, showDashboard: true,
missingInitialFilters: [], missingInitialFilters: [],
@@ -340,7 +341,7 @@ describe('DashboardBuilder', () => {
expect(queryByTestId('dashboard-filters-panel')).toBeInTheDocument(); expect(queryByTestId('dashboard-filters-panel')).toBeInTheDocument();
}); });
it('should not render the filter bar when in edit mode even if nativeFiltersEnabled is true', () => { test('should not render the filter bar when in edit mode even if nativeFiltersEnabled is true', () => {
jest.spyOn(useNativeFiltersModule, 'useNativeFilters').mockReturnValue({ jest.spyOn(useNativeFiltersModule, 'useNativeFilters').mockReturnValue({
showDashboard: true, showDashboard: true,
missingInitialFilters: [], missingInitialFilters: [],

View File

@@ -54,6 +54,7 @@ buildActiveFilters({
components: dashboardWithFilter, components: dashboardWithFilter,
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('for dashboard filters', () => { describe('for dashboard filters', () => {
test('does not show number when there are no active filters', () => { test('does not show number when there are no active filters', () => {
const store = getMockStoreWithFilters(); const store = getMockStoreWithFilters();
@@ -96,6 +97,7 @@ describe('for dashboard filters', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('for native filters', () => { describe('for native filters', () => {
test('does not show number when there are no active filters', () => { test('does not show number when there are no active filters', () => {
const store = getMockStoreWithNativeFilters(); const store = getMockStoreWithNativeFilters();

View File

@@ -28,8 +28,9 @@ const setup = (overrides?: MissingChartProps) => (
<MissingChart height={100} {...overrides} /> <MissingChart height={100} {...overrides} />
); );
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('MissingChart', () => { describe('MissingChart', () => {
it('renders a .missing-chart-container', () => { test('renders a .missing-chart-container', () => {
const rendered = render(setup()); const rendered = render(setup());
const missingChartContainer = rendered.container.querySelector( const missingChartContainer = rendered.container.querySelector(
@@ -38,7 +39,7 @@ describe('MissingChart', () => {
expect(missingChartContainer).toBeVisible(); expect(missingChartContainer).toBeVisible();
}); });
it('renders a .missing-chart-body', () => { test('renders a .missing-chart-body', () => {
const rendered = render(setup()); const rendered = render(setup());
const missingChartBody = rendered.container.querySelector( const missingChartBody = rendered.container.querySelector(

View File

@@ -180,6 +180,7 @@ afterAll(() => {
fetchMock.restore(); fetchMock.restore();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('PropertiesModal', () => { describe('PropertiesModal', () => {
jest.setTimeout(60000); // Increased timeout for complex modal rendering jest.setTimeout(60000); // Increased timeout for complex modal rendering

View File

@@ -157,6 +157,7 @@ test('displays current color scheme value', () => {
}); });
// CSS Template Tests // CSS Template Tests
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('CSS Template functionality', () => { describe('CSS Template functionality', () => {
test('does not show CSS template select when feature flag is disabled', () => { test('does not show CSS template select when feature flag is disabled', () => {
mockIsFeatureEnabled.mockReturnValue(false); mockIsFeatureEnabled.mockReturnValue(false);

View File

@@ -77,33 +77,34 @@ const defaultProps: Omit<SliceAdderProps, 'theme'> = {
const renderSliceAdder = (props = defaultProps) => const renderSliceAdder = (props = defaultProps) =>
render(<SliceAdder {...props} />, { store: mockStore }); render(<SliceAdder {...props} />, { store: mockStore });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('SliceAdder', () => { describe('SliceAdder', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('renders the create new chart button', () => { test('renders the create new chart button', () => {
renderSliceAdder(); renderSliceAdder();
expect(screen.getByText('Create new chart')).toBeInTheDocument(); expect(screen.getByText('Create new chart')).toBeInTheDocument();
}); });
it('renders loading state', () => { test('renders loading state', () => {
renderSliceAdder({ ...defaultProps, isLoading: true }); renderSliceAdder({ ...defaultProps, isLoading: true });
expect(screen.getByRole('status')).toBeInTheDocument(); expect(screen.getByRole('status')).toBeInTheDocument();
}); });
it('renders error message', () => { test('renders error message', () => {
const errorMessage = 'Error loading charts'; const errorMessage = 'Error loading charts';
renderSliceAdder({ ...defaultProps, errorMessage }); renderSliceAdder({ ...defaultProps, errorMessage });
expect(screen.getByText(errorMessage)).toBeInTheDocument(); expect(screen.getByText(errorMessage)).toBeInTheDocument();
}); });
it('fetches slices on mount', () => { test('fetches slices on mount', () => {
renderSliceAdder(); renderSliceAdder();
expect(defaultProps.fetchSlices).toHaveBeenCalledWith(1, '', 'changed_on'); expect(defaultProps.fetchSlices).toHaveBeenCalledWith(1, '', 'changed_on');
}); });
it('handles search input changes', async () => { test('handles search input changes', async () => {
renderSliceAdder(); renderSliceAdder();
const searchInput = screen.getByPlaceholderText('Filter your charts'); const searchInput = screen.getByPlaceholderText('Filter your charts');
await userEvent.type(searchInput, 'test search'); await userEvent.type(searchInput, 'test search');
@@ -114,7 +115,7 @@ describe('SliceAdder', () => {
); );
}); });
it('handles sort selection changes', async () => { test('handles sort selection changes', async () => {
renderSliceAdder(); renderSliceAdder();
// Update selector to match the actual rendered element // Update selector to match the actual rendered element
const sortSelect = screen.getByText('Sort by recent'); const sortSelect = screen.getByText('Sort by recent');
@@ -124,7 +125,7 @@ describe('SliceAdder', () => {
expect(defaultProps.fetchSlices).toHaveBeenCalledWith(1, '', 'viz_type'); expect(defaultProps.fetchSlices).toHaveBeenCalledWith(1, '', 'viz_type');
}); });
it('handles show only my charts toggle', async () => { test('handles show only my charts toggle', async () => {
renderSliceAdder(); renderSliceAdder();
const checkbox = screen.getByRole('checkbox'); const checkbox = screen.getByRole('checkbox');
await userEvent.click(checkbox); await userEvent.click(checkbox);
@@ -135,7 +136,7 @@ describe('SliceAdder', () => {
); );
}); });
it('opens new chart in new tab when create new chart is clicked', () => { test('opens new chart in new tab when create new chart is clicked', () => {
const windowSpy = jest.spyOn(window, 'open').mockImplementation(); const windowSpy = jest.spyOn(window, 'open').mockImplementation();
renderSliceAdder(); renderSliceAdder();
const createButton = screen.getByText('Create new chart'); const createButton = screen.getByText('Create new chart');
@@ -148,6 +149,7 @@ describe('SliceAdder', () => {
windowSpy.mockRestore(); windowSpy.mockRestore();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('sortByComparator', () => { describe('sortByComparator', () => {
const baseSlice = { const baseSlice = {
slice_url: '/superset/explore/', slice_url: '/superset/explore/',
@@ -170,7 +172,7 @@ describe('SliceAdder', () => {
query_context: null, query_context: null,
}; };
it('should sort by changed_on in descending order', () => { test('should sort by changed_on in descending order', () => {
const input = [ const input = [
{ {
...baseSlice, ...baseSlice,
@@ -198,7 +200,7 @@ describe('SliceAdder', () => {
expect(sorted[2].changed_on).toBe(1577836800000); expect(sorted[2].changed_on).toBe(1577836800000);
}); });
it('should sort by other fields in ascending order', () => { test('should sort by other fields in ascending order', () => {
const input = [ const input = [
{ {
...baseSlice, ...baseSlice,
@@ -228,7 +230,7 @@ describe('SliceAdder', () => {
}); });
}); });
it('should update selectedSliceIdsSet when props change', () => { test('should update selectedSliceIdsSet when props change', () => {
const { rerender } = renderSliceAdder(); const { rerender } = renderSliceAdder();
rerender(<SliceAdder {...defaultProps} selectedSliceIds={[129]} />); rerender(<SliceAdder {...defaultProps} selectedSliceIds={[129]} />);
// Verify the internal state was updated by checking if new charts are available // Verify the internal state was updated by checking if new charts are available

View File

@@ -27,6 +27,7 @@ import {
} from 'src/dashboard/util/componentTypes'; } from 'src/dashboard/util/componentTypes';
import { UnwrappedDragDroppable as DragDroppable } from 'src/dashboard/components/dnd/DragDroppable'; import { UnwrappedDragDroppable as DragDroppable } from 'src/dashboard/components/dnd/DragDroppable';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DragDroppable', () => { describe('DragDroppable', () => {
const props = { const props = {
component: newComponentFactory(CHART_TYPE), component: newComponentFactory(CHART_TYPE),
@@ -60,7 +61,7 @@ describe('DragDroppable', () => {
}; };
} }
it('should call its child function', () => { test('should call its child function', () => {
const renderChild = jest.fn(provided => ( const renderChild = jest.fn(provided => (
<div data-test="child-content" {...provided}> <div data-test="child-content" {...provided}>
Test Content Test Content
@@ -76,7 +77,7 @@ describe('DragDroppable', () => {
); );
}); });
it('should call its child function with "dragSourceRef" if editMode=true', () => { test('should call its child function with "dragSourceRef" if editMode=true', () => {
const renderChild = jest.fn().mockImplementation(provided => ( const renderChild = jest.fn().mockImplementation(provided => (
<div data-test="child-content" {...provided}> <div data-test="child-content" {...provided}>
Test Content Test Content
@@ -100,7 +101,7 @@ describe('DragDroppable', () => {
); );
}); });
it('should call its child function with "dropIndicatorProps" dependent on editMode and isDraggingOver', () => { test('should call its child function with "dropIndicatorProps" dependent on editMode and isDraggingOver', () => {
const renderChild = jest.fn(provided => ( const renderChild = jest.fn(provided => (
<div data-test="child-content" {...provided}> <div data-test="child-content" {...provided}>
Test Content Test Content
@@ -135,7 +136,7 @@ describe('DragDroppable', () => {
}); });
}); });
it('should call props.dragPreviewRef and props.droppableRef on mount', () => { test('should call props.dragPreviewRef and props.droppableRef on mount', () => {
const dragPreviewRef = jest.fn(); const dragPreviewRef = jest.fn();
const droppableRef = jest.fn(); const droppableRef = jest.fn();
@@ -144,7 +145,7 @@ describe('DragDroppable', () => {
expect(droppableRef).toHaveBeenCalledTimes(1); expect(droppableRef).toHaveBeenCalledTimes(1);
}); });
it('should handle forbidden drops correctly', () => { test('should handle forbidden drops correctly', () => {
const renderChild = jest.fn(provided => ( const renderChild = jest.fn(provided => (
<div data-test="child-content" {...provided}> <div data-test="child-content" {...provided}>
Test Content Test Content
@@ -178,7 +179,7 @@ describe('DragDroppable', () => {
}); });
}); });
it('should handle orientation prop correctly', () => { test('should handle orientation prop correctly', () => {
const { container } = setup({ orientation: 'column' }); const { container } = setup({ orientation: 'column' });
expect(container.firstChild).toHaveClass('dragdroppable-column'); expect(container.firstChild).toHaveClass('dragdroppable-column');
@@ -186,7 +187,7 @@ describe('DragDroppable', () => {
expect(container2.firstChild).toHaveClass('dragdroppable-row'); expect(container2.firstChild).toHaveClass('dragdroppable-row');
}); });
it('should handle disabled drag and drop', () => { test('should handle disabled drag and drop', () => {
const renderChild = jest.fn(provided => ( const renderChild = jest.fn(provided => (
<div data-test="child-content" {...provided}> <div data-test="child-content" {...provided}>
Test Content Test Content
@@ -221,7 +222,7 @@ describe('DragDroppable', () => {
}); });
// Later in the file, remove the require and use the imported getEmptyImage // Later in the file, remove the require and use the imported getEmptyImage
it('should handle empty drag preview correctly', () => { test('should handle empty drag preview correctly', () => {
const dragPreviewRef = jest.fn(); const dragPreviewRef = jest.fn();
setup({ setup({
@@ -237,7 +238,7 @@ describe('DragDroppable', () => {
); );
}); });
it('should call onDropIndicatorChange when appropriate', () => { test('should call onDropIndicatorChange when appropriate', () => {
const onDropIndicatorChange = jest.fn(); const onDropIndicatorChange = jest.fn();
const { rerender } = setup({ const { rerender } = setup({
component: newComponentFactory(TAB_TYPE), component: newComponentFactory(TAB_TYPE),

View File

@@ -45,6 +45,7 @@ import { GRID_BASE_UNIT, GRID_GUTTER_SIZE } from '../../../util/constants';
const DEFAULT_HEADER_HEIGHT = 22; const DEFAULT_HEADER_HEIGHT = 22;
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ChartHolder', () => { describe('ChartHolder', () => {
let scrollViewBase: any; let scrollViewBase: any;
@@ -110,7 +111,7 @@ describe('ChartHolder', () => {
store, store,
}); });
it('should render empty state', async () => { test('should render empty state', async () => {
renderWrapper(); renderWrapper();
expect( expect(
@@ -124,7 +125,7 @@ describe('ChartHolder', () => {
expect(screen.getByRole('img', { name: 'empty' })).toBeVisible(); expect(screen.getByRole('img', { name: 'empty' })).toBeVisible();
}); });
it('should render anchor link when not editing', async () => { test('should render anchor link when not editing', async () => {
const store = createMockStore(); const store = createMockStore();
const { rerender } = renderWrapper(store, { editMode: false }); const { rerender } = renderWrapper(store, { editMode: false });
@@ -155,7 +156,7 @@ describe('ChartHolder', () => {
).toEqual(0); ).toEqual(0);
}); });
it('should highlight when path matches', async () => { test('should highlight when path matches', async () => {
const store = createMockStore({ const store = createMockStore({
dashboardState: { dashboardState: {
...mockState.dashboardState, ...mockState.dashboardState,
@@ -202,7 +203,7 @@ describe('ChartHolder', () => {
); );
}); });
it('should calculate the default widthMultiple', async () => { test('should calculate the default widthMultiple', async () => {
const widthMultiple = 5; const widthMultiple = 5;
renderWrapper(createMockStore(), { renderWrapper(createMockStore(), {
editMode: true, editMode: true,
@@ -231,7 +232,7 @@ describe('ChartHolder', () => {
expect(computedWidth).toEqual(`${expectedWidth}px`); expect(computedWidth).toEqual(`${expectedWidth}px`);
}); });
it('should set the resizable width to auto when parent component type is column', async () => { test('should set the resizable width to auto when parent component type is column', async () => {
renderWrapper(createMockStore(), { renderWrapper(createMockStore(), {
editMode: true, editMode: true,
parentComponent: { parentComponent: {
@@ -255,7 +256,7 @@ describe('ChartHolder', () => {
expect(computedWidth).toEqual('auto'); expect(computedWidth).toEqual('auto');
}); });
it("should override the widthMultiple if there's a column in the parent chain whose width is less than the chart", async () => { test("should override the widthMultiple if there's a column in the parent chain whose width is less than the chart", async () => {
const widthMultiple = 10; const widthMultiple = 10;
const parentColumnWidth = 6; const parentColumnWidth = 6;
renderWrapper(createMockStore(), { renderWrapper(createMockStore(), {
@@ -288,7 +289,7 @@ describe('ChartHolder', () => {
expect(computedWidth).toEqual(`${expectedWidth}px`); expect(computedWidth).toEqual(`${expectedWidth}px`);
}); });
it('should calculate the chartWidth', async () => { test('should calculate the chartWidth', async () => {
const widthMultiple = 7; const widthMultiple = 7;
const columnWidth = 250; const columnWidth = 250;
renderWrapper(createMockStore(), { renderWrapper(createMockStore(), {
@@ -319,7 +320,7 @@ describe('ChartHolder', () => {
expect(computedWidth).toEqual(expectedWidth); expect(computedWidth).toEqual(expectedWidth);
}); });
it('should calculate the chartWidth on full screen mode', async () => { test('should calculate the chartWidth on full screen mode', async () => {
const widthMultiple = 7; const widthMultiple = 7;
const columnWidth = 250; const columnWidth = 250;
renderWrapper(createMockStore(), { renderWrapper(createMockStore(), {
@@ -345,7 +346,7 @@ describe('ChartHolder', () => {
expect(computedWidth).toEqual(expectedWidth); expect(computedWidth).toEqual(expectedWidth);
}); });
it('should calculate the chartHeight', async () => { test('should calculate the chartHeight', async () => {
const heightMultiple = 12; const heightMultiple = 12;
renderWrapper(createMockStore(), { renderWrapper(createMockStore(), {
fullSizeChartId: null, fullSizeChartId: null,
@@ -372,7 +373,7 @@ describe('ChartHolder', () => {
expect(computedWidth).toEqual(expectedWidth); expect(computedWidth).toEqual(expectedWidth);
}); });
it('should calculate the chartHeight on full screen mode', async () => { test('should calculate the chartHeight on full screen mode', async () => {
const heightMultiple = 12; const heightMultiple = 12;
renderWrapper(createMockStore(), { renderWrapper(createMockStore(), {
component: { component: {
@@ -397,7 +398,7 @@ describe('ChartHolder', () => {
expect(computedWidth).toEqual(expectedWidth); expect(computedWidth).toEqual(expectedWidth);
}); });
it('should call deleteComponent when deleted', async () => { test('should call deleteComponent when deleted', async () => {
const deleteComponent = sinon.spy(); const deleteComponent = sinon.spy();
const store = createMockStore(); const store = createMockStore();
const { rerender } = renderWrapper(store, { const { rerender } = renderWrapper(store, {

View File

@@ -26,6 +26,7 @@ import {
import { screen, render, userEvent } from 'spec/helpers/testing-library'; import { screen, render, userEvent } from 'spec/helpers/testing-library';
import Divider from './Divider'; import Divider from './Divider';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Divider', () => { describe('Divider', () => {
const props = { const props = {
id: 'id', id: 'id',
@@ -46,19 +47,19 @@ describe('Divider', () => {
useDnd: true, useDnd: true,
}); });
it('should render a Draggable', () => { test('should render a Draggable', () => {
setup(); setup();
expect(screen.getByTestId('dragdroppable-object')).toBeInTheDocument(); expect(screen.getByTestId('dragdroppable-object')).toBeInTheDocument();
}); });
it('should render a div with class "dashboard-component-divider"', () => { test('should render a div with class "dashboard-component-divider"', () => {
const { container } = setup(); const { container } = setup();
expect( expect(
container.querySelector('.dashboard-component-divider'), container.querySelector('.dashboard-component-divider'),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('should render a HoverMenu with DeleteComponentButton in editMode', () => { test('should render a HoverMenu with DeleteComponentButton in editMode', () => {
setup(); setup();
expect(screen.queryByTestId('hover-menu')).not.toBeInTheDocument(); expect(screen.queryByTestId('hover-menu')).not.toBeInTheDocument();
expect(screen.queryByRole('button')).not.toBeInTheDocument(); expect(screen.queryByRole('button')).not.toBeInTheDocument();
@@ -72,7 +73,7 @@ describe('Divider', () => {
); );
}); });
it('should call deleteComponent when deleted', () => { test('should call deleteComponent when deleted', () => {
const deleteComponent = sinon.spy(); const deleteComponent = sinon.spy();
setup({ editMode: true, deleteComponent }); setup({ editMode: true, deleteComponent });
userEvent.click(screen.getByRole('button')); userEvent.click(screen.getByRole('button'));

View File

@@ -132,6 +132,7 @@ const renderWithRedux = (component: React.ReactElement) =>
}, },
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DynamicComponent', () => { describe('DynamicComponent', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();

View File

@@ -31,6 +31,7 @@ import {
import { mockStoreWithTabs } from 'spec/fixtures/mockStore'; import { mockStoreWithTabs } from 'spec/fixtures/mockStore';
import Header from './Header'; import Header from './Header';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Header', () => { describe('Header', () => {
const props = { const props = {
id: 'id', id: 'id',
@@ -57,17 +58,17 @@ describe('Header', () => {
); );
} }
it('should render a Draggable', () => { test('should render a Draggable', () => {
setup(); setup();
expect(screen.getByTestId('dragdroppable-object')).toBeInTheDocument(); expect(screen.getByTestId('dragdroppable-object')).toBeInTheDocument();
}); });
it('should render a WithPopoverMenu', () => { test('should render a WithPopoverMenu', () => {
setup(); setup();
expect(screen.getByRole('none')).toBeInTheDocument(); expect(screen.getByRole('none')).toBeInTheDocument();
}); });
it('should render a HoverMenu in editMode', () => { test('should render a HoverMenu in editMode', () => {
setup(); setup();
expect(screen.queryByTestId('hover-menu')).not.toBeInTheDocument(); expect(screen.queryByTestId('hover-menu')).not.toBeInTheDocument();
@@ -76,14 +77,14 @@ describe('Header', () => {
expect(hoverMenus[0]).toBeInTheDocument(); expect(hoverMenus[0]).toBeInTheDocument();
}); });
it('should render an EditableTitle with meta.text', () => { test('should render an EditableTitle with meta.text', () => {
setup(); setup();
const titleElement = screen.getByTestId('editable-title'); const titleElement = screen.getByTestId('editable-title');
expect(titleElement).toBeInTheDocument(); expect(titleElement).toBeInTheDocument();
expect(titleElement).toHaveTextContent(props.component.meta.text); expect(titleElement).toHaveTextContent(props.component.meta.text);
}); });
it('should call updateComponents when EditableTitle changes', () => { test('should call updateComponents when EditableTitle changes', () => {
const updateComponents = sinon.spy(); const updateComponents = sinon.spy();
setup({ editMode: true, updateComponents }); setup({ editMode: true, updateComponents });
@@ -103,13 +104,13 @@ describe('Header', () => {
); );
}); });
it('should render a DeleteComponentButton when focused in editMode', () => { test('should render a DeleteComponentButton when focused in editMode', () => {
setup({ editMode: true }); setup({ editMode: true });
const trashButton = screen.getByRole('img', { name: 'delete' }); const trashButton = screen.getByRole('img', { name: 'delete' });
expect(trashButton).toBeInTheDocument(); expect(trashButton).toBeInTheDocument();
}); });
it('should call deleteComponent when deleted', () => { test('should call deleteComponent when deleted', () => {
const deleteComponent = sinon.spy(); const deleteComponent = sinon.spy();
setup({ editMode: true, deleteComponent }); setup({ editMode: true, deleteComponent });
@@ -119,17 +120,17 @@ describe('Header', () => {
expect(deleteComponent.callCount).toBe(1); expect(deleteComponent.callCount).toBe(1);
}); });
it('should render the AnchorLink in view mode', () => { test('should render the AnchorLink in view mode', () => {
setup(); setup();
expect(screen.getByTestId('anchor-link')).toBeInTheDocument(); expect(screen.getByTestId('anchor-link')).toBeInTheDocument();
}); });
it('should not render the AnchorLink in edit mode', () => { test('should not render the AnchorLink in edit mode', () => {
setup({ editMode: true }); setup({ editMode: true });
expect(screen.queryByTestId('anchor-link')).not.toBeInTheDocument(); expect(screen.queryByTestId('anchor-link')).not.toBeInTheDocument();
}); });
it('should not render the AnchorLink in embedded mode', () => { test('should not render the AnchorLink in embedded mode', () => {
setup({ embeddedMode: true }); setup({ embeddedMode: true });
expect(screen.queryByTestId('anchor-link')).not.toBeInTheDocument(); expect(screen.queryByTestId('anchor-link')).not.toBeInTheDocument();
}); });

View File

@@ -22,6 +22,7 @@ import { mockStore } from 'spec/fixtures/mockStore';
import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout'; import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout';
import MarkdownConnected from './Markdown'; import MarkdownConnected from './Markdown';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Markdown', () => { describe('Markdown', () => {
const props = { const props = {
id: 'id', id: 'id',
@@ -81,12 +82,12 @@ describe('Markdown', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should render the markdown component', async () => { test('should render the markdown component', async () => {
await setup(); await setup();
expect(screen.getByTestId('dashboard-markdown-editor')).toBeInTheDocument(); expect(screen.getByTestId('dashboard-markdown-editor')).toBeInTheDocument();
}); });
it('should render the markdown content in preview mode by default', async () => { test('should render the markdown content in preview mode by default', async () => {
await setup(); await setup();
expect(screen.queryByRole('textbox')).not.toBeInTheDocument(); expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
expect( expect(
@@ -94,7 +95,7 @@ describe('Markdown', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('should render editor when in edit mode and clicked', async () => { test('should render editor when in edit mode and clicked', async () => {
await setup({ editMode: true }); await setup({ editMode: true });
const container = screen.getByTestId('dashboard-component-chart-holder'); const container = screen.getByTestId('dashboard-component-chart-holder');
await act(async () => { await act(async () => {
@@ -104,7 +105,7 @@ describe('Markdown', () => {
expect(await screen.findByRole('textbox')).toBeInTheDocument(); expect(await screen.findByRole('textbox')).toBeInTheDocument();
}); });
it('should switch between edit and preview modes', async () => { test('should switch between edit and preview modes', async () => {
await setup({ editMode: true }); await setup({ editMode: true });
const container = screen.getByTestId('dashboard-component-chart-holder'); const container = screen.getByTestId('dashboard-component-chart-holder');
@@ -129,7 +130,7 @@ describe('Markdown', () => {
expect(screen.queryByRole('textbox')).not.toBeInTheDocument(); expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
}); });
it('should call updateComponents when switching from edit to preview with changes', async () => { test('should call updateComponents when switching from edit to preview with changes', async () => {
const updateComponents = jest.fn(); const updateComponents = jest.fn();
const mockCode = 'new markdown!'; const mockCode = 'new markdown!';
@@ -201,7 +202,7 @@ describe('Markdown', () => {
}); });
}); });
it('should show placeholder text when markdown is empty', async () => { test('should show placeholder text when markdown is empty', async () => {
await setup({ await setup({
component: { component: {
...mockLayout.present.MARKDOWN_ID, ...mockLayout.present.MARKDOWN_ID,
@@ -214,7 +215,7 @@ describe('Markdown', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('should handle markdown errors gracefully', async () => { test('should handle markdown errors gracefully', async () => {
const addDangerToast = jest.fn(); const addDangerToast = jest.fn();
const { container } = await setup({ const { container } = await setup({
addDangerToast, addDangerToast,
@@ -250,7 +251,7 @@ describe('Markdown', () => {
}); });
}); });
it('should resize editor when width changes', async () => { test('should resize editor when width changes', async () => {
const { rerender } = await setup({ editMode: true }); const { rerender } = await setup({ editMode: true });
await act(async () => { await act(async () => {
@@ -278,7 +279,7 @@ describe('Markdown', () => {
}); });
}); });
it('should update content when undo/redo changes occur', async () => { test('should update content when undo/redo changes occur', async () => {
const { rerender } = await setup({ const { rerender } = await setup({
editMode: true, editMode: true,
component: { component: {
@@ -305,7 +306,7 @@ describe('Markdown', () => {
expect(screen.getByText('updated')).toBeInTheDocument(); expect(screen.getByText('updated')).toBeInTheDocument();
}); });
it('should adjust width based on parent type', async () => { test('should adjust width based on parent type', async () => {
const { rerender } = await setup(); const { rerender } = await setup();
// Check ROW_TYPE width // Check ROW_TYPE width

View File

@@ -202,6 +202,7 @@ test('should increment the depth of its children', () => {
); );
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('visibility handling for intersection observers', () => { describe('visibility handling for intersection observers', () => {
const mockIntersectionObserver = jest.fn(); const mockIntersectionObserver = jest.fn();
const mockObserve = jest.fn(); const mockObserve = jest.fn();

View File

@@ -48,6 +48,7 @@ const mockProps: TabsRendererProps = {
tabBarPaddingLeft: 16, tabBarPaddingLeft: 16,
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('TabsRenderer', () => { describe('TabsRenderer', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();

View File

@@ -25,6 +25,7 @@ import DraggableNewComponent from 'src/dashboard/components/gridComponents/new/D
import { CHART_TYPE } from 'src/dashboard/util/componentTypes'; import { CHART_TYPE } from 'src/dashboard/util/componentTypes';
// TODO: rewrite to rtl // TODO: rewrite to rtl
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('DraggableNewComponent', () => { describe('DraggableNewComponent', () => {
const props = { const props = {
id: 'id', id: 'id',
@@ -45,27 +46,27 @@ describe('DraggableNewComponent', () => {
setup(); setup();
}); });
it('should render a DragDroppable', () => { test('should render a DragDroppable', () => {
expect(screen.getByTestId('dragdroppable-object')).toBeInTheDocument(); expect(screen.getByTestId('dragdroppable-object')).toBeInTheDocument();
}); });
it('should pass component={ type, id } to DragDroppable', () => { test('should pass component={ type, id } to DragDroppable', () => {
const dragComponent = screen.getByTestId('dragdroppable-object'); const dragComponent = screen.getByTestId('dragdroppable-object');
expect(dragComponent).toHaveClass( expect(dragComponent).toHaveClass(
'dragdroppable dragdroppable--edit-mode dragdroppable-row', 'dragdroppable dragdroppable--edit-mode dragdroppable-row',
); );
}); });
it('should pass appropriate parent source and id to DragDroppable', () => { test('should pass appropriate parent source and id to DragDroppable', () => {
const dragComponent = screen.getByTestId('new-component'); const dragComponent = screen.getByTestId('new-component');
expect(dragComponent).toHaveAttribute('draggable', 'true'); expect(dragComponent).toHaveAttribute('draggable', 'true');
}); });
it('should render the passed label', () => { test('should render the passed label', () => {
expect(screen.getByText(props.label)).toBeInTheDocument(); expect(screen.getByText(props.label)).toBeInTheDocument();
}); });
it('should add the passed className', () => { test('should add the passed className', () => {
const component = screen const component = screen
.getByTestId('new-component') .getByTestId('new-component')
.querySelector('.new-component-placeholder'); .querySelector('.new-component-placeholder');

View File

@@ -77,8 +77,9 @@ test('should apply', () => {
expect(mockedProps.onApply).toHaveBeenCalled(); expect(mockedProps.onApply).toHaveBeenCalled();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('custom width', () => { describe('custom width', () => {
it('sets its default width with OPEN_FILTER_BAR_WIDTH', () => { test('sets its default width with OPEN_FILTER_BAR_WIDTH', () => {
const mockedProps = createProps(); const mockedProps = createProps();
render(<ActionButtons {...mockedProps} />, { useRedux: true }); render(<ActionButtons {...mockedProps} />, { useRedux: true });
const container = screen.getByTestId('filterbar-action-buttons'); const container = screen.getByTestId('filterbar-action-buttons');
@@ -87,7 +88,7 @@ describe('custom width', () => {
}); });
}); });
it('sets custom width', () => { test('sets custom width', () => {
const mockedProps = createProps(); const mockedProps = createProps();
const expectedWidth = 423; const expectedWidth = 423;
const { getByTestId } = render( const { getByTestId } = render(

View File

@@ -119,7 +119,7 @@ const setup = (props = DEFAULT_PROPS) =>
initialState: INITIAL_STATE, initialState: INITIAL_STATE,
}); });
it('Renders charts scoping list panel', () => { test('Renders charts scoping list panel', () => {
setup(); setup();
expect(screen.getByText('Add custom scoping')).toBeVisible(); expect(screen.getByText('Add custom scoping')).toBeVisible();
expect(screen.getByText('All charts/global scoping')).toBeVisible(); expect(screen.getByText('All charts/global scoping')).toBeVisible();
@@ -131,7 +131,7 @@ it('Renders charts scoping list panel', () => {
expect(screen.queryByText('[new custom scoping]')).not.toBeInTheDocument(); expect(screen.queryByText('[new custom scoping]')).not.toBeInTheDocument();
}); });
it('Renders custom scoping item', () => { test('Renders custom scoping item', () => {
setup({ setup({
...DEFAULT_PROPS, ...DEFAULT_PROPS,
activeChartId: -1, activeChartId: -1,
@@ -158,7 +158,7 @@ it('Renders custom scoping item', () => {
expect(screen.getByText('[new custom scoping]')).toHaveClass('active'); expect(screen.getByText('[new custom scoping]')).toHaveClass('active');
}); });
it('Uses callbacks on click', () => { test('Uses callbacks on click', () => {
setup(); setup();
userEvent.click(screen.getByText('Add custom scoping')); userEvent.click(screen.getByText('Add custom scoping'));
@@ -177,7 +177,7 @@ it('Uses callbacks on click', () => {
expect(DEFAULT_PROPS.removeCustomScope).toHaveBeenCalledWith(4); expect(DEFAULT_PROPS.removeCustomScope).toHaveBeenCalledWith(4);
}); });
it('Renders charts scoping list panel with FilterTitle rendered with role="button"', () => { test('Renders charts scoping list panel with FilterTitle rendered with role="button"', () => {
setup(); setup();
expect(screen.getByText('All charts/global scoping')).toBeVisible(); expect(screen.getByText('All charts/global scoping')).toBeVisible();
expect(screen.getByText('All charts/global scoping')).toHaveAttribute( expect(screen.getByText('All charts/global scoping')).toHaveAttribute(

View File

@@ -158,14 +158,14 @@ afterEach(() => {
fetchMock.restore(); fetchMock.restore();
}); });
it('renders modal', () => { test('renders modal', () => {
setup(); setup();
expect(screen.getByRole('dialog')).toBeInTheDocument(); expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByTestId('scoping-tree-panel')).toBeInTheDocument(); expect(screen.getByTestId('scoping-tree-panel')).toBeInTheDocument();
expect(screen.getByTestId('scoping-list-panel')).toBeInTheDocument(); expect(screen.getByTestId('scoping-list-panel')).toBeInTheDocument();
}); });
it('switch currently edited chart scoping', async () => { test('switch currently edited chart scoping', async () => {
setup(); setup();
const withinScopingList = within(screen.getByTestId('scoping-list-panel')); const withinScopingList = within(screen.getByTestId('scoping-list-panel'));
expect(withinScopingList.getByText('All charts/global scoping')).toHaveClass( expect(withinScopingList.getByText('All charts/global scoping')).toHaveClass(
@@ -180,7 +180,7 @@ it('switch currently edited chart scoping', async () => {
}); });
}); });
it('scoping tree global and custom checks', () => { test('scoping tree global and custom checks', () => {
setup(); setup();
expect( expect(
@@ -200,7 +200,7 @@ it('scoping tree global and custom checks', () => {
).toHaveLength(2); ).toHaveLength(2);
}); });
it('add new custom scoping', async () => { test('add new custom scoping', async () => {
setup(); setup();
userEvent.click(screen.getByText('Add custom scoping')); userEvent.click(screen.getByText('Add custom scoping'));
@@ -226,7 +226,7 @@ it('add new custom scoping', async () => {
).toHaveLength(2); ).toHaveLength(2);
}); });
it('edit scope and save', async () => { test('edit scope and save', async () => {
setup(); setup();
// unselect chart 2 in global scoping // unselect chart 2 in global scoping

View File

@@ -89,6 +89,7 @@ const addFilterFlow = async () => {
// await screen.findByText('All filters (1)'); // await screen.findByText('All filters (1)');
}; };
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FilterBar', () => { describe('FilterBar', () => {
new MainPreset().register(); new MainPreset().register();
const toggleFiltersBar = jest.fn(); const toggleFiltersBar = jest.fn();
@@ -178,39 +179,39 @@ describe('FilterBar', () => {
}, },
); );
it('should render', () => { test('should render', () => {
const { container } = renderWrapper(); const { container } = renderWrapper();
expect(container).toBeInTheDocument(); expect(container).toBeInTheDocument();
}); });
it('should render the "Filters" heading', () => { test('should render the "Filters" heading', () => {
renderWrapper(); renderWrapper();
expect(screen.getByText('Filters')).toBeInTheDocument(); expect(screen.getByText('Filters')).toBeInTheDocument();
}); });
it('should render the "Clear all" option', () => { test('should render the "Clear all" option', () => {
renderWrapper(); renderWrapper();
expect(screen.getByText('Clear all')).toBeInTheDocument(); expect(screen.getByText('Clear all')).toBeInTheDocument();
}); });
it('should render the "Apply filters" option', () => { test('should render the "Apply filters" option', () => {
renderWrapper(); renderWrapper();
expect(screen.getByText('Apply filters')).toBeInTheDocument(); expect(screen.getByText('Apply filters')).toBeInTheDocument();
}); });
it('should render the collapse icon', () => { test('should render the collapse icon', () => {
renderWrapper(); renderWrapper();
expect( expect(
screen.getByRole('img', { name: 'vertical-align' }), screen.getByRole('img', { name: 'vertical-align' }),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('should render the filter icon', () => { test('should render the filter icon', () => {
renderWrapper(); renderWrapper();
expect(screen.getByRole('img', { name: 'filter' })).toBeInTheDocument(); expect(screen.getByRole('img', { name: 'filter' })).toBeInTheDocument();
}); });
it('should toggle', () => { test('should toggle', () => {
renderWrapper(); renderWrapper();
const collapse = screen.getByRole('img', { const collapse = screen.getByRole('img', {
name: 'vertical-align', name: 'vertical-align',
@@ -220,7 +221,7 @@ describe('FilterBar', () => {
expect(toggleFiltersBar).toHaveBeenCalled(); expect(toggleFiltersBar).toHaveBeenCalled();
}); });
it('open filter bar', () => { test('open filter bar', () => {
renderWrapper(); renderWrapper();
expect(screen.getByTestId(getTestId('filter-icon'))).toBeInTheDocument(); expect(screen.getByTestId(getTestId('filter-icon'))).toBeInTheDocument();
expect(screen.getByTestId(getTestId('expand-button'))).toBeInTheDocument(); expect(screen.getByTestId(getTestId('expand-button'))).toBeInTheDocument();
@@ -229,7 +230,7 @@ describe('FilterBar', () => {
expect(toggleFiltersBar).toHaveBeenCalledWith(true); expect(toggleFiltersBar).toHaveBeenCalledWith(true);
}); });
it('no edit filter button by disabled permissions', () => { test('no edit filter button by disabled permissions', () => {
renderWrapper(openedBarProps, { renderWrapper(openedBarProps, {
...stateWithoutNativeFilters, ...stateWithoutNativeFilters,
dashboardInfo: { metadata: {} }, dashboardInfo: { metadata: {} },
@@ -240,7 +241,7 @@ describe('FilterBar', () => {
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
it('close filter bar', () => { test('close filter bar', () => {
renderWrapper(openedBarProps); renderWrapper(openedBarProps);
const collapseButton = screen.getByTestId(getTestId('collapse-button')); const collapseButton = screen.getByTestId(getTestId('collapse-button'));
@@ -250,14 +251,14 @@ describe('FilterBar', () => {
expect(toggleFiltersBar).toHaveBeenCalledWith(false); expect(toggleFiltersBar).toHaveBeenCalledWith(false);
}); });
it('no filters', () => { test('no filters', () => {
renderWrapper(openedBarProps, stateWithoutNativeFilters); renderWrapper(openedBarProps, stateWithoutNativeFilters);
expect(screen.getByTestId(getTestId('clear-button'))).toBeDisabled(); expect(screen.getByTestId(getTestId('clear-button'))).toBeDisabled();
expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled(); expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled();
}); });
it('renders dividers', async () => { test('renders dividers', async () => {
const divider = { const divider = {
id: 'NATIVE_FILTER_DIVIDER-1', id: 'NATIVE_FILTER_DIVIDER-1',
type: 'DIVIDER', type: 'DIVIDER',
@@ -295,7 +296,7 @@ describe('FilterBar', () => {
expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled(); expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled();
}); });
it('create filter and apply it flow', async () => { test('create filter and apply it flow', async () => {
renderWrapper(openedBarProps, stateWithoutNativeFilters); renderWrapper(openedBarProps, stateWithoutNativeFilters);
expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled(); expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled();
@@ -304,7 +305,7 @@ describe('FilterBar', () => {
expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled(); expect(screen.getByTestId(getTestId('apply-button'))).toBeDisabled();
}); });
it('should render without errors with proper state setup', () => { test('should render without errors with proper state setup', () => {
const stateWithFilter = { const stateWithFilter = {
...stateWithoutNativeFilters, ...stateWithoutNativeFilters,
dashboardInfo: { dashboardInfo: {

View File

@@ -24,7 +24,9 @@ import {
checkIsMissingRequiredValue, checkIsMissingRequiredValue,
} from './utils'; } from './utils';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FilterBar Utils - Validation and Apply Logic', () => { describe('FilterBar Utils - Validation and Apply Logic', () => {
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('checkIsValidateError', () => { describe('checkIsValidateError', () => {
test('should return true when no filters have validation errors', () => { test('should return true when no filters have validation errors', () => {
const dataMask: DataMaskStateWithId = { const dataMask: DataMaskStateWithId = {
@@ -89,6 +91,7 @@ describe('FilterBar Utils - Validation and Apply Logic', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('checkIsMissingRequiredValue', () => { describe('checkIsMissingRequiredValue', () => {
test('should return true for required filter with undefined value', () => { test('should return true for required filter with undefined value', () => {
const filter = { const filter = {
@@ -165,6 +168,7 @@ describe('FilterBar Utils - Validation and Apply Logic', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('checkIsApplyDisabled', () => { describe('checkIsApplyDisabled', () => {
test('should return true when filters have validation errors', () => { test('should return true when filters have validation errors', () => {
const dataMaskSelected: DataMaskStateWithId = { const dataMaskSelected: DataMaskStateWithId = {

View File

@@ -29,15 +29,16 @@ const defaultProps = {
const renderCollapsibleControl = (props = {}) => const renderCollapsibleControl = (props = {}) =>
render(<CollapsibleControl {...defaultProps} {...props} />); render(<CollapsibleControl {...defaultProps} {...props} />);
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('CollapsibleControl', () => { describe('CollapsibleControl', () => {
it('renders title correctly', () => { test('renders title correctly', () => {
const { getByRole } = renderCollapsibleControl(); const { getByRole } = renderCollapsibleControl();
expect( expect(
getByRole('checkbox', { name: /test control/i }), getByRole('checkbox', { name: /test control/i }),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('renders tooltip when provided', () => { test('renders tooltip when provided', () => {
const tooltipText = 'Test tooltip'; const tooltipText = 'Test tooltip';
renderCollapsibleControl({ tooltip: tooltipText }); renderCollapsibleControl({ tooltip: tooltipText });
@@ -45,18 +46,18 @@ describe('CollapsibleControl', () => {
expect(tooltip).toBeInTheDocument(); expect(tooltip).toBeInTheDocument();
}); });
it('starts collapsed when initialValue is false', () => { test('starts collapsed when initialValue is false', () => {
renderCollapsibleControl({ initialValue: false }); renderCollapsibleControl({ initialValue: false });
expect(screen.queryByTestId('child-content')).not.toBeInTheDocument(); expect(screen.queryByTestId('child-content')).not.toBeInTheDocument();
}); });
it('starts expanded when initialValue is true', () => { test('starts expanded when initialValue is true', () => {
renderCollapsibleControl({ initialValue: true }); renderCollapsibleControl({ initialValue: true });
expect(screen.getByTestId('child-content')).toBeInTheDocument(); expect(screen.getByTestId('child-content')).toBeInTheDocument();
}); });
it('toggles content when clicked', async () => { test('toggles content when clicked', async () => {
renderCollapsibleControl(); renderCollapsibleControl();
const checkbox = screen.getByRole('checkbox', { name: /Test Control/i }); const checkbox = screen.getByRole('checkbox', { name: /Test Control/i });
@@ -69,7 +70,7 @@ describe('CollapsibleControl', () => {
expect(screen.queryByTestId('child-content')).not.toBeInTheDocument(); expect(screen.queryByTestId('child-content')).not.toBeInTheDocument();
}); });
it('calls onChange handler when toggled', async () => { test('calls onChange handler when toggled', async () => {
const onChangeMock = jest.fn(); const onChangeMock = jest.fn();
renderCollapsibleControl({ onChange: onChangeMock }); renderCollapsibleControl({ onChange: onChangeMock });
const checkbox = screen.getByRole('checkbox', { name: /Test Control/i }); const checkbox = screen.getByRole('checkbox', { name: /Test Control/i });
@@ -81,7 +82,7 @@ describe('CollapsibleControl', () => {
expect(onChangeMock).toHaveBeenCalledWith(false); expect(onChangeMock).toHaveBeenCalledWith(false);
}); });
it('respects disabled prop', async () => { test('respects disabled prop', async () => {
const onChangeMock = jest.fn(); const onChangeMock = jest.fn();
renderCollapsibleControl({ renderCollapsibleControl({
disabled: true, disabled: true,
@@ -95,7 +96,7 @@ describe('CollapsibleControl', () => {
expect(onChangeMock).not.toHaveBeenCalled(); expect(onChangeMock).not.toHaveBeenCalled();
}); });
it('updates when controlled checked prop changes', () => { test('updates when controlled checked prop changes', () => {
const { rerender } = renderCollapsibleControl({ checked: false }); const { rerender } = renderCollapsibleControl({ checked: false });
expect(screen.queryByTestId('child-content')).not.toBeInTheDocument(); expect(screen.queryByTestId('child-content')).not.toBeInTheDocument();
@@ -103,7 +104,7 @@ describe('CollapsibleControl', () => {
expect(screen.getByTestId('child-content')).toBeInTheDocument(); expect(screen.getByTestId('child-content')).toBeInTheDocument();
}); });
it('maintains local state when in uncontrolled mode', async () => { test('maintains local state when in uncontrolled mode', async () => {
renderCollapsibleControl({ initialValue: false }); renderCollapsibleControl({ initialValue: false });
const checkbox = screen.getByRole('checkbox', { name: /Test Control/i }); const checkbox = screen.getByRole('checkbox', { name: /Test Control/i });

View File

@@ -26,6 +26,7 @@ import {
import type { FormInstance } from '@superset-ui/core/components'; import type { FormInstance } from '@superset-ui/core/components';
import { createMockModal } from './utils'; import { createMockModal } from './utils';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FilterScope TreeInitialization', () => { describe('FilterScope TreeInitialization', () => {
let formRef: { current: FormInstance | null }; let formRef: { current: FormInstance | null };
@@ -40,7 +41,7 @@ describe('FilterScope TreeInitialization', () => {
jest.useRealTimers(); jest.useRealTimers();
}); });
it('correct init tree with values', async () => { test('correct init tree with values', async () => {
const { MockModalComponent } = createMockModal({ const { MockModalComponent } = createMockModal({
scope: { scope: {
rootPath: ['TAB_ID'], rootPath: ['TAB_ID'],

View File

@@ -26,6 +26,7 @@ import {
import type { FormInstance } from '@superset-ui/core/components'; import type { FormInstance } from '@superset-ui/core/components';
import { createMockModal, getTreeSwitcher } from './utils'; import { createMockModal, getTreeSwitcher } from './utils';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('FilterScope TreeSelection', () => { describe('FilterScope TreeSelection', () => {
let formRef: { current: FormInstance | null }; let formRef: { current: FormInstance | null };
@@ -40,7 +41,7 @@ describe('FilterScope TreeSelection', () => {
jest.useRealTimers(); jest.useRealTimers();
}); });
it('select tree values with 1 excluded', async () => { test('select tree values with 1 excluded', async () => {
const { MockModalComponent } = createMockModal({ formRef }); const { MockModalComponent } = createMockModal({ formRef });
const modal = render(<MockModalComponent />); const modal = render(<MockModalComponent />);
@@ -81,7 +82,7 @@ describe('FilterScope TreeSelection', () => {
modal.unmount(); modal.unmount();
}); });
it('select 1 value only', async () => { test('select 1 value only', async () => {
const { MockModalComponent } = createMockModal({ formRef }); const { MockModalComponent } = createMockModal({ formRef });
const modal = render(<MockModalComponent />); const modal = render(<MockModalComponent />);

View File

@@ -24,6 +24,7 @@ import { buildTree } from './utils';
// This test file is using data from a real example dashboard to test real world data sets. ts-ignore is set for this entire file // This test file is using data from a real example dashboard to test real world data sets. ts-ignore is set for this entire file
// until we can reconcile adjusting types to match the actual data structures used // until we can reconcile adjusting types to match the actual data structures used
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('Ensure buildTree does not throw runtime errors when encountering an invalid node', () => { describe('Ensure buildTree does not throw runtime errors when encountering an invalid node', () => {
const node = { const node = {
children: ['TABS-97PVJa11D_'], children: ['TABS-97PVJa11D_'],
@@ -18047,7 +18048,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in
]; ];
const initiallyExcludedCharts: number[] = []; const initiallyExcludedCharts: number[] = [];
it('Succeeds with valid', () => { test('Succeeds with valid', () => {
expect(() => { expect(() => {
buildTree( buildTree(
// @ts-ignore // @ts-ignore
@@ -18062,7 +18063,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in
}).not.toThrow(); }).not.toThrow();
}); });
it('Avoids runtime error with invalid inputs', () => { test('Avoids runtime error with invalid inputs', () => {
expect(() => { expect(() => {
buildTree( buildTree(
// @ts-expect-error // @ts-expect-error

View File

@@ -209,6 +209,7 @@ test('Clicking on checkbox when resetConfig:false', () => {
expect(setNativeFilterFieldValues).not.toHaveBeenCalled(); expect(setNativeFilterFieldValues).not.toHaveBeenCalled();
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ColumnSelect filterValues behavior', () => { describe('ColumnSelect filterValues behavior', () => {
beforeEach(() => { beforeEach(() => {
(getControlItems as jest.Mock).mockReturnValue([ (getControlItems as jest.Mock).mockReturnValue([

View File

@@ -85,6 +85,7 @@ test('the form validates required fields', async () => {
expect(onSave).toHaveBeenCalledTimes(0); expect(onSave).toHaveBeenCalledTimes(0);
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('createNewOnOpen', () => { describe('createNewOnOpen', () => {
test('does not show alert when there is no unsaved filters', async () => { test('does not show alert when there is no unsaved filters', async () => {
const onCancel = jest.fn(); const onCancel = jest.fn();

View File

@@ -19,6 +19,7 @@
import { CHART_TYPE } from 'src/dashboard/util/componentTypes'; import { CHART_TYPE } from 'src/dashboard/util/componentTypes';
import { getCrossFilterIndicator } from './selectors'; import { getCrossFilterIndicator } from './selectors';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('getCrossFilterIndicator', () => { describe('getCrossFilterIndicator', () => {
const chartId = 123; const chartId = 123;
const chartLayoutItems = [ const chartLayoutItems = [
@@ -37,7 +38,7 @@ describe('getCrossFilterIndicator', () => {
}, },
]; ];
it('returns correct indicator with label from filterState.label', () => { test('returns correct indicator with label from filterState.label', () => {
const dataMask = { const dataMask = {
filterState: { label: 'foo', value: 'bar' }, filterState: { label: 'foo', value: 'bar' },
extraFormData: {}, extraFormData: {},
@@ -51,7 +52,7 @@ describe('getCrossFilterIndicator', () => {
}); });
}); });
it('returns correct indicator with label from filterState.value', () => { test('returns correct indicator with label from filterState.value', () => {
const dataMask = { const dataMask = {
filterState: { value: ['bar', 'baz'] }, filterState: { value: ['bar', 'baz'] },
extraFormData: {}, extraFormData: {},
@@ -65,7 +66,7 @@ describe('getCrossFilterIndicator', () => {
}); });
}); });
it('returns correct indicator with column and customColumnLabel', () => { test('returns correct indicator with column and customColumnLabel', () => {
const dataMask = { const dataMask = {
filterState: { filterState: {
value: 'valA', value: 'valA',
@@ -84,7 +85,7 @@ describe('getCrossFilterIndicator', () => {
}); });
}); });
it('returns correct indicator with column from extraFormData.filters', () => { test('returns correct indicator with column from extraFormData.filters', () => {
const filterClause = { col: 'colB', op: 'IS NOT NULL' as const }; const filterClause = { col: 'colB', op: 'IS NOT NULL' as const };
const dataMask = { const dataMask = {
filterState: { value: 'valB' }, filterState: { value: 'valB' },
@@ -99,7 +100,7 @@ describe('getCrossFilterIndicator', () => {
}); });
}); });
it('returns correct indicator with column from filterState.filters', () => { test('returns correct indicator with column from filterState.filters', () => {
const dataMask = { const dataMask = {
filterState: { value: 'valC', filters: { colC: 'something' } }, filterState: { value: 'valC', filters: { colC: 'something' } },
extraFormData: {}, extraFormData: {},
@@ -113,7 +114,7 @@ describe('getCrossFilterIndicator', () => {
}); });
}); });
it('returns empty name and path if chartLayoutItem is not found', () => { test('returns empty name and path if chartLayoutItem is not found', () => {
const dataMask = { const dataMask = {
filterState: { value: 'valD' }, filterState: { value: 'valD' },
extraFormData: {}, extraFormData: {},
@@ -127,7 +128,7 @@ describe('getCrossFilterIndicator', () => {
}); });
}); });
it('returns null value if no label or value in filterState', () => { test('returns null value if no label or value in filterState', () => {
const dataMask = { const dataMask = {
filterState: {}, filterState: {},
extraFormData: {}, extraFormData: {},

View File

@@ -39,8 +39,9 @@ beforeEach(() => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('useIsFilterInScope', () => { describe('useIsFilterInScope', () => {
it('should return true for dividers (always in scope)', () => { test('should return true for dividers (always in scope)', () => {
const divider: Divider = { const divider: Divider = {
id: 'divider_1', id: 'divider_1',
type: NativeFilterType.Divider, type: NativeFilterType.Divider,
@@ -52,7 +53,7 @@ describe('useIsFilterInScope', () => {
expect(result.current(divider)).toBe(true); expect(result.current(divider)).toBe(true);
}); });
it('should return true for filters with charts in active tabs', () => { test('should return true for filters with charts in active tabs', () => {
const filter: Filter = { const filter: Filter = {
id: 'filter_1', id: 'filter_1',
name: 'Test Filter', name: 'Test Filter',
@@ -71,7 +72,7 @@ describe('useIsFilterInScope', () => {
expect(result.current(filter)).toBe(true); expect(result.current(filter)).toBe(true);
}); });
it('should return false for filters with inactive rootPath', () => { test('should return false for filters with inactive rootPath', () => {
const filter: Filter = { const filter: Filter = {
id: 'filter_3', id: 'filter_3',
name: 'Test Filter 3', name: 'Test Filter 3',
@@ -90,8 +91,9 @@ describe('useIsFilterInScope', () => {
}); });
}); });
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('useSelectFiltersInScope', () => { describe('useSelectFiltersInScope', () => {
it('should return all filters in scope when no tabs exist', () => { test('should return all filters in scope when no tabs exist', () => {
const filters: Filter[] = [ const filters: Filter[] = [
{ {
id: 'filter_1', id: 'filter_1',

View File

@@ -21,22 +21,23 @@ import { DashboardLayout } from 'src/dashboard/types';
import { CHART_TYPE } from 'src/dashboard/util/componentTypes'; import { CHART_TYPE } from 'src/dashboard/util/componentTypes';
import { nativeFilterGate, findTabsWithChartsInScope } from './utils'; import { nativeFilterGate, findTabsWithChartsInScope } from './utils';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('nativeFilterGate', () => { describe('nativeFilterGate', () => {
it('should return true for regular chart', () => { test('should return true for regular chart', () => {
expect(nativeFilterGate([])).toEqual(true); expect(nativeFilterGate([])).toEqual(true);
}); });
it('should return true for cross filter chart', () => { test('should return true for cross filter chart', () => {
expect(nativeFilterGate([Behavior.InteractiveChart])).toEqual(true); expect(nativeFilterGate([Behavior.InteractiveChart])).toEqual(true);
}); });
it('should return true for native filter chart with cross filter support', () => { test('should return true for native filter chart with cross filter support', () => {
expect( expect(
nativeFilterGate([Behavior.NativeFilter, Behavior.InteractiveChart]), nativeFilterGate([Behavior.NativeFilter, Behavior.InteractiveChart]),
).toEqual(true); ).toEqual(true);
}); });
it('should return false for native filter behavior', () => { test('should return false for native filter behavior', () => {
expect(nativeFilterGate([Behavior.NativeFilter])).toEqual(false); expect(nativeFilterGate([Behavior.NativeFilter])).toEqual(false);
}); });
}); });

View File

@@ -22,6 +22,7 @@ import ResizableContainer, {
ResizableContainerProps, ResizableContainerProps,
} from 'src/dashboard/components/resizable/ResizableContainer'; } from 'src/dashboard/components/resizable/ResizableContainer';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ResizableContainer', () => { describe('ResizableContainer', () => {
const props = { const props = {
editMode: false, editMode: false,
@@ -34,7 +35,7 @@ describe('ResizableContainer', () => {
<ResizableContainer {...props} {...overrides} /> <ResizableContainer {...props} {...overrides} />
); );
it('should render a Resizable container', () => { test('should render a Resizable container', () => {
const rendered = render(setup()); const rendered = render(setup());
const resizableContainer = rendered.container.querySelector( const resizableContainer = rendered.container.querySelector(
'.resizable-container', '.resizable-container',

View File

@@ -21,22 +21,23 @@ import { render } from 'spec/helpers/testing-library';
import ResizableHandle from 'src/dashboard/components/resizable/ResizableHandle'; import ResizableHandle from 'src/dashboard/components/resizable/ResizableHandle';
/* eslint-disable react/jsx-pascal-case */ /* eslint-disable react/jsx-pascal-case */
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('ResizableHandle', () => { describe('ResizableHandle', () => {
it('should render a right resize handle', () => { test('should render a right resize handle', () => {
const rendered = render(<ResizableHandle.right />); const rendered = render(<ResizableHandle.right />);
expect( expect(
rendered.container.querySelector('.resize-handle.resize-handle--right'), rendered.container.querySelector('.resize-handle.resize-handle--right'),
).toBeVisible(); ).toBeVisible();
}); });
it('should render a bottom resize handle', () => { test('should render a bottom resize handle', () => {
const rendered = render(<ResizableHandle.bottom />); const rendered = render(<ResizableHandle.bottom />);
expect( expect(
rendered.container.querySelector('.resize-handle.resize-handle--bottom'), rendered.container.querySelector('.resize-handle.resize-handle--bottom'),
).toBeVisible(); ).toBeVisible();
}); });
it('should render a bottomRight resize handle', () => { test('should render a bottomRight resize handle', () => {
const rendered = render(<ResizableHandle.bottomRight />); const rendered = render(<ResizableHandle.bottomRight />);
expect( expect(
rendered.container.querySelector( rendered.container.querySelector(

View File

@@ -33,13 +33,14 @@ import {
} from 'spec/fixtures/mockSliceEntities'; } from 'spec/fixtures/mockSliceEntities';
import { filterComponent } from 'spec/fixtures/mockDashboardLayout'; import { filterComponent } from 'spec/fixtures/mockDashboardLayout';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('dashboardFilters reducer', () => { describe('dashboardFilters reducer', () => {
const { form_data } = sliceEntitiesForDashboard.slices[filterId]; const { form_data } = sliceEntitiesForDashboard.slices[filterId];
const component = filterComponent; const component = filterComponent;
const directPathToFilter = (component.parents || []).slice(); const directPathToFilter = (component.parents || []).slice();
directPathToFilter.push(component.id); directPathToFilter.push(component.id);
it('should overwrite a filter if merge is false', () => { test('should overwrite a filter if merge is false', () => {
expect( expect(
dashboardFiltersReducer(dashboardFilters, { dashboardFiltersReducer(dashboardFilters, {
type: CHANGE_FILTER, type: CHANGE_FILTER,
@@ -72,7 +73,7 @@ describe('dashboardFilters reducer', () => {
}); });
}); });
it('should merge a filter if merge is true', () => { test('should merge a filter if merge is true', () => {
expect( expect(
dashboardFiltersReducer(dashboardFilters, { dashboardFiltersReducer(dashboardFilters, {
type: CHANGE_FILTER, type: CHANGE_FILTER,
@@ -105,7 +106,7 @@ describe('dashboardFilters reducer', () => {
}); });
}); });
it('should buildActiveFilters on UPDATE_DASHBOARD_FILTERS_SCOPE', () => { test('should buildActiveFilters on UPDATE_DASHBOARD_FILTERS_SCOPE', () => {
const regionScope = { const regionScope = {
scope: ['TAB-1'], scope: ['TAB-1'],
immune: [], immune: [],

View File

@@ -46,12 +46,13 @@ import {
NEW_ROW_ID, NEW_ROW_ID,
} from 'src/dashboard/util/constants'; } from 'src/dashboard/util/constants';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('dashboardLayout reducer', () => { describe('dashboardLayout reducer', () => {
it('should return initial state for unrecognized actions', () => { test('should return initial state for unrecognized actions', () => {
expect(layoutReducer(undefined, {})).toEqual({}); expect(layoutReducer(undefined, {})).toEqual({});
}); });
it('should delete a component, remove its reference in its parent, and recursively all of its children', () => { test('should delete a component, remove its reference in its parent, and recursively all of its children', () => {
expect( expect(
layoutReducer( layoutReducer(
{ {
@@ -87,7 +88,7 @@ describe('dashboardLayout reducer', () => {
}); });
}); });
it('should delete a parent if the parent was a row and no longer has children', () => { test('should delete a parent if the parent was a row and no longer has children', () => {
expect( expect(
layoutReducer( layoutReducer(
{ {
@@ -122,7 +123,7 @@ describe('dashboardLayout reducer', () => {
}); });
}); });
it('should update components', () => { test('should update components', () => {
expect( expect(
layoutReducer( layoutReducer(
{ {
@@ -173,7 +174,7 @@ describe('dashboardLayout reducer', () => {
}); });
}); });
it('should move a component', () => { test('should move a component', () => {
const layout = { const layout = {
source: { source: {
id: 'source', id: 'source',
@@ -222,7 +223,7 @@ describe('dashboardLayout reducer', () => {
}); });
}); });
it('should wrap a moved component in a row if need be', () => { test('should wrap a moved component in a row if need be', () => {
const layout = { const layout = {
source: { source: {
id: 'source', id: 'source',
@@ -262,7 +263,7 @@ describe('dashboardLayout reducer', () => {
expect(Object.keys(result)).toHaveLength(4); expect(Object.keys(result)).toHaveLength(4);
}); });
it('should add top-level tabs from a new tabs component, moving grid children to new tab', () => { test('should add top-level tabs from a new tabs component, moving grid children to new tab', () => {
const layout = { const layout = {
[DASHBOARD_ROOT_ID]: { [DASHBOARD_ROOT_ID]: {
id: DASHBOARD_ROOT_ID, id: DASHBOARD_ROOT_ID,
@@ -308,7 +309,7 @@ describe('dashboardLayout reducer', () => {
expect(result[DASHBOARD_GRID_ID].children).toHaveLength(0); expect(result[DASHBOARD_GRID_ID].children).toHaveLength(0);
}); });
it('should add top-level tabs from an existing tabs component, moving grid children to new tab', () => { test('should add top-level tabs from an existing tabs component, moving grid children to new tab', () => {
const layout = { const layout = {
[DASHBOARD_ROOT_ID]: { [DASHBOARD_ROOT_ID]: {
id: DASHBOARD_ROOT_ID, id: DASHBOARD_ROOT_ID,
@@ -360,7 +361,7 @@ describe('dashboardLayout reducer', () => {
expect(result[DASHBOARD_GRID_ID].children).toHaveLength(0); expect(result[DASHBOARD_GRID_ID].children).toHaveLength(0);
}); });
it('should remove top-level tabs, moving children to the grid', () => { test('should remove top-level tabs, moving children to the grid', () => {
const layout = { const layout = {
[DASHBOARD_ROOT_ID]: { [DASHBOARD_ROOT_ID]: {
id: DASHBOARD_ROOT_ID, id: DASHBOARD_ROOT_ID,
@@ -425,7 +426,7 @@ describe('dashboardLayout reducer', () => {
}); });
}); });
it('should create a component', () => { test('should create a component', () => {
const layout = { const layout = {
[DASHBOARD_ROOT_ID]: { [DASHBOARD_ROOT_ID]: {
id: DASHBOARD_ROOT_ID, id: DASHBOARD_ROOT_ID,
@@ -458,7 +459,7 @@ describe('dashboardLayout reducer', () => {
expect(result[newId].type).toBe(ROW_TYPE); expect(result[newId].type).toBe(ROW_TYPE);
}); });
it('recursivelyDeleteChildren should be error proof with bad inputs', () => { test('recursivelyDeleteChildren should be error proof with bad inputs', () => {
/* /*
** The recursivelyDeleteChildren function was missing runtime safety checks before operating ** The recursivelyDeleteChildren function was missing runtime safety checks before operating
** on sub properties of object causing runtime errors when a componentId lookup returned and unexpected value ** on sub properties of object causing runtime errors when a componentId lookup returned and unexpected value

View File

@@ -33,12 +33,13 @@ import {
import dashboardStateReducer from 'src/dashboard/reducers/dashboardState'; import dashboardStateReducer from 'src/dashboard/reducers/dashboardState';
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('dashboardState reducer', () => { describe('dashboardState reducer', () => {
it('should return initial state', () => { test('should return initial state', () => {
expect(dashboardStateReducer(undefined, {})).toEqual({}); expect(dashboardStateReducer(undefined, {})).toEqual({});
}); });
it('should add a slice', () => { test('should add a slice', () => {
expect( expect(
dashboardStateReducer( dashboardStateReducer(
{ sliceIds: [1] }, { sliceIds: [1] },
@@ -47,7 +48,7 @@ describe('dashboardState reducer', () => {
).toEqual({ sliceIds: [1, 2] }); ).toEqual({ sliceIds: [1, 2] });
}); });
it('should remove a slice', () => { test('should remove a slice', () => {
expect( expect(
dashboardStateReducer( dashboardStateReducer(
{ sliceIds: [1, 2], filters: {} }, { sliceIds: [1, 2], filters: {} },
@@ -56,7 +57,7 @@ describe('dashboardState reducer', () => {
).toEqual({ sliceIds: [1], filters: {} }); ).toEqual({ sliceIds: [1], filters: {} });
}); });
it('should toggle fav star', () => { test('should toggle fav star', () => {
expect( expect(
dashboardStateReducer( dashboardStateReducer(
{ isStarred: false }, { isStarred: false },
@@ -65,7 +66,7 @@ describe('dashboardState reducer', () => {
).toEqual({ isStarred: true }); ).toEqual({ isStarred: true });
}); });
it('should toggle edit mode', () => { test('should toggle edit mode', () => {
expect( expect(
dashboardStateReducer( dashboardStateReducer(
{ editMode: false }, { editMode: false },
@@ -76,7 +77,7 @@ describe('dashboardState reducer', () => {
}); });
}); });
it('should toggle expanded slices', () => { test('should toggle expanded slices', () => {
expect( expect(
dashboardStateReducer( dashboardStateReducer(
{ expandedSlices: { 1: true, 2: false } }, { expandedSlices: { 1: true, 2: false } },
@@ -92,7 +93,7 @@ describe('dashboardState reducer', () => {
).toEqual({ expandedSlices: { 1: true, 2: true } }); ).toEqual({ expandedSlices: { 1: true, 2: true } });
}); });
it('should set hasUnsavedChanges', () => { test('should set hasUnsavedChanges', () => {
expect(dashboardStateReducer({}, { type: ON_CHANGE })).toEqual({ expect(dashboardStateReducer({}, { type: ON_CHANGE })).toEqual({
hasUnsavedChanges: true, hasUnsavedChanges: true,
}); });
@@ -107,7 +108,7 @@ describe('dashboardState reducer', () => {
}); });
}); });
it('should set maxUndoHistoryExceeded', () => { test('should set maxUndoHistoryExceeded', () => {
expect( expect(
dashboardStateReducer( dashboardStateReducer(
{}, {},
@@ -121,7 +122,7 @@ describe('dashboardState reducer', () => {
}); });
}); });
it('should set unsaved changes, max undo history, and editMode to false on save', () => { test('should set unsaved changes, max undo history, and editMode to false on save', () => {
const result = dashboardStateReducer( const result = dashboardStateReducer(
{ hasUnsavedChanges: true }, { hasUnsavedChanges: true },
{ type: ON_SAVE }, { type: ON_SAVE },
@@ -132,7 +133,7 @@ describe('dashboardState reducer', () => {
expect(result.updatedColorScheme).toBe(false); expect(result.updatedColorScheme).toBe(false);
}); });
it('should reset lastModifiedTime on save', () => { test('should reset lastModifiedTime on save', () => {
const initTime = new Date().getTime() / 1000; const initTime = new Date().getTime() / 1000;
dashboardStateReducer( dashboardStateReducer(
{ {
@@ -150,7 +151,7 @@ describe('dashboardState reducer', () => {
).toBeGreaterThanOrEqual(initTime); ).toBeGreaterThanOrEqual(initTime);
}); });
it('should clear the focused filter field', () => { test('should clear the focused filter field', () => {
const initState = { const initState = {
focusedFilterField: { focusedFilterField: {
chartId: 1, chartId: 1,
@@ -167,7 +168,7 @@ describe('dashboardState reducer', () => {
expect(cleared.focusedFilterField).toBeNull(); expect(cleared.focusedFilterField).toBeNull();
}); });
it('should only clear focused filter when the fields match', () => { test('should only clear focused filter when the fields match', () => {
// dashboard only has 1 focused filter field at a time, // dashboard only has 1 focused filter field at a time,
// but when user switch different filter boxes, // but when user switch different filter boxes,
// browser didn't always fire onBlur and onFocus events in order. // browser didn't always fire onBlur and onFocus events in order.
@@ -199,7 +200,7 @@ describe('dashboardState reducer', () => {
}); });
}); });
it('should toggle native filters bar', () => { test('should toggle native filters bar', () => {
expect( expect(
dashboardStateReducer( dashboardStateReducer(
{ nativeFiltersBarOpen: false }, { nativeFiltersBarOpen: false },

Some files were not shown because too many files have changed in this diff Show More