From 7b15f45a6aef4bf3a11e0e5fc1f144e4a1ad4788 Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Thu, 27 Jun 2019 22:55:49 -0700 Subject: [PATCH] Allow preferences to be modified and persisted in fakeAPI mode Fixes #301 Removed the preference loading code in PreferenceSettings, as it already gets the preference data from the PreferencesContext provider. Signed-off-by: Mcat12 --- .../common/context/PreferencesContext.tsx | 19 +++++++----- .../__tests__/PreferencesContext.test.tsx | 31 +++++++++++++++++-- .../settings/PreferenceSettings.tsx | 28 +++++------------ src/setupTests.tsx | 4 ++- 4 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/components/common/context/PreferencesContext.tsx b/src/components/common/context/PreferencesContext.tsx index 617fffe..65b6576 100644 --- a/src/components/common/context/PreferencesContext.tsx +++ b/src/components/common/context/PreferencesContext.tsx @@ -11,6 +11,7 @@ import React, { ReactNode } from "react"; import { WithAPIData } from "../WithAPIData"; import api from "../../../util/api"; +import config from "../../../config"; /** * The data shared by the preferences context @@ -56,18 +57,18 @@ export const loadInitialPreferences = (): ApiPreferences => { }; /** - * The context which will be used initially, until the API responds with the - * real preferences. These preferences are loaded from cache if available. + * Load the context which will be used initially, until the API responds with + * the real preferences. These preferences are loaded from cache if available. */ -const initialContext: PreferencesContextType = { +export const loadInitialContext = (): PreferencesContextType => ({ settings: loadInitialPreferences(), refresh: () => {} -}; +}); /** * The React context which provides the preferences to consumers */ -export const PreferencesContext = React.createContext(initialContext); +export const PreferencesContext = React.createContext(loadInitialContext()); /** * Provide the web interface preferences via React context. @@ -81,9 +82,13 @@ export const PreferencesProvider = ({ children: ReactNode; }) => ( Promise.resolve(loadInitialPreferences()) + : api.getPreferences + } renderInitial={() => ( - + {children} )} diff --git a/src/components/common/context/__tests__/PreferencesContext.test.tsx b/src/components/common/context/__tests__/PreferencesContext.test.tsx index 6f01b1d..3a940fa 100644 --- a/src/components/common/context/__tests__/PreferencesContext.test.tsx +++ b/src/components/common/context/__tests__/PreferencesContext.test.tsx @@ -8,16 +8,20 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -import React from "react"; +import React, { ProviderProps } from "react"; import { defaultPreferences, loadInitialPreferences, - WEB_PREFERENCES_STORAGE_KEY, + PreferencesContextType, PreferencesProvider, - PreferencesContextType + WEB_PREFERENCES_STORAGE_KEY } from "../PreferencesContext"; import { shallow } from "enzyme"; import { WithAPIData } from "../../WithAPIData"; +import config from "../../../../config"; +import api from "../../../../util/api"; + +jest.mock("../../../../util/api"); it("loads the default preferences if none are cached", () => { const preferences = loadInitialPreferences(); @@ -59,6 +63,27 @@ it("provides the initial settings while loading", () => { expect(wrapper.props().value.settings).toEqual(expectedPreferences); }); +it("should use the cached settings instead of the API when in fakeAPI mode", async () => { + const expectedPreferences: ApiPreferences = { + language: "testLang", + layout: "boxed" + }; + + config.fakeAPI = true; + localStorage.setItem( + WEB_PREFERENCES_STORAGE_KEY, + JSON.stringify(expectedPreferences) + ); + + const wrapper = shallow( + {null} + ).dive(); + + const props = wrapper.props() as ProviderProps; + expect(props.value.settings).toEqual(expectedPreferences); + expect(api.getPreferences).not.toHaveBeenCalled(); +}); + it("caches the settings after loading and provides the new settings", () => { const expectedPreferences: ApiPreferences = { language: "testLang", diff --git a/src/components/settings/PreferenceSettings.tsx b/src/components/settings/PreferenceSettings.tsx index cc63881..7b5a75f 100644 --- a/src/components/settings/PreferenceSettings.tsx +++ b/src/components/settings/PreferenceSettings.tsx @@ -20,6 +20,7 @@ import Alert, { AlertType } from "../common/Alert"; import { Button, Col, Form, FormGroup, Input, Label } from "reactstrap"; import { PreferencesContext } from "../common/context/PreferencesContext"; import languages from "../../languages.json"; +import config from "../../config"; export interface PreferenceSettingsProps { settings: ApiPreferences; @@ -51,27 +52,9 @@ class PreferenceSettings extends Component< settings: this.props.settings }; - private loadHandler: undefined | CancelablePromise; private updateHandler: undefined | CancelablePromise; - loadPreferences = () => { - this.loadHandler = makeCancelable(api.getPreferences()); - this.loadHandler.promise - .then(res => { - this.setState({ settings: res }); - }) - .catch(ignoreCancel); - }; - - componentDidMount() { - this.loadPreferences(); - } - componentWillUnmount() { - if (this.loadHandler) { - this.loadHandler.cancel(); - } - if (this.updateHandler) { this.updateHandler.cancel(); } @@ -116,9 +99,12 @@ class PreferenceSettings extends Component< translateMessage: true }); - this.updateHandler = makeCancelable( - api.updatePreferences(this.state.settings) - ); + // Allow preference changes when using the fake API + const apiPromise = config.fakeAPI + ? Promise.resolve({ status: "success" } as ApiSuccessResponse) + : api.updatePreferences(this.state.settings); + + this.updateHandler = makeCancelable(apiPromise); this.updateHandler.promise .then(() => { this.setState({ diff --git a/src/setupTests.tsx b/src/setupTests.tsx index 1efe8e4..8392c70 100644 --- a/src/setupTests.tsx +++ b/src/setupTests.tsx @@ -15,6 +15,7 @@ import api from "./util/api"; import fetchMock from "fetch-mock"; import "jest-localstorage-mock"; import i18next from "i18next"; +import config from "./config"; // Setup enzyme configure({ adapter: new Adapter() }); @@ -35,10 +36,11 @@ jest.mock("react-i18next", () => ({ })); beforeEach(() => { - // Temporary fix to reset logged in state for each test. + // Temporary fix to reset global state for each test. // The permanent fix would be to not use a global variable, and instead give this information to components through // props. Redux would be good for this, if we want to add it to the project. api.loggedIn = false; + config.fakeAPI = false; // Clear local storage mock localStorage.clear();