Spaces:
Build error
Build error
| import { render, screen, waitFor } from "@testing-library/react"; | |
| import { afterEach, describe, expect, it, vi } from "vitest"; | |
| import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; | |
| import userEvent from "@testing-library/user-event"; | |
| import AppSettingsScreen from "#/routes/app-settings"; | |
| import OpenHands from "#/api/open-hands"; | |
| import { MOCK_DEFAULT_USER_SETTINGS } from "#/mocks/handlers"; | |
| import { AvailableLanguages } from "#/i18n"; | |
| import * as CaptureConsent from "#/utils/handle-capture-consent"; | |
| import * as ToastHandlers from "#/utils/custom-toast-handlers"; | |
| const renderAppSettingsScreen = () => | |
| render(<AppSettingsScreen />, { | |
| wrapper: ({ children }) => ( | |
| <QueryClientProvider client={new QueryClient()}> | |
| {children} | |
| </QueryClientProvider> | |
| ), | |
| }); | |
| describe("Content", () => { | |
| it("should render the screen", () => { | |
| renderAppSettingsScreen(); | |
| screen.getByTestId("app-settings-screen"); | |
| }); | |
| it("should render the correct default values", async () => { | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue({ | |
| ...MOCK_DEFAULT_USER_SETTINGS, | |
| language: "no", | |
| user_consents_to_analytics: true, | |
| enable_sound_notifications: true, | |
| }); | |
| renderAppSettingsScreen(); | |
| await waitFor(() => { | |
| const language = screen.getByTestId("language-input"); | |
| const analytics = screen.getByTestId("enable-analytics-switch"); | |
| const sound = screen.getByTestId("enable-sound-notifications-switch"); | |
| expect(language).toHaveValue("Norsk"); | |
| expect(analytics).toBeChecked(); | |
| expect(sound).toBeChecked(); | |
| }); | |
| }); | |
| it("should render the language options", async () => { | |
| renderAppSettingsScreen(); | |
| const language = await screen.findByTestId("language-input"); | |
| await userEvent.click(language); | |
| AvailableLanguages.forEach((lang) => { | |
| const option = screen.getByText(lang.label); | |
| expect(option).toBeInTheDocument(); | |
| }); | |
| }); | |
| }); | |
| describe("Form submission", () => { | |
| afterEach(() => { | |
| vi.clearAllMocks(); | |
| }); | |
| it("should submit the form with the correct values", async () => { | |
| const saveSettingsSpy = vi.spyOn(OpenHands, "saveSettings"); | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); | |
| renderAppSettingsScreen(); | |
| const language = await screen.findByTestId("language-input"); | |
| const analytics = await screen.findByTestId("enable-analytics-switch"); | |
| const sound = await screen.findByTestId( | |
| "enable-sound-notifications-switch", | |
| ); | |
| expect(language).toHaveValue("English"); | |
| expect(analytics).not.toBeChecked(); | |
| expect(sound).not.toBeChecked(); | |
| // change language | |
| await userEvent.click(language); | |
| const norsk = screen.getByText("Norsk"); | |
| await userEvent.click(norsk); | |
| expect(language).toHaveValue("Norsk"); | |
| // toggle options | |
| await userEvent.click(analytics); | |
| expect(analytics).toBeChecked(); | |
| await userEvent.click(sound); | |
| expect(sound).toBeChecked(); | |
| // submit the form | |
| const submit = await screen.findByTestId("submit-button"); | |
| await userEvent.click(submit); | |
| expect(saveSettingsSpy).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| language: "no", | |
| user_consents_to_analytics: true, | |
| enable_sound_notifications: true, | |
| }), | |
| ); | |
| }); | |
| it("should only enable the submit button when there are changes", async () => { | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); | |
| renderAppSettingsScreen(); | |
| const submit = await screen.findByTestId("submit-button"); | |
| expect(submit).toBeDisabled(); | |
| // Language check | |
| const language = await screen.findByTestId("language-input"); | |
| await userEvent.click(language); | |
| const norsk = screen.getByText("Norsk"); | |
| await userEvent.click(norsk); | |
| expect(submit).not.toBeDisabled(); | |
| await userEvent.click(language); | |
| const english = screen.getByText("English"); | |
| await userEvent.click(english); | |
| expect(submit).toBeDisabled(); | |
| // Analytics check | |
| const analytics = await screen.findByTestId("enable-analytics-switch"); | |
| await userEvent.click(analytics); | |
| expect(submit).not.toBeDisabled(); | |
| await userEvent.click(analytics); | |
| expect(submit).toBeDisabled(); | |
| // Sound check | |
| const sound = await screen.findByTestId( | |
| "enable-sound-notifications-switch", | |
| ); | |
| await userEvent.click(sound); | |
| expect(submit).not.toBeDisabled(); | |
| await userEvent.click(sound); | |
| expect(submit).toBeDisabled(); | |
| }); | |
| it("should call handleCaptureConsents with true when the analytics switch is toggled", async () => { | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); | |
| const handleCaptureConsentsSpy = vi.spyOn( | |
| CaptureConsent, | |
| "handleCaptureConsent", | |
| ); | |
| renderAppSettingsScreen(); | |
| const analytics = await screen.findByTestId("enable-analytics-switch"); | |
| const submit = await screen.findByTestId("submit-button"); | |
| await userEvent.click(analytics); | |
| await userEvent.click(submit); | |
| await waitFor(() => | |
| expect(handleCaptureConsentsSpy).toHaveBeenCalledWith(true), | |
| ); | |
| }); | |
| it("should call handleCaptureConsents with false when the analytics switch is toggled", async () => { | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue({ | |
| ...MOCK_DEFAULT_USER_SETTINGS, | |
| user_consents_to_analytics: true, | |
| }); | |
| const handleCaptureConsentsSpy = vi.spyOn( | |
| CaptureConsent, | |
| "handleCaptureConsent", | |
| ); | |
| renderAppSettingsScreen(); | |
| const analytics = await screen.findByTestId("enable-analytics-switch"); | |
| const submit = await screen.findByTestId("submit-button"); | |
| await userEvent.click(analytics); | |
| await userEvent.click(submit); | |
| await waitFor(() => | |
| expect(handleCaptureConsentsSpy).toHaveBeenCalledWith(false), | |
| ); | |
| }); | |
| // flaky test | |
| it.skip("should disable the button when submitting changes", async () => { | |
| renderAppSettingsScreen(); | |
| const submit = await screen.findByTestId("submit-button"); | |
| expect(submit).toBeDisabled(); | |
| const sound = await screen.findByTestId( | |
| "enable-sound-notifications-switch", | |
| ); | |
| await userEvent.click(sound); | |
| expect(submit).not.toBeDisabled(); | |
| // submit the form | |
| await userEvent.click(submit); | |
| expect(submit).toHaveTextContent("Saving..."); | |
| expect(submit).toBeDisabled(); | |
| await waitFor(() => expect(submit).toHaveTextContent("Save")); | |
| }); | |
| it("should disable the button after submitting changes", async () => { | |
| const saveSettingsSpy = vi.spyOn(OpenHands, "saveSettings"); | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); | |
| renderAppSettingsScreen(); | |
| const submit = await screen.findByTestId("submit-button"); | |
| expect(submit).toBeDisabled(); | |
| const sound = await screen.findByTestId( | |
| "enable-sound-notifications-switch", | |
| ); | |
| await userEvent.click(sound); | |
| expect(submit).not.toBeDisabled(); | |
| // submit the form | |
| await userEvent.click(submit); | |
| expect(saveSettingsSpy).toHaveBeenCalled(); | |
| await waitFor(() => expect(submit).toBeDisabled()); | |
| }); | |
| }); | |
| describe("Status toasts", () => { | |
| it("should call displaySuccessToast when the settings are saved", async () => { | |
| const saveSettingsSpy = vi.spyOn(OpenHands, "saveSettings"); | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); | |
| const displaySuccessToastSpy = vi.spyOn( | |
| ToastHandlers, | |
| "displaySuccessToast", | |
| ); | |
| renderAppSettingsScreen(); | |
| // Toggle setting to change | |
| const sound = await screen.findByTestId( | |
| "enable-sound-notifications-switch", | |
| ); | |
| await userEvent.click(sound); | |
| const submit = await screen.findByTestId("submit-button"); | |
| await userEvent.click(submit); | |
| expect(saveSettingsSpy).toHaveBeenCalled(); | |
| await waitFor(() => expect(displaySuccessToastSpy).toHaveBeenCalled()); | |
| }); | |
| it("should call displayErrorToast when the settings fail to save", async () => { | |
| const saveSettingsSpy = vi.spyOn(OpenHands, "saveSettings"); | |
| const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); | |
| getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); | |
| const displayErrorToastSpy = vi.spyOn(ToastHandlers, "displayErrorToast"); | |
| saveSettingsSpy.mockRejectedValue(new Error("Failed to save settings")); | |
| renderAppSettingsScreen(); | |
| // Toggle setting to change | |
| const sound = await screen.findByTestId( | |
| "enable-sound-notifications-switch", | |
| ); | |
| await userEvent.click(sound); | |
| const submit = await screen.findByTestId("submit-button"); | |
| await userEvent.click(submit); | |
| expect(saveSettingsSpy).toHaveBeenCalled(); | |
| expect(displayErrorToastSpy).toHaveBeenCalled(); | |
| }); | |
| }); | |