Repository: Hacker0x01/react-datepicker (ts)

Issue:
Disabled time does not have aria-disabled attribute (unlike disabled dates)
**Describe the bug**
When certain time is excluded, it does _not_ have aria attribute `aria-disabled` unlike disabled dates

**To Reproduce**
Steps to reproduce the behavior:

1. Go to https://reactdatepicker.com/#example-exclude-times
2. Inspect `Time` column using Chrome's dev tools
3. See html output similar to this:
```html
<li class="react-datepicker__time-list-item  react-datepicker__time-list-item--disabled" tabindex="-1" role="option">5:00 PM</li>
```
4. Go to https://reactdatepicker.com/#example-exclude-dates
5. Inspect disabled date cell using Chrome's dev tools
6. See html output similar to this:
```html
<div class="react-datepicker__day react-datepicker__day--015 react-datepicker__day--disabled react-datepicker__day--excluded react-datepicker__day--selected react-datepicker__day--today" tabindex="0" aria-label="Not available Friday, September 15th, 2023" role="option" title="" aria-disabled="true" aria-current="date" aria-selected="true">15</div>
```

**Expected behavior**
See attribute `aria-disabled="true"` present for _both_, disabled dates _and_ disabled times.

Pull request description:
Fix #4259: Add the aria-disabled on the Time component's disabled time units 
Closes #4259

### Summary
This PR addresses an issue where the Time component is missing the attribute `aria-disabled` on it's disabled items.

### Changes made
- Updated the Time component to add the `aria-disabled` attribute over it's disabled items
- Made the logic to find the disable time unit sharable in a reusable helper function
- Updated the corresponding test cases to also check for the existence of the `aria-disabled` attribute along with the class `.react-datepicker__time-list-item--disabled`
- Migrated the test cases to use `RTL` from `enzyme` as suggested by @martijnrusschen in the issue #4300 for React 18 upgrade

Patch:
diff --git a/src/time.jsx b/src/time.jsx
index aa3376ee..4295abaa 100644
--- a/src/time.jsx
+++ b/src/time.jsx
@@ -100,6 +100,14 @@ export default class Time extends React.Component {
   isSelectedTime = (time) =>
     this.props.selected && isSameMinute(this.props.selected, time);
 
+  isDisabledTime = (time) =>
+    ((this.props.minTime || this.props.maxTime) &&
+      isTimeInDisabledRange(time, this.props)) ||
+    ((this.props.excludeTimes ||
+      this.props.includeTimes ||
+      this.props.filterTime) &&
+      isTimeDisabled(time, this.props));
+
   liClasses = (time) => {
     let classes = [
       "react-datepicker__time-list-item",
@@ -110,14 +118,7 @@ export default class Time extends React.Component {
       classes.push("react-datepicker__time-list-item--selected");
     }
 
-    if (
-      ((this.props.minTime || this.props.maxTime) &&
-        isTimeInDisabledRange(time, this.props)) ||
-      ((this.props.excludeTimes ||
-        this.props.includeTimes ||
-        this.props.filterTime) &&
-        isTimeDisabled(time, this.props))
-    ) {
+    if (this.isDisabledTime(time)) {
       classes.push("react-datepicker__time-list-item--disabled");
     }
     if (
@@ -216,6 +217,7 @@ export default class Time extends React.Component {
           tabIndex={time === timeToFocus ? 0 : -1}
           role="option"
           aria-selected={this.isSelectedTime(time) ? "true" : undefined}
+          aria-disabled={this.isDisabledTime(time) ? "true" : undefined}
         >
           {formatDate(time, format, this.props.locale)}
         </li>


Test patch:
diff --git a/test/exclude_times_test.test.js b/test/exclude_times_test.test.js
index 71765a3d..be69a844 100644
--- a/test/exclude_times_test.test.js
+++ b/test/exclude_times_test.test.js
@@ -24,5 +24,10 @@ describe("DatePicker", () => {
       ".react-datepicker__time-list-item--disabled",
     );
     expect(disabledTimeItems.length).toBe(4);
+
+    const allDisabledTimeItemsHaveAriaDisabled = Array.from(
+      disabledTimeItems,
+    ).every((time) => time.getAttribute("aria-disabled") === "true");
+    expect(allDisabledTimeItemsHaveAriaDisabled).toBe(true);
   });
 });
diff --git a/test/filter_times_test.test.js b/test/filter_times_test.test.js
index 3fd80d3f..51ff1a44 100644
--- a/test/filter_times_test.test.js
+++ b/test/filter_times_test.test.js
@@ -1,16 +1,22 @@
 import React from "react";
-import { mount } from "enzyme";
+import { render } from "@testing-library/react";
 import { getHours } from "../src/date_utils";
 import TimeComponent from "../src/time";
 
 describe("TimeComponent", () => {
   it("should disable times matched by filterTime prop", () => {
-    const timeComponent = mount(
+    const { container: timeComponent } = render(
       <TimeComponent filterTime={(time) => getHours(time) !== 17} />,
     );
 
-    expect(
-      timeComponent.find(".react-datepicker__time-list-item--disabled"),
-    ).toHaveLength(2);
+    const disabledTimeItems = timeComponent.querySelectorAll(
+      ".react-datepicker__time-list-item--disabled",
+    );
+    expect(disabledTimeItems.length).toBe(2);
+
+    const allDisabledTimeItemsHaveAriaDisabled = Array.from(
+      disabledTimeItems,
+    ).every((time) => time.getAttribute("aria-disabled") === "true");
+    expect(allDisabledTimeItemsHaveAriaDisabled).toBe(true);
   });
 });
diff --git a/test/include_times_test.test.js b/test/include_times_test.test.js
index fd6679c4..31e60812 100644
--- a/test/include_times_test.test.js
+++ b/test/include_times_test.test.js
@@ -1,12 +1,12 @@
 import React from "react";
-import { mount } from "enzyme";
+import { render } from "@testing-library/react";
 import * as utils from "../src/date_utils";
 import TimeComponent from "../src/time";
 
 describe("TimeComponent", () => {
   it("should only enable times specified in includeTimes props", () => {
     const today = utils.getStartOfDay(utils.newDate());
-    const timeComponent = mount(
+    const { container: timeComponent } = render(
       <TimeComponent
         includeTimes={[
           utils.addMinutes(today, 60),
@@ -16,9 +16,14 @@ describe("TimeComponent", () => {
       />,
     );
 
-    const disabledItems = timeComponent.find(
+    const disabledTimeItems = timeComponent.querySelectorAll(
       ".react-datepicker__time-list-item--disabled",
     );
-    expect(disabledItems).toHaveLength(45);
+    expect(disabledTimeItems.length).toBe(45);
+
+    const allDisabledTimeItemsHaveAriaDisabled = Array.from(
+      disabledTimeItems,
+    ).every((time) => time.getAttribute("aria-disabled") === "true");
+    expect(allDisabledTimeItemsHaveAriaDisabled).toBe(true);
   });
 });