PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.3.2
Presto Player v4.3.2
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 / components / Emails / test / Utils.spec.js
presto-player / src / admin / dashboard / components / Emails / test Last commit date
Utils.spec.js 2 months ago
Utils.spec.js
233 lines
1 import { render, screen } from "@testing-library/react";
2 import {
3 formatPublishDate,
4 getBadge,
5 renderTruncated,
6 TRUNCATE_LENGTH,
7 togglePageSelection,
8 isPageFullySelected,
9 isPagePartiallySelected,
10 } from "../Utils";
11
12 describe("Emails/Utils", () => {
13 describe("formatPublishDate", () => {
14 it('returns "Just Now" for empty / null / undefined input', () => {
15 expect(formatPublishDate("")).toBe("Just Now");
16 expect(formatPublishDate(null)).toBe("Just Now");
17 expect(formatPublishDate(undefined)).toBe("Just Now");
18 });
19
20 it('returns "Just Now" for an unparseable date string', () => {
21 expect(formatPublishDate("not-a-date")).toBe("Just Now");
22 });
23
24 it("formats a valid local date as YYYY/MM/DD at h:mm am/pm", () => {
25 // Construct an unambiguous local-time date so getHours/getMinutes
26 // are independent of the host timezone.
27 const local = new Date(2026, 4, 10, 13, 5).toString();
28 expect(formatPublishDate(local)).toBe("2026/05/10 at 1:05 pm");
29 });
30
31 it("renders midnight as 12:00 am", () => {
32 const local = new Date(2026, 0, 1, 0, 0).toString();
33 expect(formatPublishDate(local)).toBe("2026/01/01 at 12:00 am");
34 });
35
36 it("renders noon as 12:00 pm", () => {
37 const local = new Date(2026, 0, 1, 12, 0).toString();
38 expect(formatPublishDate(local)).toBe("2026/01/01 at 12:00 pm");
39 });
40
41 it("zero-pads single-digit months, days, and minutes", () => {
42 const local = new Date(2026, 1, 3, 9, 7).toString();
43 expect(formatPublishDate(local)).toBe("2026/02/03 at 9:07 am");
44 });
45 });
46
47 describe("getBadge", () => {
48 const cases = [
49 ["publish", "Published"],
50 ["draft", "Draft"],
51 ["trash", "Trashed"],
52 ["pending", "Pending Review"],
53 ["private", "Private"],
54 ["future", "Scheduled"],
55 ];
56
57 it.each(cases)('renders the "%s" status as label "%s"', (status, label) => {
58 render(<>{getBadge(status)}</>);
59 expect(screen.getByText(label)).toBeInTheDocument();
60 });
61
62 it('falls back to "Unknown" for an unrecognized status', () => {
63 render(<>{getBadge("nonsense")}</>);
64 expect(screen.getByText("Unknown")).toBeInTheDocument();
65 });
66 });
67
68 describe("renderTruncated", () => {
69 it('returns "—" for empty input', () => {
70 expect(renderTruncated("")).toBe("");
71 expect(renderTruncated(null)).toBe("");
72 expect(renderTruncated(undefined)).toBe("");
73 });
74
75 it('returns "—" when input is already an em dash', () => {
76 expect(renderTruncated("")).toBe("");
77 });
78
79 // Three branches in one table:
80 // - at-or-under threshold returns the input string verbatim
81 // - over threshold (default maxLen) renders prefix + ellipsis
82 // - over a custom maxLen behaves the same with maxLen wired through
83 it.each([
84 [
85 "returns the full string when at the threshold",
86 "x".repeat(TRUNCATE_LENGTH),
87 undefined,
88 { passthrough: "x".repeat(TRUNCATE_LENGTH) },
89 ],
90 [
91 "truncates at the default threshold with an ellipsis trigger",
92 "x".repeat(TRUNCATE_LENGTH + 5),
93 undefined,
94 { prefix: "x".repeat(TRUNCATE_LENGTH - 1) },
95 ],
96 [
97 "respects a custom maxLen",
98 "hello world",
99 5,
100 { prefix: "hell", absent: "world" },
101 ],
102 ])("renderTruncated: %s", (_label, input, maxLen, asserts) => {
103 const out = maxLen === undefined
104 ? renderTruncated(input)
105 : renderTruncated(input, maxLen);
106
107 if (asserts.passthrough !== undefined) {
108 expect(out).toBe(asserts.passthrough);
109 return;
110 }
111 const { container } = render(<>{out}</>);
112 expect(container.textContent).toContain(asserts.prefix);
113 expect(container.textContent).toContain("");
114 if (asserts.absent) {
115 expect(container.textContent).not.toContain(asserts.absent);
116 }
117 });
118 });
119
120 // Helpers for the table's bulk-select header. The behavior contract:
121 // - togglePageSelection: scopes select-all to the current page; never touches
122 // ids that belong to other pages, so selections survive pagination.
123 // - isPageFullySelected: "every visible row is selected"
124 // - isPagePartiallySelected: "some, but not all, visible rows are selected"
125 // An empty current page reports as neither full nor partial — the header
126 // checkbox must not render as checked when there's nothing to act on.
127 describe("togglePageSelection", () => {
128 const page = [{ id: 1 }, { id: 2 }, { id: 3 }];
129
130 it("adds current page ids to an empty selection on check", () => {
131 expect(togglePageSelection([], page, true)).toEqual([1, 2, 3]);
132 });
133
134 it("preserves ids from other pages when checking the current page", () => {
135 // 99 and 100 are off-page selections that must survive.
136 expect(togglePageSelection([99, 100], page, true)).toEqual([
137 99,
138 100,
139 1,
140 2,
141 3,
142 ]);
143 });
144
145 it("dedupes when a current page id is already selected", () => {
146 // Asserted by content + length, not order — the helper makes no
147 // ordering guarantee and callers don't rely on one.
148 const next = togglePageSelection([2, 99], page, true);
149 expect(next).toHaveLength(4);
150 expect(next).toEqual(expect.arrayContaining([1, 2, 3, 99]));
151 });
152
153 it("removes only current page ids on uncheck", () => {
154 // Off-page ids (99) stay; on-page ids (1, 3) are stripped.
155 expect(togglePageSelection([1, 3, 99], page, false)).toEqual([99]);
156 });
157
158 it("is a no-op uncheck when nothing on the current page was selected", () => {
159 expect(togglePageSelection([99], page, false)).toEqual([99]);
160 });
161
162 it("handles a null/undefined prev selection", () => {
163 expect(togglePageSelection(null, page, true)).toEqual([1, 2, 3]);
164 expect(togglePageSelection(undefined, page, false)).toEqual([]);
165 });
166
167 it("handles an empty / missing page", () => {
168 expect(togglePageSelection([99], [], true)).toEqual([99]);
169 expect(togglePageSelection([99], undefined, false)).toEqual([99]);
170 });
171 });
172
173 describe("isPageFullySelected", () => {
174 const page = [{ id: 1 }, { id: 2 }, { id: 3 }];
175
176 it("is true when every page item is in the selection", () => {
177 expect(isPageFullySelected(page, [1, 2, 3])).toBe(true);
178 });
179
180 it("is true when the selection is a superset of the page", () => {
181 // Off-page selections (99) shouldn't block "fully selected" for this page.
182 expect(isPageFullySelected(page, [1, 2, 3, 99])).toBe(true);
183 });
184
185 it("is false when one page item is missing from the selection", () => {
186 expect(isPageFullySelected(page, [1, 3])).toBe(false);
187 });
188
189 it("is false when the selection is empty", () => {
190 expect(isPageFullySelected(page, [])).toBe(false);
191 });
192
193 it("is false for an empty / missing page (nothing on screen to be 'fully selected')", () => {
194 expect(isPageFullySelected([], [1, 2, 3])).toBe(false);
195 expect(isPageFullySelected(undefined, [1, 2, 3])).toBe(false);
196 });
197
198 it("tolerates a null/undefined selection", () => {
199 expect(isPageFullySelected(page, null)).toBe(false);
200 expect(isPageFullySelected(page, undefined)).toBe(false);
201 });
202 });
203
204 describe("isPagePartiallySelected", () => {
205 const page = [{ id: 1 }, { id: 2 }, { id: 3 }];
206
207 it("is true when some — but not all — page items are selected", () => {
208 expect(isPagePartiallySelected(page, [1])).toBe(true);
209 expect(isPagePartiallySelected(page, [2, 3])).toBe(true);
210 });
211
212 it("is false when no page items are selected (even if off-page items are)", () => {
213 expect(isPagePartiallySelected(page, [])).toBe(false);
214 expect(isPagePartiallySelected(page, [99])).toBe(false);
215 });
216
217 it("is false when every page item is selected (that's full, not partial)", () => {
218 expect(isPagePartiallySelected(page, [1, 2, 3])).toBe(false);
219 expect(isPagePartiallySelected(page, [1, 2, 3, 99])).toBe(false);
220 });
221
222 it("is false for an empty / missing page", () => {
223 expect(isPagePartiallySelected([], [1])).toBe(false);
224 expect(isPagePartiallySelected(undefined, [1])).toBe(false);
225 });
226
227 it("tolerates a null/undefined selection", () => {
228 expect(isPagePartiallySelected(page, null)).toBe(false);
229 expect(isPagePartiallySelected(page, undefined)).toBe(false);
230 });
231 });
232 });
233