import React from "react"; import { Text } from "react-native"; import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils"; import { subscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor"; jest.useFakeTimers({ legacyFakeTimers: true }); // `isOnline` (@applicaster/quick-brick-core/App/NetworkStatusProvider/utils) // only treats connectionInfo as "ready" when it has NetInfoState-shaped // isConnected/isInternetReachable/details fields, so the mock has to mirror // that shape for online/offline to actually be distinguishable. let mockConnectionStatus = false; jest.mock("@applicaster/zapp-react-native-utils/reactHooks/connection", () => { return { ...jest.requireActual( "@applicaster/zapp-react-native-utils/reactHooks/connection" ), useConnectionInfo: jest.fn(() => ({ details: {}, isConnected: mockConnectionStatus, isInternetReachable: mockConnectionStatus, })), }; }); jest.mock("@applicaster/zapp-react-native-redux", () => ({ ...jest.requireActual("@applicaster/zapp-react-native-redux"), usePlugins: () => [ { name: "offline experience", identifier: "offline-experience", type: "general", module: { useOfflineExperienceConfiguration: () => ({ configurationFields: {}, localizations: { offline_toast_message: "No internet connection", online_toast_message: "You are back online", }, }), }, }, ], })); jest.mock("react-native-safe-area-context", () => ({ ...jest.requireActual("react-native-safe-area-context"), useSafeAreaInsets: () => ({ top: 44 }), })); describe("OfflineHandler", () => { const { OfflineHandler } = require("../"); beforeEach(() => { mockConnectionStatus = false; }); it("renders its children without wrapping them in a notification view", () => { const { toJSON } = renderWithProviders( child content ); expect(toJSON()).toMatchSnapshot(); }); it("emits a showToast event on mount when the device starts offline", () => { mockConnectionStatus = false; const handleShowToast = jest.fn(); const unsubscribe = subscriberFor("showToast", handleShowToast); renderWithProviders(); expect(handleShowToast).toHaveBeenCalledWith( expect.objectContaining({ id: "offline-status", message: "No internet connection", timeout: 5000, }), // the shared event bus appends a dispose fn as the last handler arg expect.any(Function) ); unsubscribe(); }); it("does not emit a showToast event on mount when the device starts online", () => { mockConnectionStatus = true; const handleShowToast = jest.fn(); const unsubscribe = subscriberFor("showToast", handleShowToast); renderWithProviders(); expect(handleShowToast).not.toHaveBeenCalled(); unsubscribe(); }); it("emits a showToast event when the device comes back online", () => { mockConnectionStatus = false; const handleShowToast = jest.fn(); const unsubscribe = subscriberFor("showToast", handleShowToast); const { rerender } = renderWithProviders(); // ignore the offline toast emitted on mount; we only care about the // offline -> online transition here handleShowToast.mockClear(); mockConnectionStatus = true; rerender(); expect(handleShowToast).toHaveBeenCalledWith( expect.objectContaining({ id: "offline-status", message: "You are back online", timeout: 2000, }), // the shared event bus appends a dispose fn as the last handler arg expect.any(Function) ); unsubscribe(); }); });