Skip to content

Commit 68c4f46

Browse files
committed
fix(ui5-select): prevent crash on ArrowUp/Down when value matches no option
If select's value property is set to a string that doesn’t match any option, nothing is selected (selectedIndex = -1). When you press ArrowUp or ArrowDown, _changeSelectedItem tries to use invalid indices, which causes it to access undefined and crash at runtime. Fixes: #12093
1 parent a8e8dd1 commit 68c4f46

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,4 +1393,50 @@ describe("Select general interaction", () => {
13931393

13941394
cy.get("[ui5-select]").should("have.prop", "value", "Third");
13951395
});
1396+
1397+
it("navigates with ArrowDown when initial value does not match any option", () => {
1398+
cy.mount(
1399+
<Select id="sel-down" value="missing">
1400+
<Option value="A">A</Option>
1401+
<Option value="B">B</Option>
1402+
<Option value="C">C</Option>
1403+
</Select>
1404+
);
1405+
1406+
cy.get("#sel-down")
1407+
.should("have.attr", "value", "missing")
1408+
.find("[ui5-option][selected]")
1409+
.should("not.exist");
1410+
1411+
cy.get("#sel-down").realClick().realPress("ArrowDown");
1412+
1413+
cy.get("#sel-down")
1414+
.find("[ui5-option]")
1415+
.eq(0)
1416+
.should("have.attr", "selected");
1417+
cy.get("#sel-down").should("have.prop", "value", "A");
1418+
});
1419+
1420+
it("navigates with ArrowUp when initial value does not match any option", () => {
1421+
cy.mount(
1422+
<Select id="sel-up" value="missing">
1423+
<Option value="A">A</Option>
1424+
<Option value="B">B</Option>
1425+
<Option value="C">C</Option>
1426+
</Select>
1427+
);
1428+
1429+
cy.get("#sel-up")
1430+
.should("have.attr", "value", "missing")
1431+
.find("[ui5-option][selected]")
1432+
.should("not.exist");
1433+
1434+
cy.get("#sel-up").realClick().realPress("ArrowUp");
1435+
1436+
cy.get("#sel-up")
1437+
.find("[ui5-option]")
1438+
.eq(2)
1439+
.should("have.attr", "selected");
1440+
cy.get("#sel-up").should("have.prop", "value", "C");
1441+
});
13961442
});

packages/main/src/Select.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,15 +768,27 @@ class Select extends UI5Element implements IFormInputElement {
768768
_changeSelectedItem(oldIndex: number, newIndex: number) {
769769
const options: Array<IOption> = this.options;
770770

771+
// Normalize: first navigation with Up when nothing selected -> last item
772+
if (oldIndex === -1 && newIndex < 0 && options.length) {
773+
newIndex = options.length - 1;
774+
}
775+
776+
// Abort on invalid target
777+
if (newIndex < 0 || newIndex >= options.length) {
778+
return;
779+
}
780+
771781
const previousOption = options[oldIndex];
772782
const nextOption = options[newIndex];
773783

774784
if (previousOption === nextOption) {
775785
return;
776786
}
777787

778-
previousOption.selected = false;
779-
previousOption.focused = false;
788+
if (previousOption) {
789+
previousOption.selected = false;
790+
previousOption.focused = false;
791+
}
780792

781793
nextOption.selected = true;
782794
nextOption.focused = true;

0 commit comments

Comments
 (0)