diff --git a/frontend/src/pages/ExperimentList.test.tsx b/frontend/src/pages/ExperimentList.test.tsx index 40509f0721d..7f9c87eb5b4 100644 --- a/frontend/src/pages/ExperimentList.test.tsx +++ b/frontend/src/pages/ExperimentList.test.tsx @@ -29,7 +29,8 @@ import { RoutePage, QUERY_PARAMS } from '../components/Router'; import { range } from 'lodash'; import { ButtonKeys } from '../lib/Buttons'; import { NamespaceContext } from 'src/lib/KubeflowClient'; -import { render } from '@testing-library/react'; +import { render, act } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; // Default arguments for Apis.experimentServiceApi.listExperiment. const LIST_EXPERIMENT_DEFAULTS = [ @@ -71,17 +72,22 @@ describe('ExperimentList', () => { ); } + function mockListNExpperiments(n: number = 1) { + return () => + Promise.resolve({ + experiments: range(n).map(i => ({ + id: 'test-experiment-id' + i, + name: 'test experiment name' + i, + })), + }); + } + async function mountWithNExperiments( n: number, nRuns: number, { namespace }: { namespace?: string } = {}, ): Promise { - listExperimentsSpy.mockImplementation(() => ({ - experiments: range(n).map(i => ({ - id: 'test-experiment-id' + i, - name: 'test experiment name' + i, - })), - })); + listExperimentsSpy.mockImplementation(mockListNExpperiments(n)); listRunsSpy.mockImplementation(() => ({ runs: range(nRuns).map(i => ({ id: 'test-run-id' + i, name: 'test run name' + i })), })); @@ -473,5 +479,29 @@ describe('ExperimentList', () => { 'test-ns-2', ); }); + + it("doesn't keep error message for request from previous namespace", async () => { + listExperimentsSpy.mockImplementation(() => Promise.reject('namespace cannot be empty')); + const { rerender } = render( + + + + + , + ); + + listExperimentsSpy.mockImplementation(mockListNExpperiments()); + rerender( + + + + + , + ); + await act(TestUtils.flushPromises); + expect(updateBannerSpy).toHaveBeenLastCalledWith( + {}, // Empty object means banner has no error message + ); + }); }); }); diff --git a/frontend/src/pages/ExperimentList.tsx b/frontend/src/pages/ExperimentList.tsx index b9a18c55814..2fb9d83944e 100644 --- a/frontend/src/pages/ExperimentList.tsx +++ b/frontend/src/pages/ExperimentList.tsx @@ -227,7 +227,7 @@ export class ExperimentList extends Page<{ namespace?: string }, ExperimentListS }), ); - this.setState({ displayExperiments }); + this.setStateSafe({ displayExperiments }); return response.next_page_token || ''; } diff --git a/frontend/src/pages/Page.tsx b/frontend/src/pages/Page.tsx index d66b9a40067..156f6cf4fe5 100644 --- a/frontend/src/pages/Page.tsx +++ b/frontend/src/pages/Page.tsx @@ -54,6 +54,9 @@ export abstract class Page extends React.Component

{ } public clearBanner(): void { + if (!this._isMounted) { + return; + } this.props.updateBanner({}); } @@ -63,6 +66,9 @@ export abstract class Page extends React.Component

{ mode?: 'error' | 'warning', ): Promise { const errorMessage = await errorToMessage(error); + if (!this._isMounted) { + return; + } this.props.updateBanner({ additionalInfo: errorMessage ? errorMessage : undefined, message: message + (errorMessage ? ' Click Details for more information.' : ''), @@ -72,6 +78,9 @@ export abstract class Page extends React.Component

{ } public showErrorDialog(title: string, content: string): void { + if (!this._isMounted) { + return; + } this.props.updateDialog({ buttons: [{ text: 'Dismiss' }], content,