Skip to content

Performance regression in getComputedStyle() #3984

@Janpot

Description

@Janpot

Node.js version

20.19.1

jsdom version

27.1.0

Minimal reproduction case

// package.json
{
  "name": "jsdom-regression-repro",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node compare.js"
  },
  "dependencies": {
    "jsdom-26": "npm:jsdom@26.0.0",
    "jsdom-27": "npm:jsdom@27.1.0"
  }
}
<!-- jsdom-regression-repro.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>jsdom Performance Regression Test</title>
  </head>
  <body>
    <div></div>
    <div>
      <div class="MuiDateRangeCalendar-root">
        <div class="MuiDateRangeCalendar-monthContainer">
          <div class="MuiPickersArrowSwitcher-root">
            <button
              class="MuiButtonBase-root MuiIconButton-root"
              tabindex="0"
              type="button"
              title="Previous month"
              aria-label="Previous month"
            >
              <svg
                class="MuiSvgIcon-root"
                focusable="false"
                aria-hidden="true"
                viewBox="0 0 24 24"
                data-testid="ArrowLeftIcon"
              >
                <path
                  d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"
                ></path>
              </svg>
            </button>
            <span class="MuiTypography-root" id="_r_0_-grid-0-label"
              >January 2019</span
            >
            <button
              class="MuiButtonBase-root MuiIconButton-root"
              tabindex="0"
              type="button"
              title="Next month"
              aria-label="Next month"
            >
              <svg
                class="MuiSvgIcon-root"
                focusable="false"
                aria-hidden="true"
                viewBox="0 0 24 24"
                data-testid="ArrowRightIcon"
              >
                <path
                  d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"
                ></path>
              </svg>
            </button>
          </div>
          <div
            role="grid"
            aria-labelledby="_r_0_-grid-0-label"
            class="MuiDayCalendar-root"
          >
            <div role="row" class="MuiDayCalendar-header">
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Sunday"
                >S</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Monday"
                >M</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Tuesday"
                >T</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Wednesday"
                >W</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Thursday"
                >T</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Friday"
                >F</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Saturday"
                >S</span
              >
            </div>
            <div class="MuiPickersSlideTransition-root" role="presentation">
              <div
                data-testid="pickers-calendar"
                role="rowgroup"
                class="MuiDayCalendar-monthContainer"
              >
                <div
                  role="row"
                  class="MuiDayCalendar-weekContainer"
                  aria-rowindex="1"
                >
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-outsideCurrentMonth MuiDateRangePickerDay-hiddenDayFiller"
                  >
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <div
                        class="MuiPickersDay-root MuiPickersDay-hiddenDaySpacingFiller"
                        role="gridcell"
                      ></div>
                    </div>
                  </div>
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-outsideCurrentMonth MuiDateRangePickerDay-endOfMonth MuiDateRangePickerDay-hiddenDayFiller"
                  >
                    <div
                      class="MuiDateRangePickerDay-rangeIntervalPreview MuiDateRangePickerDay-rangeIntervalDayPreviewEnd"
                    >
                      <div
                        class="MuiPickersDay-root MuiPickersDay-hiddenDaySpacingFiller"
                        role="gridcell"
                      ></div>
                    </div>
                  </div>
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-startOfMonth MuiDateRangePickerDay-firstVisibleCell"
                  >
                    <div
                      class="MuiDateRangePickerDay-rangeIntervalPreview MuiDateRangePickerDay-rangeIntervalDayPreviewStart"
                    >
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="0"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546300800000"
                        aria-colindex="3"
                        aria-selected="false"
                      >
                        1
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546387200000"
                        aria-colindex="4"
                        aria-selected="false"
                      >
                        2
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546473600000"
                        aria-colindex="5"
                        aria-selected="false"
                      >
                        3
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546560000000"
                        aria-colindex="6"
                        aria-selected="false"
                      >
                        4
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546646400000"
                        aria-colindex="7"
                        aria-selected="false"
                      >
                        5
                      </button>
                    </div>
                  </div>
                </div>
                <div
                  role="row"
                  class="MuiDayCalendar-weekContainer"
                  aria-rowindex="2"
                >
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546732800000"
                        aria-colindex="1"
                        aria-selected="false"
                      >
                        6
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546819200000"
                        aria-colindex="2"
                        aria-selected="false"
                      >
                        7
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546905600000"
                        aria-colindex="3"
                        aria-selected="false"
                      >
                        8
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1546992000000"
                        aria-colindex="4"
                        aria-selected="false"
                      >
                        9
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547078400000"
                        aria-colindex="5"
                        aria-selected="false"
                      >
                        10
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547164800000"
                        aria-colindex="6"
                        aria-selected="false"
                      >
                        11
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547251200000"
                        aria-colindex="7"
                        aria-selected="false"
                      >
                        12
                      </button>
                    </div>
                  </div>
                </div>
                <div
                  role="row"
                  class="MuiDayCalendar-weekContainer"
                  aria-rowindex="3"
                >
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547337600000"
                        aria-colindex="1"
                        aria-selected="false"
                      >
                        13
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547424000000"
                        aria-colindex="2"
                        aria-selected="false"
                      >
                        14
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547510400000"
                        aria-colindex="3"
                        aria-selected="false"
                      >
                        15
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547596800000"
                        aria-colindex="4"
                        aria-selected="false"
                      >
                        16
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547683200000"
                        aria-colindex="5"
                        aria-selected="false"
                      >
                        17
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547769600000"
                        aria-colindex="6"
                        aria-selected="false"
                      >
                        18
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547856000000"
                        aria-colindex="7"
                        aria-selected="false"
                      >
                        19
                      </button>
                    </div>
                  </div>
                </div>
                <div
                  role="row"
                  class="MuiDayCalendar-weekContainer"
                  aria-rowindex="4"
                >
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1547942400000"
                        aria-colindex="1"
                        aria-selected="false"
                      >
                        20
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548028800000"
                        aria-colindex="2"
                        aria-selected="false"
                      >
                        21
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548115200000"
                        aria-colindex="3"
                        aria-selected="false"
                      >
                        22
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548201600000"
                        aria-colindex="4"
                        aria-selected="false"
                      >
                        23
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548288000000"
                        aria-colindex="5"
                        aria-selected="false"
                      >
                        24
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548374400000"
                        aria-colindex="6"
                        aria-selected="false"
                      >
                        25
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548460800000"
                        aria-colindex="7"
                        aria-selected="false"
                      >
                        26
                      </button>
                    </div>
                  </div>
                </div>
                <div
                  role="row"
                  class="MuiDayCalendar-weekContainer"
                  aria-rowindex="5"
                >
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548547200000"
                        aria-colindex="1"
                        aria-selected="false"
                      >
                        27
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548633600000"
                        aria-colindex="2"
                        aria-selected="false"
                      >
                        28
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548720000000"
                        aria-colindex="3"
                        aria-selected="false"
                      >
                        29
                      </button>
                    </div>
                  </div>
                  <div class="MuiDateRangePickerDay-root">
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548806400000"
                        aria-colindex="4"
                        aria-selected="false"
                      >
                        30
                      </button>
                    </div>
                  </div>
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-endOfMonth MuiDateRangePickerDay-lastVisibleCell"
                  >
                    <div
                      class="MuiDateRangePickerDay-rangeIntervalPreview MuiDateRangePickerDay-rangeIntervalDayPreviewEnd"
                    >
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548892800000"
                        aria-colindex="5"
                        aria-selected="false"
                      >
                        31
                      </button>
                    </div>
                  </div>
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-outsideCurrentMonth MuiDateRangePickerDay-startOfMonth MuiDateRangePickerDay-hiddenDayFiller"
                  >
                    <div
                      class="MuiDateRangePickerDay-rangeIntervalPreview MuiDateRangePickerDay-rangeIntervalDayPreviewStart"
                    >
                      <div
                        class="MuiPickersDay-root MuiPickersDay-hiddenDaySpacingFiller"
                        role="gridcell"
                      ></div>
                    </div>
                  </div>
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-outsideCurrentMonth MuiDateRangePickerDay-hiddenDayFiller"
                  >
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <div
                        class="MuiPickersDay-root MuiPickersDay-hiddenDaySpacingFiller"
                        role="gridcell"
                      ></div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="MuiDateRangeCalendar-monthContainer">
          <div class="MuiPickersArrowSwitcher-root">
            <button
              class="MuiButtonBase-root MuiIconButton-root"
              tabindex="0"
              type="button"
              title="Previous month"
              aria-label="Previous month"
            >
              <svg
                class="MuiSvgIcon-root"
                focusable="false"
                aria-hidden="true"
                viewBox="0 0 24 24"
                data-testid="ArrowLeftIcon"
              >
                <path
                  d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"
                ></path>
              </svg>
            </button>
            <span class="MuiTypography-root" id="_r_0_-grid-1-label"
              >February 2019</span
            >
            <button
              class="MuiButtonBase-root MuiIconButton-root"
              tabindex="0"
              type="button"
              title="Next month"
              aria-label="Next month"
            >
              <svg
                class="MuiSvgIcon-root"
                focusable="false"
                aria-hidden="true"
                viewBox="0 0 24 24"
                data-testid="ArrowRightIcon"
              >
                <path
                  d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"
                ></path>
              </svg>
            </button>
          </div>
          <div
            role="grid"
            aria-labelledby="_r_0_-grid-1-label"
            class="MuiDayCalendar-root"
          >
            <div role="row" class="MuiDayCalendar-header">
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Sunday"
                >S</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Monday"
                >M</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Tuesday"
                >T</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Wednesday"
                >W</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Thursday"
                >T</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Friday"
                >F</span
              >
              <span
                class="MuiTypography-root"
                role="columnheader"
                aria-label="Saturday"
                >S</span
              >
            </div>
            <div class="MuiPickersSlideTransition-root" role="presentation">
              <div
                data-testid="pickers-calendar"
                role="rowgroup"
                class="MuiDayCalendar-monthContainer"
              >
                <!-- February 2019 days abbreviated for brevity - same structure as January -->
                <div
                  role="row"
                  class="MuiDayCalendar-weekContainer"
                  aria-rowindex="1"
                >
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-outsideCurrentMonth MuiDateRangePickerDay-hiddenDayFiller"
                  >
                    <div class="MuiDateRangePickerDay-rangeIntervalPreview">
                      <div
                        class="MuiPickersDay-root MuiPickersDay-hiddenDaySpacingFiller"
                        role="gridcell"
                      ></div>
                    </div>
                  </div>
                  <div
                    class="MuiDateRangePickerDay-root MuiDateRangePickerDay-startOfMonth MuiDateRangePickerDay-firstVisibleCell"
                  >
                    <div
                      class="MuiDateRangePickerDay-rangeIntervalPreview MuiDateRangePickerDay-rangeIntervalDayPreviewStart"
                    >
                      <button
                        class="MuiButtonBase-root MuiPickersDay-root MuiDateRangePickerDay-day"
                        tabindex="-1"
                        type="button"
                        data-testid="DateRangePickerDay"
                        role="gridcell"
                        data-timestamp="1548979200000"
                        aria-colindex="6"
                        aria-selected="false"
                      >
                        1
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>
// compare.js
/**
 * jsdom Performance Regression - getComputedStyle Isolation
 * This test isolates the performance regression to window.getComputedStyle().
 */

import { readFile } from 'fs/promises';

async function testJsdomVersion(jsdomPackage, versionLabel) {
  const html = await readFile('./jsdom-regression-repro.html', 'utf-8');

  // Dynamically import the jsdom version
  const { JSDOM } = await import(jsdomPackage);

  // Initialize jsdom for testing
  const dom = new JSDOM(html);
  const document = dom.window.document;
  const window = dom.window;

  // Get all elements with roles for testing
  const allRoleElements = document.querySelectorAll('[role]');
  console.log(
    `  Found ${allRoleElements.length} elements with role attributes`
  );

  // Test: getComputedStyle performance
  function testGetComputedStyle() {
    const start = performance.now();
    for (let i = 0; i < 100; i++) {
      for (const element of allRoleElements) {
        window.getComputedStyle(element);
      }
    }
    return performance.now() - start;
  }

  // Warmup test runs
  testGetComputedStyle();
  testGetComputedStyle();

  // Run test multiple times
  const iterations = 10;
  const timings = [];

  for (let i = 0; i < iterations; i++) {
    timings.push(testGetComputedStyle());
  }

  // Calculate average
  const avgTime = timings.reduce((a, b) => a + b, 0) / iterations;

  return {
    versionLabel,
    elementCount: allRoleElements.length,
    avgTime,
    timings,
  };
}

// Run tests for both versions
console.log('jsdom Performance Regression - getComputedStyle');
console.log('='.repeat(80));
console.log(
  'Test: Call window.getComputedStyle() on 65 elements, 100 times (6,500 calls)'
);
console.log('='.repeat(80));
console.log('');

console.log('Testing jsdom 26.0.0...');
const results26 = await testJsdomVersion('jsdom-26', 'jsdom 26.0.0');

console.log('Testing jsdom 27.1.0...');
const results27 = await testJsdomVersion('jsdom-27', 'jsdom 27.1.0');

console.log('');
console.log('='.repeat(80));
console.log('RESULTS');
console.log('='.repeat(80));
console.log('');

console.log(`${results26.versionLabel}:`);
console.log(`  Average time: ${results26.avgTime.toFixed(3)}ms`);
console.log('');

console.log(`${results27.versionLabel}:`);
console.log(`  Average time: ${results27.avgTime.toFixed(3)}ms`);
console.log('');

// Calculate regression
const regression =
  ((results27.avgTime - results26.avgTime) / results26.avgTime) * 100;
const multiplier = results27.avgTime / results26.avgTime;

console.log('='.repeat(80));
console.log('REGRESSION ANALYSIS');
console.log('='.repeat(80));
console.log('');
console.log(
  `  Difference: +${(results27.avgTime - results26.avgTime).toFixed(3)}ms`
);
console.log(`  Regression: +${regression.toFixed(1)}%`);
console.log(`  Multiplier: ${multiplier.toFixed(2)}x slower`);

See the following StackBlitz

How does similar code behave in browsers?

Didn't notice any performance regressions in browsers recently

What is the problem?

At MUI we recently upgraded JSDOM from 26 to 27 and noticed the runtime of our tests doubled. The main culprit I could find was @testing-library/dom getByRole which got a 4x slowdown. I traced it down to dom-accessibility-api computeAccessibleName which further lead me to getComputedStyle in jsdom.

Output of the script on my local machine

jsdom Performance Regression - getComputedStyle
================================================================================
Test: Call window.getComputedStyle() on 65 elements, 100 times (6,500 calls)
================================================================================

Testing jsdom 26.0.0...
  Found 65 elements with role attributes
Testing jsdom 27.1.0...
  Found 65 elements with role attributes

================================================================================
RESULTS
================================================================================

jsdom 26.0.0:
  Average time: 259.998ms

jsdom 27.1.0:
  Average time: 1410.337ms

================================================================================
REGRESSION ANALYSIS
================================================================================

  Difference: +1150.339ms
  Regression: +442.4%
  Multiplier: 5.42x slower

I think there will be more perf regressions, but this one so far seems to be the biggest one.

Potentially the same root cause as #3967

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions