Skip to content

Commit ca17793

Browse files
Merge branch 'main' into fix/UserMenuItem_subitem
2 parents c41ed82 + a904c5e commit ca17793

28 files changed

Lines changed: 957 additions & 41 deletions

packages/base/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"devDependencies": {
6565
"@custom-elements-manifest/analyzer": "^0.10.10",
6666
"@openui5/sap.ui.core": "1.146.0",
67-
"@sap-theming/theming-base-content": "11.34.1",
67+
"@sap-theming/theming-base-content": "11.35.0",
6868
"@ui5/cypress-internal": "0.1.0",
6969
"@ui5/webcomponents-tools": "2.22.0-rc.2",
7070
"clean-css": "^5.2.2",

packages/main/cypress/specs/ColorPalette.cy.tsx

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,257 @@ describe("Color Palette Item - tooltip", () => {
312312
.and("not.contain", "#d60d5a");
313313
});
314314
});
315+
316+
describe("Color Palette Item: click event", () => {
317+
it("should fire item-click event when item is clicked", () => {
318+
const clickSpy = cy.spy().as("clickSpy");
319+
const itemClickSpy = cy.spy().as("itemClickSpy");
320+
321+
cy.mount(
322+
<ColorPalette>
323+
<ColorPaletteItem id="item1" value="red" selected></ColorPaletteItem>
324+
<ColorPaletteItem id="item2" value="blue"></ColorPaletteItem>
325+
</ColorPalette>
326+
);
327+
328+
cy.get<ColorPalette>("[ui5-color-palette]")
329+
.then($el => {
330+
$el[0].addEventListener("item-click", itemClickSpy);
331+
});
332+
333+
cy.get("#item2")
334+
.then($el => {
335+
$el[0].addEventListener("click", clickSpy);
336+
});
337+
338+
cy.get("#item2")
339+
.realClick();
340+
341+
cy.get("@clickSpy")
342+
.should("have.been.calledOnce");
343+
344+
cy.get("@itemClickSpy")
345+
.should("have.been.calledOnce");
346+
});
347+
348+
it("should prevent selection when preventDefault is called", () => {
349+
cy.mount(
350+
<ColorPalette>
351+
<ColorPaletteItem id="item1" value="red"></ColorPaletteItem>
352+
<ColorPaletteItem id="item2" value="blue"></ColorPaletteItem>
353+
</ColorPalette>
354+
);
355+
356+
cy.get<ColorPalette>("[ui5-color-palette]")
357+
.then($el => {
358+
$el[0].addEventListener("item-click", cy.spy().as("itemClickSpy"));
359+
});
360+
361+
// First, select item1
362+
cy.get("#item1")
363+
.realClick();
364+
365+
cy.get("#item1")
366+
.should("have.attr", "selected");
367+
cy.get("#item2")
368+
.should("not.have.attr", "selected");
369+
370+
// Now add preventDefault to item2
371+
cy.get("#item2")
372+
.then($el => {
373+
$el[0].addEventListener("click", (e: Event) => {
374+
e.preventDefault();
375+
});
376+
});
377+
378+
// Try to click item2 with preventDefault
379+
cy.get("#item2")
380+
.realClick();
381+
382+
// Item1 should still be selected because we called preventDefault on item2
383+
cy.get("#item1")
384+
.should("have.attr", "selected");
385+
cy.get("#item2")
386+
.should("not.have.attr", "selected");
387+
388+
// The item-click event on ColorPalette should only have been called once (for item1)
389+
cy.get("@itemClickSpy")
390+
.should("have.been.calledOnce");
391+
});
392+
393+
it("should provide correct modifier keys in click event detail", () => {
394+
cy.mount(
395+
<ColorPalette>
396+
<ColorPaletteItem id="item1" value="red"></ColorPaletteItem>
397+
<ColorPaletteItem id="item2" value="blue"></ColorPaletteItem>
398+
</ColorPalette>
399+
);
400+
401+
cy.get("#item2")
402+
.then($el => {
403+
$el[0].addEventListener("click", cy.spy((e: CustomEvent) => {
404+
// Check that event detail contains item and originalEvent
405+
expect(e.detail).to.have.property("item");
406+
expect(e.detail).to.have.property("originalEvent");
407+
408+
// Check item properties
409+
expect(e.detail.item.value).to.equal("blue");
410+
411+
// Check modifier keys from originalEvent
412+
const originalEvent = e.detail.originalEvent;
413+
expect(originalEvent.altKey).to.be.false;
414+
expect(originalEvent.ctrlKey).to.be.false;
415+
expect(originalEvent.metaKey).to.be.false;
416+
expect(originalEvent.shiftKey).to.be.false;
417+
}).as("clickSpy"));
418+
});
419+
420+
cy.get("#item2")
421+
.realClick();
422+
423+
cy.get("@clickSpy")
424+
.should("have.been.calledOnce");
425+
});
426+
427+
it("should provide correct modifier keys when Ctrl is pressed", () => {
428+
let eventDetail: any;
429+
430+
cy.mount(
431+
<ColorPalette>
432+
<ColorPaletteItem id="item1" value="red"></ColorPaletteItem>
433+
<ColorPaletteItem id="item2" value="blue"></ColorPaletteItem>
434+
</ColorPalette>
435+
);
436+
437+
cy.get("#item2")
438+
.then($el => {
439+
$el[0].addEventListener("click", (e: Event) => {
440+
eventDetail = (e as CustomEvent).detail;
441+
});
442+
});
443+
444+
// Manually dispatch a MouseEvent with ctrlKey
445+
cy.get("#item2")
446+
.shadow()
447+
.find(".ui5-cp-item")
448+
.then($item => {
449+
const mouseEvent = new MouseEvent('click', {
450+
bubbles: true,
451+
cancelable: true,
452+
ctrlKey: true,
453+
altKey: false,
454+
metaKey: false,
455+
shiftKey: false
456+
});
457+
$item[0].dispatchEvent(mouseEvent);
458+
});
459+
460+
cy.then(() => eventDetail)
461+
.then((detail) => {
462+
expect(detail, "event detail should exist").to.exist;
463+
expect(detail.item.value, "item value should be blue").to.equal("blue");
464+
const originalEvent = detail.originalEvent;
465+
expect(originalEvent.ctrlKey, "ctrlKey should be true").to.be.true;
466+
expect(originalEvent.altKey, "altKey should be false").to.be.false;
467+
expect(originalEvent.metaKey, "metaKey should be false").to.be.false;
468+
expect(originalEvent.shiftKey, "shiftKey should be false").to.be.false;
469+
});
470+
});
471+
472+
it("should provide correct modifier keys when Alt is pressed", () => {
473+
cy.mount(
474+
<ColorPalette>
475+
<ColorPaletteItem id="item1" value="red"></ColorPaletteItem>
476+
<ColorPaletteItem id="item2" value="blue"></ColorPaletteItem>
477+
</ColorPalette>
478+
);
479+
480+
cy.get("#item2")
481+
.then($el => {
482+
$el[0].addEventListener("click", cy.spy((e: CustomEvent) => {
483+
const originalEvent = e.detail.originalEvent;
484+
expect(originalEvent.altKey).to.be.true;
485+
expect(originalEvent.ctrlKey).to.be.false;
486+
expect(originalEvent.metaKey).to.be.false;
487+
expect(originalEvent.shiftKey).to.be.false;
488+
}).as("clickSpyAlt"));
489+
});
490+
491+
cy.get("#item2")
492+
.realClick({ altKey: true });
493+
494+
cy.get("@clickSpyAlt")
495+
.should("have.been.calledOnce");
496+
});
497+
498+
it("should provide correct modifier keys when Shift is pressed", () => {
499+
cy.mount(
500+
<ColorPalette>
501+
<ColorPaletteItem id="item1" value="red"></ColorPaletteItem>
502+
<ColorPaletteItem id="item2" value="blue"></ColorPaletteItem>
503+
</ColorPalette>
504+
);
505+
506+
cy.get("#item2")
507+
.then($el => {
508+
$el[0].addEventListener("click", cy.spy((e: CustomEvent) => {
509+
const originalEvent = e.detail.originalEvent;
510+
expect(originalEvent.shiftKey).to.be.true;
511+
expect(originalEvent.altKey).to.be.false;
512+
expect(originalEvent.ctrlKey).to.be.false;
513+
expect(originalEvent.metaKey).to.be.false;
514+
}).as("clickSpyShift"));
515+
});
516+
517+
cy.get("#item2")
518+
.realClick({ shiftKey: true });
519+
520+
cy.get("@clickSpyShift")
521+
.should("have.been.calledOnce");
522+
});
523+
524+
it("should provide correct modifier keys when multiple modifiers are pressed", () => {
525+
let eventDetail: any;
526+
527+
cy.mount(
528+
<ColorPalette>
529+
<ColorPaletteItem id="item1" value="red"></ColorPaletteItem>
530+
<ColorPaletteItem id="item2" value="blue"></ColorPaletteItem>
531+
</ColorPalette>
532+
);
533+
534+
cy.get("#item2")
535+
.then($el => {
536+
$el[0].addEventListener("click", (e: Event) => {
537+
eventDetail = (e as CustomEvent).detail;
538+
});
539+
});
540+
541+
// Manually dispatch a MouseEvent with multiple modifier keys
542+
cy.get("#item2")
543+
.shadow()
544+
.find(".ui5-cp-item")
545+
.then($item => {
546+
const mouseEvent = new MouseEvent('click', {
547+
bubbles: true,
548+
cancelable: true,
549+
ctrlKey: true,
550+
altKey: false,
551+
metaKey: false,
552+
shiftKey: true
553+
});
554+
$item[0].dispatchEvent(mouseEvent);
555+
});
556+
557+
cy.then(() => eventDetail)
558+
.then((detail) => {
559+
expect(detail, "event detail should exist").to.exist;
560+
expect(detail.item.value, "item value should be blue").to.equal("blue");
561+
const originalEvent = detail.originalEvent;
562+
expect(originalEvent.ctrlKey, "ctrlKey should be true").to.be.true;
563+
expect(originalEvent.shiftKey, "shiftKey should be true").to.be.true;
564+
expect(originalEvent.altKey, "altKey should be false").to.be.false;
565+
expect(originalEvent.metaKey, "metaKey should be false").to.be.false;
566+
});
567+
});
568+
});

packages/main/cypress/specs/ComboBox.mobile.cy.tsx

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import ComboBox from "../../src/ComboBox.js";
22
import ComboBoxItem from "../../src/ComboBoxItem.js";
33
import ComboBoxItemGroup from "../../src/ComboBoxItemGroup.js";
44
import type ResponsivePopover from "../../src/ResponsivePopover.js";
5-
import { COMBOBOX_DIALOG_OK_BUTTON, COMBOBOX_DIALOG_CANCEL_BUTTON } from "../../src/generated/i18n/i18n-defaults.js";
5+
import { COMBOBOX_DIALOG_OK_BUTTON, COMBOBOX_DIALOG_CANCEL_BUTTON, INPUT_SUGGESTIONS_TITLE } from "../../src/generated/i18n/i18n-defaults.js";
6+
import Label from "../../src/Label.js";
67

78
describe("Basic mobile picker rendering and interaction", () => {
89
beforeEach(() => {
@@ -618,3 +619,54 @@ describe("Mobile Highlighting", () => {
618619
.should("contain.html", "<b>A</b>");
619620
});
620621
});
622+
623+
describe("Dialog header title", () => {
624+
beforeEach(() => {
625+
cy.ui5SimulateDevice("phone");
626+
});
627+
628+
it("Should display label text as dialog header title when label for is used", () => {
629+
cy.mount(
630+
<>
631+
<Label for="myCB">Country</Label>
632+
<ComboBox id="myCB">
633+
<ComboBoxItem text="Algeria" />
634+
<ComboBoxItem text="Argentina" />
635+
</ComboBox>
636+
</>
637+
);
638+
639+
cy.get("#myCB").realClick();
640+
641+
cy.get("#myCB")
642+
.shadow()
643+
.find<ResponsivePopover>("[ui5-responsive-popover]")
644+
.ui5ResponsivePopoverOpened();
645+
646+
cy.get("#myCB")
647+
.shadow()
648+
.find("[ui5-responsive-popover] .ui5-responsive-popover-header-text")
649+
.should("have.text", "Country");
650+
});
651+
652+
it("Should fallback to 'All Items' when no label is associated", () => {
653+
cy.mount(
654+
<ComboBox id="myCB">
655+
<ComboBoxItem text="Algeria" />
656+
<ComboBoxItem text="Argentina" />
657+
</ComboBox>
658+
);
659+
660+
cy.get("#myCB").realClick();
661+
662+
cy.get("#myCB")
663+
.shadow()
664+
.find<ResponsivePopover>("[ui5-responsive-popover]")
665+
.ui5ResponsivePopoverOpened();
666+
667+
cy.get("#myCB")
668+
.shadow()
669+
.find("[ui5-responsive-popover] .ui5-responsive-popover-header-text")
670+
.should("have.text", INPUT_SUGGESTIONS_TITLE.defaultText);
671+
});
672+
});

packages/main/cypress/specs/Input.mobile.cy.tsx

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import Input from "../../src/Input.js";
22
import "../../src/features/InputSuggestions.js";
33
import type ResponsivePopover from "../../src/ResponsivePopover.js";
44
import SuggestionItem from "../../src/SuggestionItem.js";
5-
import { INPUT_SUGGESTIONS_OK_BUTTON, INPUT_SUGGESTIONS_CANCEL_BUTTON } from "../../src/generated/i18n/i18n-defaults.js";
5+
import { INPUT_SUGGESTIONS_OK_BUTTON, INPUT_SUGGESTIONS_CANCEL_BUTTON, INPUT_SUGGESTIONS_TITLE } from "../../src/generated/i18n/i18n-defaults.js";
6+
import Label from "../../src/Label.js";
67

78
describe("Input on mobile device", () => {
89
beforeEach(() => {
@@ -442,3 +443,54 @@ describe("Property open", () => {
442443
.ui5ResponsivePopoverClosed();
443444
});
444445
});
446+
447+
describe("Dialog header title", () => {
448+
beforeEach(() => {
449+
cy.ui5SimulateDevice("phone");
450+
});
451+
452+
it("Should display label text as dialog header title when label for is used", () => {
453+
cy.mount(
454+
<>
455+
<Label for="myInput">Country</Label>
456+
<Input id="myInput" showSuggestions>
457+
<SuggestionItem text="Item 1" />
458+
<SuggestionItem text="Item 2" />
459+
</Input>
460+
</>
461+
);
462+
463+
cy.get("#myInput").realClick();
464+
465+
cy.get("#myInput")
466+
.shadow()
467+
.find<ResponsivePopover>("[ui5-responsive-popover]")
468+
.ui5ResponsivePopoverOpened();
469+
470+
cy.get("#myInput")
471+
.shadow()
472+
.find("[ui5-responsive-popover] .ui5-responsive-popover-header-text")
473+
.should("have.text", "Country");
474+
});
475+
476+
it("Should fallback to 'All Items' when no label is associated", () => {
477+
cy.mount(
478+
<Input id="myInput" showSuggestions>
479+
<SuggestionItem text="Item 1" />
480+
<SuggestionItem text="Item 2" />
481+
</Input>
482+
);
483+
484+
cy.get("#myInput").realClick();
485+
486+
cy.get("#myInput")
487+
.shadow()
488+
.find<ResponsivePopover>("[ui5-responsive-popover]")
489+
.ui5ResponsivePopoverOpened();
490+
491+
cy.get("#myInput")
492+
.shadow()
493+
.find("[ui5-responsive-popover] .ui5-responsive-popover-header-text")
494+
.should("have.text", INPUT_SUGGESTIONS_TITLE.defaultText);
495+
});
496+
});

0 commit comments

Comments
 (0)