diff --git a/.eslintrc.js b/.eslintrc.js index 7e52c7daf82..15dd4c30a55 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -134,7 +134,14 @@ module.exports = { importNames: ["pot"], message: 'Importing { pot } from "@pagopa/ts-commons" is not allowed. Use \'import * as pot from "@pagopa/ts-commons/lib/pot"\' instead.', } - ], + ], + patterns: [ + { + group: ["**/config"], + importNames: ["privacyUrl"], + message: 'Importing "privacyUrl" from "config.ts" module is restricted. Please use "tosConfigSelector" to obtain it instead.' + } + ] } ] }, diff --git a/ts/features/messages/saga/__test__/handleLoadMessageData.test.ts b/ts/features/messages/saga/__test__/handleLoadMessageData.test.ts index 0680dc58818..f4a8bacf8b2 100644 --- a/ts/features/messages/saga/__test__/handleLoadMessageData.test.ts +++ b/ts/features/messages/saga/__test__/handleLoadMessageData.test.ts @@ -19,13 +19,14 @@ import { ThirdPartyMessageWithContent } from "../../../../../definitions/backend import { thirdPartyFromIdSelector } from "../../store/reducers/thirdPartyById"; import { TagEnum } from "../../../../../definitions/backend/MessageCategoryPN"; import { isPnEnabledSelector } from "../../../../store/reducers/backendStatus"; -import * as config from "../../../../config"; import { isLoadingOrUpdatingInbox } from "../../store/reducers/allPaginated"; import { ThirdPartyMessage } from "../../../../../definitions/backend/ThirdPartyMessage"; import { ThirdPartyAttachment } from "../../../../../definitions/backend/ThirdPartyAttachment"; -// eslint-disable-next-line functional/immutable-data -Object.defineProperty(config, "euCovidCertificateEnabled", { value: true }); +jest.mock("../../../../config.ts", () => ({ + ...jest.requireActual("../../../../config.ts"), + euCovidCertificateEnabled: true +})); describe("getPaginatedMessage", () => { it("when no paginated message is in store, it should dispatch a loadMessageById.request and retrieve its result from the store if it succeeds", () => { diff --git a/ts/features/tos/store/selectors/index.ts b/ts/features/tos/store/selectors/index.ts index 5be70b6eea4..823ebb6689b 100644 --- a/ts/features/tos/store/selectors/index.ts +++ b/ts/features/tos/store/selectors/index.ts @@ -2,12 +2,13 @@ import { createSelector } from "reselect"; import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/lib/Option"; import { TosConfig } from "../../../../../definitions/content/TosConfig"; +// eslint-disable-next-line no-restricted-imports import { privacyUrl } from "../../../../config"; import { backendStatusSelector } from "../../../../store/reducers/backendStatus"; const DEFAULT_TOS_CONFIG: TosConfig = { tos_url: privacyUrl, - tos_version: 4.8 + tos_version: 4.9 }; export const tosConfigSelector = createSelector( diff --git a/ts/features/wallet/onboarding/paypal/screen/__mocks__/psp.ts b/ts/features/wallet/onboarding/paypal/screen/__mocks__/psp.ts index f25ff3e30ca..402236e1c69 100644 --- a/ts/features/wallet/onboarding/paypal/screen/__mocks__/psp.ts +++ b/ts/features/wallet/onboarding/paypal/screen/__mocks__/psp.ts @@ -1,6 +1,7 @@ import { NonNegativeNumber } from "@pagopa/ts-commons/lib/numbers"; import { IOPayPalPsp } from "../../types"; -import { privacyUrl } from "../../../../../../config"; + +const mockPrivacyUrl = "https://io.italia.it/app-content/tos_privacy.html"; export const pspList: ReadonlyArray = [ { @@ -8,13 +9,13 @@ export const pspList: ReadonlyArray = [ logoUrl: "https://paytipper.com/wp-content/uploads/2021/02/logo.png", name: "PayTipper", fee: 100 as NonNegativeNumber, - privacyUrl + privacyUrl: mockPrivacyUrl }, { id: "2", logoUrl: "https://www.dropbox.com/s/smk5cyxx1qevn6a/mat_bank.png?dl=1", name: "Mat Bank", fee: 50 as NonNegativeNumber, - privacyUrl + privacyUrl: mockPrivacyUrl } ]; diff --git a/ts/features/wallet/onboarding/paypal/screen/__tests__/PspRadioItem.test.tsx b/ts/features/wallet/onboarding/paypal/screen/__tests__/PspRadioItem.test.tsx index 3dcb98bc703..790e4ae8fd3 100644 --- a/ts/features/wallet/onboarding/paypal/screen/__tests__/PspRadioItem.test.tsx +++ b/ts/features/wallet/onboarding/paypal/screen/__tests__/PspRadioItem.test.tsx @@ -2,7 +2,6 @@ import { NonNegativeNumber } from "@pagopa/ts-commons/lib/numbers"; import { render } from "@testing-library/react-native"; import React from "react"; import { PspRadioItem } from "../../components/PspRadioItem"; -import { privacyUrl } from "../../../../../../config"; import { IOPayPalPsp } from "../../types"; jest.mock("react-native-safe-area-context", () => ({ @@ -11,12 +10,14 @@ jest.mock("react-native-safe-area-context", () => ({ .mockReturnValue({ top: 20, left: 0, right: 0, bottom: 0 }) })); +const mockPrivacyUrl = "https://io.italia.it/app-content/tos_privacy.html"; + const payPalPsp: IOPayPalPsp = { id: "1", logoUrl: "https://paytipper.com/wp-content/uploads/2021/02/logo.png", name: "PayTipper", fee: 100 as NonNegativeNumber, - privacyUrl + privacyUrl: mockPrivacyUrl }; describe("PspRadioItem", () => { diff --git a/ts/screens/authentication/LandingScreen.tsx b/ts/screens/authentication/LandingScreen.tsx index 648f0e0d1f4..4a4c010e77a 100644 --- a/ts/screens/authentication/LandingScreen.tsx +++ b/ts/screens/authentication/LandingScreen.tsx @@ -22,7 +22,6 @@ import LoadingSpinnerOverlay from "../../components/LoadingSpinnerOverlay"; import SectionStatusComponent from "../../components/SectionStatus"; import { IOStyles } from "../../components/core/variables/IOStyles"; import { ContextualHelpPropsMarkdown } from "../../components/screens/BaseScreenComponent"; -import { privacyUrl } from "../../config"; import { isCieLoginUatEnabledSelector } from "../../features/cieLogin/store/selectors"; import { cieFlowForDevServerEnabled } from "../../features/cieLogin/utils"; import { @@ -45,6 +44,7 @@ import { useOnFirstRender } from "../../utils/hooks/useOnFirstRender"; import { openWebUrl } from "../../utils/url"; import { useHeaderSecondLevel } from "../../hooks/useHeaderSecondLevel"; import { setAccessibilityFocus } from "../../utils/accessibility"; +import { tosConfigSelector } from "../../features/tos/store/selectors"; import { trackCieLoginSelected, trackMethodInfo, @@ -71,6 +71,9 @@ export const LandingScreen = () => { const accessibilityFirstFocuseViewRef = React.useRef(null); const insets = useSafeAreaInsets(); + const tosConfig = useIOSelector(tosConfigSelector); + const privacyUrl = tosConfig.tos_url; + const [isRootedOrJailbroken, setIsRootedOrJailbroken] = React.useState< O.Option >(O.none); @@ -185,7 +188,7 @@ export const LandingScreen = () => { const navigateToPrivacyUrl = React.useCallback(() => { trackMethodInfo(); openWebUrl(privacyUrl); - }, []); + }, [privacyUrl]); const navigateToCieUatSelectionScreen = React.useCallback(() => { if (isCieSupported()) { diff --git a/ts/screens/onboarding/__tests__/OnboardingTosScreen.test.tsx b/ts/screens/onboarding/__tests__/OnboardingTosScreen.test.tsx index c793f0a265b..ebaf2d0425d 100644 --- a/ts/screens/onboarding/__tests__/OnboardingTosScreen.test.tsx +++ b/ts/screens/onboarding/__tests__/OnboardingTosScreen.test.tsx @@ -8,7 +8,6 @@ import I18n from "../../../i18n"; // WebViewErrorEvent, // WebViewNavigationEvent // } from "react-native-webview/lib/WebViewTypes"; -import * as config from "../../../config"; import { appReducer } from "../../../store/reducers"; import { applicationChangeState } from "../../../store/actions/application"; import { GlobalState } from "../../../store/reducers/types"; @@ -20,29 +19,16 @@ import { renderScreenWithNavigationStoreContext } from "../../../utils/testWrapp import OnboardingTosScreen from "../OnboardingTosScreen"; import { ServicesPreferencesModeEnum } from "../../../../definitions/backend/ServicesPreferencesMode"; -const CurrentTestZendeskEnabled = true; const CurrentTestToSVersion = 2.0; -const zendeskEnabledDefaultValue = config.zendeskEnabled; - // Restore defineProperty beforeAll(() => { jest.resetAllMocks(); jest.mock("./../../../config"); - // This can be replaced by jest.replaceProperty if we update jest to 29.4+ - // eslint-disable-next-line functional/immutable-data - Object.defineProperty(config, "zendeskEnabled", { - value: CurrentTestZendeskEnabled - }); }); afterAll(() => { jest.resetAllMocks(); - // This can be removed if we update jest to 29.4+ and switch to jest.replaceProperty - // eslint-disable-next-line functional/immutable-data - Object.defineProperty(config, "zendeskEnabled", { - value: zendeskEnabledDefaultValue - }); }); describe("TosScreen", () => { diff --git a/ts/screens/profile/TosScreen.tsx b/ts/screens/profile/TosScreen.tsx index dce586f0175..9c567986c87 100644 --- a/ts/screens/profile/TosScreen.tsx +++ b/ts/screens/profile/TosScreen.tsx @@ -8,11 +8,12 @@ import { View } from "react-native"; import LoadingSpinnerOverlay from "../../components/LoadingSpinnerOverlay"; import { ContextualHelpPropsMarkdown } from "../../components/screens/BaseScreenComponent"; import TosWebviewComponent from "../../components/TosWebviewComponent"; -import { privacyUrl } from "../../config"; import { useOnFirstRender } from "../../utils/hooks/useOnFirstRender"; import { getFlowType } from "../../utils/analytics"; import { useHeaderSecondLevel } from "../../hooks/useHeaderSecondLevel"; import I18n from "../../i18n"; +import { useIOSelector } from "../../store/hooks"; +import { tosConfigSelector } from "../../features/tos/store/selectors"; import { trackTosScreen } from "./analytics"; const contextualHelpMarkdown: ContextualHelpPropsMarkdown = { @@ -26,6 +27,9 @@ const contextualHelpMarkdown: ContextualHelpPropsMarkdown = { const TosScreen = () => { const [isLoading, setIsLoading] = useState(true); + const tosConfig = useIOSelector(tosConfigSelector); + const privacyUrl = tosConfig.tos_url; + const flow = getFlowType(false, false); useOnFirstRender(() => { diff --git a/ts/screens/profile/__test__/TosScreen.test.tsx b/ts/screens/profile/__test__/TosScreen.test.tsx index 9c8754391e9..71a7c1ea2e6 100644 --- a/ts/screens/profile/__test__/TosScreen.test.tsx +++ b/ts/screens/profile/__test__/TosScreen.test.tsx @@ -8,7 +8,6 @@ import I18n from "../../../i18n"; // WebViewErrorEvent, // WebViewNavigationEvent // } from "react-native-webview/lib/WebViewTypes"; -import * as config from "../../../config"; import { appReducer } from "../../../store/reducers"; import { applicationChangeState } from "../../../store/actions/application"; import { GlobalState } from "../../../store/reducers/types"; @@ -18,29 +17,16 @@ import ROUTES from "../../../navigation/routes"; import { renderScreenWithNavigationStoreContext } from "../../../utils/testWrapper"; import TosScreen from "../TosScreen"; -const CurrentTestZendeskEnabled = true; const CurrentTestToSVersion = 2.0; -const zendeskEnabledDefaultValue = config.zendeskEnabled; - // Restore defineProperty beforeAll(() => { jest.resetAllMocks(); jest.mock("./../../../config"); - // This can be replaced by jest.replaceProperty if we update jest to 29.4+ - // eslint-disable-next-line functional/immutable-data - Object.defineProperty(config, "zendeskEnabled", { - value: CurrentTestZendeskEnabled - }); }); afterAll(() => { jest.resetAllMocks(); - // This can be removed if we update jest to 29.4+ and switch to jest.replaceProperty - // eslint-disable-next-line functional/immutable-data - Object.defineProperty(config, "zendeskEnabled", { - value: zendeskEnabledDefaultValue - }); }); describe("TosScreen", () => { @@ -64,14 +50,10 @@ describe("TosScreen", () => { expect(helpButtonRTI).toBeDefined(); }); }); - describe("When rendering the screen", () => { - it("The title should have a specific text", () => { - const renderAPI = commonSetup(); - const textRTI = renderAPI.queryByText( - I18n.t("profile.main.privacy.title") - ); - expect(textRTI).toBeDefined(); - }); + it("The title should have a specific text", () => { + const renderAPI = commonSetup(); + const textRTI = renderAPI.queryByText(I18n.t("profile.main.privacy.title")); + expect(textRTI).toBeDefined(); }); describe("When rendering the screen initially", () => { it("There should be the loading spinner overlay without the cancel button", async () => { diff --git a/ts/screens/profile/components/ShareDataComponent/index.tsx b/ts/screens/profile/components/ShareDataComponent/index.tsx index 57321527441..3e4b0ed6831 100644 --- a/ts/screens/profile/components/ShareDataComponent/index.tsx +++ b/ts/screens/profile/components/ShareDataComponent/index.tsx @@ -2,10 +2,11 @@ import { VSpacer } from "@pagopa/io-app-design-system"; import React, { memo } from "react"; import { Body } from "../../../../components/core/typography/Body"; import { Link } from "../../../../components/core/typography/Link"; -import { privacyUrl } from "../../../../config"; import I18n from "../../../../i18n"; import { openWebUrl } from "../../../../utils/url"; import { TrackingInfo } from "../../analytics/mixpanel/mixpanelAnalytics"; +import { useIOSelector } from "../../../../store/hooks"; +import { tosConfigSelector } from "../../../../features/tos/store/selectors"; import { AnalyticsFeatureInfo, FeatureProps, @@ -14,6 +15,9 @@ import { } from "./ShareDataFeatureInfos"; export const ShareDataComponent = memo(({ trackAction }: FeatureProps) => { + const tosConfig = useIOSelector(tosConfigSelector); + const privacyUrl = tosConfig.tos_url; + const handleOnPress = () => { trackAction(TrackingInfo.TOS); openWebUrl(privacyUrl); diff --git a/ts/screens/profile/components/__test__/ShareDataComponent.test.tsx b/ts/screens/profile/components/__test__/ShareDataComponent.test.tsx index f6149f81463..07eab2f7838 100644 --- a/ts/screens/profile/components/__test__/ShareDataComponent.test.tsx +++ b/ts/screens/profile/components/__test__/ShareDataComponent.test.tsx @@ -1,8 +1,13 @@ -import { fireEvent, render } from "@testing-library/react-native"; +import { fireEvent } from "@testing-library/react-native"; import React from "react"; +import { createStore } from "redux"; import { openWebUrl } from "../../../../utils/url"; import { ShareDataComponent } from "../ShareDataComponent"; import I18n from "../../../../i18n"; +import { renderScreenWithNavigationStoreContext } from "../../../../utils/testWrapper"; +import { GlobalState } from "../../../../store/reducers/types"; +import { appReducer } from "../../../../store/reducers"; +import { applicationChangeState } from "../../../../store/actions/application"; const mockPresentFn = jest.fn(); const mockTrackInfo = jest.fn(); @@ -76,5 +81,11 @@ describe("Test ShareDataComponent", () => { }); }); +const globalState = appReducer(undefined, applicationChangeState("active")); const renderComponent = () => - render(); + renderScreenWithNavigationStoreContext( + () => , + "DUMMY", + {}, + createStore(appReducer, globalState as any) + ); diff --git a/ts/utils/login.ts b/ts/utils/login.ts index 829a6940a60..3cbc9758438 100644 --- a/ts/utils/login.ts +++ b/ts/utils/login.ts @@ -2,9 +2,9 @@ import { WebViewNavigation } from "react-native-webview/lib/WebViewTypes"; import URLParse from "url-parse"; import * as O from "fp-ts/lib/Option"; import * as E from "fp-ts/lib/Either"; -import * as config from "../config"; import { SessionToken } from "../types/SessionToken"; import { trackLoginSpidError } from "../screens/authentication/analytics/spidAnalytics"; +import { apiUrlPrefix, spidRelayState } from "../config"; import { isStringNullyOrEmpty } from "./strings"; /** * Helper functions for handling the SPID login flow through a webview. @@ -76,7 +76,7 @@ export const extractLoginResult = (url: string): LoginResult | undefined => { /** for a given idp id get the relative login uri */ export const getIdpLoginUri = (idpId: string, level: number) => - `${config.apiUrlPrefix}/login?authLevel=SpidL${level}&entityID=${idpId}&RelayState=${config.spidRelayState}`; + `${apiUrlPrefix}/login?authLevel=SpidL${level}&entityID=${idpId}&RelayState=${spidRelayState}`; /** * Extract the login result from the given url.