Skip to content

Commit c3b050d

Browse files
committed
chore: add unit tests
1 parent b888971 commit c3b050d

2 files changed

Lines changed: 365 additions & 17 deletions

File tree

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
import ListItemCustom from "../../src/ListItemCustom.js";
2+
import List from "../../src/List.js";
3+
import Button from "../../src/Button.js";
4+
import CheckBox from "../../src/CheckBox.js";
5+
6+
describe("ListItemCustom - _onfocusin and _onfocusout Tests", () => {
7+
describe("With pure HTML elements", () => {
8+
it("should update invisible text content on focusin and clear on focusout", () => {
9+
// Mount ListItemCustom with pure HTML elements
10+
cy.mount(
11+
<List>
12+
<ListItemCustom id="li-custom-html">
13+
<div>Test Content</div>
14+
<span>Additional Text</span>
15+
</ListItemCustom>
16+
</List>
17+
);
18+
19+
// Store the component ID for accessing the invisible text span
20+
cy.get("#li-custom-html").invoke("prop", "_id").as("itemId");
21+
22+
// Initially, the invisible text content should be empty
23+
cy.get("@itemId").then(itemId => {
24+
cy.get("#li-custom-html")
25+
.shadow()
26+
.find(`#${itemId}-invisibleTextContent`)
27+
.should("have.text", "");
28+
});
29+
30+
// Focus the list item
31+
cy.get("#li-custom-html").click();
32+
33+
// After focus, invisible text content should be populated
34+
cy.get("@itemId").then(itemId => {
35+
cy.get("#li-custom-html")
36+
.shadow()
37+
.find(`#${itemId}-invisibleTextContent`)
38+
.should("have.text", "List Item Test Content Additional Text");
39+
40+
// Check that aria-labelledby on the internal li element includes the invisibleTextContent span id
41+
cy.get("#li-custom-html")
42+
.shadow()
43+
.find("li[part='native-li']")
44+
.should("have.attr", "aria-labelledby")
45+
.and("include", `${itemId}-invisibleTextContent`);
46+
});
47+
48+
// Remove focus
49+
cy.focused().blur();
50+
51+
// After blur, invisible text content should be cleared
52+
cy.get("@itemId").then(itemId => {
53+
cy.get("#li-custom-html")
54+
.shadow()
55+
.find(`#${itemId}-invisibleTextContent`)
56+
.should("have.text", "");
57+
});
58+
});
59+
60+
it("should process text content from HTML elements for accessibility", () => {
61+
// Mount ListItemCustom with specific text content we can test for
62+
cy.mount(
63+
<List>
64+
<ListItemCustom id="li-custom-html-content">
65+
<div>Primary Content</div>
66+
<span>Secondary Information</span>
67+
<p>Paragraph text</p>
68+
</ListItemCustom>
69+
</List>
70+
);
71+
72+
// Store the component ID
73+
cy.get("#li-custom-html-content").invoke("prop", "_id").as("itemId");
74+
75+
// Focus the list item
76+
cy.get("#li-custom-html-content").click();
77+
78+
// Verify text content is processed and included in the invisible text
79+
cy.get("@itemId").then(itemId => {
80+
cy.get("#li-custom-html-content")
81+
.shadow()
82+
.find(`#${itemId}-invisibleTextContent`)
83+
.should("have.text", "List Item Primary Content Secondary Information Paragraph text");
84+
85+
// Check that aria-labelledby on the internal li element includes the invisibleTextContent span id
86+
cy.get("#li-custom-html-content")
87+
.shadow()
88+
.find("li[part='native-li']")
89+
.should("have.attr", "aria-labelledby")
90+
.and("include", `${itemId}-invisibleTextContent`);
91+
});
92+
});
93+
});
94+
95+
describe("With UI5 components", () => {
96+
it("should update invisible text content on focusin and clear on focusout with UI5 components", () => {
97+
// Mount ListItemCustom with UI5 components
98+
cy.mount(
99+
<List>
100+
<ListItemCustom id="li-custom-ui5">
101+
<Button id="test-button">Click me</Button>
102+
<CheckBox id="test-checkbox" text="Check option" required/>
103+
</ListItemCustom>
104+
</List>
105+
);
106+
107+
// Store the component ID
108+
cy.get("#li-custom-ui5").invoke("prop", "_id").as("itemId");
109+
110+
// Initially, the invisible text content should be empty
111+
cy.get("@itemId").then(itemId => {
112+
cy.get("#li-custom-ui5")
113+
.shadow()
114+
.find(`#${itemId}-invisibleTextContent`)
115+
.should("have.text", "");
116+
});
117+
118+
// Focus the list item
119+
cy.get("#li-custom-ui5").click();
120+
121+
// After focus, invisible text content should be populated
122+
cy.get("@itemId").then(itemId => {
123+
cy.get("#li-custom-ui5")
124+
.shadow()
125+
.find(`#${itemId}-invisibleTextContent`)
126+
.should("have.text", "List Item Click me Button Check option Checkbox Not checked required");
127+
128+
// Check that aria-labelledby on the internal li element includes the invisibleTextContent span id
129+
cy.get("#li-custom-ui5")
130+
.shadow()
131+
.find("li[part='native-li']")
132+
.should("have.attr", "aria-labelledby")
133+
.and("include", `${itemId}-invisibleTextContent`);
134+
});
135+
136+
// Remove focus
137+
cy.focused().blur();
138+
139+
// After blur, invisible text content should be cleared
140+
cy.get("@itemId").then(itemId => {
141+
cy.get("#li-custom-ui5")
142+
.shadow()
143+
.find(`#${itemId}-invisibleTextContent`)
144+
.should("have.text", "");
145+
});
146+
});
147+
148+
it("should handle focus changes between list item and UI5 components", () => {
149+
// Mount ListItemCustom with UI5 components
150+
cy.mount(
151+
<List>
152+
<ListItemCustom id="li-custom-ui5-focus">
153+
<Button id="test-focus-button">Click Me</Button>
154+
<CheckBox id="test-focus-checkbox" text="Check Option" />
155+
</ListItemCustom>
156+
</List>
157+
);
158+
159+
// Store the component ID
160+
cy.get("#li-custom-ui5-focus").invoke("prop", "_id").as("itemId");
161+
162+
// Click the list item first to get focus
163+
cy.get("#li-custom-ui5-focus").click();
164+
165+
// Verify invisible text is populated
166+
cy.get("@itemId").then(itemId => {
167+
cy.get("#li-custom-ui5-focus")
168+
.shadow()
169+
.find(`#${itemId}-invisibleTextContent`)
170+
.should("have.text", "List Item Click Me Button Check Option Checkbox Not checked");
171+
172+
// Check that aria-labelledby on the internal li element includes the invisibleTextContent span id
173+
cy.get("#li-custom-ui5-focus")
174+
.shadow()
175+
.find("li[part='native-li']")
176+
.should("have.attr", "aria-labelledby")
177+
.and("include", `${itemId}-invisibleTextContent`);
178+
});
179+
180+
// Now click the button - this shouldn't trigger focusout on the list item
181+
// as it's a child element
182+
cy.get("#test-focus-button").click();
183+
184+
// Verify invisible text is still populated (list item should maintain focus state)
185+
cy.get("@itemId").then(itemId => {
186+
cy.get("#li-custom-ui5-focus")
187+
.shadow()
188+
.find(`#${itemId}-invisibleTextContent`)
189+
.should("have.text", "List Item Click Me Button Check Option Checkbox Not checked");
190+
});
191+
192+
// Click outside the list to truly remove focus
193+
cy.get("body").click({ force: true });
194+
195+
// Now invisible text should be cleared
196+
cy.get("@itemId").then(itemId => {
197+
cy.get("#li-custom-ui5-focus")
198+
.shadow()
199+
.find(`#${itemId}-invisibleTextContent`)
200+
.should("have.text", "");
201+
});
202+
});
203+
});
204+
205+
describe("With mixed elements and nesting", () => {
206+
it("should process nested elements for accessibility", () => {
207+
// Mount ListItemCustom with nested elements
208+
cy.mount(
209+
<List>
210+
<ListItemCustom id="li-custom-nested">
211+
<div className="container">
212+
<span>Container Text</span>
213+
<div className="nested-container">
214+
<Button id="nested-button">Nested Button</Button>
215+
</div>
216+
</div>
217+
<p>Paragraph outside container</p>
218+
</ListItemCustom>
219+
</List>
220+
);
221+
222+
// Store the component ID
223+
cy.get("#li-custom-nested").invoke("prop", "_id").as("itemId");
224+
225+
// Focus the list item
226+
cy.get("#li-custom-nested").click();
227+
228+
// Verify text content is processed and included in the invisible text
229+
cy.get("@itemId").then(itemId => {
230+
cy.get("#li-custom-nested")
231+
.shadow()
232+
.find(`#${itemId}-invisibleTextContent`)
233+
.should("have.text", "List Item Container Text Nested Button Button Paragraph outside container");
234+
235+
// Check that aria-labelledby on the internal li element includes the invisibleTextContent span id
236+
cy.get("#li-custom-nested")
237+
.shadow()
238+
.find("li[part='native-li']")
239+
.should("have.attr", "aria-labelledby")
240+
.and("include", `${itemId}-invisibleTextContent`);
241+
});
242+
});
243+
244+
it("should handle deep nesting of elements", () => {
245+
// Mount ListItemCustom with deeply nested elements
246+
cy.mount(
247+
<List>
248+
<ListItemCustom id="li-custom-deep-nested">
249+
<div className="level1">
250+
<div className="level2">
251+
<div className="level3">
252+
<Button id="deep-nested-button">Deeply Nested Button</Button>
253+
</div>
254+
<span className="level2-span">Level 2 Text</span>
255+
</div>
256+
<CheckBox id="nested-checkbox" text="Nested" />
257+
</div>
258+
</ListItemCustom>
259+
</List>
260+
);
261+
262+
// Store the component ID
263+
cy.get("#li-custom-deep-nested").invoke("prop", "_id").as("itemId");
264+
265+
// Focus the list item
266+
cy.get("#li-custom-deep-nested").click();
267+
268+
// Verify all nested content is processed
269+
cy.get("@itemId").then(itemId => {
270+
cy.get("#li-custom-deep-nested")
271+
.shadow()
272+
.find(`#${itemId}-invisibleTextContent`)
273+
.should("have.text", "List Item Deeply Nested Button Button Level 2 Text Nested Checkbox Not checked");
274+
275+
// Check that aria-labelledby on the internal li element includes the invisibleTextContent span id
276+
cy.get("#li-custom-deep-nested")
277+
.shadow()
278+
.find("li[part='native-li']")
279+
.should("have.attr", "aria-labelledby")
280+
.and("include", `${itemId}-invisibleTextContent`);
281+
});
282+
283+
// Remove focus
284+
cy.focused().blur();
285+
286+
// After blur, invisible text content should be cleared
287+
cy.get("@itemId").then(itemId => {
288+
cy.get("#li-custom-deep-nested")
289+
.shadow()
290+
.find(`#${itemId}-invisibleTextContent`)
291+
.should("have.text", "");
292+
});
293+
});
294+
});
295+
296+
describe("Edge cases", () => {
297+
it("should handle empty list item content", () => {
298+
cy.mount(
299+
<List>
300+
<ListItemCustom id="li-custom-empty"></ListItemCustom>
301+
</List>
302+
);
303+
304+
// Store the component ID
305+
cy.get("#li-custom-empty").invoke("prop", "_id").as("itemId");
306+
307+
// Focus the list item
308+
cy.get("#li-custom-empty").click();
309+
310+
// Should still have basic announcement text
311+
cy.get("@itemId").then(itemId => {
312+
cy.get("#li-custom-empty")
313+
.shadow()
314+
.find(`#${itemId}-invisibleTextContent`)
315+
.should("have.text", "List Item");
316+
317+
// Check that aria-labelledby on the internal li element includes the invisibleTextContent span id
318+
cy.get("#li-custom-empty")
319+
.shadow()
320+
.find("li[part='native-li']")
321+
.should("have.attr", "aria-labelledby")
322+
.and("include", `${itemId}-invisibleTextContent`);
323+
});
324+
});
325+
326+
it("should handle list item with accessibleName", () => {
327+
cy.mount(
328+
<List>
329+
<ListItemCustom
330+
id="li-custom-accessible-name"
331+
accessibleName="Accessible Name Test"
332+
>
333+
<div>This content should not be announced</div>
334+
</ListItemCustom>
335+
</List>
336+
);
337+
338+
// Check that aria-labelledBy on the internal li element doesn't include the ID of the invisibleTextContent span
339+
cy.get("#li-custom-accessible-name").invoke("prop", "_id").then(itemId => {
340+
cy.get("#li-custom-accessible-name")
341+
.shadow()
342+
.find("li[part='native-li']")
343+
.invoke("attr", "aria-labelledby")
344+
.should("not.include", `${itemId}-invisibleTextContent`);
345+
});
346+
});
347+
});
348+
});

0 commit comments

Comments
 (0)