javascript - moment.js 模拟 local() 所以单元测试运行一致
问题描述
我想测试以下代码。我想知道是否有办法模拟moment.js
或强制它认为我当前的位置是America/New_York
这样我的单元测试不会在可能位于不同地理位置的 gitlab.ci 运行器中失败?
const centralTimeStartOfDay = moment.tz('America/Chicago').startOf('day');
const startHour = centralTimeStartOfDay
.hour(7)
.local()
.hour();
基本上我想硬编码我的时区,America/New_York
并希望这个函数表现一致。
编辑:
我试过了:
Date.now = () => new Date("2020-06-21T12:21:27-04:00")
moment.tz.setDefault('America/New_York')
而且,我得到了同样的结果。我想模拟当前时间,所以startHour
返回一个一致的值。
解决方案
问题
所以这个问题没有一个单一的答案。这个问题是 javascript 的一个基本问题,您可以通过以下两种方式之一查看日期:
- UTC(
getUTCHours()
等getUTCMinutes()
) - 本地(即系统
getHours()
等getMinutes()
)
并且没有指定的方法来设置有效的系统时区,甚至是 UTC 偏移量。
(浏览mdnDate
参考资料或查看规范以了解这一切有多么无用。)
“可是等等!” 我们哭了,“这不就是moment-timezone
存在的理由吗??”
不完全是。moment
并moment-timezone
更好/更轻松地控制 javascript 中的时间管理,但即使他们也无法知道本地时区Date
正在使用什么,并使用其他机制来了解这一点。这是一个如下问题。
一旦您了解了代码,您会发现 moment 的 moment.local()
方法(原型声明和setOffsetToLocal的实现)有效地执行了以下操作:
- 将时刻的 UTC 偏移设置为 0
_isUTC
通过设置为 false 来禁用“UTC 模式” 。
禁用“UTC 模式”的效果是意味着大多数访问器方法都被转发到底层Date
对象。例如,.hours()
最终调用moment/get-set.jsget()
如下所示:
export function get(mom, unit) {
return mom.isValid()
? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]()
: NaN;
}
_d
是Date
时刻 ( mom
) 包裹的对象。因此,对于非 UTC 模式的时刻,有效地moment.hours()
传递到Date.prototype.getHours()
. 不管你设置了什么moment.tz.setDefault()
,或者你是否覆盖了Date.now()
. 这些东西都没有使用。
另一件事...
你说:
基本上我想将我的时间硬编码为 America/New_York 并希望此函数的行为始终如一
但实际上,这通常是不可能的。您正在使用芝加哥,我想它已经抵消了与纽约同步的转变,但是例如,英国的转变时间与美国不同,因此如果您从美国时区到英国时区。
解决方案。
但这仍然令人沮丧,因为我不希望我在波兰和美国西海岸的开发人员因为我的 CI 服务器在 UTC 中运行而进行破坏本地测试。那么我们能做些什么呢?
第一个解决方案不是解决方案:找到一种不同的方式来做你正在做的事情!通常使用的用例.local()
是非常有限的,并且是向用户显示他们当前偏移的时间。它甚至不是他们的时区,因为本地Date
方法只会查看当前偏移量。所以大多数时候你只想在当前时间使用它,或者如果你不介意Date
你使用它的一半对象是否错误(对于使用夏令时的时区)。最好通过其他方式了解用户想要的时区,而根本不使用.local()
。
第二个解决方案也是一个非解决方案:不要太担心你的测试!显示当地时间的主要事情是它可以工作,你并不关心它到底是什么。手动验证它是否显示正确的时间,并在您的测试中验证它是否返回一个看起来合理的东西,而不检查具体时间。
如果您仍想继续,最后一个解决方案至少可以使您的案例和其他一些解决方案有效,并且如果您发现需要扩展它,您需要做什么是显而易见的。然而,这是一个复杂的领域,我不保证这不会产生一些意想不到的副作用!
在您的测试设置文件中:
[
'Date',
'Day',
'FullYear',
'Hours',
'Minutes',
'Month',
'Seconds',
].forEach(
(prop) => {
Date.prototype[`get${prop}`] = function () {
return new Date(
this.getTime()
+ moment(this.getTime()).utcOffset() * 60000
)[`getUTC${prop}`]();
};
}
);
您现在应该能够使用moment.tz.setDefault()
并且使用.local()
应该允许您访问日期时间的属性,就好像它认为本地时区是在moment-timezone
.
我想过尝试修补
moment
,但它比 . 复杂得多Date
,而且修补Date
应该是健壮的,因为它是原始的。
推荐阅读
- algorithm - 如何选择仅包含已知单词的句子的数据结构
- git - 隐藏当前分支和主分支之间的差异以将其应用于旧提交
- python - 如何处理空的“DataFrame”:没有数字数据来绘制错误以在图表上获取字符串
- flutter - 流控制器未注册接收器事件颤动
- angular-forms - 如何以角度形式实现速记验证?
- python - Django Rest Framework - 如何对 MSSQL 存储过程中的数据进行建模和序列化
- python - Django 无法读取其他应用程序的模型
- python - 使用 Python 和 Selenium 将 APK 上传到解释为 URL 的网页
- arrays - 在 bash 中对带有空格的数组进行切片
- imagemagick - 在 ImageMagick 的循环中使用复合