在 jest/enzyme 中测试音频标签本机事件处理程序和方法

eri*_*oes 5 audio event-handling reactjs jestjs enzyme

我一直无法弄清楚如何从这里的音频元素测试事件侦听器和方法。我无法进入事件处理程序调用的任何一个函数集(setDuration() 或 updateProgress)。而且,我不知道如何嘲笑audioRef.current.play() audioRef.current.duration等等。我附上了显示测试代码覆盖率的图像。目前,只有一个测试要渲染。

我试过这样的事情,但我得到 audioPlayer.timeupdate is not a function

    const map = {};
    audioPlayer.addEventListener = jest.fn((event, callback) => {
      map[event] = callback;
    });
    act(() => {
      audioPlayer.timeupdate();
    });
Run Code Online (Sandbox Code Playgroud)

来自 Audio.js

import PropTypes from "prop-types";
import get from "lodash.get";
import throttle from "lodash.throttle";
import Icon from "../../../components/core/elements/icon/default.jsx";

const AudioFlexPlayer = props => {
  const {
    podcastData,
    overrides: { audioUrl, showPodcastSubLink }
  } = props;

  const audioRef = useRef();
  const barWrapperRef = useRef();

  const [canPlay, setCanPlay] = useState(false);
  const [mouseDown, setMouseDown] = useState(false);
  const [playState, setPlayState] = useState("paused");
  const [progress, setProgress] = useState("");
  const [timeStamp, setTimestamp] = useState("");
  const audioSrc = audioUrl || get(podcastData, "audio.url");

  const handleButtonClick = () => {
    if (canPlay && audioRef.current.paused) {
      audioRef.current.play();
      setPlayState("playing");
    } else if (canPlay && !audioRef.current.paused) {
      audioRef.current.pause();
      setPlayState("paused");
    }
  };

  const handleMouseDown = () => {
    setMouseDown(true);
  };

  const formatTime = duration => {
    const minutes = Math.floor(duration / 60);
    const seconds =
      duration % 60 < 10
        ? `0${Math.round(duration % 60).toString()}`
        : Math.round(duration % 60);
    return `${minutes}:${seconds}`;
  };

  const subLinks = get(podcastData, "seriesMeta.subscriptionLinks");

  const updatePlayhead = event => {
    if (audioRef && mouseDown && barWrapperRef) {
      const boundingRect = barWrapperRef.current.getBoundingClientRect();
      const xPixelsFromEdgeOfelement = event.clientX - boundingRect.left;

      setProgress(
        Math.round(xPixelsFromEdgeOfelement / barWrapperRef.current.offsetWidth)
      );
      audioRef.current.currentTime =
        (xPixelsFromEdgeOfelement / barWrapperRef.current.offsetWidth) *
        audioRef.current.duration;
    }
    if (event.type !== "mousemove") setMouseDown(false);
  };

  useEffect(() => {
    const audioPlayer = audioRef.current;
    const setDuration = () => {
      setTimestamp(formatTime(audioRef.current.duration));
      setCanPlay(true);
    };
    const updateProgress = () => {
      const elapsedTime = Math.round(audioRef.current.currentTime);
      const elapsedTimeStamp = formatTime(elapsedTime);
      setTimestamp(
        `${elapsedTimeStamp}/${formatTime(audioRef.current.duration)}`
      );
      setProgress(
        (elapsedTime / audioRef.current.duration) *
          barWrapperRef.current.offsetWidth
      );
    };
    if (audioPlayer) {
      audioPlayer.addEventListener("timeupdate", throttle(updateProgress, 500));
      audioPlayer.addEventListener("canplay", setDuration);
    }
    return () => {
      audioPlayer.removeEventListener("timeupdate", updateProgress);
      audioPlayer.removeEventListener("canplay", setDuration);
    };
  }, [progress]);

  return (
    <Fragment>
      <div className="flex items-center justify-start">
        <div
          className="af-button brad-50 shadow flex items-center justify-center pointer mr-xs"
          onClick={handleButtonClick}
          style={{ minWidth: "32px", height: "32px" }}
        >
          {playState === "paused" && (
            <Icon
              className="fill-white"
              name="play"
              size="16"
              aria-label="play"
            />
          )}
          {playState === "playing" && (
            <Icon
              className="fill-white"
              name="pause"
              size="16"
              aria-label="pause"
            />
          )}
        </div>
        <div
          ref={barWrapperRef}
          className="mr-xs pointer pad-top-xs pad-bottom-xs w-100"
          style={{
            width: "calc(100% - 120px)"
          }}
          onMouseDown={handleMouseDown}
          onMouseMove={updatePlayhead}
          onMouseUp={updatePlayhead}
          onMouseLeave={updatePlayhead}
        >
          <div
            className="mr-xs brad-2 bg-gray-lighter relative"
            style={{
              height: "4px",
              minWidth: "25px"
            }}
          >
            <div
              className="progress-bar absolute brad-2 bg-blue left-0 pointer"
              id="progress"
              style={{
                width: progress,
                height: "4px",
                top: "25%",
                transform: "translateY(-25%)"
              }}
            >
              <div
                className="podcast-progress-point bg-white right-0 brad-50 b bc-gray-lighter absolute left-0"
                style={{
                  width: "16px",
                  height: "16px",
                  top: "25%",
                  transform: "translateY(-47%)",
                  marginLeft: progress
                }}
              />
            </div>
          </div>
        </div>
        <div className="gray-darkest">{timeStamp}</div>
      </div>
      {showPodcastSubLink && subLinks && (
        <div>
          <span className="gray-dark pad-right-xxs">Add to:</span>
          {subLinks && subLinks.applePodcasts && (
            <a
              className="blue pad-right-xxs"
              id="applePodcasts"
              href={podcastData.seriesMeta.subscriptionLinks.applePodcasts}
            >
              Apple Podcasts,
            </a>
          )}
          {subLinks && subLinks.googlePlay && (
            <a
              className="blue pad-right-xxs"
              id="googlePlay"
              href={podcastData.seriesMeta.subscriptionLinks.googlePlay}
            >
              Google Podcasts,
            </a>
          )}
          {subLinks && subLinks.stitcher && (
            <a
              className="blue"
              id="stitcher"
              href={podcastData.seriesMeta.subscriptionLinks.stitcher}
            >
              Stitcher
            </a>
          )}
        </div>
      )}
      <audio
        ref={audioRef}
        src={audioSrc}
        preload="metadata"
        type="audio/mp3"
      />
    </Fragment>
  );
};

AudioFlexPlayer.propTypes = {
  podcastData: PropTypes.object,
  overrides: PropTypes.object
};

export default AudioFlexPlayer;```


[screenshot of coverage][1]
[screenshot of coverage][2]


  [1]: https://i.stack.imgur.com/7NsZK.png
  [2]: https://i.stack.imgur.com/9CUFt.png
Run Code Online (Sandbox Code Playgroud)