Skip to content

Commit 0a5144f

Browse files
sadpandajoeclaude
andauthored
fix(tests): fix flakey tests with PropertiesModal.test.tsx, FiltersConfigModal.test.tsx and ChartList.listview.test.tsx (apache#36037)
Co-authored-by: Claude <[email protected]>
1 parent 64ca080 commit 0a5144f

File tree

3 files changed

+858
-891
lines changed

3 files changed

+858
-891
lines changed

superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx

Lines changed: 77 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,6 @@ afterEach(() => {
184184
jest.restoreAllMocks();
185185
});
186186

187-
// Set timeout for all tests in this file to prevent CI timeouts
188-
jest.setTimeout(60000);
189-
190187
function defaultRender(initialState: any = defaultState(), modalProps = props) {
191188
return render(<FiltersConfigModal {...modalProps} />, {
192189
initialState,
@@ -226,9 +223,10 @@ test('renders a value filter type', () => {
226223
test('renders a numerical range filter type', async () => {
227224
defaultRender();
228225

229-
userEvent.click(screen.getByText(VALUE_REGEX));
226+
await userEvent.click(screen.getByText(VALUE_REGEX));
230227

231-
await waitFor(() => userEvent.click(screen.getByText(NUMERICAL_RANGE_REGEX)));
228+
const numericalRangeOption = await screen.findByText(NUMERICAL_RANGE_REGEX);
229+
await userEvent.click(numericalRangeOption);
232230

233231
expect(screen.getByText(FILTER_TYPE_REGEX)).toBeInTheDocument();
234232
expect(screen.getByText(FILTER_NAME_REGEX)).toBeInTheDocument();
@@ -250,9 +248,10 @@ test('renders a numerical range filter type', async () => {
250248
test('renders a time range filter type', async () => {
251249
defaultRender();
252250

253-
userEvent.click(screen.getByText(VALUE_REGEX));
251+
await userEvent.click(screen.getByText(VALUE_REGEX));
254252

255-
await waitFor(() => userEvent.click(screen.getByText(TIME_RANGE_REGEX)));
253+
const timeRangeOption = await screen.findByText(TIME_RANGE_REGEX);
254+
await userEvent.click(timeRangeOption);
256255

257256
expect(screen.getByText(FILTER_TYPE_REGEX)).toBeInTheDocument();
258257
expect(screen.getByText(FILTER_NAME_REGEX)).toBeInTheDocument();
@@ -265,9 +264,10 @@ test('renders a time range filter type', async () => {
265264
test('renders a time column filter type', async () => {
266265
defaultRender();
267266

268-
userEvent.click(screen.getByText(VALUE_REGEX));
267+
await userEvent.click(screen.getByText(VALUE_REGEX));
269268

270-
await waitFor(() => userEvent.click(screen.getByText(TIME_COLUMN_REGEX)));
269+
const timeColumnOption = await screen.findByText(TIME_COLUMN_REGEX);
270+
await userEvent.click(timeColumnOption);
271271

272272
expect(screen.getByText(FILTER_TYPE_REGEX)).toBeInTheDocument();
273273
expect(screen.getByText(FILTER_NAME_REGEX)).toBeInTheDocument();
@@ -280,9 +280,10 @@ test('renders a time column filter type', async () => {
280280
test('renders a time grain filter type', async () => {
281281
defaultRender();
282282

283-
userEvent.click(screen.getByText(VALUE_REGEX));
283+
await userEvent.click(screen.getByText(VALUE_REGEX));
284284

285-
await waitFor(() => userEvent.click(screen.getByText(TIME_GRAIN_REGEX)));
285+
const timeGrainOption = await screen.findByText(TIME_GRAIN_REGEX);
286+
await userEvent.click(timeGrainOption);
286287

287288
expect(screen.getByText(FILTER_TYPE_REGEX)).toBeInTheDocument();
288289
expect(screen.getByText(FILTER_NAME_REGEX)).toBeInTheDocument();
@@ -295,7 +296,7 @@ test('renders a time grain filter type', async () => {
295296
test('render time filter types as disabled if there are no temporal columns in the dataset', async () => {
296297
defaultRender(noTemporalColumnsState());
297298

298-
userEvent.click(screen.getByText(VALUE_REGEX));
299+
await userEvent.click(screen.getByText(VALUE_REGEX));
299300

300301
const timeRange = await screen.findByText(TIME_RANGE_REGEX);
301302
const timeGrain = await screen.findByText(TIME_GRAIN_REGEX);
@@ -309,7 +310,7 @@ test('render time filter types as disabled if there are no temporal columns in t
309310

310311
test('validates the name', async () => {
311312
defaultRender();
312-
userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
313+
await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
313314
await waitFor(
314315
async () => {
315316
expect(await screen.findByText(NAME_REQUIRED_REGEX)).toBeInTheDocument();
@@ -320,16 +321,16 @@ test('validates the name', async () => {
320321

321322
test('validates the column', async () => {
322323
defaultRender();
323-
userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
324+
await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
324325
expect(await screen.findByText(COLUMN_REQUIRED_REGEX)).toBeInTheDocument();
325326
});
326327

327328
// eslint-disable-next-line jest/no-disabled-tests
328329
test.skip('validates the default value', async () => {
329330
defaultRender(noTemporalColumnsState());
330331
expect(await screen.findByText('birth_names')).toBeInTheDocument();
331-
userEvent.type(screen.getByRole('combobox'), `Column A{Enter}`);
332-
userEvent.click(getCheckbox(DEFAULT_VALUE_REGEX));
332+
await userEvent.type(screen.getByRole('combobox'), `Column A{Enter}`);
333+
await userEvent.click(getCheckbox(DEFAULT_VALUE_REGEX));
333334
await waitFor(() => {
334335
expect(
335336
screen.queryByText(FILL_REQUIRED_FIELDS_REGEX),
@@ -345,21 +346,24 @@ test('validates the pre-filter value', async () => {
345346
try {
346347
defaultRender();
347348

348-
userEvent.click(screen.getByText(FILTER_SETTINGS_REGEX));
349-
userEvent.click(getCheckbox(PRE_FILTER_REGEX));
349+
await userEvent.click(screen.getByText(FILTER_SETTINGS_REGEX));
350+
await userEvent.click(getCheckbox(PRE_FILTER_REGEX));
350351

351352
jest.runAllTimers();
353+
354+
await waitFor(() => {
355+
const errorMessages = screen.getAllByText(PRE_FILTER_REQUIRED_REGEX);
356+
expect(errorMessages.length).toBeGreaterThan(0);
357+
});
352358
} finally {
353359
jest.useRealTimers();
354360
}
355361

356-
jest.runOnlyPendingTimers();
357-
jest.useRealTimers();
358-
359362
// Wait for validation to complete after timer switch
360363
await waitFor(
361364
() => {
362-
expect(screen.getByText(PRE_FILTER_REQUIRED_REGEX)).toBeInTheDocument();
365+
const errorMessages = screen.queryAllByText(PRE_FILTER_REQUIRED_REGEX);
366+
expect(errorMessages.length).toBeGreaterThan(0);
363367
},
364368
{ timeout: 15000 },
365369
);
@@ -368,13 +372,13 @@ test('validates the pre-filter value', async () => {
368372
// eslint-disable-next-line jest/no-disabled-tests
369373
test.skip("doesn't render time range pre-filter if there are no temporal columns in datasource", async () => {
370374
defaultRender(noTemporalColumnsState());
371-
userEvent.click(screen.getByText(DATASET_REGEX));
372-
await waitFor(() => {
375+
await userEvent.click(screen.getByText(DATASET_REGEX));
376+
await waitFor(async () => {
373377
expect(screen.queryByLabelText('Loading')).not.toBeInTheDocument();
374-
userEvent.click(screen.getByText('birth_names'));
378+
await userEvent.click(screen.getByText('birth_names'));
375379
});
376-
userEvent.click(screen.getByText(FILTER_SETTINGS_REGEX));
377-
userEvent.click(getCheckbox(PRE_FILTER_REGEX));
380+
await userEvent.click(screen.getByText(FILTER_SETTINGS_REGEX));
381+
await userEvent.click(getCheckbox(PRE_FILTER_REGEX));
378382
await waitFor(() =>
379383
expect(
380384
screen.queryByText(TIME_RANGE_PREFILTER_REGEX),
@@ -439,9 +443,9 @@ test('deletes a filter', async () => {
439443
const removeButtons = screen.getAllByRole('button', {
440444
name: 'delete',
441445
});
442-
userEvent.click(removeButtons[2]);
446+
await userEvent.click(removeButtons[2]);
443447

444-
userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
448+
await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
445449

446450
await waitFor(() =>
447451
expect(onSave).toHaveBeenCalledWith(
@@ -476,8 +480,8 @@ test('deletes a filter including dependencies', async () => {
476480
const removeButtons = screen.getAllByRole('button', {
477481
name: 'delete',
478482
});
479-
userEvent.click(removeButtons[1]);
480-
userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
483+
await userEvent.click(removeButtons[1]);
484+
await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
481485
await waitFor(() =>
482486
expect(onSave).toHaveBeenCalledWith(
483487
expect.objectContaining({
@@ -525,7 +529,7 @@ test('switches the order between two filters', async () => {
525529

526530
fireEvent.dragEnd(draggableFilters[0]);
527531

528-
userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
532+
await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
529533

530534
await waitFor(() =>
531535
expect(onSave).toHaveBeenCalledWith(
@@ -568,14 +572,14 @@ test('rearranges three filters and deletes one of them', async () => {
568572
const deleteButtons = screen.getAllByRole('button', {
569573
name: 'delete',
570574
});
571-
userEvent.click(deleteButtons[1]);
575+
await userEvent.click(deleteButtons[1]);
572576

573577
fireEvent.dragStart(draggableFilters[0]);
574578
fireEvent.dragOver(draggableFilters[2]);
575579
fireEvent.drop(draggableFilters[2]);
576580
fireEvent.dragEnd(draggableFilters[0]);
577581

578-
userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
582+
await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
579583

580584
await waitFor(() =>
581585
expect(onSave).toHaveBeenCalledWith(
@@ -594,47 +598,51 @@ test('rearranges three filters and deletes one of them', async () => {
594598

595599
test('modifies the name of a filter', async () => {
596600
jest.useFakeTimers();
597-
const nativeFilterState = [
598-
buildNativeFilter('NATIVE_FILTER-1', 'state', []),
599-
buildNativeFilter('NATIVE_FILTER-2', 'country', []),
600-
];
601-
602-
const state = {
603-
...defaultState(),
604-
dashboardInfo: {
605-
metadata: { native_filter_configuration: nativeFilterState },
606-
},
607-
dashboardLayout,
608-
};
601+
try {
602+
const nativeFilterState = [
603+
buildNativeFilter('NATIVE_FILTER-1', 'state', []),
604+
buildNativeFilter('NATIVE_FILTER-2', 'country', []),
605+
];
606+
607+
const state = {
608+
...defaultState(),
609+
dashboardInfo: {
610+
metadata: { native_filter_configuration: nativeFilterState },
611+
},
612+
dashboardLayout,
613+
};
609614

610-
const onSave = jest.fn();
615+
const onSave = jest.fn();
611616

612-
defaultRender(state, {
613-
...props,
614-
createNewOnOpen: false,
615-
onSave,
616-
});
617-
618-
const filterNameInput = screen.getByRole('textbox', {
619-
name: FILTER_NAME_REGEX,
620-
});
617+
defaultRender(state, {
618+
...props,
619+
createNewOnOpen: false,
620+
onSave,
621+
});
621622

622-
userEvent.clear(filterNameInput);
623-
userEvent.type(filterNameInput, 'New Filter Name');
623+
const filterNameInput = screen.getByRole('textbox', {
624+
name: FILTER_NAME_REGEX,
625+
});
624626

625-
jest.runAllTimers();
627+
await userEvent.clear(filterNameInput);
628+
await userEvent.type(filterNameInput, 'New Filter Name');
626629

627-
userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
630+
jest.runAllTimers();
628631

629-
await waitFor(() =>
630-
expect(onSave).toHaveBeenCalledWith(
631-
expect.objectContaining({
632-
modified: expect.arrayContaining([
633-
expect.objectContaining({ name: 'New Filter Name' }),
634-
]),
635-
}),
636-
),
637-
);
632+
await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
633+
634+
await waitFor(() =>
635+
expect(onSave).toHaveBeenCalledWith(
636+
expect.objectContaining({
637+
modified: expect.arrayContaining([
638+
expect.objectContaining({ name: 'New Filter Name' }),
639+
]),
640+
}),
641+
),
642+
);
643+
} finally {
644+
jest.useRealTimers();
645+
}
638646
});
639647

640648
test('renders a filter with a chart containing BigInt values', async () => {

0 commit comments

Comments
 (0)