使用 Capybara 存根浏览器时间和时区
Stub browser time and time zone with Capybara
我有一个 JavaScript 组件(例如日期选择器)严重依赖 -
- 当前系统时间
- 当前系统时区
在 Ruby 和 Capybara 中,可以在 Timecop 等库的帮助下随时存根。
是否也可以在 Capybara 控制的无头浏览器中存根这些值?
谢谢!
编辑:这是一个示例,说明 Ruby 是如何被存根的,但 Capybara 的浏览器仍然使用系统时间
before do
now = Time.zone.parse("Apr 15, 2018 12:00PM")
Timecop.freeze(now)
visit root_path
binding.pry
end
> Time.zone.now
=> Sun, 15 Apr 2018 12:00:00 UTC +00:00
> page.evaluate_script("new Date();")
=> "2018-03-27T04:15:44Z"
如您所见,Timecop 仅影响测试和被测应用程序中的时间。浏览器 运行 作为一个单独的进程,完全不受 Timecop 的影响。因此,您需要 stub/mock 浏览器中的时间以及使用旨在执行此操作的许多 JS 库之一。我通常使用的是 sinon
- http://sinonjs.org/ - ,我有条件地将其安装在页面 head
中,使用类似
的东西
- if defined?(Timecop) && Timecop.top_stack_item
= javascript_include_tag "sinon.js" # adjust based on where you're loading sinon from
- unix_millis = (Time.now.to_f * 1000.0).to_i
:javascript
sinon.useFakeTimers(#{unix_millis});
这应该在 haml
模板中工作(如果使用 erb
则进行调整),并且会在访问页面时安装和模拟浏览器时间,同时使用 Timecop 模拟应用程序时间。
这有助于我与 zonebie
gem
配对使用
RSpec.configure do |config|
config.before(:suite) do
ENV['TZ'] = Time.zone.tzinfo.name
# ...
end
end
我知道这个问题有点老了,但我们有同样的要求,并找到了以下解决方案来处理 rails 6:
context 'different timezones between back-end and front-end' do
it 'shows the event timestamp according to front-end timezone' do
# Arrange
previous_timezone = Time.zone
previous_timezone_env = ENV['TZ']
server_timezone = "Europe/Copenhagen"
browser_timezone = "America/Godthab"
Time.zone = server_timezone
ENV['TZ'] = browser_timezone
Capybara.using_session(browser_timezone) do
freeze_time do
# Act
# ... Code here
# Assert
server_clock = Time.zone.now.strftime('%H:%M')
client_clock = Time.zone.now.in_time_zone(browser_timezone).strftime('%H:%M')
expect(page).not_to have_content(server_clock)
expect(page).to have_content(client_clock)
end
end
# (restore)
Time.zone = previous_timezone
ENV['TZ'] = previous_timezone_env
end
end
我有一个 JavaScript 组件(例如日期选择器)严重依赖 -
- 当前系统时间
- 当前系统时区
在 Ruby 和 Capybara 中,可以在 Timecop 等库的帮助下随时存根。
是否也可以在 Capybara 控制的无头浏览器中存根这些值?
谢谢!
编辑:这是一个示例,说明 Ruby 是如何被存根的,但 Capybara 的浏览器仍然使用系统时间
before do
now = Time.zone.parse("Apr 15, 2018 12:00PM")
Timecop.freeze(now)
visit root_path
binding.pry
end
> Time.zone.now
=> Sun, 15 Apr 2018 12:00:00 UTC +00:00
> page.evaluate_script("new Date();")
=> "2018-03-27T04:15:44Z"
如您所见,Timecop 仅影响测试和被测应用程序中的时间。浏览器 运行 作为一个单独的进程,完全不受 Timecop 的影响。因此,您需要 stub/mock 浏览器中的时间以及使用旨在执行此操作的许多 JS 库之一。我通常使用的是 sinon
- http://sinonjs.org/ - ,我有条件地将其安装在页面 head
中,使用类似
- if defined?(Timecop) && Timecop.top_stack_item
= javascript_include_tag "sinon.js" # adjust based on where you're loading sinon from
- unix_millis = (Time.now.to_f * 1000.0).to_i
:javascript
sinon.useFakeTimers(#{unix_millis});
这应该在 haml
模板中工作(如果使用 erb
则进行调整),并且会在访问页面时安装和模拟浏览器时间,同时使用 Timecop 模拟应用程序时间。
这有助于我与 zonebie
gem
RSpec.configure do |config|
config.before(:suite) do
ENV['TZ'] = Time.zone.tzinfo.name
# ...
end
end
我知道这个问题有点老了,但我们有同样的要求,并找到了以下解决方案来处理 rails 6:
context 'different timezones between back-end and front-end' do
it 'shows the event timestamp according to front-end timezone' do
# Arrange
previous_timezone = Time.zone
previous_timezone_env = ENV['TZ']
server_timezone = "Europe/Copenhagen"
browser_timezone = "America/Godthab"
Time.zone = server_timezone
ENV['TZ'] = browser_timezone
Capybara.using_session(browser_timezone) do
freeze_time do
# Act
# ... Code here
# Assert
server_clock = Time.zone.now.strftime('%H:%M')
client_clock = Time.zone.now.in_time_zone(browser_timezone).strftime('%H:%M')
expect(page).not_to have_content(server_clock)
expect(page).to have_content(client_clock)
end
end
# (restore)
Time.zone = previous_timezone
ENV['TZ'] = previous_timezone_env
end
end