-
Notifications
You must be signed in to change notification settings - Fork 18k
fix(dashboard): handle favorite fetch for deleted dashboards #37497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,6 +24,8 @@ import { | |||||||||||||||||||||||||
| SAVE_DASHBOARD_STARTED, | ||||||||||||||||||||||||||
| saveDashboardRequest, | ||||||||||||||||||||||||||
| SET_OVERRIDE_CONFIRM, | ||||||||||||||||||||||||||
| fetchFaveStar, | ||||||||||||||||||||||||||
| TOGGLE_FAVE_STAR, | ||||||||||||||||||||||||||
| } from 'src/dashboard/actions/dashboardState'; | ||||||||||||||||||||||||||
| import { UPDATE_COMPONENTS_PARENTS_LIST } from 'src/dashboard/actions/dashboardLayout'; | ||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||
|
|
@@ -234,4 +236,61 @@ describe('dashboardState actions', () => { | |||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks | ||||||||||||||||||||||||||
| describe('fetchFaveStar', () => { | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing global test function definitions in scope
The new test code uses Code suggestionCheck the AI-generated fix before applying Code Review Run #8471c0 Should Bito avoid suggestions like this for future reviews? (Manage Rules)
|
||||||||||||||||||||||||||
| test('dispatches TOGGLE_FAVE_STAR on successful fetch', async () => { | ||||||||||||||||||||||||||
| const dashboardId = 123; | ||||||||||||||||||||||||||
| const dispatch = sinon.stub(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| getStub.restore(); | ||||||||||||||||||||||||||
| getStub = sinon.stub(SupersetClient, 'get').resolves({ | ||||||||||||||||||||||||||
| json: { | ||||||||||||||||||||||||||
| result: [{ id: dashboardId, value: true }], | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const thunk = fetchFaveStar(dashboardId); | ||||||||||||||||||||||||||
| await thunk(dispatch); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| await waitFor(() => expect(dispatch.callCount).toBe(1)); | ||||||||||||||||||||||||||
| expect(dispatch.getCall(0).args[0].type).toBe(TOGGLE_FAVE_STAR); | ||||||||||||||||||||||||||
| expect(dispatch.getCall(0).args[0].isStarred).toBe(true); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| test('does not dispatch error toast on 404 response', async () => { | ||||||||||||||||||||||||||
| const dashboardId = 999; | ||||||||||||||||||||||||||
| const dispatch = sinon.stub(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| getStub.restore(); | ||||||||||||||||||||||||||
| const error404 = new Error('Not found'); | ||||||||||||||||||||||||||
| error404.status = 404; | ||||||||||||||||||||||||||
| getStub = sinon.stub(SupersetClient, 'get').rejects(error404); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| const error404 = new Error('Not found'); | |
| error404.status = 404; | |
| getStub = sinon.stub(SupersetClient, 'get').rejects(error404); | |
| getStub = sinon | |
| .stub(SupersetClient, 'get') | |
| .rejects({ | |
| response: { | |
| status: 404, | |
| statusText: 'Not Found', | |
| bodyUsed: false, | |
| }, | |
| }); |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mocked 404 failure here rejects with a plain Error that has a status field, but fetchFaveStar now calls getClientErrorObject(error) and checks errorObject.status. getClientErrorObject does not read status off a generic Error, so errorObject.status will be undefined and this test will fail (it will dispatch the danger toast instead of skipping). Update the stub to reject with the same shape SupersetClient uses (e.g., { response: new Response(..., { status: 404 }) }) so getClientErrorObject can derive status correctly.
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same mocking issue as the 404 test: rejecting with a plain Error (even with status = 500) won’t reliably propagate status through getClientErrorObject. To ensure this test is validating the intended non-404 branch, reject with a Response-like object that includes status/statusText (or mock getClientErrorObject).
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the 404 case: this test rejects with a plain Error and sets error500.status, but getClientErrorObject won’t propagate that into errorObject.status. This makes the test less representative of real SupersetClient failures and can cause unexpected behavior. Prefer rejecting with { response: new Response(..., { status: 500 }) } (or whatever SupersetClient actually rejects with) so the thunk exercises the same parsing path as production.
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with the rest of the codebase, avoid asserting on the raw string 'ADD_TOAST' and instead import and use the ADD_TOAST constant from src/components/MessageToasts/actions (e.g. as done in src/dashboard/actions/dashboardLayout.test.js:380). This reduces brittleness if the action type ever changes.
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -592,7 +592,12 @@ const Header = () => { | |||||||||||||
| const faveStarProps = useMemo( | ||||||||||||||
| () => ({ | ||||||||||||||
| itemId: dashboardInfo.id, | ||||||||||||||
| fetchFaveStar: boundActionCreators.fetchFaveStar, | ||||||||||||||
| // Only fetch favorite status for valid, existing dashboards | ||||||||||||||
| // Skip fetch entirely if dashboard ID is falsy to prevent | ||||||||||||||
| // 404 errors when navigating after dashboard deletion | ||||||||||||||
|
||||||||||||||
| // Only fetch favorite status for valid, existing dashboards | |
| // Skip fetch entirely if dashboard ID is falsy to prevent | |
| // 404 errors when navigating after dashboard deletion | |
| // Only attempt to fetch favorite status when there's a valid dashboard ID. | |
| // When the ID is falsy (e.g., dashboard not yet created or component unmounted), | |
| // skip the fetch and rely on fetchFaveStar to handle 404s for deleted/stale IDs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There’s trailing whitespace on the blank line after
getClientErrorObject(error);(shown in the diff). Please remove it to avoid failing lint rules likeno-trailing-spaces/ prettier formatting checks.