36e5a9c1 Andy McCall 1 month ago ↶
1
{% extends "base.html" %}
2
{% import "repo_tabs.html" as m %}
3
{% block title %}Tests · {{ repo.owner }}/{{ repo.name }}{% endblock %}
4
{% block tabs %}{% call m::tabs(repo, "tests") %}{% endblock %}
5
{% block content %}
6
{% if let Some(r) = report %}
7
< section class = " cov-hero " >
8
< div class = " cov-hero-head " >
9
< div >
10
< h1 > Tests</ h1 >
11
< div class = " cov-sub " > {% if bookmarks.len() > 1 %}< form class = " inline " method = " get" action = " {{ repo.url }}/tests" > < label for = " t-bm" class = " mute " > bookmark</ label > < select id = " t-bm " name = " bookmark" onchange = " this . form . submit ( ) " > {% for b in bookmarks %}< option value = " {{ b }}" {% if b.as_str () == bookmark.as_str () %} selected {% endif %}> {{ b }}</ option > {% endfor %}</ select > < noscript > < button > Show</ button > </ noscript > </ form > {% else %}< span class = " mute " > on</ span > < strong > {{ bookmark }}</ strong > {% endif %}
12
· < a href = " {{ repo.url }}/flow/{{ r.run_number }}" > run #{{ r.run_number }}</ a > · job {{ r.job }} · < time title = " {{ r.created_ms|when_i }}" > {{ r.created_ms|ago_i }}</ time > </ div >
13
</ div >
14
< div class = " cov-score {{ self.class_of(r) }} " >
15
< div class = " cov-big " > {% if r.broken() > 0 %}{{ r.broken() }} failing{% else %}{{ self.rate(r) }}{% endif %}</ div >
16
< div class = " cov-change same " > {% if r.broken() > 0 %}{{ self.rate(r) }} of {{ r.tests - r.skipped }} passed{% else %}of {{ r.tests - r.skipped }} tests passed{% endif %}</ div >
17
</ div >
18
</ div >
19
{% if runs > 1 %}< div class = " cov-hero-chart " > {{ rate_chart|safe }}</ div > {% endif %}
20
</ section >
21
22
< section class = " cov-facts " >
23
< div > < span class = " k " > Tests</ span > < span class = " v " > {{ r.tests }}{% if let Some(d) = self.count_delta() %} < small > {{ self.signed(d) }}</ small > {% endif %}</ span > </ div >
24
< div > < span class = " k " > Passed</ span > < span class = " v cov-good " > {{ r.passed }}</ span > </ div >
25
< div > < span class = " k " > Failed</ span > < span class = " v{% if r.failed > 0 %} cov-poor{% endif %} " > {{ r.failed }}</ span > </ div >
26
{% if r.errors > 0 %}< div > < span class = " k " > Errored</ span > < span class = " v cov-poor " > {{ r.errors }}</ span > </ div > {% endif %}
27
< div > < span class = " k " > Skipped</ span > < span class = " v " > {{ r.skipped }}</ span > </ div >
28
< div > < span class = " k " > Test time</ span > < span class = " v " > {{ self.time(r.time_ms) }}{% if let Some(d) = self.time_delta() %} < small > {{ d }}</ small > {% endif %}</ span > </ div >
29
{% if let Some(t) = first_ms %}< div > < span class = " k " > Reporting since</ span > < span class = " v small " > < time title = " {{ t|when_i }}" > {{ t|ago_i }}</ time > </ span > </ div > {% endif %}
30
</ section >
31
32
< div class = " cov-grid " >
33
< section class = " panel cov-card " >
34
< h2 > This run</ h2 >
35
< ul class = " cov-stats " >
36
< li > < strong > {{ r.passed }}</ strong > of < strong > {{ r.tests - r.skipped }}</ strong > tests passed < span class = " {{ self.class_of(r) }} " > ({{ self.rate(r) }})</ span > {% if r.skipped > 0 %}, {{ r.skipped }} skipped{% endif %}</ li >
37
{% if let Some(p) = previous %}< li > Against < a href = " {{ repo.url }}/tests?report={{ p.id }}" > run #{{ p.run_number }}</ a > : {{ broke.len() }} newly failing, {{ fixed.len() }} fixed{% if added > 0 %}, {{ added }} new tests{% endif %}</ li > {% else %}< li > The first report of job {{ r.job }} here</ li > {% endif %}
38
</ ul >
39
{% if !broke.is_empty() %}< h3 > Newly failing</ h3 >
40
< ul class = " t-list " > {% for c in broke %}< li > < span class = " cov-poor " > ✕</ span > < code > {{ c.title }}</ code > </ li > {% endfor %}</ ul > {% endif %}
41
{% if !fixed.is_empty() %}< h3 > Fixed</ h3 >
42
< ul class = " t-list " > {% for c in fixed %}< li > < span class = " cov-good " > ✓</ span > < code > {{ c.title }}</ code > </ li > {% endfor %}</ ul > {% endif %}
43
</ section >
44
< section class = " panel cov-card " >
45
< h2 > Flaky < small class = " mute " > failed and passed in the last {{ flaky_runs }} runs</ small > </ h2 >
46
{% if flaky.is_empty() %}< p class = " mute small " > None: every test kept its result.</ p > {% else %}
3d5c825a Andy McCall 29 days ago ↶
47
< table class = " cov-moved " > {% for f in flaky %}< tr > < td > < a href = " {{ repo.url }}/tests/case?classname={{ f.classname|urlencode }}&name={{ f.name|urlencode }}&bookmark={{ bookmark|urlencode }}" > < code > {{ f.title() }}</ code > </ a > </ td > < td class = " num " > < span class = " cov-poor " > {{ f.failed }} ✕</ span > < span class = " cov-good " > {{ f.passed }} ✓</ span > </ td > </ tr > {% endfor %}</ table > {% endif %}
36e5a9c1 Andy McCall 1 month ago ↶
48
</ section >
49
</ div >
50
51
{% if !failures.is_empty() %}< section class = " panel " >
52
< h2 > Failures < small class = " mute " > {{ r.broken() }} in run #{{ r.run_number }}{% if r.broken() > failures.len() as i64 %}, the first {{ failures.len() }} shown{% endif %}</ small > </ h2 >
53
< div class = " flow-tests " > {% for f in failures %}< details class = " tests-failure " >
3d5c825a Andy McCall 29 days ago ↶
54
< summary > < span class = " bad " > {% if f.status == "error" %}!{% else %}✕{% endif %}</ span > < code > {{ f.title() }}</ code > < a class = " small " href = " {{ repo.url }}/tests/case?classname={{ f.classname|urlencode }}&name={{ f.name|urlencode }}&bookmark={{ bookmark|urlencode }}" > history</ a > {% if !f.message.is_empty() %} < span class = " small mute " > {{ f.message }}</ span > {% endif %}</ summary >
36e5a9c1 Andy McCall 1 month ago ↶
55
{% if !f.output.is_empty() %}< pre class = " flow-log " > {{ f.output }}</ pre > {% endif %}
56
</ details > {% endfor %}</ div >
57
</ section > {% endif %}
58
59
{% if runs > 1 %}< section class = " panel " >
60
< h2 > Tests run < small class = " mute " > < span class = " cov-key covered " > passed</ span > < span class = " cov-key relevant " > failed</ span > </ small > </ h2 >
61
{{ count_chart|safe }}
62
</ section > {% endif %}
63
64
< section class = " panel " >
65
< h2 > Slowest tests < small class = " mute " > in run #{{ r.run_number }}</ small > </ h2 >
66
< div class = " table " > < table class = " cov-files " >
67
< tr > < th > Test</ th > < th class = " num " > Time</ th > </ tr >
3d5c825a Andy McCall 29 days ago ↶
68
{% for c in slowest %}< tr > < td > < a href = " {{ repo.url }}/tests/case?classname={{ c.classname|urlencode }}&name={{ c.name|urlencode }}&bookmark={{ bookmark|urlencode }}" > < code > {{ c.title() }}</ code > </ a > {% if c.status != "passed" %} < span class = " cov-poor small " > {{ c.status }}</ span > {% endif %}</ td > < td class = " num " > {{ self.time(c.time_ms) }}</ td > </ tr > {% endfor %}
36e5a9c1 Andy McCall 1 month ago ↶
69
</ table > </ div >
70
</ section >
71
72
{% if recent.len() > 1 %}< section class = " panel " >
73
< h2 > Recent runs on {{ bookmark }}</ h2 >
74
< div class = " table " > < table class = " cov-runs " >
75
< tr > < th > Run</ th > < th > Job</ th > < th > Passing</ th > < th class = " num " > Tests</ th > < th class = " num " > Failed</ th > < th class = " num " > Time</ th > < th > When</ th > </ tr >
76
{% for x in recent %}< tr {% if x.report.id = = r.id %} class = " on " {% endif %}>
77
< td > < a href = " {{ repo.url }}/tests?report={{ x.report.id }}" > #{{ x.report.run_number }}</ a > </ td >
78
< td > {{ x.report.job }}</ td >
79
< td > < span class = " cov-bar {{ self.class_of(x.report) }} " > < span style = " width : {% if let Some(p ) = crate : :web::test_reports::pass_rate(x.report ) %}{{ p }}{% else %}0{% endif %}%" > </ span > </ span > {{ self.rate(x.report) }}</ td >
80
< td class = " num " > {{ x.report.tests }}{% if let Some(d) = x.delta %}{% if *d != 0 %} < small class = " mute " > {{ self.signed(d) }}</ small > {% endif %}{% endif %}</ td >
81
< td class = " num " > {% if x.report.broken() > 0 %}< span class = " cov-poor " > {{ x.report.broken() }}</ span > {% else %}0{% endif %}</ td >
82
< td class = " num " > {{ self.time(x.report.time_ms) }}</ td >
83
< td class = " small " > < time title = " {{ x.report.created_ms|when_i }}" > {{ x.report.created_ms|ago_i }}</ time > </ td >
84
</ tr > {% endfor %}
85
</ table > </ div >
86
</ section > {% endif %}
87
{% else %}
88
< div class = " head " > < h1 > Tests < small > of {{ bookmark }}</ small > </ h1 > </ div >
89
< section class = " panel " >
90
< p > No test report for < strong > {{ bookmark }}</ strong > yet.</ p >
91
< p > Give a job in < code > .flow/pipeline.kdl</ code > an artifact named < code > junit</ code > holding a JUnit XML report, kept with < code > when "always"</ code > so a failing run still sends it. For pytest:</ p >
92
< pre > job "test" {
93
sandbox "python"
94
exec "pytest" "--junitxml=/src/out/junit.xml"
95
output {
96
artifact "junit" {
97
path "/src/out/junit.xml"
98
when "always"
99
}
100
}
101
}</ pre >
102
< p class = " small mute " > cargo-nextest (a < code > junit</ code > profile), Jest's junit reporter and gotestsum write JUnit XML too.</ p >
103
</ section >
104
{% endif %}
105
{% endblock %}