useCompleteOnboarding.spec.js
1 month ago
useDateRangePicker.spec.js
2 months ago
useEmail.spec.js
2 months ago
useEngagementChartData.spec.js
2 months ago
useLicenseSettings.spec.js
2 months ago
useLink.spec.js
2 months ago
useMediaDetail.spec.js
2 months ago
useMediaLibrary.spec.js
2 months ago
useMediaList.spec.js
2 months ago
usePerformanceSettings.spec.js
2 months ago
useRegisterActivePage.spec.js
2 months ago
useSettingOption.spec.js
2 months ago
useSimpleSettingsPage.spec.js
2 months ago
useTopPerforming.spec.js
2 months ago
useTopVideosPaginated.spec.js
2 months ago
useUpgradeCTA.spec.js
2 months ago
useUserDetail.spec.js
2 months ago
useLicenseSettings.spec.js
134 lines
| 1 | import { renderHook, act } from "@testing-library/react-hooks"; |
| 2 | import apiFetch from "@wordpress/api-fetch"; |
| 3 | import useLicenseSettings from "../useLicenseSettings"; |
| 4 | |
| 5 | jest.mock("@wordpress/api-fetch"); |
| 6 | |
| 7 | beforeEach(() => { |
| 8 | apiFetch.mockReset(); |
| 9 | }); |
| 10 | |
| 11 | // useLicenseSettings holds a module-level `cachedStatus` that survives |
| 12 | // across tests in this file. We sequence tests so the cache evolves |
| 13 | // predictably: |
| 14 | // |
| 15 | // 1. mount-time failure → cache stays null (catch doesn't set it) |
| 16 | // 2. mount-time success → cache becomes {active:true, key:'ABC-123'} |
| 17 | // 3. cache hit on remount → asserts no second /status fetch |
| 18 | // 4. activate / deactivate flows → drive the cache via the hook's API |
| 19 | // |
| 20 | // Tests below MUST run in this order. |
| 21 | describe("useLicenseSettings", () => { |
| 22 | it("logs and clears loading when the initial /license/status fetch fails", async () => { |
| 23 | const errorSpy = jest |
| 24 | .spyOn(console, "error") |
| 25 | .mockImplementation(() => {}); |
| 26 | apiFetch.mockRejectedValueOnce(new Error("network")); |
| 27 | |
| 28 | const { result, waitForNextUpdate } = renderHook(() => |
| 29 | useLicenseSettings() |
| 30 | ); |
| 31 | await waitForNextUpdate(); |
| 32 | |
| 33 | expect(result.current.isLoading).toBe(false); |
| 34 | expect(result.current.isActive).toBe(false); |
| 35 | expect(errorSpy).toHaveBeenCalled(); |
| 36 | errorSpy.mockRestore(); |
| 37 | }); |
| 38 | |
| 39 | it("fetches /license/status on first successful mount and reflects the response", async () => { |
| 40 | apiFetch.mockResolvedValueOnce({ active: true, key: "ABC-123" }); |
| 41 | |
| 42 | const { result, waitForNextUpdate } = renderHook(() => |
| 43 | useLicenseSettings() |
| 44 | ); |
| 45 | expect(result.current.isLoading).toBe(true); |
| 46 | await waitForNextUpdate(); |
| 47 | |
| 48 | expect(apiFetch).toHaveBeenCalledWith({ |
| 49 | path: "/presto-player/v1/license/status", |
| 50 | }); |
| 51 | expect(result.current.isLoading).toBe(false); |
| 52 | expect(result.current.isActive).toBe(true); |
| 53 | expect(result.current.licenseKey).toBe("ABC-123"); |
| 54 | }); |
| 55 | |
| 56 | it("does not refetch on a remount within the same module load (cache hit)", () => { |
| 57 | // cachedStatus is now {active:true, key:'ABC-123'} from the prior test. |
| 58 | const { result } = renderHook(() => useLicenseSettings()); |
| 59 | expect(result.current.isLoading).toBe(false); |
| 60 | expect(result.current.isActive).toBe(true); |
| 61 | expect(result.current.licenseKey).toBe("ABC-123"); |
| 62 | expect(apiFetch).not.toHaveBeenCalled(); |
| 63 | }); |
| 64 | |
| 65 | describe("activate", () => { |
| 66 | it("POSTs the key, flips state, and returns the response", async () => { |
| 67 | const { result } = renderHook(() => useLicenseSettings()); |
| 68 | |
| 69 | apiFetch.mockResolvedValueOnce({ key: "NEW-KEY", message: "ok" }); |
| 70 | |
| 71 | let activateResult; |
| 72 | await act(async () => { |
| 73 | activateResult = await result.current.activate("NEW-KEY"); |
| 74 | }); |
| 75 | |
| 76 | expect(apiFetch).toHaveBeenLastCalledWith({ |
| 77 | path: "/presto-player/v1/license/activate", |
| 78 | method: "POST", |
| 79 | data: { key: "NEW-KEY" }, |
| 80 | }); |
| 81 | expect(result.current.isActive).toBe(true); |
| 82 | expect(result.current.licenseKey).toBe("NEW-KEY"); |
| 83 | expect(result.current.isActivating).toBe(false); |
| 84 | expect(activateResult).toEqual({ key: "NEW-KEY", message: "ok" }); |
| 85 | }); |
| 86 | |
| 87 | it("clears isActivating on failure and rethrows", async () => { |
| 88 | const { result } = renderHook(() => useLicenseSettings()); |
| 89 | |
| 90 | apiFetch.mockRejectedValueOnce(new Error("invalid")); |
| 91 | |
| 92 | await act(async () => { |
| 93 | await expect(result.current.activate("BAD")).rejects.toThrow( |
| 94 | "invalid" |
| 95 | ); |
| 96 | }); |
| 97 | |
| 98 | expect(result.current.isActivating).toBe(false); |
| 99 | }); |
| 100 | }); |
| 101 | |
| 102 | describe("deactivate", () => { |
| 103 | it("POSTs to /deactivate and clears state", async () => { |
| 104 | const { result } = renderHook(() => useLicenseSettings()); |
| 105 | |
| 106 | apiFetch.mockResolvedValueOnce({ ok: true }); |
| 107 | |
| 108 | await act(async () => { |
| 109 | await result.current.deactivate(); |
| 110 | }); |
| 111 | |
| 112 | expect(apiFetch).toHaveBeenLastCalledWith({ |
| 113 | path: "/presto-player/v1/license/deactivate", |
| 114 | method: "POST", |
| 115 | }); |
| 116 | expect(result.current.isActive).toBe(false); |
| 117 | expect(result.current.licenseKey).toBe(""); |
| 118 | expect(result.current.isDeactivating).toBe(false); |
| 119 | }); |
| 120 | |
| 121 | it("clears isDeactivating on failure and rethrows", async () => { |
| 122 | const { result } = renderHook(() => useLicenseSettings()); |
| 123 | |
| 124 | apiFetch.mockRejectedValueOnce(new Error("server")); |
| 125 | |
| 126 | await act(async () => { |
| 127 | await expect(result.current.deactivate()).rejects.toThrow("server"); |
| 128 | }); |
| 129 | |
| 130 | expect(result.current.isDeactivating).toBe(false); |
| 131 | }); |
| 132 | }); |
| 133 | }); |
| 134 |