PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.3.2
Presto Player v4.3.2
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 / useEmail.spec.js
presto-player / src / admin / dashboard / hooks / test Last commit date
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 1 month 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
useEmail.spec.js
155 lines
1 import { renderHook, act } from "@testing-library/react-hooks";
2 import apiFetch from "@wordpress/api-fetch";
3 import useEmail, { EMAIL_SUBMISSIONS_PATH } from "../useEmail";
4
5 jest.mock("@wordpress/api-fetch");
6
7 const makeRow = (id, date) => ({
8 id,
9 email: `user${id}@example.com`,
10 video_title: "Video",
11 preset_name: "Default",
12 date,
13 });
14
15 // Fake of the Response object the hook gets back when apiFetch is called
16 // with `parse: false`. Returns a single page; total-pages defaults to 1.
17 const fakeResponse = (items, totalPages = 1) => ({
18 headers: { get: (name) => (name === "X-WP-TotalPages" ? String(totalPages) : null) },
19 json: async () => items,
20 });
21
22 const mockPagesOnce = (...pages) => {
23 pages.forEach((page, idx) => {
24 apiFetch.mockResolvedValueOnce(fakeResponse(page, pages.length));
25 });
26 };
27
28 beforeEach(() => {
29 apiFetch.mockReset();
30 });
31
32 describe("useEmail", () => {
33 it("fetches /email-submissions on mount and exposes raw + sorted lists", async () => {
34 mockPagesOnce([
35 makeRow(1, "2026-01-01T00:00:00"),
36 makeRow(2, "2026-03-01T00:00:00"),
37 ]);
38
39 const { result, waitForNextUpdate } = renderHook(() => useEmail());
40
41 expect(result.current.loading).toBe(true);
42 await waitForNextUpdate();
43
44 expect(apiFetch).toHaveBeenCalledWith({
45 path: `${EMAIL_SUBMISSIONS_PATH}?per_page=100&page=1`,
46 method: "GET",
47 parse: false,
48 });
49 expect(result.current.loading).toBe(false);
50 expect(result.current.rawEmails).toHaveLength(2);
51 // Default sort: date desc → newest first.
52 expect(result.current.emails.map((r) => r.id)).toEqual([2, 1]);
53 expect(result.current.sortField).toBe("date");
54 expect(result.current.sortOrder).toBe("desc");
55 });
56
57 it("walks pages reported by X-WP-TotalPages and concatenates results", async () => {
58 mockPagesOnce(
59 [makeRow(1, "2026-01-01T00:00:00")],
60 [makeRow(2, "2026-02-01T00:00:00")],
61 [makeRow(3, "2026-03-01T00:00:00")]
62 );
63
64 const { result, waitForNextUpdate } = renderHook(() => useEmail());
65 await waitForNextUpdate();
66
67 expect(apiFetch).toHaveBeenCalledTimes(3);
68 expect(result.current.rawEmails).toHaveLength(3);
69 expect(result.current.emails.map((r) => r.id)).toEqual([3, 2, 1]);
70 });
71
72 it("returns an empty list and clears loading when the API rejects", async () => {
73 // Hook logs the failure on its way to a graceful empty state — silence
74 // the expected console.error so the failure mode is the only signal.
75 const errorSpy = jest
76 .spyOn(console, "error")
77 .mockImplementation(() => {});
78 apiFetch.mockRejectedValueOnce(new Error("boom"));
79
80 const { result, waitForNextUpdate } = renderHook(() => useEmail());
81 await waitForNextUpdate();
82
83 expect(result.current.loading).toBe(false);
84 expect(result.current.emails).toEqual([]);
85 expect(result.current.rawEmails).toEqual([]);
86 expect(errorSpy).toHaveBeenCalled();
87 errorSpy.mockRestore();
88 });
89
90 it("returns an empty list when the API returns a non-array payload", async () => {
91 apiFetch.mockResolvedValueOnce(fakeResponse({ unexpected: "shape" }));
92
93 const { result, waitForNextUpdate } = renderHook(() => useEmail());
94 await waitForNextUpdate();
95
96 expect(result.current.emails).toEqual([]);
97 });
98
99 it("flips sortOrder when handleSort is called for the active field (date)", async () => {
100 mockPagesOnce([
101 makeRow(1, "2026-01-01T00:00:00"),
102 makeRow(2, "2026-03-01T00:00:00"),
103 ]);
104 const { result, waitForNextUpdate } = renderHook(() => useEmail());
105 await waitForNextUpdate();
106
107 // Currently desc; toggle → asc → oldest first.
108 act(() => {
109 result.current.handleSort("date");
110 });
111 expect(result.current.sortOrder).toBe("asc");
112 expect(result.current.emails.map((r) => r.id)).toEqual([1, 2]);
113
114 // Toggle again → desc.
115 act(() => {
116 result.current.handleSort("date");
117 });
118 expect(result.current.sortOrder).toBe("desc");
119 });
120
121 it("switching to a different sort field resets order to asc (or desc for date)", async () => {
122 mockPagesOnce([
123 makeRow(1, "2026-01-01T00:00:00"),
124 makeRow(2, "2026-03-01T00:00:00"),
125 ]);
126 const { result, waitForNextUpdate } = renderHook(() => useEmail());
127 await waitForNextUpdate();
128
129 act(() => {
130 result.current.handleSort("email");
131 });
132 expect(result.current.sortField).toBe("email");
133 expect(result.current.sortOrder).toBe("asc");
134
135 act(() => {
136 result.current.handleSort("date");
137 });
138 expect(result.current.sortField).toBe("date");
139 expect(result.current.sortOrder).toBe("desc");
140 });
141
142 it("treats missing dates as epoch 0 in the comparator", async () => {
143 mockPagesOnce([
144 { ...makeRow(1, ""), date: "" },
145 makeRow(2, "2026-01-01T00:00:00"),
146 ]);
147 const { result, waitForNextUpdate } = renderHook(() => useEmail());
148 await waitForNextUpdate();
149
150 // desc → real date first, missing-date row last.
151 expect(result.current.emails.map((r) => r.id)).toEqual([2, 1]);
152 });
153
154 });
155