Skip to content

Commit b8f5308

Browse files
committed
fix: merging all hover test
1 parent 4ef0e13 commit b8f5308

16 files changed

Lines changed: 491 additions & 2292 deletions
Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
/**
2+
* Consolidated hover tests for all field types
3+
*
4+
* This file replaces multiple redundant test files that were testing the same scenarios
5+
* for different field types. All field types follow the same hover behavior pattern:
6+
* 1. Single field: shows outline and custom cursor with correct icon
7+
* 2. Multiple field container: shows outline and cursor on container
8+
* 3. Multiple field instance: shows outline and cursor on individual instances
9+
*
10+
* Removed redundant files:
11+
* - boolean.test.ts (only had single field test)
12+
* - date.test.ts (only had single field test)
13+
* - number.test.ts (standard pattern)
14+
* - markdown.test.ts (standard pattern)
15+
* - html-rte.test.ts (standard pattern)
16+
* - json-rte.test.ts (standard pattern)
17+
* - link.test.ts (standard pattern)
18+
* - reference.test.ts (standard pattern)
19+
* - select.test.ts (standard pattern)
20+
*
21+
* Kept separate files for unique test cases:
22+
* - file.test.ts (has URL-specific test for file.url fields)
23+
* - group.test.ts (has nested field test)
24+
* - single-line.test.ts (has title field test with specific style assertions)
25+
*/
26+
27+
import { getFieldSchemaMap } from "../../../../__test__/data/fieldSchemaMap";
28+
import { waitForHoverOutline } from "../../../../__test__/utils";
29+
import Config from "../../../../configManager/configManager";
30+
import { VisualBuilder } from "../../../index";
31+
import { FieldSchemaMap } from "../../../utils/fieldSchemaMap";
32+
import { mockDomRect } from "./mockDomRect";
33+
import { waitFor } from "@testing-library/preact";
34+
35+
vi.mock("../../../utils/visualBuilderPostMessage", async () => {
36+
const { getAllContentTypes } = await vi.importActual<
37+
typeof import("../../../../__test__/data/contentType")
38+
>("../../../../__test__/data/contentType");
39+
const contentTypes = getAllContentTypes();
40+
return {
41+
__esModule: true,
42+
default: {
43+
send: vi.fn().mockImplementation((eventName: string) => {
44+
if (eventName === "init")
45+
return Promise.resolve({
46+
contentTypes,
47+
});
48+
return Promise.resolve();
49+
}),
50+
},
51+
};
52+
});
53+
54+
// Mock waitForHoverOutline to wait for outline with optimized timeout
55+
// This speeds up tests while still ensuring the outline is actually present
56+
vi.mock("../../../../__test__/utils", async () => {
57+
const actual = await vi.importActual<
58+
typeof import("../../../../__test__/utils")
59+
>("../../../../__test__/utils");
60+
const { waitFor } = await import("@testing-library/preact");
61+
62+
return {
63+
...actual,
64+
waitForHoverOutline: vi.fn().mockImplementation(async () => {
65+
// Wait for outline with shorter timeout and faster polling for tests
66+
await waitFor(
67+
() => {
68+
const hoverOutline = document.querySelector(
69+
"[data-testid='visual-builder__hover-outline'][style]"
70+
);
71+
if (!hoverOutline) {
72+
throw new Error("Hover outline not found");
73+
}
74+
},
75+
{ timeout: 5000, interval: 50 } // Faster polling, shorter timeout for tests
76+
);
77+
}),
78+
};
79+
});
80+
81+
vi.mock("../../../../utils/index.ts", async () => {
82+
const actual = await vi.importActual("../../../../utils");
83+
return {
84+
__esModule: true,
85+
...actual,
86+
isOpenInBuilder: vi.fn().mockReturnValue(true),
87+
};
88+
});
89+
90+
global.ResizeObserver = vi.fn().mockImplementation(() => ({
91+
observe: vi.fn(),
92+
unobserve: vi.fn(),
93+
disconnect: vi.fn(),
94+
}));
95+
96+
// Field type configurations for parameterized testing
97+
// Note: Some field types (boolean, date, markdown) don't have multiple field support or have different CSLP patterns
98+
// They are only tested as single fields
99+
const SINGLE_FIELD_TYPES = [
100+
{
101+
name: "boolean",
102+
cslp: "all_fields.bltapikey.en-us.boolean",
103+
icon: "boolean",
104+
},
105+
{ name: "date", cslp: "all_fields.bltapikey.en-us.date", icon: "isodate" },
106+
{
107+
name: "markdown",
108+
cslp: "all_fields.bltapikey.en-us.markdown",
109+
icon: "markdown_rte",
110+
},
111+
] as const;
112+
113+
const MULTIPLE_FIELD_TYPES = [
114+
{
115+
name: "number",
116+
cslp: "all_fields.bltapikey.en-us.number",
117+
icon: "number",
118+
multipleCslp: "all_fields.bltapikey.en-us.number_multiple_",
119+
},
120+
{
121+
name: "html-rte",
122+
cslp: "all_fields.bltapikey.en-us.rich_text_editor",
123+
icon: "html_rte",
124+
multipleCslp: "all_fields.bltapikey.en-us.rich_text_editor_multiple_",
125+
},
126+
{
127+
name: "json-rte",
128+
cslp: "all_fields.bltapikey.en-us.json_rte",
129+
icon: "json_rte",
130+
multipleCslp:
131+
"all_fields.bltapikey.en-us.json_rich_text_editor_multiple_",
132+
},
133+
{
134+
name: "link",
135+
cslp: "all_fields.bltapikey.en-us.link",
136+
icon: "link",
137+
multipleCslp: "all_fields.bltapikey.en-us.link_multiple_",
138+
},
139+
{
140+
name: "reference",
141+
cslp: "all_fields.bltapikey.en-us.reference",
142+
icon: "reference",
143+
multipleCslp: "all_fields.bltapikey.en-us.reference_multiple_",
144+
},
145+
{
146+
name: "select",
147+
cslp: "all_fields.bltapikey.en-us.select",
148+
icon: "select",
149+
multipleCslp: "all_fields.bltapikey.en-us.select_multiple_",
150+
},
151+
{
152+
name: "single-line",
153+
cslp: "all_fields.bltapikey.en-us.single_line",
154+
icon: "singleline",
155+
multipleCslp:
156+
"all_fields.bltapikey.en-us.single_line_textbox_multiple_",
157+
},
158+
{
159+
name: "multi-line",
160+
cslp: "all_fields.bltapikey.en-us.multi_line",
161+
icon: "multiline",
162+
multipleCslp: "all_fields.bltapikey.en-us.multi_line_textbox_multiple_",
163+
},
164+
] as const;
165+
166+
describe("When an element is hovered in visual builder mode", () => {
167+
let mousemoveEvent: Event;
168+
169+
beforeAll(() => {
170+
FieldSchemaMap.setFieldSchema(
171+
"all_fields",
172+
getFieldSchemaMap().all_fields
173+
);
174+
});
175+
176+
beforeEach(() => {
177+
Config.reset();
178+
Config.set("mode", 2);
179+
mousemoveEvent = new Event("mousemove", {
180+
bubbles: true,
181+
cancelable: true,
182+
});
183+
});
184+
185+
afterEach(() => {
186+
vi.clearAllMocks();
187+
document.getElementsByTagName("html")[0].innerHTML = "";
188+
});
189+
190+
afterAll(() => {
191+
Config.reset();
192+
});
193+
194+
// Parameterized tests for single-only field types (no multiple support)
195+
describe.each(SINGLE_FIELD_TYPES)("$name field", ({ cslp, icon }) => {
196+
let fieldElement: HTMLElement;
197+
let visualBuilder: VisualBuilder;
198+
199+
beforeEach(() => {
200+
fieldElement = document.createElement("p");
201+
fieldElement.setAttribute("data-cslp", cslp);
202+
fieldElement.getBoundingClientRect = vi
203+
.fn()
204+
.mockReturnValue(mockDomRect.singleLeft());
205+
206+
document.body.appendChild(fieldElement);
207+
visualBuilder = new VisualBuilder();
208+
});
209+
210+
afterEach(() => {
211+
visualBuilder.destroy();
212+
});
213+
214+
test("should have outline and custom cursor", async () => {
215+
fieldElement.dispatchEvent(mousemoveEvent);
216+
await waitForHoverOutline();
217+
218+
const hoverOutline = document.querySelector(
219+
"[data-testid='visual-builder__hover-outline']"
220+
);
221+
expect(hoverOutline).toHaveAttribute("style");
222+
223+
// Wait for cursor icon to be set (not "loading")
224+
await waitFor(
225+
() => {
226+
const customCursor = document.querySelector(
227+
`[data-testid="visual-builder__cursor"]`
228+
);
229+
expect(customCursor).toHaveAttribute("data-icon", icon);
230+
},
231+
{ timeout: 5000, interval: 50 }
232+
);
233+
234+
const customCursor = document.querySelector(
235+
`[data-testid="visual-builder__cursor"]`
236+
);
237+
expect(customCursor).toHaveAttribute("data-icon", icon);
238+
expect(customCursor?.classList.contains("visible")).toBeTruthy();
239+
});
240+
});
241+
242+
// Parameterized tests for field types with multiple support
243+
describe.each(MULTIPLE_FIELD_TYPES)("$name field", ({ cslp, icon }) => {
244+
let fieldElement: HTMLElement;
245+
let visualBuilder: VisualBuilder;
246+
247+
beforeEach(() => {
248+
// Use div for reference, p for others
249+
fieldElement =
250+
icon === "reference"
251+
? document.createElement("div")
252+
: document.createElement("p");
253+
254+
fieldElement.setAttribute("data-cslp", cslp);
255+
fieldElement.getBoundingClientRect = vi
256+
.fn()
257+
.mockReturnValue(mockDomRect.singleLeft());
258+
259+
document.body.appendChild(fieldElement);
260+
visualBuilder = new VisualBuilder();
261+
});
262+
263+
afterEach(() => {
264+
visualBuilder.destroy();
265+
});
266+
267+
test("should have outline and custom cursor", async () => {
268+
fieldElement.dispatchEvent(mousemoveEvent);
269+
await waitForHoverOutline();
270+
271+
const hoverOutline = document.querySelector(
272+
"[data-testid='visual-builder__hover-outline']"
273+
);
274+
expect(hoverOutline).toHaveAttribute("style");
275+
276+
// Wait for cursor icon to be set (not "loading")
277+
await waitFor(
278+
() => {
279+
const customCursor = document.querySelector(
280+
`[data-testid="visual-builder__cursor"]`
281+
);
282+
expect(customCursor).toHaveAttribute("data-icon", icon);
283+
},
284+
{ timeout: 5000, interval: 50 }
285+
);
286+
287+
const customCursor = document.querySelector(
288+
`[data-testid="visual-builder__cursor"]`
289+
);
290+
expect(customCursor).toHaveAttribute("data-icon", icon);
291+
expect(customCursor?.classList.contains("visible")).toBeTruthy();
292+
});
293+
});
294+
295+
// Parameterized tests for multiple field containers (only for types that support multiple)
296+
describe.each(MULTIPLE_FIELD_TYPES)(
297+
"$name field (multiple)",
298+
({ multipleCslp, icon }) => {
299+
let container: HTMLDivElement;
300+
let firstField: HTMLElement;
301+
let secondField: HTMLElement;
302+
let visualBuilder: VisualBuilder;
303+
304+
beforeEach(() => {
305+
container = document.createElement("div");
306+
container.setAttribute("data-cslp", multipleCslp);
307+
container.getBoundingClientRect = vi
308+
.fn()
309+
.mockReturnValue(mockDomRect.singleHorizontal());
310+
311+
// Use div for reference, p for others
312+
const elementType = icon === "reference" ? "div" : "p";
313+
firstField = document.createElement(elementType);
314+
firstField.setAttribute("data-cslp", `${multipleCslp}.0`);
315+
firstField.getBoundingClientRect = vi
316+
.fn()
317+
.mockReturnValue(mockDomRect.singleLeft());
318+
319+
secondField = document.createElement(elementType);
320+
secondField.setAttribute("data-cslp", `${multipleCslp}.1`);
321+
secondField.getBoundingClientRect = vi
322+
.fn()
323+
.mockReturnValue(mockDomRect.singleRight());
324+
325+
container.appendChild(firstField);
326+
container.appendChild(secondField);
327+
document.body.appendChild(container);
328+
329+
visualBuilder = new VisualBuilder();
330+
});
331+
332+
afterEach(() => {
333+
visualBuilder.destroy();
334+
});
335+
336+
test("should have outline and custom cursor on container", async () => {
337+
container.dispatchEvent(mousemoveEvent);
338+
await waitForHoverOutline();
339+
340+
const hoverOutline = document.querySelector(
341+
"[data-testid='visual-builder__hover-outline']"
342+
);
343+
expect(hoverOutline).toHaveAttribute("style");
344+
345+
// Wait for cursor icon to be set (not "loading")
346+
await waitFor(
347+
() => {
348+
const customCursor = document.querySelector(
349+
`[data-testid="visual-builder__cursor"]`
350+
);
351+
expect(customCursor).toHaveAttribute("data-icon", icon);
352+
},
353+
{ timeout: 5000, interval: 50 }
354+
);
355+
356+
const customCursor = document.querySelector(
357+
`[data-testid="visual-builder__cursor"]`
358+
);
359+
expect(customCursor).toHaveAttribute("data-icon", icon);
360+
expect(
361+
customCursor?.classList.contains("visible")
362+
).toBeTruthy();
363+
});
364+
365+
test("should have outline and custom cursor on individual instances", async () => {
366+
firstField.dispatchEvent(mousemoveEvent);
367+
await waitForHoverOutline();
368+
369+
const hoverOutline = document.querySelector(
370+
"[data-testid='visual-builder__hover-outline']"
371+
);
372+
expect(hoverOutline).toHaveAttribute("style");
373+
374+
// Wait for cursor icon to be set (not "loading")
375+
await waitFor(
376+
() => {
377+
const customCursor = document.querySelector(
378+
`[data-testid="visual-builder__cursor"]`
379+
);
380+
expect(customCursor).toHaveAttribute("data-icon", icon);
381+
},
382+
{ timeout: 5000, interval: 50 }
383+
);
384+
385+
const customCursor = document.querySelector(
386+
`[data-testid="visual-builder__cursor"]`
387+
);
388+
expect(customCursor).toHaveAttribute("data-icon", icon);
389+
expect(
390+
customCursor?.classList.contains("visible")
391+
).toBeTruthy();
392+
}, 60000);
393+
}
394+
);
395+
});

0 commit comments

Comments
 (0)