【问题标题】:React Jest setInterval test coverageReact Jest setInterval 测试覆盖率
【发布时间】:2020-06-03 22:10:49
【问题描述】:

我正在尝试对功能组件进行一些测试覆盖。我在 useEffect 中有一个 setInterval 可以每隔几秒更改一条消息。对于我的测试似乎我没有测试 useEffect 中的任何内容。我试过jest.useFakeTimers();

我也在设置 useState。

组件:

import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import styled from "styled-components";
// Array of strings
import { messages } from "./messages";

export const Wrapper = styled.div`
  font-family: 'Lato', sans-serif !important;
  box-sizing: border-box;
  width: 100%;
  display: block;
  padding-right: 15px;
  padding-left: 15px;
  margin-right: auto;
  margin-left: auto;
  height: 100vh;
  h1 {
    font-size: 2rem;
    color: rgb(100, 100, 100);
  }
};
`;

const loadMessage = () => {
  // this is the line that is not being tested.
  return messages[Math.floor(Math.random() * messages.length)];
};

export const Loader = () => {
  const [message, setMessage] = useState("Loading...");

  useEffect(() => {
    const id = setInterval(() => {
      // this is the line that is not being tested.
      setMessage(loadMessage());
    }, 3000);
    return () => clearInterval(id);
  }, [message]);

  return (
    <Wrapper id="login-content">
      <Row className="align-items-center h-100">
        <Col className="col-md-12 mx-auto">
          <div className="container text-center">
            <h1 className="loader" data-testid="loader" aria-live="polite">
              {message}
            </h1>
          </div>
        </Col>
      </Row>
    </Wrapper>
  );
};

测试:

import React from "react";
import { shallow } from "enzyme";
import { Loader } from "./Loader";

const doAsync = c => {
  setTimeout(() => {
    c(true);
  }, 3000);
};

jest.useFakeTimers();

describe("Loader component", () => {
  it("tests state", () => {
    const wrapper = shallow(<Loader />);
    const message = wrapper.find(".loader").text();

    jest.advanceTimersByTime(3000);

    const callback1 = () => {
      expect(wrapper.find(".loader").text()).not.toMatch(message);
    };

    doAsync(callback1);

    jest.useRealTimers();
  });
});

【问题讨论】:

  • 是你expect不一定执行的问题吗?如果是这样,您可能希望使用it("tests state", (done) =&gt; { ...,然后在您的expect 语句之后但仍在callback1 中,调用done();。另外,我对advanceTimersByTime 不熟悉,但如果您关心这一点,我希望您在拨打doAsync 之后再拨打它;不过不确定。
  • 是的,我的期望没有执行。 TBH,我只是想尝试一种测试 useState 的好方法。
  • 您要测试useStateuseEffect?还是两者兼而有之?
  • @WillCain 两者。我的测试覆盖率专门要求 setMessage 变量,但如果可能的话,我想测试两者。

标签: reactjs jestjs react-hooks use-effect


【解决方案1】:

我偶然发现了酶问题:https://github.com/airbnb/enzyme/issues/2086

useEffect 函数在组件运行时似乎没有执行 用浅层渲染。

鉴于此,我要做的是模拟 UseEffect。

const doAsync = c => {
  setTimeout(() => {
    c(true);
  }, 3000);
};

jest.useFakeTimers();

describe("Loader component", () => {
  beforeEach(() => {
    const useEffect = jest
      .spyOn(React, "useEffect")
      .mockImplementation(f => f());
  });

  it("tests state", done => {
    const wrapper = shallow(<Loader />);
    const message = wrapper.find(".loader").text();

    jest.advanceTimersByTime(3000);

    const callback1 = () => {
      expect(wrapper.find(".loader").text()).not.toMatch(message);
    };

    doAsync(callback1);

    jest.useRealTimers();
    done();
  });
});

这使我的测试通过并获得 100% 的覆盖率。

【讨论】:

  • 不错的发现。顺便说一句,不确定完整(非浅层)渲染是否可以接受,但如果可以,那也许是另一种选择。另外,我不确定您的expect 是否会在不将done() 移动到callback1 中的情况下可靠地执行,但当然您可以使用不正确的expectconsole.log 或调试器来验证这一点。
  • 我按照这个例子进行了测试,测试通过了,但我放了一些日志,我希望有两个重复但只显示一次。然后以一种本应失败但仍然通过的方式更改了我的测试... Idk 为什么添加超时会使测试通过,但绝对不是正确的答案
猜你喜欢
  • 2019-06-11
  • 1970-01-01
  • 2018-02-17
  • 2019-04-08
  • 1970-01-01
  • 2019-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多