Skip to content

Commit d0f7341

Browse files
committed
tech(pat-toolbar): Add/Extend tests.
1 parent 1e0aaba commit d0f7341

File tree

1 file changed

+323
-7
lines changed

1 file changed

+323
-7
lines changed

src/pat/toolbar/toolbar.test.js

Lines changed: 323 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,347 @@
1+
import { jest } from "@jest/globals";
12
import "./toolbar";
3+
import $ from "jquery";
24
import registry from "@patternslib/patternslib/src/core/registry";
35
import utils from "@patternslib/patternslib/src/core/utils";
6+
import Cookies from "js-cookie";
47

58
describe("Toolbar", function () {
9+
let original_fetch;
10+
611
beforeEach(function () {
12+
// Mock jQuery.ajax
13+
global.$ = $;
14+
$.ajax = jest.fn();
15+
16+
// Mock Cookies.set
17+
jest.spyOn(Cookies, "set");
18+
19+
// Set up portal URL on body
20+
document.body.setAttribute("data-portal-url", "http://example.com");
21+
722
document.body.innerHTML = `
8-
<div id="edit-zone">
9-
<div class="offcanvas-toggler">
10-
<a class="toggler-hover" data-bs-toggle="offcanvas" href="#edit-zone"></a>
23+
<div class="pat-toolbar">
24+
<div class="plone-toolbar-main">
25+
<button class="toolbar-collapse">Collapse</button>
26+
<button class="toolbar-expand">Expand</button>
27+
</div>
28+
<div id="collapse-personaltools">
29+
Personal Tools
1130
</div>
12-
<div class="pat-toolbar offcanvas" />
1331
</div>
1432
`;
33+
34+
this.toolbar_element = document.querySelector(".pat-toolbar");
1535
});
1636

1737
afterEach(function () {
18-
document.body.outerHTML = "";
38+
document.body.innerHTML = "";
39+
document.body.removeAttribute("data-portal-url");
40+
document.body.className = "";
41+
jest.restoreAllMocks();
1942
});
2043

2144
it("Initializes correctly", async function () {
2245
expect(document.body.querySelectorAll(".pat-toolbar.initialized").length).toBe(
23-
0
46+
0,
2447
);
2548
registry.scan(document.body);
2649
await utils.timeout(1);
2750
expect(document.body.querySelectorAll(".pat-toolbar.initialized").length).toBe(
28-
1
51+
1,
52+
);
53+
});
54+
55+
it("handles structure-url-changed event and makes correct AJAX call", async function () {
56+
// Mock successful AJAX response - just verify the call is made correctly
57+
const ajax_mock = jest.fn().mockReturnValue({
58+
done: jest.fn().mockReturnValue({ fail: jest.fn() }),
59+
});
60+
$.ajax = ajax_mock;
61+
62+
registry.scan(document.body);
63+
await utils.timeout(1);
64+
65+
// Trigger the structure-url-changed event (needs jQuery for custom events)
66+
$("body").trigger("structure-url-changed", "/new-path");
67+
68+
// Verify AJAX call was made with correct URL
69+
expect(ajax_mock).toHaveBeenCalledWith({
70+
url: "http://example.com/new-path/@@render-toolbar",
71+
});
72+
73+
// Verify the done callback was set up
74+
expect(ajax_mock().done).toHaveBeenCalled();
75+
});
76+
77+
it("handles toolbar collapse", async function () {
78+
registry.scan(document.body);
79+
await utils.timeout(1);
80+
81+
// Initially, body should not have the expanded class
82+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
83+
false,
84+
);
85+
86+
// Add the expanded class to test removal
87+
document.body.classList.add("plone-toolbar-left-expanded");
88+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
89+
true,
90+
);
91+
92+
// Click the collapse button (using native DOM click)
93+
document.querySelector(".toolbar-collapse").click();
94+
95+
// Check that the expanded class was removed
96+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
97+
false,
98+
);
99+
100+
// Check that cookie was set with expanded: false
101+
expect(Cookies.set).toHaveBeenCalledWith(
102+
"plone-toolbar",
103+
JSON.stringify({ expanded: false }),
104+
{ path: "/" },
105+
);
106+
});
107+
108+
it("handles toolbar expand", async function () {
109+
registry.scan(document.body);
110+
await utils.timeout(1);
111+
112+
// Initially, body should not have the expanded class
113+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
114+
false,
115+
);
116+
117+
// Click the expand button (using native DOM click)
118+
document.querySelector(".toolbar-expand").click();
119+
120+
// Check that the expanded class was added
121+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
122+
true,
123+
);
124+
125+
// Check that cookie was set with expanded: true
126+
expect(Cookies.set).toHaveBeenCalledWith(
127+
"plone-toolbar",
128+
JSON.stringify({ expanded: true }),
129+
{ path: "/" },
130+
);
131+
});
132+
133+
it("handles multiple collapse/expand cycles", async function () {
134+
registry.scan(document.body);
135+
await utils.timeout(1);
136+
137+
// Start collapsed
138+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
139+
false,
140+
);
141+
142+
// Expand (using native DOM click)
143+
document.querySelector(".toolbar-expand").click();
144+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
145+
true,
146+
);
147+
148+
// Collapse (using native DOM click)
149+
document.querySelector(".toolbar-collapse").click();
150+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
151+
false,
152+
);
153+
154+
// Expand again (using native DOM click)
155+
document.querySelector(".toolbar-expand").click();
156+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
157+
true,
158+
);
159+
160+
// Verify cookies were set for each action
161+
expect(Cookies.set).toHaveBeenCalledTimes(3);
162+
});
163+
164+
it("calls registry.scan on updated toolbar content", async function () {
165+
// Spy on registry.scan to verify it gets called
166+
const scan_spy = jest.spyOn(registry, "scan");
167+
168+
const ajax_mock = jest.fn().mockReturnValue({
169+
done: jest.fn((callback) => {
170+
// Simulate successful response with toolbar content
171+
callback(`
172+
<body>
173+
<div id="edit-zone">
174+
<div class="plone-toolbar-main">
175+
<div class="pat-modal">Modal Pattern</div>
176+
</div>
177+
<div id="collapse-personaltools">
178+
Personal Tools
179+
</div>
180+
</div>
181+
</body>
182+
`);
183+
return { fail: jest.fn() };
184+
}),
185+
});
186+
$.ajax = ajax_mock;
187+
188+
registry.scan(document.body);
189+
await utils.timeout(1);
190+
191+
// Reset the scan spy after initial scan
192+
scan_spy.mockClear();
193+
194+
// Trigger the structure-url-changed event (needs jQuery for custom events)
195+
$("body").trigger("structure-url-changed", "/test-path");
196+
197+
await utils.timeout(100);
198+
199+
// Verify that registry.scan was called (it should be called with the new toolbar content)
200+
expect(scan_spy).toHaveBeenCalled();
201+
});
202+
203+
it("works without data-portal-url attribute", async function () {
204+
// Remove portal URL attribute
205+
document.body.removeAttribute("data-portal-url");
206+
207+
$.ajax.mockImplementation((options) => {
208+
return {
209+
done: (callback) => {
210+
callback('<body><div id="edit-zone"></div></body>');
211+
return { fail: () => {} };
212+
},
213+
};
214+
});
215+
216+
registry.scan(document.body);
217+
await utils.timeout(1);
218+
219+
// Trigger the structure-url-changed event (needs jQuery for custom events)
220+
$("body").trigger("structure-url-changed", "/test-path");
221+
222+
// Should still make AJAX call, but with undefined portal URL
223+
expect($.ajax).toHaveBeenCalledWith({
224+
url: "undefined/test-path/@@render-toolbar",
225+
});
226+
});
227+
228+
it("handles missing toolbar elements gracefully", async function () {
229+
// Test that the pattern doesn't crash when elements are missing
230+
const ajax_mock = jest.fn().mockReturnValue({
231+
done: jest.fn((callback) => {
232+
// Simulate calling the callback with empty response
233+
callback('<body><div id="edit-zone"></div></body>');
234+
return { fail: jest.fn() };
235+
}),
236+
});
237+
$.ajax = ajax_mock;
238+
239+
registry.scan(document.body);
240+
await utils.timeout(1);
241+
242+
// Store original number of elements
243+
const original_toolbar_count =
244+
document.querySelectorAll(".plone-toolbar-main").length;
245+
const original_personal_count = document.querySelectorAll(
246+
"#collapse-personaltools",
247+
).length;
248+
249+
// Trigger the structure-url-changed event (needs jQuery for custom events)
250+
$("body").trigger("structure-url-changed", "/test-path");
251+
252+
await utils.timeout(100);
253+
254+
// Verify AJAX was called
255+
expect(ajax_mock).toHaveBeenCalled();
256+
257+
// The test should not crash - that's the main point of this test
258+
// The elements may be removed or remain, depending on jQuery's replaceWith behavior
259+
expect(true).toBe(true); // Test passes if we reach here without errors
260+
});
261+
262+
it("works with different navigation structures", async function () {
263+
// Test with different HTML structure - using buttons in a nav element instead of divs
264+
document.body.innerHTML = `
265+
<div class="pat-toolbar">
266+
<button class="toolbar-collapse">Hide Toolbar</button>
267+
<button class="toolbar-expand">Show Toolbar</button>
268+
</div>
269+
`;
270+
271+
registry.scan(document.body);
272+
await utils.timeout(1);
273+
274+
// Test expand functionality with buttons in nav structure (using native DOM click)
275+
document.querySelector(".toolbar-expand").click();
276+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
277+
true,
278+
);
279+
280+
// Test collapse functionality with native DOM click
281+
document.querySelector(".toolbar-collapse").click();
282+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
283+
false,
284+
);
285+
});
286+
});
287+
288+
describe("Toolbar - Edge Cases", function () {
289+
beforeEach(function () {
290+
// Mock Cookies.set
291+
jest.spyOn(Cookies, "set");
292+
$.ajax = jest.fn();
293+
});
294+
295+
afterEach(function () {
296+
document.body.innerHTML = "";
297+
document.body.className = "";
298+
jest.restoreAllMocks();
299+
});
300+
301+
it("handles multiple toolbar instances", async function () {
302+
document.body.innerHTML = `
303+
<div class="pat-toolbar" id="toolbar1">
304+
<button class="toolbar-expand">Expand 1</button>
305+
</div>
306+
<div class="pat-toolbar" id="toolbar2">
307+
<button class="toolbar-collapse">Collapse 2</button>
308+
</div>
309+
`;
310+
311+
registry.scan(document.body);
312+
await utils.timeout(1);
313+
314+
// Both toolbars should be initialized
315+
expect(document.querySelectorAll(".pat-toolbar.initialized").length).toBe(2);
316+
317+
// Clicks on different toolbars should both work (using native DOM click)
318+
document.querySelector("#toolbar1 .toolbar-expand").click();
319+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
320+
true,
321+
);
322+
323+
document.querySelector("#toolbar2 .toolbar-collapse").click();
324+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
325+
false,
326+
);
327+
});
328+
329+
it("handles clicks on nested elements", async function () {
330+
document.body.innerHTML = `
331+
<div class="pat-toolbar">
332+
<div class="toolbar-expand">
333+
<span class="icon">Expand</span>
334+
</div>
335+
</div>
336+
`;
337+
338+
registry.scan(document.body);
339+
await utils.timeout(1);
340+
341+
// Click on nested span should still trigger expand (using native DOM click)
342+
document.querySelector(".toolbar-expand .icon").click();
343+
expect(document.body.classList.contains("plone-toolbar-left-expanded")).toBe(
344+
true,
29345
);
30346
});
31347
});

0 commit comments

Comments
 (0)