# All files / src/test-utils drag.ts

94.04% Statements 79/84
66.66% Branches 4/6
100% Functions 3/3
94.04% Lines 79/84

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    851x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    2x
    2x
    2x
    2x
    2x
    2x
    1x
    1x
    2x
    2x

    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    2x
    2x
    2x
    2x
    2x
    2x

    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    40x
    40x
    40x
    40x
    40x
    2x
    2x
    2x
    2x
     import { fireEvent } from "@testing-library/dom";
    import type { MouseEvent } from "react";
    import { wait } from "../utils/wait.js";

    interface XYCoords {
      x: number;
      y: number;
    }

    interface BaseDragOptions {
      to?: XYCoords | Element;
      delta?: XYCoords;
      steps?: number;
      duration?: number;
    }

    type DragOptions = BaseDragOptions &
      ({ to: XYCoords | Element; delta?: never } | { delta: XYCoords; to?: never });

    const getElementClientCenter = (element: Element): XYCoords => {
      const { left, top, width, height } = element.getBoundingClientRect();
      return {
        x: left + width / 2,
        y: top + height / 2,
      };
    };

    const getCoords = (elementOrCoords: Element | XYCoords): XYCoords =>
      "x" in elementOrCoords && "y" in elementOrCoords
        ? elementOrCoords
        : getElementClientCenter(elementOrCoords);

    /**
     * This is internal for now. No idea if it's actually worthwhile though since
     * you have to mock the `getBoundingClientRect()` to work.
     *
     * @internal
     * @see https://github.com/testing-library/testing-library-docs/blob/c20f8a8931e9f0a158fda9f01bbea8cb45ed1651/docs/example-drag.mdx
     */
    export async function drag(
      element: Element,
      options: DragOptions
    ): Promise<void> {
      const { delta, to: inTo, steps = 20, duration = 500 } = options;
      const from = getElementClientCenter(element);
      const to = delta
        ? {
            x: from.x + delta.x,
            y: from.y + delta.y,
          }
        : getCoords(inTo);

      const step: XYCoords = {
        x: (to.x - from.x) / steps,
        y: (to.y - from.y) / steps,
      };

      const currentEvent = {
        clientX: from.x,
        clientY: from.y,
        button: 0,
        altKey: false,
        ctrlKey: false,
        metaKey: false,
        shiftKey: false,
      } satisfies Partial<MouseEvent>;

      fireEvent.mouseEnter(element, currentEvent);
      fireEvent.mouseOver(element, currentEvent);
      fireEvent.mouseMove(element, currentEvent);
      fireEvent.mouseDown(element, currentEvent);
      fireEvent.dragStart(element, currentEvent);

      const delay = duration / steps;
      for (let i = 0; i < steps; i++) {
        currentEvent.clientX += step.x;
        currentEvent.clientY += step.y;
        await wait(delay);
        fireEvent.mouseMove(element, currentEvent);
      }

      fireEvent.mouseUp(element, currentEvent);
      fireEvent.dragEnd(element, currentEvent);
    }