您可以使用 capybara 系统/功能测试来捕获伊斯坦布尔的 JS 代码覆盖率。
我们是用 webpack 做的,它可能可以用资产管道来做,但我不知道从哪里开始。
一般来说,您需要将 istanbul 加入您的 webpack 管道,然后您需要从每个页面中删除 __coverage__ 变量,然后再移动到测试中的下一页。
yarn add istanbul-instrumenter-loader -D
yarn add nyc -D
在 config/webpack/development.js - 是的,开发,而不是测试 - 确保你没有 NODE_ENV === 测试
if (process.env.CI) {
environment.loaders.append('istanbul-instrumenter', {
test: /(\.js)$/,
use: {
loader: 'istanbul-instrumenter-loader',
options: { esModules: true },
},
enforce: 'post',
exclude: /node_modules/,
})
}
然后您需要抓取这些功能/系统测试。我们正在使用带有 rspec 的系统测试 - 这是我们运行的帮助程序
spec/support/js_code_coverage_helper.rb
# frozen_string_literal: true
# ugly hack to get in between the teardown of the browser session to collect the JS info for coverage - have to grab it
# from the rails system test because rspec doesn't expose it and the after block doesn't fire in the right place.
module JsCodeHelpers
def before_teardown
dump_js_coverage
super
end
def dump_js_coverage
return if page.driver.class.name == 'Capybara::RackTest::Driver' # HACK
return unless ENV['CI']
coverage_report_dir = '.nyc_output'
FileUtils.mkdir_p coverage_report_dir if ENV['CI']
page_coverage = page.evaluate_script('JSON.stringify(window.__coverage__);')
return if page_coverage.blank?
File.open(Rails.root.join(coverage_report_dir, "system_test_#{Time.current.to_i}.json"), 'w') do |report|
report.puts page_coverage
end
end
end
require 'action_dispatch/system_testing/test_helpers/setup_and_teardown'
ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.prepend(JsCodeHelpers)
# another ugly hack to scrape coverage information before any potential element navs us away from the page we're on - if we move to
# another page then we lose the __coverage__ variable. we do end up multi-capturing coverage - that's not important now.
require 'capybara/node/element'
module ClickTaker
# private method that all the clicks use - this is as close as we can get to the bare browser easily
def perform_click_action(keys, wait: nil, **options)
dump_js_coverage
super
end
def select_option(wait: nil)
dump_js_coverage
super
end
def send_keys(*args)
dump_js_coverage
super
end
def trigger(event)
dump_js_coverage
super
end
def drag_to(node, **options)
dump_js_coverage
super
end
def drop(*args)
dump_js_coverage
super
end
def execute_script(script, *args)
dump_js_coverage
super
end
def evaluate_script(script, *args)
dump_js_coverage
super
end
def evaluate_async_script(script, *args)
dump_js_coverage
super
end
def dump_js_coverage
return if session.driver.class.name == 'Capybara::RackTest::Driver' # HACK
return unless ENV['CI']
coverage_report_dir = '.nyc_output'
FileUtils.mkdir_p coverage_report_dir if ENV['CI']
page_coverage = session.evaluate_script('JSON.stringify(window.__coverage__);')
return if page_coverage.blank?
File.open(Rails.root.join(coverage_report_dir, "system_test_#{Time.current.to_i}.json"), 'w') do |report|
report.puts page_coverage
end
end
end
Capybara::Node::Element.prepend(ClickTaker)
这是一个 WIP/hack,直到我找到一种更好的方法来捕获页面转换之间的所有内容 - 但它效果很好。
请注意,我们的配置需要 CI=true 才能运行 - 这对远程来说很简单,但 CI=true rspec spec/system 将为您提供 js 覆盖率
然后你可以对 .nyc_output 中的文件做任何你需要的事情
yarn nyc report
yarn nyc merge ./.nyc_output coverage.json
唯一的缺点是,如果它在转到下一页之前捕获文件(所有点击...),它会在一行(行数)上显示同一覆盖范围的多个点击,这对我们来说更好我们不会对所有事情都使用远程表单 - 如果我们在提交/发布后在新页面上完成测试,我们会丢失在表单上运行的任何内容。