{%- 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
{% for p in ticks %}{{ '%g'|format(p|round(1)) }}%{% endfor %} {%- set pts = [] %}{% for r in runs %}{% set _ = pts.append(x(loop.index0) ~ ',' ~ y(r.percentage)) %}{% endfor %} {% if n > 1 %}{% endif %} {% for r in runs %}{{ r.timestamp }} · {{ r.percentage }}% ({{ r.passed }} passed, {{ r.failed }} failed, {{ r.error }} errors){% endfor %} {% for r in runs %}{% if n <= 12 or loop.first or loop.last or loop.index0 % ((n // 8) or 1) == 0 %}{{ r.timestamp[5:10] }}{% endif %}{% endfor %}

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 %} {% for f in [0, 0.5, 1] %}{% set gy = '%.1f'|format(T + ph - f * ph) %}{{ (f * 100)|int }}%{% endfor %} {% for r in runs %}{% set total = r.total or 1 %}{% set cx = L2 + (loop.index0 + 0.5) * pw2 / n %}{% set ns = namespace(top=T + ph) %} {{ r.timestamp }}: {{ r.passed }} passed, {{ r.failed }} failed, {{ r.error }} errors, {{ r.skipped }} skipped {% for key in ['passed', 'skipped', 'error', 'failed'] %}{% if r[key] %}{% set h = r[key] * ph / total %}{% set ns.top = ns.top - h %}{% endif %}{% endfor %} {% endfor %}
{%- 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 %} {% for f in [0, 0.5, 1] %}{% set gy = '%.1f'|format(T + ph - f * ph) %}{{ '%.0f'|format(f * max_d) }}s{% endfor %} {% for r in runs %}{% set c = dpts[loop.index0].split(',') %}{{ r.timestamp }} · {{ r.duration }}s{% endfor %}
{% endif %} {%- macro strip(outcomes) %}{% endmacro %}

Flaky tests

fail, pass, fail again
{% if flaky_tests %}
{% for t in flaky_tests %}{% endfor %}
TestHistoryFlips
{{ t.name|e }}{{ strip(t.outcomes) }}{{ t.flips }}
{% 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 %}
{% for t in failure_streaks %}{% endfor %}
TestStreakSince
{{ t.name|e }}{{ t.streak }}{{ t.since }}
{% else %}

Nothing is failing in the latest run.

{% endif %}

Most failing tests

oldest run on the left
{% if most_failing %}
{% for t in most_failing %}{% endfor %}
TestHistoryFailuresFailure rate
{{ t.name|e }}{{ strip(t.outcomes) }}{{ t.failures }} / {{ t.runs }}{{ t.failure_rate }}%
{% 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
{% endfor %}
{% else %}

No timing data recorded.

{% endif %}

Runs

newest first
{% for r in runs|reverse %}{% endfor %}
WhenTestsFailedErrorsPass rateTime
{{ r.timestamp }}{{ r.total }}{{ r.failed }}{{ r.error }}{{ r.percentage }}%{{ '%.1f'|format(r.duration or 0) }}s