React / Jest - 如何模拟触摸“滑动”事件

3

我有一个组件,当发生滑动交互时触发函数调用。这个滑动交互可以通过touchEvent或mouseEvent执行。我的目标是检查是否在发生滑动时调用了该函数。但是我未能在Jest测试中模拟touchEvent,使用了swiper、react、react-testing-library和jest。

在线编辑器链接进行测试:Codesandbox

实际的类

const App = ({ funcCalledOnSlideChange }) => {
  return (
    <Swiper
      pagination={{
        clickable: true
      }}
      modules={[Pagination]}
      watchOverflow
      onSlideChange={funcCalledOnSlideChange}
    >
      <SwiperSlide>
        <img className="slide" />
      </SwiperSlide>
      <SwiperSlide>
        <img className="slide-second" />
      </SwiperSlide>
    </Swiper>
  );
};

实际测试

const mockFunc = jest.fn();

function sendTouchEvent({ x, y, element, eventType }) {
  const touchObj = new Touch({
    identifier: Date.now(),
    target: element,
    clientX: x,
    clientY: y,
    radiusX: 2.5,
    radiusY: 2.5,
    rotationAngle: 10,
    force: 0.5
  });

  const touchEvent = new TouchEvent(eventType, {
    cancelable: true,
    bubbles: true,
    touches: [touchObj],
    targetTouches: [],
    changedTouches: [touchObj]
  });

  element.dispatchEvent(touchEvent);
}

test("should swipe by touch event", async () => {
  const { container } = render(<App funcCalledOnSlideChange={mockFunc} />);
  const swiperSlide = container.querySelector(".swiper-slide");

  act(() => {
    sendTouchEvent({
      x: 350,
      y: 100,
      element: swiperSlide,
      eventType: "touchstart"
    });
    sendTouchEvent({
      x: 200,
      y: 100,
      element: swiperSlide,
      eventType: "touchmove"
    });
    sendTouchEvent({
      x: 150,
      y: 100,
      element: swiperSlide,
      eventType: "touchend"
    });
  });

  await waitFor(() => {
    expect(mockFunc).toBeCalled();
  });
});

实际错误:

Failed to construct 'Touch': Failed to read the 'target' property from 'TouchInit': Failed to read the 'target' property from 'TouchInit': Required member is undefined.

你尝试过从用户事件库中使用 pointer 吗?https://testing-library.com/docs/user-event/pointer - pdpino
你找到解决方案了吗? - james emanon
不,我只是放弃了:D - MarcoLe
1个回答

0

模拟触摸事件并不是很容易,最终我找到了解决方案,并将其用于我的滑块库。

第一步是创建一个包含Touch对象的模拟TouchEvent对象。

Touch

export default class Touch {
  constructor(pageX) {
    this.pageX = pageX;
  }
}

我们不需要该对象的完整属性,只需要pageX属性来模拟向左或向右滑动。

TouchEvent

export default class TouchEvent {
  constructor(type, options) {
    this.type = type;
    this.changedTouches = options.changedTouches;
  }

  preventDefault() {
    return false;
  }
}

然后,我们可以使用工厂来生产 TouchEvent。
import TouchEvent from './touch-event';
import Touch from './touch';

/**
 * Create a mocked TouchEvent object.
 *
 * @param {String} type
 * @param {String} direction
 * @param {Number} distance
 * @return {Object}
 */
export default function touchEventFactory(type, direction, distance) {
  const options = {};
  const touches = [];
  let touch = null;

  if (type === 'touchstart' || type === 'touchmove') {
    touch = new Touch(300);
  } else if (type === 'touchend') {
    if (direction === 'right') {
      touch = new Touch(300 - distance);
    } else {
      touch = new Touch(300 + distance);
    }
  }

  touches.push(touch);
  options.changedTouches = touches;
  return new TouchEvent(type, options);
}

在测试中使用它:

sliderEvent.mock('touchstart', touchEventFactory('touchstart', 'left', 0));

sliderEvent是我项目中的一个EventAdapter,用于收集引用并可用于测试。

您可以在存储库中查看tests/features/touch.test.jshttps://github.com/terrylinooo/sliderm.js

希望这可以帮助到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接