Repository: Sage/carbon (ts)

Issue:
Incorrect behaviour when a `MultiSelect` has multiple options with the same label
### Description

When a `MultiSelect` contains multiple options in which some of them share identical text, it causes undesired behaviour. See the below video for an example of this. 

https://github.com/user-attachments/assets/1b9e2ed8-f787-43d5-8b07-99ce087e491c



### Reproduction

https://stackblitz.com/edit/parsium-carbon-starter-elineo?file=src%2FApp.tsx

### Steps to reproduce

1. Create a `MultiSelect` component
2. Add `Option` children to this component, in which at least 2 contain duplicated text, and at least 1 contains non-duplicated text
3. Click the non-duplicated option, then the following 2 duplicated options
4. Try to delete the non-duplicated option

### JIRA ticket numbers (Sage only)

_No response_

### Suggested solution

_No response_

### Carbon version

141.0.1

### Design tokens version

_No response_

### Relevant browsers

Chrome

### Relevant OSs

MacOS

### Additional context

_No response_

### Confidentiality

- [X] I confirm there is no confidential or commercially sensitive information included.

Pull request description:
fix(multi-select): ensure unique keys when options passed object values with duplicate text property FE-6718
fix #6843

### Proposed behaviour

<!--
A clear and concise description of what changes this PR makes. If applicable, include any UI screenshots to help explain your request. If you are a Sage contributor, please DO NOT share any commercially sensitive information, such as UI screenshots or code from Sage products.
-->
Ensures that no duplicate keys are generated when options are passed `value` as an object and contain duplicate `text` property values

https://github.com/user-attachments/assets/82ac2421-548a-42fb-9ea0-d09277be835a


### Current behaviour

<!--
A clear and concise description of the behaviour before this change. If applicable, include any UI screenshots to help explain your request. If you are a Sage contributor, please DO NOT share any commercially sensitive information, such as UI screenshots or code from Sage products.
-->
When using object as value and duplicate text property values it generates duplicate keys and when user tries to delete the unique Pill it does not delete and replaces text with duplicate string etc

https://github.com/user-attachments/assets/1b9e2ed8-f787-43d5-8b07-99ce087e491c

### Checklist

<!-- Each PR should include the following -->

- [x] Commits follow our style guide
- [x] Related issues linked in commit messages if required
- [x] Screenshots are included in the PR if useful
- [x] Playwright automation tests added or updated if required
- [x] Storybook added or updated if required

#### QA

- [ ] Tested in provided StackBlitz sandbox/Storybook
- [ ] Add new Playwright test coverage if required
- [ ] Carbon implementation matches Design System/designs
- [ ] UI Tests GitHub check reviewed if required

### Additional context

<!-- Add any other context or links about the pull request here. -->

### Testing instructions

`Options with same name` test story added for testing

Patch:
diff --git a/src/components/select/multi-select/multi-select.component.tsx b/src/components/select/multi-select/multi-select.component.tsx
index d786bc6f2..35602a6d9 100644
--- a/src/components/select/multi-select/multi-select.component.tsx
+++ b/src/components/select/multi-select/multi-select.component.tsx
@@ -28,8 +28,6 @@ import Logger from "../../../__internal__/utils/logger";
 import useStableCallback from "../../../hooks/__internal__/useStableCallback";
 import useFormSpacing from "../../../hooks/__internal__/useFormSpacing";
 import useInputAccessibility from "../../../hooks/__internal__/useInputAccessibility/useInputAccessibility";
-import { OptionProps } from "../option";
-import { OptionRowProps } from "../option-row";
 import { CustomSelectChangeEvent } from "../simple-select";
 
 let deprecateUncontrolledWarnTriggered = false;
@@ -345,6 +343,7 @@ export const MultiSelect = React.forwardRef(
 
     const mapValuesToPills = useMemo(() => {
       const canDelete = !disabled && !readOnly;
+      let matchingOptionValue: string;
 
       if (!actualValue?.length) {
         return "";
@@ -364,6 +363,11 @@ export const MultiSelect = React.forwardRef(
 
         /* istanbul ignore else */
         if (React.isValidElement(matchingOption)) {
+          matchingOptionValue =
+            matchingOption?.props.value?.value !== undefined
+              ? matchingOption?.props.value?.value
+              : matchingOption?.props.value;
+
           pillProps = {
             title: matchingOption.props.text,
             fill: matchingOption.props.fill,
@@ -373,10 +377,7 @@ export const MultiSelect = React.forwardRef(
 
         const title = pillProps.title || /* istanbul ignore next */ "";
         const key =
-          title +
-          ((React.isValidElement(matchingOption) &&
-            (matchingOption.props as OptionProps | OptionRowProps).value) ||
-            /* istanbul ignore next */ index);
+          title + matchingOptionValue || /* istanbul ignore next */ index;
 
         return (
           <StyledSelectPillContainer key={key}>
diff --git a/src/components/select/multi-select/multi-select.pw.tsx b/src/components/select/multi-select/multi-select.pw.tsx
index e44ed30b6..c363f7425 100644
--- a/src/components/select/multi-select/multi-select.pw.tsx
+++ b/src/components/select/multi-select/multi-select.pw.tsx
@@ -17,6 +17,7 @@ import {
   MultiSelectErrorOnChangeNewValidation,
   SelectionConfirmed,
   MultiSelectWithDisabledOption,
+  OptionsWithSameName,
 } from "../../../../src/components/select/multi-select/components.test-pw";
 import {
   commonDataElementInputPreview,
@@ -1130,6 +1131,26 @@ test.describe("MultiSelect component", () => {
     await expect(selectInput(page)).toHaveCSS("border-radius", "4px");
     await expect(selectListWrapper(page)).toHaveCSS("border-radius", "4px");
   });
+
+  test("should delete options with when user clicks the close icon within a pill and there are options with same text", async ({
+    mount,
+    page,
+  }) => {
+    await mount(<OptionsWithSameName />);
+    await dropdownButton(page).click();
+
+    await selectOption(page, 2).click();
+    await selectOption(page, 0).click();
+    await selectOption(page, 1).click();
+
+    await expect(multiSelectPillByText(page, "Blue")).toHaveCount(1);
+    await expect(multiSelectPillByText(page, "Black")).toHaveCount(2);
+
+    await pillCloseIcon(page).nth(0).click();
+
+    await expect(multiSelectPillByText(page, "Blue")).toHaveCount(0);
+    await expect(multiSelectPillByText(page, "Black")).toHaveCount(2);
+  });
 });
 
 test.describe("Check events for MultiSelect component", () => {


Test patch:
diff --git a/src/components/select/multi-select/components.test-pw.tsx b/src/components/select/multi-select/components.test-pw.tsx
index 6a3b14972..95d9a050c 100644
--- a/src/components/select/multi-select/components.test-pw.tsx
+++ b/src/components/select/multi-select/components.test-pw.tsx
@@ -523,3 +523,33 @@ export const MultiSelectWithDisabledOption = () => {
     </>
   );
 };
+
+const optionListValues = [
+  {
+    id: "Amber",
+    value: 1,
+    text: "Black",
+  },
+  {
+    id: "Black",
+    value: 2,
+    text: "Black",
+  },
+  {
+    id: "Blue",
+    value: 3,
+    text: "Blue",
+  },
+];
+
+export const OptionsWithSameName = () => (
+  <MultiSelect
+    name="multi-options-with-same-name"
+    id="multi-options-with-same-name"
+    label="multi options with same name"
+  >
+    {optionListValues.map((option) => (
+      <Option key={option.id} text={option.text} value={option} />
+    ))}
+  </MultiSelect>
+);
diff --git a/src/components/select/multi-select/multi-select-test.stories.tsx b/src/components/select/multi-select/multi-select-test.stories.tsx
index 8b5e5fabb..8c8a9fcf8 100644
--- a/src/components/select/multi-select/multi-select-test.stories.tsx
+++ b/src/components/select/multi-select/multi-select-test.stories.tsx
@@ -565,3 +565,36 @@ export const SingleOption = () => {
 };
 
 SingleOption.storyName = "Single Option";
+
+const optionListValues = [
+  {
+    id: "Amber",
+    value: 1,
+    text: "Black",
+  },
+  {
+    id: "Black",
+    value: 2,
+    text: "Black",
+  },
+  {
+    id: "Blue",
+    value: 3,
+    text: "Blue",
+  },
+];
+
+export const OptionsWithSameName = () => {
+  return (
+    <MultiSelect
+      name="multi-options-with-same-name"
+      id="multi-options-with-same-name"
+      label="multi options with same name"
+    >
+      {optionListValues.map((option) => (
+        <Option key={option.id} text={option.text} value={option} />
+      ))}
+    </MultiSelect>
+  );
+};
+OptionsWithSameName.storyName = "Options with same name";