美文网首页
倒计时组件(React hook)和单元测试

倒计时组件(React hook)和单元测试

作者: 景阳冈大虫在此 | 来源:发表于2022-07-01 14:47 被阅读0次
GiftItem 效果图

目标

如何测试倒计时

实现

倒计时组件

  • 剩余时间展示格式为:x天HH:mm:ss
  • 超过时间,将文案变成已结束
  • 在时间范围之前,将文案变成未开始
  • 支持data为空值

一个坑

我之前的想法是,直接拿时间的差值用moment这种算时间的把时间算出来,因为时间戳0是1970.01.01 00:00:00 。
然后结果是不对的,原因如下:


因为时间戳0是对于本初子午线,也就是0时区那里来说的,对于位处于东八区的我们来说,时间戳0是-8hour。
然后用new Date(0)得出来的结果就是,它去掉符号了,算出来是早上八点。这样我的倒计时结果就不对了。
当然改进的方法就是将起始时间戳改成今天的0点,然后加上这个时间戳差值。但是我还是决定自己算一遍,为了代码的可读性。
const delta = endTime - now;
const nowDay = Math.floor(delta / (1000 * 60 * 60 * 24));
let remainTime: any = delta - nowDay * (1000 * 60 * 60 * 24);
const hour = Math.floor(remainTime / (1000 * 60 * 60));
remainTime %= 1000 * 60 * 60;
const minute = Math.floor(remainTime / (1000 * 60));
remainTime %= 1000 * 60;
const second = Math.floor(remainTime / 1000);
const nowTime = `${`0${hour}`.slice(-2)}:${`0${minute}`.slice(-2)}:${`0${second}`.slice(
  -2,
)}`;
const time = (
  <span>
    {nowDay > 0 && `${nowDay}天`}
    {`${nowTime}`}
  </span>
);

代码

import React, { ReactNode, useEffect, useMemo, useState } from 'react';
import { NewShopTaskNoviceGiftGroupVO } from 'src/service/NewShopGiftPack/types';
import ContentWrap from '../ContentWrap';
import $style from './style.less';

interface PropsType {
  children?: ReactNode;
  data: NewShopTaskNoviceGiftGroupVO;
}

export default function (props: PropsType) {
  const { children, data } = props;
  const { statusDesc, title, status , startTime, endTime} = data || {};
  const [now, setNow] = useState(new Date().getTime());
  const extra = useMemo(() => {
    let res: ReactNode = statusDesc;
    if (status === 'RUNNING') {
      if (startTime > now) {
        res = '未开始';
      } else if (endTime > now && startTime < now) {
        const delta = endTime - now;
        const nowDay = Math.floor(delta / (1000 * 60 * 60 * 24));
        let remainTime: any = delta - nowDay * (1000 * 60 * 60 * 24);
        const hour = Math.floor(remainTime / (1000 * 60 * 60));
        remainTime %= 1000 * 60 * 60;
        const minute = Math.floor(remainTime / (1000 * 60));
        remainTime %= 1000 * 60;
        const second = Math.floor(remainTime / 1000);
        const nowTime = `${`0${hour}`.slice(-2)}:${`0${minute}`.slice(-2)}:${`0${second}`.slice(
          -2,
        )}`;
        const time = (
          <span>
            {nowDay > 0 && `${nowDay}天`}
            {`${nowTime}`}
          </span>
        );
        res = (
          <div className={$style.countDown}>
            {`${statusDesc},距结束`}
            {time}
          </div>
        );
      } else if (endTime < now) {
        res = '已结束';
      }
    }

    return res;
  }, [status, statusDesc, endTime, startTime, now]);

  useEffect(() => {
    const clock = setTimeout(() => {
      if (endTime > now && startTime < now) {
        setNow(new Date().getTime());
      }
    }, 100);
    return () => clearTimeout(clock);
  }, [endTime, startTime, now]);

  return (
    <div className={$style.giftItem}>
      <ContentWrap title={title} extra={extra}>
        {children}
      </ContentWrap>
    </div>
  );
}

单测

  • 使用MockDate设置时间,这个时间是不会变动的,然后计算应该有的结果和组件render后的结果对比就行;
  • 测试在时间内,在时间前,在时间后,和边界情况00:00:00
    单测如下:
import React from 'react';
import MockDate from 'mockdate';
import { render, mount } from 'enzyme';
import GiftItem from '../../../components/GiftItem/index.tsx';

describe('NewShopGiftPack/components/GiftItem', () => {
  it('should be able to set undefined or null', () => {
    expect(() => {
      const wrapper = mount(<GiftItem />);
      wrapper.setProps({ data: undefined });
    }).not.toThrow();

    expect(() => {
      const wrapper = mount(<GiftItem />);
      wrapper.setProps({ data: undefined });
    }).not.toThrow();

    expect(() => {
      mount(<GiftItem />);
    }).not.toThrow();
  });

  const mockData = {
    statusDesc: '进行中',
    title: '',
    status: 'RUNNING',
    endTime: 1657883990000,
    startTime: 1657728000000,
  };

  it('count-down case: status RUNNING and during time range ', () => {
    const fakeDay = new Date(
      mockData.endTime - 1000 * 60 * 60 * 24 - 1000 - 60 * 1000 - 60 * 60 * 1000,
    ).getTime();
    MockDate.set(fakeDay);

    const wrapper = render(<GiftItem data={mockData} />);
    expect(wrapper.find('.countDown').length).toBe(1); // show count-down

    const currentRemainTime = wrapper.find('.countDown span').first().text(); // x天HH:mm:ss
    expect(currentRemainTime).toBe('1天01:01:01');
    MockDate.reset();
  });

  it('count-down case: status RUNNING and remain 1 ms ending', () => {
    MockDate.set(mockData.endTime - 1);
    const wrapper = render(<GiftItem data={mockData} />);
    expect(wrapper.find('.countDown').length).toBe(1); // show count-down
    const currentRemainTime = wrapper.find('.countDown span').first().text(); // x天HH:mm:ss
    expect(currentRemainTime).toBe('00:00:00');
    MockDate.reset();
  });

  it('count-down case: status RUNNING and before the time range', () => {
    MockDate.set(mockData.startTime - 1);
    const wrapper = render(<GiftItem data={mockData} />);
    expect(wrapper.find('.countDown').length).toBe(0); // countDown should disappear
    expect(wrapper.find('.extra').first().text()).toBe('未开始'); // when current date is out of the time range, text there should be rewrite with ignoring the RUNNING status
    MockDate.reset();
  });

  it('count-down case: status RUNNING and behind the time range', () => {
    MockDate.set(mockData.endTime + 1);
    const wrapper = render(<GiftItem data={mockData} />);
    expect(wrapper.find('.countDown').length).toBe(0); // countDown should disappear
    expect(wrapper.find('.extra').first().text()).toBe('已结束'); // when current date is out of the time range, text there should be rewrite with ignoring the RUNNING status
    MockDate.reset();
  });
});


参考:
http://t.zoukankan.com/jwentest-p-7477733.html

相关文章

  • 学习react hook的总结

    react16推出了react hook,react hook使得functional组件拥有了class组件的一...

  • 倒计时组件(React hook)和单元测试

    目标 如何测试倒计时 实现 倒计时组件 剩余时间展示格式为:x天HH:mm:ss 超过时间,将文案变成已结束 在时...

  • React Hook

    简介 :原本函数组件和类组件同为react组件,但是由于函数组件为无状态组件,react hook 的引入,让函数...

  • react hook介绍

    react hook是什么 react hook是react中引入新特性,它可以让react函数组件也拥有状态;通...

  • React Hook介绍与使用心得

    关于React Hook React Hook 对于React来说无疑是一个伟大的特性,它将React从类组件推向...

  • React Hook

    Hook 是能让你在函数组件中“钩入” React 特性的函数(hook是react16.8的新增特性,让函数组件...

  • react中常见hook的使用方式与区别

    1、什么是hook?react hook是react 16.8推出的方法,能够让函数式组件像类式组件一样拥有sta...

  • React Hooks - 学习笔记

    React Hooks Hook 是能让你在函数组件中“钩入” React 特性的函数。 State Hook u...

  • react中调用子组件的方法

    class组件 父组件 子组件 react hook 父组件调用子组件方法 父组件 子组件

  • useRef、useImperativeHandle、useCa

    react hook父组件调用子组件父子: 官方文档 useImperativeHandle useImperat...

网友评论

      本文标题:倒计时组件(React hook)和单元测试

      本文链接:https://www.haomeiwen.com/subject/kznfbrtx.html