Jest:测试Intl.DateTimeFormat

时间:2018-03-01 15:12:22

标签: javascript jestjs datetime-format

我想测试一个我写的过滤函数,它返回一个使用Intl.DateTimeFormat格式化的日期(' en-GB',options):

// module "date.js"
export default function (dateISOString) {
    const options = {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        timeZone: 'UTC'
    };
    let d = new Date(dateISOString);
    return new Intl.DateTimeFormat('en-GB', options).format(d);
};

这是我的测试,使用Jest:

import date from '@/filters/date';
describe('date', () => {
    it('should format the date into dd/mm/yyyy', () => {
        expect(date('2014-02-11')).toEqual('11/02/2014');
    });
});

但它失败了:

Expected value to equal:
  "11/02/2014"
Received:
  "02/11/2014"

是否可以使用Jest测试(或模拟)Intl API? 看起来问题是由于Impl API在浏览器和Node环境中的不同行为。

4 个答案:

答案 0 :(得分:7)

我设法找到解决此问题的唯一解决方案是安装full-icu,它似乎在测试过程中为节点提供了正确的语言环境。

需要该软件包,因为默认情况下,节点仅附带一组有限的区域设置,如下所述:https://nodejs.org/docs/latest-v9.x/api/intl.html

安装该软件包后,我必须采取的额外步骤是更改我的测试命令:

"test": "NODE_ICU_DATA=node_modules/full-icu jest --config jest.config.js"

我在几个不同的环境中遇到了这个问题。在Mac OS上本地运行测试时以及在CI期间在Docker容器内运行测试时。

有趣的是,在通过WebStorm的Jest集成运行测试时,我不需要使用导出。看起来Intl库的行为在节点中远非稳定。

答案 1 :(得分:1)

您可以使用here

中所述的polyfill
import IntlPolyfill from 'intl';
import 'intl/locale-data/jsonp/ru';

if (global.Intl) {
    Intl.NumberFormat = IntlPolyfill.NumberFormat;
    Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
} else {
    global.Intl = IntlPolyfill;
}

答案 2 :(得分:1)

package.json 中添加 intl

 "intl": "*",

jest.config.js

module.exports = {
    moduleNameMapper: {
        Intl: '<rootDir>/node_modules/intl/'
    }
};

然后在 Date.spec.js

 describe(`Date by locale`, () => {
     beforeAll(() => {  global.Intl = require('intl'); });
    // Add your tests here. 
    // Add a temporary console.log to verify the correct output
 }

答案 3 :(得分:0)

如果您想更改每次测试的区域,刚刚找到了一个解决方案。

这里的好处是对 Intl 对象的改动很小,因为我们只是使用普通的 api 来设置默认值

const timezoneMock = function(zone: string) {
    const DateTimeFormat = Intl.DateTimeFormat
    jest
    .spyOn(global.Intl, 'DateTimeFormat')
    .mockImplementation((locale, options) => new DateTimeFormat(locale, {...options, timeZone: zone}))
  }

  afterEach(() => {
    jest.restoreAllMocks();
  })

然后

  describe('when Europe/London', () => {
    it('returns local time', () => {
      timezoneMock('Europe/London')
   //etc....