diff --git a/packages/main/cypress/specs/ToolbarSelect.cy.tsx b/packages/main/cypress/specs/ToolbarSelect.cy.tsx
index 1c07e3644ea1..8ecb2b592624 100644
--- a/packages/main/cypress/specs/ToolbarSelect.cy.tsx
+++ b/packages/main/cypress/specs/ToolbarSelect.cy.tsx
@@ -369,7 +369,7 @@ describe("Toolbar general interaction", () => {
});
cy.get("@toolbarSelect").then($select => {
- $select.get(0).addEventListener("ui5-change", (e) => {
+ $select.get(0).addEventListener("ui5-change", (_: Event) => {
const input = document.querySelector("[data-testid='selectResult']") as HTMLInputElement;
input.value = "1";
});
@@ -400,7 +400,6 @@ describe("Toolbar general interaction", () => {
describe("value and label properties", () => {
it("Should verify the initial value of the ToolbarSelect", () => {
- // Mount the Toolbar with a ToolbarSelect component
cy.mount(
@@ -412,13 +411,16 @@ describe("Toolbar general interaction", () => {
);
- // Verify the initial value of the ToolbarSelect
- cy.get("ui5-select", { includeShadowDom: true })
- .should("have.attr", "value", "Option 2");
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(1)
+ .should("have.attr", "selected");
});
it("Should verify the label slot content", () => {
- // Mount the Toolbar with a ToolbarSelect component
cy.mount(
@@ -430,14 +432,12 @@ describe("Toolbar general interaction", () => {
);
- // Verify the label slot content
- cy.get("ui5-toolbar-select")
+ cy.get("[ui5-toolbar-select]")
.find("span[slot='label']")
.should("contain.text", "Select an Option:");
});
it("Should change the value and update the selection", () => {
- // Mount the Toolbar with a ToolbarSelect component
cy.mount(
@@ -448,20 +448,25 @@ describe("Toolbar general interaction", () => {
);
- // Change the value of the ToolbarSelect
- cy.get("ui5-select", { includeShadowDom: true })
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
.realClick()
- .find("ui5-option")
+ .find("[ui5-option]")
.contains("Option 3")
.realClick();
- // Verify the updated value of the ToolbarSelect
- cy.get("ui5-select", { includeShadowDom: true })
- .should("have.attr", "value", "Option 3");
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(2)
+ .should("have.attr", "selected");
});
it("Should handle a value with no corresponding option", () => {
- // Mount the Toolbar with a ToolbarSelect component
cy.mount(
@@ -472,13 +477,12 @@ describe("Toolbar general interaction", () => {
);
- // Verify that no option is selected when the value does not match any option
- cy.get("ui5-select", { includeShadowDom: true })
- .should("have.attr", "value", "NonExistentOption");
+ cy.get("[ui5-toolbar-select-option]").eq(0).should("not.have.attr", "selected");
+ cy.get("[ui5-toolbar-select-option]").eq(1).should("not.have.attr", "selected");
+ cy.get("[ui5-toolbar-select-option]").eq(2).should("not.have.attr", "selected");
});
it("Should update the value programmatically and reflect the selection", () => {
- // Mount the Toolbar with a ToolbarSelect component
cy.mount(
@@ -489,12 +493,15 @@ describe("Toolbar general interaction", () => {
);
- // Update the value programmatically
- cy.get("ui5-toolbar-select").invoke("attr", "value", "Option 3");
+ cy.get("[ui5-toolbar-select]").invoke("attr", "value", "Option 3");
- // Verify the updated value and selection
- cy.get("ui5-select", { includeShadowDom: true })
- .should("have.attr", "value", "Option 3");
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(2)
+ .should("have.attr", "selected");
});
});
@@ -518,7 +525,7 @@ describe("Toolbar general interaction", () => {
});
// Verify the toolbar-select is rendered inside the popover
- cy.get("ui5-toolbar-select").should("be.visible");
+ cy.get("[ui5-toolbar-select]").should("be.visible");
});
it("Should update selection when option's selected property is changed programmatically", () => {
@@ -539,8 +546,8 @@ describe("Toolbar general interaction", () => {
// Attach click handler once the button is in the DOM
cy.get("#btn").then($btn => {
$btn.get(0).addEventListener("click", () => {
- const select = document.querySelector("ui5-toolbar-select");
- const options = select?.querySelectorAll("ui5-toolbar-select-option");
+ const select = document.querySelector("[ui5-toolbar-select]");
+ const options = select?.querySelectorAll("[ui5-toolbar-select-option]");
options?.forEach(opt => {
(opt as ToolbarSelectOption).selected = false;
});
@@ -565,11 +572,16 @@ describe("Toolbar general interaction", () => {
});
// The rendered select reflects option 2 as the selected value
- cy.get("ui5-select", { includeShadowDom: true })
- .should("have.attr", "value", "2");
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(1)
+ .should("have.attr", "selected");
});
- it("Should ensure only one option is selected at any time", () => {
+ it("Should display the last selected option when multiple options are set selected", () => {
cy.mount(
<>
@@ -583,7 +595,6 @@ describe("Toolbar general interaction", () => {
>
);
- // Set up button to attempt selecting multiple options
cy.document().then(doc => {
const btn = doc.getElementById("selectMultiple");
btn?.addEventListener("click", () => {
@@ -591,20 +602,112 @@ describe("Toolbar general interaction", () => {
const opt2 = doc.getElementById("opt2") as ToolbarSelectOption;
const opt3 = doc.getElementById("opt3") as ToolbarSelectOption;
- // Try to select multiple options
opt1.selected = true;
opt2.selected = true;
- opt3.selected = true; // This should be the final selection
+ opt3.selected = true;
});
});
- // Click button to attempt multiple selections
cy.get("#selectMultiple").realClick();
- // Verify only the last option (opt3) is selected
- cy.get("[ui5-toolbar-select-option]").eq(2).should("have.attr", "selected");
+ // Inner display shows the last selected option (opt3)
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(2)
+ .should("have.attr", "selected");
+ });
+
+ it("Should clear outer selection when value is set to empty string after render", () => {
+ cy.mount(
+
+
+ Option 1
+ Option 2
+ Option 3
+
+
+ );
+
+ cy.document().then(doc => {
+ const select = doc.querySelector("[ui5-toolbar-select]") as ToolbarSelect;
+ select.value = "";
+ });
+
cy.get("[ui5-toolbar-select-option]").eq(0).should("not.have.attr", "selected");
cy.get("[ui5-toolbar-select-option]").eq(1).should("not.have.attr", "selected");
- cy.get("ui5-select", { includeShadowDom: true }).should("have.attr", "value", "3");
+ cy.get("[ui5-toolbar-select-option]").eq(2).should("not.have.attr", "selected");
+ });
+
+ it("Should not let stale _pendingValue override a later programmatic selected change", () => {
+ cy.mount(
+ <>
+
+
+ Option 1
+ Option 2
+ Option 3
+
+
+
+ >
+ );
+
+ cy.get("#prog-btn").then($btn => {
+ $btn.get(0).addEventListener("click", () => {
+ const options = document.querySelectorAll("[ui5-toolbar-select-option]");
+ options.forEach(opt => { (opt as ToolbarSelectOption).selected = false; });
+ (document.getElementById("prog-opt3") as ToolbarSelectOption).selected = true;
+ });
+ });
+
+ cy.get("#prog-btn").realClick();
+
+ cy.get("[ui5-toolbar-select-option]").eq(2).should("have.attr", "selected");
+ cy.get("[ui5-toolbar-select-option]").eq(0).should("not.have.attr", "selected");
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(2)
+ .should("have.attr", "selected");
+ });
+
+ it("Should not let _pendingValue set by value='X' override a later option.selected change before pending is cleared", () => {
+ cy.mount(
+ <>
+
+
+ Option 1
+ Option 2
+ Option 3
+
+
+
+ >
+ );
+
+ cy.get("#pending-btn").then($btn => {
+ $btn.get(0).addEventListener("click", () => {
+ const options = document.querySelectorAll("[ui5-toolbar-select-option]");
+ options.forEach(opt => { (opt as ToolbarSelectOption).selected = false; });
+ (document.getElementById("pending-opt2") as ToolbarSelectOption).selected = true;
+ });
+ });
+
+ cy.get("#pending-btn").realClick();
+
+ cy.get("[ui5-toolbar-select-option]").eq(1).should("have.attr", "selected");
+ cy.get("[ui5-toolbar-select-option]").eq(0).should("not.have.attr", "selected");
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(1)
+ .should("have.attr", "selected");
});
});
\ No newline at end of file
diff --git a/packages/main/src/ToolbarSelect.ts b/packages/main/src/ToolbarSelect.ts
index 74fde918b1ad..324ad71fdcf9 100644
--- a/packages/main/src/ToolbarSelect.ts
+++ b/packages/main/src/ToolbarSelect.ts
@@ -154,22 +154,36 @@ class ToolbarSelect extends ToolbarItemBase {
*/
@property()
set value(newValue: string) {
- if (this.select && this.select.value !== newValue) {
- this.select.value = newValue;
+ if (this.options.length) {
+ // Options are available: resolve immediately by setting selected on the matching outer option.
+ // Empty string clears all selections.
+ this.options.forEach(option => {
+ option.selected = newValue !== "" && (option.value === newValue || option.textContent?.trim() === newValue);
+ });
+ this._pendingValue = "";
+ this._hasPendingValue = false;
+ } else {
+ // Options not yet available (pre-render): stage for onBeforeRendering to resolve.
+ this._pendingValue = newValue;
+ this._hasPendingValue = true;
}
- this._value = newValue;
}
get value(): string | undefined {
- return this.select ? this.select.value : this._value;
+ const selectedOption = this.options.find(o => o.selected);
+ return selectedOption?.value || selectedOption?.textContent?.trim() || "";
}
get select(): Select | null {
return this.shadowRoot!.querySelector