Created
November 2, 2024 10:02
-
-
Save dapicester/24edf9bd198d52102e1bbaaff1dc045d to your computer and use it in GitHub Desktop.
Instrument JavaScript code with Istanbul when running system tests on Rails 7 with importmaps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# test/application_system_test_case.rb | |
require "test_helper" | |
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase | |
include IstanbulInstrumentation | |
instrument_dir "app/javascript/controllers" | |
driven_by :selenium, using: :chrome, screen_size: [1400, 1400] | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# config/importmap.rb | |
pin "application" | |
pin "@hotwired/turbo-rails", to: "turbo.min.js" | |
pin "@hotwired/stimulus", to: "stimulus.min.js" | |
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" | |
if Rails.env.test? | |
# Use instrumented code to collect coverage. | |
pin_all_from "app/javascript/controllers-instrumented", under: "controllers", to: "controllers-instrumented" | |
else | |
pin_all_from "app/javascript/controllers", under: "controllers" | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# lib/istanbul_instrumentation.rb | |
# Mixin enabling Istanbul instrumentation and generating coverage report. | |
# It uses `npx` to download and run `nyc`. | |
module IstanbulInstrumentation | |
extend ActiveSupport::Concern | |
COVERAGE_DIR = Rails.root.join(".nyc_output") | |
class_methods do | |
# Add path to the list of directories to be instrumented. | |
def instrument_dir(dirname) | |
directories << instrument_code(dirname) | |
end | |
# Runs a command in subshell. Throws exception on non-zero exit codes or errors. | |
def run_command(cmd) | |
system cmd, exception: true | |
end | |
# Runs istanbul client to instrument the JavaScript code. | |
# Returns the instrumented code path. | |
def instrument_code(source) | |
destination = "#{source}-instrumented" | |
puts "Instrumenting the code at #{source} into #{destination}" | |
run_command "npx nyc instrument #{source} #{destination}" | |
destination | |
end | |
# Generates istanbul reports in the given format (default: text). | |
def generate_coverage_report(*formats) | |
puts "Generating Istanbul coverage report" | |
run_command "npx nyc report #{formats.map { |fmt| "--reporter=#{fmt}" }.join " "}" | |
end | |
# Removes instrumented code and intermediate coverage reports. | |
def cleanup | |
FileUtils.rm_r [ COVERAGE_DIR, *directories ] | |
end | |
end | |
included do | |
class_attribute :directories, default: [] | |
Minitest.after_run do | |
generate_coverage_report "lcov", "text-summary" | |
cleanup | |
end | |
end | |
def teardown | |
super | |
collect_coverage | |
end | |
# Collect the coverage from the instrumented code and save into JSON file. | |
def collect_coverage | |
coverage = page.evaluate_script("window.__coverage__") | |
return unless coverage.present? | |
FileUtils.mkdir COVERAGE_DIR unless Dir.exist? COVERAGE_DIR | |
filename = File.join(COVERAGE_DIR, "coverage_#{self.class_name.tableize}_#{self.name}.json") | |
File.open(filename, "w") do |file| | |
file.puts JSON.pretty_generate coverage | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment