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

2022-07-01  本文已影响0人  景阳冈大虫在此
GiftItem 效果图

目标

如何测试倒计时

实现

倒计时组件

一个坑

我之前的想法是,直接拿时间的差值用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>
  );
}

单测

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

上一篇 下一篇

猜你喜欢

热点阅读