Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
Unreleased
==========

## Breaking Changes
* JSON formatter: group stats changed from `{ "covered_percent": 80.0 }` to full stats shape `{ "covered": 8, "missed": 2, "total": 10, "percent": 80.0, "strength": 0.0 }`. The key `covered_percent` is renamed to `percent`.
* JSON formatter: `simplecov_json_formatter` gem is now built in. `require "simplecov_json_formatter"` continues to work via a shim.
* `StringFilter` now matches at path-segment boundaries. `"lib"` matches `/lib/` but no longer matches `/library/`. Use a `Regexp` filter for substring matching.
* Removed `docile` gem dependency. The `SimpleCov.configure` DSL block is now evaluated via `instance_exec` with instance variable proxying.

## Enhancements
* JSON formatter: added `total` section with aggregate coverage statistics (covered, missed, total, percent, strength) for line, branch, and method coverage
* JSON formatter: per-file output now includes `lines_covered_percent`, and when enabled: `branches_covered_percent`, `methods` array, and `methods_covered_percent`
* JSON formatter: group stats now include full statistics for all enabled coverage types, not just line coverage percent
* JSON formatter: added `silent:` keyword to `JSONFormatter.new` to suppress console output
* Merged `simplecov-html` formatter into the main gem. A backward-compatibility shim ensures `require "simplecov-html"` still works.
* Merged `simplecov_json_formatter` into the main gem. A backward-compatibility shim ensures `require "simplecov_json_formatter"` still works.
* Added `rake assets:compile` task for building the HTML formatter's frontend assets via esbuild
* Added TypeScript type checking CI workflow
* Separated rubocop into its own `lint.yml` CI workflow
* `CommandGuesser` now appends the framework name to parallel test data (e.g. `"RSpec (1/2)"` instead of `"(1/2)"`)

## Bugfixes
* Don't report misleading 100% branch/method coverage for files added via `track_files` that were never loaded. See #902
* Fix HTML formatter tab bar layout: dark mode toggle no longer wraps onto two lines, and tabs connect seamlessly with the content panel
* Fix branch coverage cucumber feature to match the HTML formatter's updated output format

0.22.1 (2024-09-02)
==========
Expand Down
5 changes: 4 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ task test: %i[spec cucumber test_html]
task default: %i[rubocop spec cucumber test_html]

namespace :assets do
desc "Compile frontend assets (JS + CSS) using esbuild"
desc "Compile frontend assets (HTML, JS, CSS) using esbuild"
task :compile do
frontend = File.expand_path("html_frontend", __dir__)
outdir = File.expand_path("lib/simplecov/formatter/html_formatter/public", __dir__)
Expand All @@ -62,5 +62,8 @@ namespace :assets do
io.close_write
File.write("#{outdir}/application.css", io.read)
end

# HTML: copy static index.html
FileUtils.cp(File.join(frontend, "src/index.html"), File.join(outdir, "index.html"))
end
end
3 changes: 1 addition & 2 deletions features/branch_coverage.feature
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ Feature:
end
"""
When I open the coverage report generated with `bundle exec rspec spec`
Then the output should contain "Line coverage: 56 / 61 (91.80%)"
And the output should contain "Branch coverage: 2 / 4 (50.00%)"
Then the output should contain "56 / 61 LOC (91.8%) covered"
And I should see the groups:
| name | coverage | files |
| All Files | 91.80% | 7 |
Expand Down
24 changes: 23 additions & 1 deletion features/step_definitions/html_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,29 @@
end

Then /^there should be (\d+) skipped lines in the source files$/ do |expected_count|
count = page.evaluate_script("document.querySelectorAll('.source_files template').length > 0 ? Array.from(document.querySelectorAll('.source_files template')).reduce(function(sum, t) { return sum + t.content.querySelectorAll('ol li.skipped').length; }, 0) : document.querySelectorAll('.source_table ol li.skipped').length")
# Materialize all source files (renders them from coverage data), then count skipped lines
count = page.evaluate_script(<<~JS)
(function() {
// Check for pre-rendered templates (old simplecov-html)
var templates = document.querySelectorAll('.source_files template');
if (templates.length > 0) {
return Array.from(templates).reduce(function(sum, t) {
return sum + t.content.querySelectorAll('ol li.skipped').length;
}, 0);
}
// New architecture: count skipped lines directly from coverage data
if (window.SIMPLECOV_DATA) {
var count = 0;
var coverage = window.SIMPLECOV_DATA.coverage;
Object.keys(coverage).forEach(function(fn) {
var lines = coverage[fn].lines;
lines.forEach(function(l) { if (l === 'ignored') count++; });
});
return count;
}
return document.querySelectorAll('.source_table ol li.skipped').length;
})()
JS
expect(count).to eq(expected_count.to_i)
end

Expand Down
9 changes: 7 additions & 2 deletions features/step_definitions/json_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
coverage_hash = json_report.fetch "coverage"
directory = Dir.pwd

expect(coverage_hash.fetch("#{directory}/lib/faked_project.rb")).to eq "lines" => [nil, nil, 1, 1, 1, nil, nil, nil, 5, 3, nil, nil, 1]
expect(coverage_hash.fetch("#{directory}/lib/faked_project/some_class.rb")).to eq "lines" => [nil, nil, 1, 1, 1, nil, 1, 2, nil, nil, 1, 1, nil, nil, 1, 1, 1, nil, 0, nil, nil, 0, nil, nil, 1, nil, 1, 0, nil, nil]
faked_project = coverage_hash.fetch("#{directory}/lib/faked_project.rb")
expect(faked_project["lines"]).to eq [nil, nil, 1, 1, 1, nil, nil, nil, 5, 3, nil, nil, 1]
expect(faked_project["lines_covered_percent"]).to be_a(Float)

some_class = coverage_hash.fetch("#{directory}/lib/faked_project/some_class.rb")
expect(some_class["lines"]).to eq [nil, nil, 1, 1, 1, nil, 1, 2, nil, nil, 1, 1, nil, nil, 1, 1, 1, nil, 0, nil, nil, 0, nil, nil, 1, nil, 1, 0, nil, nil]
expect(some_class["lines_covered_percent"]).to be_a(Float)
end
end
17 changes: 16 additions & 1 deletion features/support/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,23 @@ def extended(base)

# Rack app for Capybara which returns the latest coverage report from Aruba temp project dir
coverage_dir = File.expand_path("../../tmp/aruba/project/coverage/", __dir__)

# Prevent the browser from caching coverage_data.js between scenario visits
class NoCacheMiddleware
def initialize(app)
@app = app
end

def call(env)
status, headers, body = @app.call(env)
headers["cache-control"] = "no-store"
[status, headers, body]
end
end

Capybara.app = Rack::Builder.new do
use Rack::Static, urls: {"/" => "index.html"}, root: coverage_dir, header_rules: [[:all, {"cache-control" => "no-store"}]]
use NoCacheMiddleware
use Rack::Static, urls: {"/" => "index.html"}, root: coverage_dir
run Rack::Directory.new(coverage_dir)
end.to_app

Expand Down
Loading