{%- set brand = branding or {} %}
{%- set sm = summary %}
{%- set latest = runs[-1] if runs else none %}
{%- set status = 'empty' if not latest or not latest.total else ('failed' if latest.failed + latest.error else 'passed') %}
{%- set n = runs|length %}
{% if brand.favicon %}{% endif %}
{{ history_title|e }}
{%- if brand.logo %}{% else %}{% endif %}
pyrept test history
Latest run {% if status == 'failed' %}failed{% elif status == 'passed' %}passed{% else %}had no tests{% endif %}
{{ history_title|e }}
{{ n }} run{{ '' if n == 1 else 's' }}{% if n %} · {{ runs[0].timestamp }} → {{ latest.timestamp }}{% endif %}generated {{ generated }}
Runs
{{ sm.runs }}
Tests seen
{{ sm.tests }}
Latest pass rate
{{ sm.latest_percentage if sm.latest_percentage is not none else '–' }}{% if sm.latest_percentage is not none %}%{% endif %}{% if sm.percentage_change is number %}{{ '%+.2f'|format(sm.percentage_change) }}{% endif %}
Average pass rate
{{ sm.average_percentage }}%
Flaky tests
{{ sm.flaky }}
Failing now
{{ sm.failing_now }}
{% if n %}
{%- set W, H, L, R, T, B = 1000, 230, 44, 14, 14, 30 %}
{%- set pw = W - L - R %}{% set ph = H - T - B %}
{%- set step = pw / (n - 1) if n > 1 else 0 %}
{%- set low = runs|map(attribute='percentage')|min %}
{%- set floor = [((low - 5) // 10 * 10)|int, 0]|max if low > 15 else 0 %}
{%- set span = 100 - floor %}
{%- set ticks = [floor, floor + span / 4, floor + span / 2, floor + 3 * span / 4, 100] %}
{%- macro x(i) %}{{ '%.1f'|format(L + (i * step if n > 1 else pw / 2)) }}{% endmacro %}
{%- macro y(p) %}{{ '%.1f'|format(T + (100 - p) * ph / span) }}{% endmacro %}
Pass rate over time
skipped tests excluded
Outcomes per run
PassedFailedErrorSkipped
{#- Half-width charts get their own, narrower coordinate system so labels stay readable. #}
{%- set W2, L2 = 520, 44 %}{% set pw2 = W2 - L2 - R %}
{%- set step2 = pw2 / (n - 1) if n > 1 else 0 %}
{%- set bw = (pw2 / n) * 0.64 %}
{%- set max_d = runs|map(attribute='duration')|max or 1 %}
Run duration
longest {{ '%.1f'|format(max_d) }}s
{%- set dpts = [] %}{% for r in runs %}{% set _ = dpts.append(('%.1f'|format(L2 + (loop.index0 * step2 if n > 1 else pw2 / 2))) ~ ',' ~ ('%.1f'|format(T + ph - (r.duration or 0) * ph / max_d))) %}{% endfor %}
{% endif %}
{%- macro strip(outcomes) %}{% for o in outcomes %}{% endfor %}{% endmacro %}
Flaky tests
fail, pass, fail again
{% if flaky_tests %}
Test
History
Flips
{% for t in flaky_tests %}
{{ t.name|e }}
{{ strip(t.outcomes) }}
{{ t.flips }}
{% endfor %}
{% else %}
No flaky tests. A test counts as flaky when it fails in two or more separate stretches with passing runs in between, or passes only after a retry.
{% endif %}
Failing now
consecutive failing runs
{% if failure_streaks %}
Test
Streak
Since
{% for t in failure_streaks %}
{{ t.name|e }}
{{ t.streak }}
{{ t.since }}
{% endfor %}
{% else %}
Nothing is failing in the latest run.
{% endif %}
Most failing tests
oldest run on the left
{% if most_failing %}
Test
History
Failures
Failure rate
{% for t in most_failing %}
{{ t.name|e }}
{{ strip(t.outcomes) }}
{{ t.failures }} / {{ t.runs }}
{{ t.failure_rate }}%
{% endfor %}
{% else %}
No failures in these runs.
{% endif %}
Slowest tests
average across runs
{% if slowest_tests %}
{%- set top = slowest_tests[0].average or 1 %}
{% for t in slowest_tests %}
{{ t.name|e }}{{ '%.3f'|format(t.average) }}s · max {{ '%.3f'|format(t.max) }}s