Skip to content

Commit

Permalink
Merge pull request #2275 from trilitech/async_handler
Browse files Browse the repository at this point in the history
fix: avoid double toast by handleAsyncActionUnsafe
  • Loading branch information
dianasavvatina authored Dec 18, 2024
2 parents 12bc5ea + 04064fe commit 28166c5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 15 deletions.
39 changes: 38 additions & 1 deletion packages/state/src/hooks/useAsyncActionHandler.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CustomError } from "@umami/utils";

import { useAsyncActionHandler } from "./useAsyncActionHandler";
import { act, mockToast, renderHook, waitFor } from "../testUtils";

Expand Down Expand Up @@ -144,12 +146,12 @@ describe("useAsyncActionHandler", () => {
describe("handleAsyncActionUnsafe", () => {
it("returns the result of the computation", async () => {
const view = fixture();

const result = await act(() =>
view.result.current.handleAsyncActionUnsafe(() => Promise.resolve(42))
);

expect(result).toBe(42);
expect(mockToast).toHaveBeenCalledTimes(0);
});

it("throws when the computation fails", async () => {
Expand All @@ -160,6 +162,41 @@ describe("useAsyncActionHandler", () => {
view.result.current.handleAsyncActionUnsafe(() => Promise.reject(new Error("test error")))
)
).rejects.toThrow("test error");
expect(mockToast).toHaveBeenCalledTimes(2);
});

it("Unsafe propagates the error and shows the toast once on first handling", async () => {
const view = fixture();

expect(mockToast).toHaveBeenCalledTimes(0);

const error: any = new CustomError("test nested error handling");
await expect(
act(() => view.result.current.handleAsyncActionUnsafe(() => Promise.reject(error)))
).rejects.toThrow("test nested error handling");
// check that error.processed is set to true
expect(error.processed).toBe(true);
expect(mockToast).toHaveBeenCalledWith({
description: "test nested error handling",
status: "error",
isClosable: true,
});
expect(mockToast).toHaveBeenCalledTimes(2);
});

it("Unsafe propagates the error and shows no toast on second handling", async () => {
const view = fixture();

expect(mockToast).toHaveBeenCalledTimes(0);

const error: any = new CustomError("test nested error handling");
error.processed = true;
await expect(
act(() => view.result.current.handleAsyncActionUnsafe(() => Promise.reject(error)))
).rejects.toThrow("test nested error handling");
// check that error.processed is still true
expect(error.processed).toBe(true);
expect(mockToast).toHaveBeenCalledTimes(0);
});
});
});
35 changes: 21 additions & 14 deletions packages/state/src/hooks/useAsyncActionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,29 @@ export const useAsyncActionHandler = () => {
} catch (error: any) {
const errorContext = getErrorContext(error);

toast({
description: errorContext.description,
status: "error",
isClosable: true,
...(typeof toastOptions === "function" ? toastOptions(error) : toastOptions),
});
// Prevent double toast and record of the same error if case of nested handleAsyncActionUnsafe calls.
// Still we need to re-throw the error to propagate it to the caller.
// There is no problem with handleAsyncAction calls as they stop the propagation of the error.
if (!error.processed) {
error.processed = true;

// TODO: fix this dirty hack
mockToast({
description: errorContext.description,
status: "error",
isClosable: true,
...(typeof toastOptions === "function" ? toastOptions(error) : toastOptions),
});
toast({
description: errorContext.description,
status: "error",
isClosable: true,
...(typeof toastOptions === "function" ? toastOptions(error) : toastOptions),
});

dispatch(errorsActions.add(errorContext));
// TODO: fix this dirty hack
mockToast({
description: errorContext.description,
status: "error",
isClosable: true,
...(typeof toastOptions === "function" ? toastOptions(error) : toastOptions),
});

dispatch(errorsActions.add(errorContext));
}
throw error;
} finally {
isLoadingRef.current = false;
Expand Down

1 comment on commit 28166c5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Title Lines Statements Branches Functions
apps/desktop Coverage: 83%
83.81% (1786/2131) 79.58% (850/1068) 78.27% (454/580)
apps/web Coverage: 83%
83.81% (1786/2131) 79.58% (850/1068) 78.27% (454/580)
packages/components Coverage: 97%
97.51% (196/201) 95.91% (94/98) 88.13% (52/59)
packages/core Coverage: 81%
82.47% (207/251) 72.72% (88/121) 81.35% (48/59)
packages/crypto Coverage: 100%
100% (43/43) 90.9% (10/11) 100% (7/7)
packages/data-polling Coverage: 97%
95.27% (141/148) 87.5% (21/24) 92.85% (39/42)
packages/multisig Coverage: 98%
98.47% (129/131) 85.71% (18/21) 100% (36/36)
packages/social-auth Coverage: 100%
100% (21/21) 100% (11/11) 100% (3/3)
packages/state Coverage: 85%
84.79% (820/967) 81.03% (188/232) 78.59% (301/383)
packages/tezos Coverage: 89%
88.72% (118/133) 94.59% (35/37) 86.84% (33/38)
packages/tzkt Coverage: 89%
87.32% (62/71) 87.5% (14/16) 80.48% (33/41)

Please sign in to comment.