Skip to content

Create Code Coverage Summary

Tiffany Forkner edited this page Feb 28, 2025 · 2 revisions

Important

All of the files in this section should be created in the gh-pages branch.

Set Up the Directory Structure

Add the following file structure. The GitHub Actions assume this file structure, so they would need to be updated accordingly if the structure is changed.

|--  _data
	|--  coverage
|-- coverage

Create the Threshold Data File

Create _data/coverage/thresholds.yml this will hold our pass and fail threshold for test coverage so that the percentages can be color coded to their coverage level. You can set whatever you want for your project, but you will want the pass values to match your threshold definition from your test configuration.

pass:
  lines: 90
  functions: 85
  statements: 90
  branches: 80

fail:
  lines: 70
  functions: 65
  statements: 70
  branches: 60

Create Coverage Result Filter

Create _plugins/coverage-result-filter.rb. The helper method coverage_status takes in the percent coverage from the coverage report data and compares it to the values in _data/coverage/thresholds.yml to determine if the coverage passes, fails, or is between passing and failing

module Jekyll
  module CoverageResultFilter
    def coverage_status(input, name)
      if input >= @context.registers[:site].data["coverage"]["thresholds"]["pass"][name]
        "pass"
      elsif input >= @context.registers[:site].data["coverage"]["thresholds"]["fail"][name]
        "warn"
      else
        "fail"
      end
    end
  end
end

Liquid::Template.register_filter(Jekyll::CoverageResultFilter)

Create Code Coverage Report Summary Snippet

Note

The coverage data comes from the Istanbul json coverage summary in this format.

{
 "total": {
   "lines":{
     "total":4754,
     "covered":4405,
     "skipped":0,
     "pct":92.65
   },
   "statements":{
     "total":5206,
     "covered":4800,
     "skipped":0,
     "pct":92.2
   },
   "functions":{
     "total":1556,
     "covered":1362,
     "skipped":0,
     "pct":87.53
   },
   "branches":{
     "total":2846,
     "covered":2337,
     "skipped":0,
     "pct":82.11
   },
   
 },
 
}

Create a file _includes/coverage-summary.html to display the data from the json summary report. This is an example of what we are using.

Tip

_includes/coverage-summary.html

This snippet expects values to be passed in using parameters total (JSON code coverage report data) and branch (the branch the report ran on, for now this is always main).

{% if include.total %}
 <!-- if total was included, display the summary -->
 <div class="test-coverage-report-container">
   <!-- loop through the keys in total -->
   {% for stat in include.total %}
     <!-- assign the key to name -->
     {% assign name = stat[0] %}
     <!-- the coverage summary includes a field called "branchesTrue", but we want to skip it because it's a duplicate of "branches" -->
     {% if name != "branchesTrue" %}
       <!-- assign the value to values -->
       {% assign values = stat[1] %}
       <div class="stat-container">
         <div class="stat-header">
           <!-- Liquid provides a helper method to capitalize text -->
           {{ name | capitalize }}
         </div>
         <!-- use the custom coverage_status filter with the stat name to get the correct styling for the percent -->
         <div class="stat-percent coverage-{{ values.pct | coverage_status: name }}">
           <!-- Liquid provides a helper method for rounding floats to a number -->
           {{ values.pct | round: 1 }} %
         </div>
         <div class="stat-fraction">
           {{ values.covered }} / {{ values.total }}
         </div>
       </div>
     {% endif %}
   {% endfor %}
 </div>
 <div class="coverage-link">
   <!-- Liquid provides a helper method that will create the link relative to the baseurl set in _config.yml -->
   <a href="{{ '/coverage' | relative_url }}" target="_blank">View Full Report</a>
 </div>
{% else %}
 <!-- if the total was not included, display a message that there is nothing to display -->
 <div>There is currently no coverage report for {{ include.branch }}.</div>
{% endif %}

Add Styling for Code Coverage Summary

Create a custom CSS file for styling your reports. This may also be done as part of the site CSS file. This is an example of what we are using.

Tip

assets/css/coverage.css

.test-coverage-report-container {
   display: flex;
   flex-direction: row;
   gap: 1rem;
}

.stat-container {
   border: 1px solid #d0d7de;
   border-radius: 6px;
   width: 100%;
   padding: 1rem;
   display: flex;
   flex-direction: column;
   align-items: center;
   gap: 1.5rem;
}

.stat-header {
   font-size: large;
   font-weight: 500;
}

.stat-percent {
   font-size: xx-large;
   font-weight: bolder;
   flex-grow: 1;
}

.stat-fraction {
   font-size: smaller;
   font-weight: normal;
}

.coverage-link {
   margin-top: 1rem;
   display: flex;
   justify-content: end;
   min-height: 1rem;
}

.coverage-pass {
   color: rgb(2, 119, 2);
}

.coverage-fail {
   color: rgb(155, 0, 0);
}

.coverage-warn {
   color: rgb(243, 186, 17);
}

The site is not configured to use the styling yet, that will be added in the next section. With our snippet and styling, our code coverage report summary looks like this.

test coverage statistics for lines, statements, functions, and branches

Clone this wiki locally