微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

警告:测试中的 Slider 更新未包含在 act(...)

如何解决警告:测试中的 Slider 更新未包含在 act(...)

我在尝试使用“react-test-renderer”测试一段代码时遇到以下错误

下面是我的测试

import React from "react";
import { act,create } from "react-test-renderer";
import { Slider } from "../../../../src/components/slider/Slider";

describe("SliderComponent",() => {
  // it("renders without crashing",(done) => {
  //   const component = create(<Slider loop={false} itemsPerPage={3} slidesCount={8} />);
  //   const tree = component.toJSON();
  //   expect(tree).toMatchSnapshot();
  //   component.unmount();
  //   done();
  // });

  // it("changes active item after delay",done => {
  //   const sliderCount = jest.fn();
  //   const component = create(<Slider onActiveItemChange={sliderCount} loop={true} delay={50} itemsPerPage={3}
  //                                    slidesCount={8} activeSlide={0} />);
  //   const tree = component.toJSON();
  //   expect(tree).toMatchSnapshot();
  //   act(() => {
  //     setTimeout(() => {
  //       expect(sliderCount).toBeCalled();
  //       component.unmount();
  //       done();
  //     },51);
  //   });

  // });

  // it("active item is not changed before delay",done => {
  //   const sliderCount = jest.fn();
  //   const component = create(<Slider onActiveItemChange={sliderCount} loop={true} delay={60} itemsPerPage={3}
  //                                    slidesCount={8} />);
  //   const tree = component.toJSON();
  //   expect(tree).toMatchSnapshot();
  //   act(() => {
  //     setTimeout(() => {
  //       expect(sliderCount.mock.calls.length).toBe(0);
  //       component.unmount();
  //       done();
  //     },50);
  //   });

  // });

  // it("when loop is set to false,active item is not changed after delay",done => {
  //   const sliderCount = jest.fn();
  //   const component = create(<Slider onActiveItemChange={sliderCount} loop={false} delay={20} itemsPerPage={3}
  //                                    slidesCount={8} activeSlide={0} />);
  //   const tree = component.toJSON();
  //   expect(tree).toMatchSnapshot();
  //   act(() => {
  //     setTimeout(() => {
  //       expect(sliderCount.mock.calls.length).toBe(0);
  //       component.unmount();
  //       done();
  //     },30);
  //   });

  // });

  // it('has list items that on click changes list active item',done => {
  //   const sliderCount = jest.fn();
  //   const component = create(<Slider onActiveItemChange={sliderCount} loop={false} delay={1000} itemsPerPage={3}
  //                                    slidesCount={8} activeSlide={0} />);
  //   const testInstance = component.root;
  //   act(() => {
  //     testInstance.findAllByType('li')[1].props.onClick();
  //     expect(sliderCount).toHaveBeenCalled();
  //     component.unmount();
  //     done();

  //   })
  // });

  it("loop resumes after click",done => {
    const sliderCount = jest.fn();
    // const component = create(<Slider onActiveItemChange={sliderCount} loop={true} delay={50} itemsPerPage={1}
    //   slidesCount={3} activeSlide={0} />);
     act(() => {
      const component = create(<Slider onActiveItemChange={sliderCount} loop={true} delay={50} itemsPerPage={1}
        slidesCount={3} activeSlide={0} />);
        const testInstance = component.root;
        testInstance.findAllByType('li')[1].props.onClick(); 
        setTimeout(() => {
          expect(sliderCount).toBeCalled();
          component.unmount();
          done();
        },51);
    });
  });

});

注释掉的测试成功通过。但是最后一次测试失败了

  SliderComponent
    × loop resumes after click (25 ms)

  ● SliderComponent › loop resumes after click

    Can't access .root on unmounted test renderer

      81 |       const component = create(<Slider onActiveItemChange={sliderCount} loop={true} delay={50} itemsPerPage={1}
      82 |         slidesCount={3} activeSlide={0} />);
    > 83 |         const testInstance = component.root;
         |                                        ^
      84 |         testInstance.findAllByType('li')[1].props.onClick();
      85 |         setTimeout(() => {
      86 |           expect(sliderCount).toBeCalled();

      at Object.root (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:17237:15)
      at __tests__/src/components/slider/Slider.test.tsx:83:40
      at batchedUpdates (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13452:12)
      at act (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15280:14)
      at Object.<anonymous> (__tests__/src/components/slider/Slider.test.tsx:80:6)

如果我将代码 const component = create(<Slider onActiveItemChange={sliderCount} loop={true} delay={50} itemsPerPage={1} slidesCount={3} activeSlide={0} />); 移到 act() 函数之外,我会得到

  console.error
    Warning: An update to Slider inside a test was not wrapped in act(...).

    When testing,code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
        at Slider (C:\Users\KOTIENO1\Desktop\Projects\SafcomProjects\WORK\platform-of-choice\src\components\slider\Slider.tsx:1072:5)



      at printWarning (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:68:30)
      at error (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:44:5)
      at warnIfNotCurrentlyActingUpdatesInDEV (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15034:9)
      at dispatchAction (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7129:9)
      at Object.next (src/components/slider/Slider.tsx:1192:9)
      at Object.next (node_modules/rxjs/src/internal/Subscriber.ts:194:14)
      at SafeSubscriber.Object.<anonymous>.Subscriber._next (node_modules/rxjs/src/internal/Subscriber.ts:119:22)

下面是我要测试的代码

import React,{ useEffect,useState } from "react";
import styled,{ css } from "styled-components";
import { BehaviorSubject,Subject,timer } from "rxjs";
import { repeatWhen,take,takeuntil,takeWhile,tap } from "rxjs/operators";

interface iSliderProps {
  slidesCount: number;
  activeSlide?: number;
  onActiveItemChange?;
  itemsPerPage?: number;
  delay?: number;
  interval?: number;
  loop?: boolean;
}

const SliderWrapper = styled.ul`
  list-style-type: none;
  margin: 0;
  padding: 0;
  overflow: hidden;
  //background: red;
`;

const SliderItem = styled.li`
  float: left;
  background: #FFF;
  cursor: pointer;
  margin: 0.1rem;
  list-style: none;
  width: 0.25rem;
  height: 0.25rem;
  border: 1px solid #00943C;
  border-radius: 0.5rem;

  ${props => props.active && css`
    background: #00943C;
    cursor: default;
    width: 1.5rem;`
  }

  ${props => !props.active && css`
    &:hover {
      background: #00943C;
    }
  `
  }
`;

export const Slider = (props: iSliderProps) => {

  const {
    slidesCount,activeSlide = 0,onActiveItemChange = () => {
    },itemsPerPage = 1,delay = 5000,interval = 5000,loop = true
  } = props;

  const [currentActiveSlide,setCurrentActiveSlide] = useState(activeSlide);
  const sliderCount = Math.ceil(slidesCount / itemsPerPage);
  const timerStart$ = new BehaviorSubject(null);
  const timerStop$ = new Subject<null>();
  const timer$ = timer(delay,interval).pipe(
    takeWhile(() => loop),takeuntil(timerStop$),repeatWhen(() => timerStart$)
  );

  useEffect(() => {
    const timerSubscription = timer$.subscribe({
      next: (i) => {
        const nextSlide = i >= sliderCount ? i % sliderCount : i;
        onActiveItemChange(nextSlide);
        setCurrentActiveSlide(nextSlide);
      }
    });
    return () => timerSubscription.unsubscribe();
  },[]);

  const handleSliderItemClick = (i: number) => {
    setCurrentActiveSlide(i);
    onActiveItemChange(i);
    timerStop$.next(null);
    timer(delay).pipe(
      take(1),tap(() => timerStart$.next(null))
    );
  };

  const slides = Object.keys(new Array(sliderCount).fill("")).map(id => ({ id }));
  return (
    <>
      <SliderWrapper>
        {slides.map(({ id },i) =>
          <SliderItem
            key={id}
            aria-label={"scroll page number " + id}
            onClick={() => handleSliderItemClick(i)}
            active={i === currentActiveSlide}
          />)}
      </SliderWrapper>
    </>
  );
};

特别是我试图覆盖测试中未覆盖的线

Uncovered lines

我已在 When testing,code that causes React state updates should be wrapped into actReact Testing Library / Jest Update not wrapped in act(...) 下方进行了检查,但我似乎无法在测试中找出问题所在。

测试通过,但错误仍然存​​在

Photo showing passing tests

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。