Skip to content
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

Add AnnouncementBanner tests; Fix defaultState location #3311

Merged
merged 13 commits into from
Aug 22, 2024
Merged
3 changes: 2 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@
"banners": {
"title": "Banners",
"loginBanner": "Login Banner",
"announcementBanner": "Announcement Banner"
"announcementBanner": "Announcement Banner",
"bannerCloseButton": "Close banner"
}
},
"userSettings": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
useEffect,
useState,
} from "react";
import { useTranslation } from "react-i18next";

import { BannerType } from "api/models";
import { getBannerText } from "backend";
Expand All @@ -18,10 +19,20 @@ import { type StoreState } from "rootRedux/types";
import { Path } from "types/path";
import theme, { themeColors } from "types/theme";

enum AnnouncementBannerId {
ButtonClose = "announcement-banner-close-button",
}

export enum AnnouncementBannerTextId {
ButtonClose = "siteSettings.banners.bannerCloseButton",
}

export default function AnnouncementBanner(): ReactElement {
const [banner, setBanner] = useState<string>("");
const [margins, setMargins] = useState<CSSProperties>({});

const { t } = useTranslation();

// Adjust the margins depending on whether there is an AppBar.
const loc = useAppSelector(
(state: StoreState) => state.analyticsState.currentPage
Expand All @@ -48,7 +59,12 @@ export default function AnnouncementBanner(): ReactElement {

return banner ? (
<Toolbar style={{ ...margins, backgroundColor: themeColors.warning }}>
<IconButton onClick={closeBanner} size="large">
<IconButton
aria-label={t(AnnouncementBannerTextId.ButtonClose)}
id={AnnouncementBannerId.ButtonClose}
onClick={closeBanner}
size="large"
>
<Cancel />
</IconButton>
<Box sx={{ width: theme.spacing(2) }} />
Expand Down
73 changes: 73 additions & 0 deletions src/components/AnnouncementBanner/tests/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { act } from "react";
import { Provider } from "react-redux";
import createMockStore from "redux-mock-store";

import AnnouncementBanner, {
AnnouncementBannerTextId,
} from "components/AnnouncementBanner";
import { defaultState } from "rootRedux/types";

jest.mock("backend", () => ({
getBannerText: () => mockGetBannerText(),
}));

const mockBannerText = "I'm a banner!";
const mockGetBannerText = jest.fn();
const mockStore = createMockStore()(defaultState);

const renderAnnouncementBanner = async (bannerText?: string): Promise<void> => {
mockGetBannerText.mockResolvedValue(bannerText ?? "");
await act(async () => {
render(
<Provider store={mockStore}>
<AnnouncementBanner />
</Provider>
);
});
};

beforeEach(() => {
jest.clearAllMocks();
});

describe("AnnouncementBanner", () => {
it("doesn't load if no banner text", async () => {
await renderAnnouncementBanner();

// Confirm no banner by the absence of its close button
expect(
screen.queryByLabelText(AnnouncementBannerTextId.ButtonClose)
).toBeNull();
});

it("loads banner with text", async () => {
await renderAnnouncementBanner(mockBannerText);

// Confirm open banner by the presence of its close button and text
expect(
screen.queryByLabelText(AnnouncementBannerTextId.ButtonClose)
).not.toBeNull();
expect(screen.queryByText(mockBannerText)).not.toBeNull();
});

it("closes when button is clicked", async () => {
// Setup
const agent = userEvent.setup();
await renderAnnouncementBanner(mockBannerText);
expect(screen.queryByText(mockBannerText)).not.toBeNull();

// Click close button
const closeButton = screen.getByLabelText(
AnnouncementBannerTextId.ButtonClose
);
await agent.click(closeButton);

// Confirm closed
expect(
screen.queryByLabelText(AnnouncementBannerTextId.ButtonClose)
).toBeNull();
expect(screen.queryByText(mockBannerText)).toBeNull();
});
});
34 changes: 0 additions & 34 deletions src/components/App/DefaultState.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ReactElement, Suspense } from "react";
import { RouterProvider } from "react-router-dom";

import AnnouncementBanner from "components/AnnouncementBanner/AnnouncementBanner";
import AnnouncementBanner from "components/AnnouncementBanner";
import UpperRightToastContainer from "components/Toast/UpperRightToastContainer";
import router from "router/browserRouter";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { render } from "@testing-library/react";
import "jest-canvas-mock";
import { act } from "react";
import { Provider } from "react-redux";
import { act, create } from "react-test-renderer";
import configureMockStore from "redux-mock-store";
import thunk from "redux-thunk";

import { defaultState } from "components/App/DefaultState";
import App from "components/App/component";
import App from "components/App";
import { defaultState } from "rootRedux/types";

jest.mock("react-router-dom");

jest.mock("components/AnnouncementBanner/AnnouncementBanner", () => "div");

const createMockStore = configureMockStore([thunk]);
const mockStore = createMockStore(defaultState);

Expand All @@ -22,7 +21,7 @@ global.analytics = { track: jest.fn() } as any;
describe("App", () => {
it("renders without crashing", async () => {
await act(async () => {
create(
render(
<Provider store={mockStore}>
<App />
</Provider>
Expand Down
2 changes: 1 addition & 1 deletion src/components/AppBar/tests/AppBarComponent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { MemoryRouter } from "react-router-dom";
import { act, create } from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import { defaultState } from "components/App/DefaultState";
import AppBar from "components/AppBar/AppBarComponent";
import { defaultState } from "rootRedux/types";

jest.mock("backend", () => ({
isSiteAdmin: () => mockIsSiteAdmin(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import configureMockStore from "redux-mock-store";

import { Word } from "api/models";
import { defaultState } from "components/App/DefaultState";
import { NoteButton } from "components/Buttons";
import {
DeleteEntry,
Expand All @@ -21,6 +20,7 @@ import { EditTextDialog } from "components/Dialogs";
import AudioPlayer from "components/Pronunciations/AudioPlayer";
import AudioRecorder from "components/Pronunciations/AudioRecorder";
import PronunciationsBackend from "components/Pronunciations/PronunciationsBackend";
import { defaultState } from "rootRedux/types";
import theme from "types/theme";
import { newPronunciation, simpleWord } from "types/word";
import { newWritingSystem } from "types/writingSystem";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import configureMockStore from "redux-mock-store";

import { Gloss, SemanticDomain, Sense, Word } from "api/models";
import { defaultState } from "components/App/DefaultState";
import DataEntryTable, {
WordAccess,
addSemanticDomainToSense,
Expand All @@ -20,6 +19,7 @@ import DataEntryTable, {
updateEntryGloss,
} from "components/DataEntry/DataEntryTable";
import NewEntry from "components/DataEntry/DataEntryTable/NewEntry";
import { defaultState } from "rootRedux/types";
import { newProject } from "types/project";
import {
newSemanticDomain,
Expand Down
12 changes: 2 additions & 10 deletions src/components/Project/tests/ProjectActions.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { type PreloadedState } from "redux";

import { type Project, type Speaker } from "api/models";
import { defaultState } from "components/App/DefaultState";
import {
asyncRefreshProjectUsers,
asyncSetNewCurrentProject,
asyncUpdateCurrentProject,
clearCurrentProject,
} from "components/Project/ProjectActions";
import { defaultState as currentProjectState } from "components/Project/ProjectReduxTypes";
import { type RootState, setupStore } from "rootRedux/store";
import { setupStore } from "rootRedux/store";
import { persistedDefaultState } from "rootRedux/testTypes";
import { newProject } from "types/project";
import { newUser } from "types/user";

Expand All @@ -26,12 +24,6 @@ const mockGetAllSemDomNames = jest.fn();
const mockUpdateProject = jest.fn();
const mockProjId = "project-id";

// Preloaded values for store when testing
const persistedDefaultState: PreloadedState<RootState> = {
...defaultState,
_persist: { version: 1, rehydrated: false },
};

beforeEach(() => {
jest.resetAllMocks();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { PreloadedState } from "redux";

import { defaultState } from "components/App/DefaultState";
import {
asyncDownloadExport,
asyncExportProject,
asyncResetExport,
} from "components/ProjectExport/Redux/ExportProjectActions";
import { ExportStatus } from "components/ProjectExport/Redux/ExportProjectReduxTypes";
import { RootState, setupStore } from "rootRedux/store";
import { setupStore } from "rootRedux/store";
import { persistedDefaultState } from "rootRedux/testTypes";

jest.mock("backend", () => ({
deleteLift: jest.fn,
Expand All @@ -20,12 +18,6 @@ const mockDownloadList = jest.fn();
const mockExportLift = jest.fn();
const mockProjId = "project-id";

// Preloaded values for store when testing
const persistedDefaultState: PreloadedState<RootState> = {
...defaultState,
_persist: { version: 1, rehydrated: false },
};

describe("ExportProjectActions", () => {
describe("asyncDownloadExport", () => {
it("correctly affects state on success", async () => {
Expand Down
3 changes: 1 addition & 2 deletions src/components/Pronunciations/tests/AudioPlayer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import { Provider } from "react-redux";
import { type ReactTestRenderer, act, create } from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import { defaultState } from "components/App/DefaultState";
import AudioPlayer, {
longPressDelay,
playButtonId,
playMenuId,
} from "components/Pronunciations/AudioPlayer";
import { PronunciationsStatus } from "components/Pronunciations/Redux/PronunciationsReduxTypes";
import { type StoreState } from "rootRedux/types";
import { type StoreState, defaultState } from "rootRedux/types";
import { newPronunciation } from "types/word";

// Mock out Menu to avoid issues with setting its anchor.
Expand Down
3 changes: 1 addition & 2 deletions src/components/Pronunciations/tests/AudioRecorder.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import { Provider } from "react-redux";
import { ReactTestRenderer, act, create } from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import { defaultState } from "components/App/DefaultState";
import AudioRecorder from "components/Pronunciations/AudioRecorder";
import { recordIconId } from "components/Pronunciations/RecorderIcon";
import { PronunciationsStatus } from "components/Pronunciations/Redux/PronunciationsReduxTypes";
import { type StoreState } from "rootRedux/types";
import { type StoreState, defaultState } from "rootRedux/types";
import theme, { themeColors } from "types/theme";

let testRenderer: ReactTestRenderer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { Provider } from "react-redux";
import { ReactTestRenderer, act, create } from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import { defaultState } from "components/App/DefaultState";
import AudioPlayer from "components/Pronunciations/AudioPlayer";
import AudioRecorder from "components/Pronunciations/AudioRecorder";
import PronunciationsBackend from "components/Pronunciations/PronunciationsBackend";
import { defaultState } from "rootRedux/types";
import theme from "types/theme";
import { newPronunciation } from "types/word";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { Provider } from "react-redux";
import renderer from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import { defaultState } from "components/App/DefaultState";
import AudioPlayer from "components/Pronunciations/AudioPlayer";
import AudioRecorder from "components/Pronunciations/AudioRecorder";
import PronunciationsFrontend from "components/Pronunciations/PronunciationsFrontend";
import { defaultState } from "rootRedux/types";
import theme from "types/theme";
import { newPronunciation } from "types/word";

Expand Down
3 changes: 1 addition & 2 deletions src/components/Pronunciations/tests/RecorderIcon.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import {
} from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import { defaultState } from "components/App/DefaultState";
import RecorderIcon, {
recordButtonId,
} from "components/Pronunciations/RecorderIcon";
import { PronunciationsStatus } from "components/Pronunciations/Redux/PronunciationsReduxTypes";
import { type StoreState } from "rootRedux/types";
import { type StoreState, defaultState } from "rootRedux/types";
import theme from "types/theme";

let testRenderer: ReactTestRenderer;
Expand Down
12 changes: 2 additions & 10 deletions src/components/TreeView/Redux/tests/TreeViewActions.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { PreloadedState } from "redux";

import { defaultState } from "components/App/DefaultState";
import {
initTreeDomain,
setDomainLanguage,
traverseTree,
} from "components/TreeView/Redux/TreeViewActions";
import { RootState, setupStore } from "rootRedux/store";
import { setupStore } from "rootRedux/store";
import { persistedDefaultState } from "rootRedux/testTypes";
import {
newSemanticDomain,
newSemanticDomainTreeNode,
Expand All @@ -27,12 +25,6 @@ global.analytics = { identify: jest.fn(), track: jest.fn() } as any;
const mockId = "1.2.3";
const mockLang = "lang";

// Preloaded values for store when testing
const persistedDefaultState: PreloadedState<RootState> = {
...defaultState,
_persist: { version: 1, rehydrated: false },
};

describe("TreeViewActions", () => {
describe("setDomainLanguage", () => {
it("correctly affects state", async () => {
Expand Down
Loading
Loading