Skip to content

Commit 846c387

Browse files
authored
Merge pull request #6045 from mozilla/MPP-4420/frontend-error-toast
feat(toast): Add toast and error page for API error handling in the frontend
2 parents db77586 + 6b302f5 commit 846c387

File tree

17 files changed

+275
-4
lines changed

17 files changed

+275
-4
lines changed

frontend/__mocks__/hooks/api/aliases.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,28 @@ function getReturnValue(
134134
};
135135
}
136136

137+
function getErrorRandomReturnValue(): ReturnType<typeof useAliases> {
138+
return {
139+
randomAliasData: {
140+
isValidating: false,
141+
isLoading: false,
142+
error: { some_error_key: "some_error_val" },
143+
mutate: jest.fn(),
144+
data: undefined,
145+
},
146+
customAliasData: {
147+
isValidating: false,
148+
isLoading: false,
149+
error: { some_error_key: "some_error_val" },
150+
mutate: jest.fn(),
151+
data: undefined,
152+
},
153+
create: jest.fn(() => Promise.resolve({ ok: true } as unknown as Response)),
154+
update: jest.fn(() => Promise.resolve({ ok: true } as unknown as Response)),
155+
delete: jest.fn(() => Promise.resolve({ ok: true } as unknown as Response)),
156+
};
157+
}
158+
137159
export const setMockAliasesData = (
138160
aliasesData?: MockData,
139161
callbacks?: Callbacks,
@@ -147,3 +169,10 @@ export const setMockAliasesDataOnce = (
147169
) => {
148170
mockedUseAliases.mockReturnValueOnce(getReturnValue(aliasesData, callbacks));
149171
};
172+
173+
export const setMockAliasesErrorOnce = (
174+
aliasesData?: MockData,
175+
callbacks?: Callbacks,
176+
) => {
177+
mockedUseAliases.mockReturnValueOnce(getErrorRandomReturnValue());
178+
};

frontend/__mocks__/hooks/api/profile.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ function getReturnValue(
6262
};
6363
}
6464

65+
function getErrorReturnValue(): ReturnType<typeof useProfiles> {
66+
return {
67+
isValidating: false,
68+
mutate: jest.fn(),
69+
update: jest.fn(),
70+
data: undefined,
71+
setSubdomain: jest.fn(),
72+
isLoading: false,
73+
error: { some_error_key: "some_error_val" },
74+
};
75+
}
76+
6577
export const setMockProfileData = (
6678
profileData?: MockData | null,
6779
callbacks?: Callbacks,
@@ -75,3 +87,7 @@ export const setMockProfileDataOnce = (
7587
) => {
7688
mockedUseProfiles.mockReturnValueOnce(getReturnValue(profileData, callbacks));
7789
};
90+
91+
export const setMockProfileErrorOnce = () => {
92+
mockedUseProfiles.mockReturnValueOnce(getErrorReturnValue());
93+
};

frontend/__mocks__/hooks/api/relayNumber.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,22 @@ function getReturnValue(
6060
};
6161
}
6262

63+
function getErrorReturnValue(): ReturnType<typeof useRelayNumber> {
64+
return {
65+
isValidating: false,
66+
isLoading: false,
67+
error: { some_error_key: "some_error_val" },
68+
mutate: jest.fn(),
69+
data: undefined,
70+
registerRelayNumber: jest.fn(() =>
71+
Promise.resolve({ ok: true } as unknown as Response),
72+
),
73+
setForwardingState: jest.fn(() =>
74+
Promise.resolve({ ok: true } as unknown as Response),
75+
),
76+
};
77+
}
78+
6379
export const setMockRelayNumberData = (
6480
relayNumbers?: Array<Partial<RelayNumber>>,
6581
callbacks?: Callbacks,
@@ -76,4 +92,8 @@ export const setMockRelayNumberDataOnce = (
7692
);
7793
};
7894

95+
export const setMockRelayNumberErrorOnce = () => {
96+
mockedUseRelayNumber.mockReturnValueOnce(getErrorReturnValue());
97+
};
98+
7999
export { useRelayNumber };

frontend/__mocks__/hooks/api/runtimeData.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,24 @@ function getReturnValue(
152152
};
153153
}
154154

155+
function getErrorReturnValue(): ReturnType<typeof useRuntimeData> {
156+
return {
157+
isValidating: false,
158+
mutate: jest.fn(),
159+
data: undefined,
160+
isLoading: false,
161+
error: { some_error_key: "some_error_val" },
162+
};
163+
}
164+
155165
export const setMockRuntimeData = (runtimeData?: Partial<RuntimeData>) => {
156166
mockedUseRuntimeData.mockReturnValue(getReturnValue(runtimeData));
157167
};
158168

159169
export const setMockRuntimeDataOnce = (runtimeData?: Partial<RuntimeData>) => {
160170
mockedUseRuntimeData.mockReturnValueOnce(getReturnValue(runtimeData));
161171
};
172+
173+
export const setMockRuntimeErrorOnce = (runtimeData?: Partial<RuntimeData>) => {
174+
mockedUseRuntimeData.mockReturnValueOnce(getErrorReturnValue());
175+
};

frontend/src/components/dashboard/aliases/AliasDeletionButton.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { render, screen, within, waitFor } from "@testing-library/react";
22
import userEvent from "@testing-library/user-event";
33
import { mockConfigModule } from "../../../../__mocks__/configMock";
4+
import { mockUseL10nModule } from "../../../../__mocks__/hooks/l10n";
45
import { mockLocalizedModule } from "../../../../__mocks__/components/Localized";
56
import { getMockRandomAlias } from "../../../../__mocks__/hooks/api/aliases";
6-
import { mockUseL10nModule } from "../../../../__mocks__/hooks/l10n";
77

88
import * as aliasApi from "../../../hooks/api/aliases";
99
import { AliasDeletionButton } from "./AliasDeletionButton";

frontend/src/components/dashboard/aliases/AliasGenerationButton.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { render, screen } from "@testing-library/react";
22
import userEvent from "@testing-library/user-event";
33
import { mockConfigModule } from "../../../../__mocks__/configMock";
4+
import { mockUseL10nModule } from "../../../../__mocks__/hooks/l10n";
45
import { getMockRandomAlias } from "../../../../__mocks__/hooks/api/aliases";
56
import { getMockProfileData } from "../../../../__mocks__/hooks/api/profile";
67
import {
78
getMockRuntimeDataWithoutPremium,
89
getMockRuntimeDataWithPeriodicalPremium,
910
} from "../../../../__mocks__/hooks/api/runtimeData";
10-
import { mockUseL10nModule } from "../../../../__mocks__/hooks/l10n";
1111

1212
import { AliasGenerationButton } from "./AliasGenerationButton";
1313

frontend/src/components/dashboard/aliases/AliasList.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { render, screen } from "@testing-library/react";
33
import userEvent from "@testing-library/user-event";
44
import { mockLocalizedModule } from "../../../../__mocks__/components/Localized";
55
import { mockConfigModule } from "../../../../__mocks__/configMock";
6+
import { mockUseL10nModule } from "../../../../__mocks__/hooks/l10n";
67
import { getMockRandomAlias } from "../../../../__mocks__/hooks/api/aliases";
78
import { getMockProfileData } from "../../../../__mocks__/hooks/api/profile";
8-
import { mockUseL10nModule } from "../../../../__mocks__/hooks/l10n";
99
import * as LocalLabelsMock from "../../../../__mocks__/hooks/localLabels";
1010
import { AliasList } from "./AliasList";
1111

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@use "~@mozilla-protocol/core/protocol/css/includes/lib" as *;
2+
@use "../../styles/text";
3+
4+
.error-general {
5+
@include text-body-sm;
6+
font-family: $font-stack-firefox;
7+
display: flex;
8+
flex-direction: column;
9+
align-items: center;
10+
justify-content: center;
11+
padding: $spacing-md;
12+
border-radius: $border-radius-md;
13+
background-color: $color-white;
14+
height: 100%;
15+
vertical-align: middle;
16+
17+
h1 {
18+
@include text-title-xs;
19+
margin-bottom: $spacing-sm;
20+
}
21+
22+
p {
23+
@include text-title-3xs;
24+
}
25+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// import { ReactNode } from "react";
2+
import styles from "./ErrorGeneral.module.scss";
3+
import { useL10n } from "../../hooks/l10n";
4+
5+
export const ErrorGeneral = () => {
6+
const l10n = useL10n();
7+
const headingText = l10n.getString("error-general").split(". ")[0];
8+
const descriptionText = l10n.getString("error-general").split(". ")[1];
9+
return (
10+
<div className={styles["error-general"]}>
11+
<h1>{headingText}</h1>
12+
<p>{descriptionText}</p>
13+
</div>
14+
);
15+
};

frontend/src/components/layout/topmessage/CsatSurvey.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { render, screen } from "@testing-library/react";
22
import { mockCookiesModule } from "../../../../__mocks__/functions/cookies";
33
import { mockGetLocaleModule } from "../../../../__mocks__/functions/getLocale";
4-
import { getMockProfileData } from "../../../../__mocks__/hooks/api/profile";
54
import { mockUseL10nModule } from "../../../../__mocks__/hooks/l10n";
5+
import { getMockProfileData } from "../../../../__mocks__/hooks/api/profile";
66

77
import { CsatSurvey } from "./CsatSurvey";
88

0 commit comments

Comments
 (0)