PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.3.3
Presto Player v4.3.3
4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.4 4.2.3 4.2.2 4.2.0 4.2.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.12.0 1.13.0 1.14.0 1.14.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.13 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3-beta1 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.0-beta1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4
presto-player / src / admin / dashboard / hooks / test / useTopPerforming.spec.js
presto-player / src / admin / dashboard / hooks / test Last commit date
useCompleteOnboarding.spec.js 2 months ago useDateRangePicker.spec.js 3 months ago useEmail.spec.js 3 months ago useEngagementChartData.spec.js 3 months ago useLicenseSettings.spec.js 3 months ago useLink.spec.js 3 months ago useMediaDetail.spec.js 3 months ago useMediaLibrary.spec.js 3 months ago useMediaList.spec.js 2 months ago usePerformanceSettings.spec.js 3 months ago useRegisterActivePage.spec.js 3 months ago useSettingOption.spec.js 3 months ago useSimpleSettingsPage.spec.js 3 months ago useTopPerforming.spec.js 3 months ago useTopVideosPaginated.spec.js 3 months ago useUpgradeCTA.spec.js 3 months ago useUserDetail.spec.js 3 months ago
useTopPerforming.spec.js
208 lines
1 import { renderHook, act } from "@testing-library/react-hooks";
2 import apiFetch from "@wordpress/api-fetch";
3 import useTopVideosPaginated from "../useTopVideosPaginated";
4 import useTopPerforming from "../useTopPerforming";
5
6 jest.mock("@wordpress/api-fetch");
7 jest.mock("../useTopVideosPaginated", () => ({
8 __esModule: true,
9 default: jest.fn(),
10 }));
11
12 const mockMediaSetPage = jest.fn();
13
14 const mediaStub = (overrides = {}) => ({
15 topMedia: [],
16 isLoading: false,
17 error: null,
18 page: 1,
19 setPage: mockMediaSetPage,
20 pagination: { totalItems: 0, totalPages: 0 },
21 ...overrides,
22 });
23
24 const mockUsersResponse = ({ items = [], total = 0, totalPages = 0 } = {}) => ({
25 headers: {
26 get: (h) =>
27 h === "X-WP-Total"
28 ? String(total)
29 : h === "X-WP-TotalPages"
30 ? String(totalPages)
31 : null,
32 },
33 json: async () => items,
34 });
35
36 const mockUserItem = (id, name) => ({
37 user: { id, name },
38 stats: [{ data: "9 views" }, { data: "30s" }],
39 });
40
41 beforeEach(() => {
42 apiFetch.mockReset();
43 useTopVideosPaginated.mockReset();
44 mockMediaSetPage.mockReset();
45 global.window.prestoPlayer = {
46 isPremium: true,
47 api: { analyticsTopUsers: "/presto-player/v1/analytics/top-users" },
48 };
49 });
50
51 afterEach(() => {
52 delete global.window.prestoPlayer;
53 });
54
55 describe("useTopPerforming", () => {
56 describe("free tier (isPremium=false)", () => {
57 beforeEach(() => {
58 window.prestoPlayer.isPremium = false;
59 useTopVideosPaginated.mockReturnValue(mediaStub());
60 });
61
62 it("does NOT call apiFetch for users", async () => {
63 renderHook(() => useTopPerforming());
64 await act(async () => {});
65 expect(apiFetch).not.toHaveBeenCalled();
66 });
67
68 it("disables the media hook by setting enabled=false", () => {
69 renderHook(() => useTopPerforming());
70 expect(useTopVideosPaginated).toHaveBeenCalledWith(
71 expect.objectContaining({ enabled: false })
72 );
73 });
74
75 });
76
77 describe("premium tier", () => {
78 beforeEach(() => {
79 useTopVideosPaginated.mockReturnValue(mediaStub());
80 });
81
82 it("fetches users with the all-time fallback when selectedDates is empty", async () => {
83 apiFetch.mockResolvedValue(
84 mockUsersResponse({
85 items: [mockUserItem(1, "Ada"), mockUserItem(2, "Bob")],
86 total: 2,
87 totalPages: 1,
88 })
89 );
90
91 const { result, waitForNextUpdate } = renderHook(() =>
92 useTopPerforming()
93 );
94
95 await waitForNextUpdate();
96
97 expect(result.current.data.topUsers).toHaveLength(2);
98 expect(result.current.data.topUsers[0]).toMatchObject({
99 id: 1,
100 name: "Ada",
101 });
102 expect(result.current.usersPagination).toEqual({
103 totalItems: 2,
104 totalPages: 1,
105 });
106
107 // The all-time path uses start=ALL_TIME_START — the dateUtils sentinel
108 // currently in use. Easier to assert via "starts with the year 2020"
109 // than to import the constant here, since we just want to verify the
110 // hook took the fallback branch.
111 const lastCall = apiFetch.mock.calls.at(-1)[0];
112 expect(lastCall.path).toContain("start=2020-01-01");
113 expect(lastCall.path).toContain("page=1");
114 });
115
116 it("uses provided selectedDates when both ends are set", async () => {
117 apiFetch.mockResolvedValue(mockUsersResponse());
118
119 const selectedDates = {
120 from: new Date(Date.UTC(2026, 0, 5)),
121 to: new Date(Date.UTC(2026, 0, 10)),
122 };
123 renderHook(() => useTopPerforming({ selectedDates }));
124 await act(async () => {});
125
126 const lastCall = apiFetch.mock.calls.at(-1)[0];
127 expect(lastCall.path).toContain("start=2026-01-05");
128 expect(lastCall.path).toContain("end=2026-01-10");
129 });
130
131 it("respects usersPerPage in the request", async () => {
132 apiFetch.mockResolvedValue(mockUsersResponse());
133
134 renderHook(() => useTopPerforming({ usersPerPage: 7 }));
135 await act(async () => {});
136
137 const lastCall = apiFetch.mock.calls.at(-1)[0];
138 expect(lastCall.path).toContain("per_page=7");
139 });
140
141 it("setUsersPage triggers a refetch on the new page", async () => {
142 apiFetch.mockResolvedValue(mockUsersResponse());
143
144 const { result, waitForNextUpdate } = renderHook(() =>
145 useTopPerforming()
146 );
147 await waitForNextUpdate();
148
149 await act(async () => {
150 result.current.setUsersPage(3);
151 });
152
153 const lastCall = apiFetch.mock.calls.at(-1)[0];
154 expect(lastCall.path).toContain("page=3");
155 });
156
157 it("resets usersPage to 1 when selectedDates change", async () => {
158 apiFetch.mockResolvedValue(mockUsersResponse());
159
160 const { result, rerender, waitForNextUpdate } = renderHook(
161 ({ selectedDates }) => useTopPerforming({ selectedDates }),
162 {
163 initialProps: {
164 selectedDates: {
165 from: new Date(Date.UTC(2026, 0, 1)),
166 to: new Date(Date.UTC(2026, 0, 7)),
167 },
168 },
169 }
170 );
171 await waitForNextUpdate();
172
173 await act(async () => {
174 result.current.setUsersPage(2);
175 });
176 expect(result.current.usersPage).toBe(2);
177
178 await act(async () => {
179 rerender({
180 selectedDates: {
181 from: new Date(Date.UTC(2026, 1, 1)),
182 to: new Date(Date.UTC(2026, 1, 7)),
183 },
184 });
185 });
186 expect(result.current.usersPage).toBe(1);
187 });
188
189 it("surfaces non-abort fetch errors and clears the user list", async () => {
190 const errorSpy = jest
191 .spyOn(console, "error")
192 .mockImplementation(() => {});
193 apiFetch.mockRejectedValueOnce(new Error("503"));
194
195 const { result, waitForNextUpdate } = renderHook(() =>
196 useTopPerforming()
197 );
198 await waitForNextUpdate();
199
200 expect(result.current.error).toBe("503");
201 expect(result.current.data.topUsers).toEqual([]);
202 expect(errorSpy).toHaveBeenCalled();
203 errorSpy.mockRestore();
204 });
205
206 });
207 });
208