robotframework-testdoc 0.6.0a3__tar.gz → 0.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/.gitignore +4 -3
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/PKG-INFO +4 -3
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/pyproject.toml +4 -3
- robotframework_testdoc-0.6.2/src/testdoc/html/templates/jinja_html_default/jinja_template.html +436 -0
- robotframework_testdoc-0.6.0a3/src/testdoc/html/templates/jinja_html_default/jinja_template.html +0 -1330
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/LICENSE +0 -0
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/README.md +0 -0
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/src/testdoc/default.toml +0 -0
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/src/testdoc/html/images/robotframework.svg +0 -0
- {robotframework_testdoc-0.6.0a3 → robotframework_testdoc-0.6.2}/src/testdoc/html/templates/mkdocs_default/overrides/partials/footer.html +0 -0
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
__pycache__/**
|
|
2
2
|
src/robotframework_testdoc.egg-info/**
|
|
3
3
|
**/__pycache__/**.pyc
|
|
4
|
-
.vscode/launch.json
|
|
5
|
-
.vscode/
|
|
6
4
|
dist/
|
|
7
5
|
*.egg-info/
|
|
8
6
|
output_doc.html
|
|
@@ -21,4 +19,7 @@ atest/testdoc_output/**
|
|
|
21
19
|
atest/mkdocs_test/**
|
|
22
20
|
atest/mkdocs_test_perf/**
|
|
23
21
|
atest/mkdocs_test_custom/**
|
|
24
|
-
docs/mkdocs/site/**
|
|
22
|
+
docs/mkdocs/site/**
|
|
23
|
+
.DS_Store
|
|
24
|
+
.vscode/mcp.json
|
|
25
|
+
.vscode/settings.json
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robotframework-testdoc
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: A CLI Tool to generate a Test Documentation for your RobotFramework Test Scripts.
|
|
5
5
|
Project-URL: Repository, https://github.com/MarvKler/robotframework-testdoc
|
|
6
6
|
Project-URL: Issues, https://github.com/MarvKler/robotframework-testdoc/issues
|
|
@@ -17,11 +17,10 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
17
17
|
Requires-Python: >=3.10
|
|
18
18
|
Requires-Dist: click
|
|
19
19
|
Requires-Dist: jinja2
|
|
20
|
-
Requires-Dist: mkdocs
|
|
21
20
|
Requires-Dist: mkdocs-include-markdown-plugin
|
|
22
21
|
Requires-Dist: mkdocs-macros-plugin
|
|
23
22
|
Requires-Dist: mkdocs-material
|
|
24
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: mkdocs<2.0.0
|
|
25
24
|
Requires-Dist: pymdown-extensions
|
|
26
25
|
Requires-Dist: robotframework
|
|
27
26
|
Requires-Dist: tomli
|
|
@@ -30,7 +29,9 @@ Requires-Dist: hatch; extra == 'dev'
|
|
|
30
29
|
Requires-Dist: mypy; extra == 'dev'
|
|
31
30
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
32
31
|
Requires-Dist: pytest; extra == 'dev'
|
|
32
|
+
Requires-Dist: rf-mcp; extra == 'dev'
|
|
33
33
|
Requires-Dist: robotframework-robocop; extra == 'dev'
|
|
34
|
+
Requires-Dist: robotframework-tablelibrary; extra == 'dev'
|
|
34
35
|
Requires-Dist: ruff; extra == 'dev'
|
|
35
36
|
Description-Content-Type: text/markdown
|
|
36
37
|
|
|
@@ -28,8 +28,7 @@ dependencies = [
|
|
|
28
28
|
"robotframework",
|
|
29
29
|
"jinja2",
|
|
30
30
|
"tomli",
|
|
31
|
-
"
|
|
32
|
-
"mkdocs",
|
|
31
|
+
"mkdocs<2.0.0",
|
|
33
32
|
"mkdocs-macros-plugin",
|
|
34
33
|
"mkdocs-material",
|
|
35
34
|
"mkdocs-include-markdown-plugin",
|
|
@@ -43,7 +42,9 @@ dev = [
|
|
|
43
42
|
"pytest",
|
|
44
43
|
"pre-commit",
|
|
45
44
|
"mypy",
|
|
46
|
-
"robotframework-robocop"
|
|
45
|
+
"robotframework-robocop",
|
|
46
|
+
"robotframework-tablelibrary",
|
|
47
|
+
"rf-mcp"
|
|
47
48
|
]
|
|
48
49
|
|
|
49
50
|
[project.scripts]
|
robotframework_testdoc-0.6.2/src/testdoc/html/templates/jinja_html_default/jinja_template.html
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" data-theme="light">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{ title }}</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' role='img' viewBox='0 0 24 24'><title>Robot Framework</title><path d='M4.9565 10.2246c0-1.8766 1.5257-3.4023 3.4-3.4023 1.8766 0 3.4024 1.5257 3.4024 3.4023 0 .6838-.5526 1.2364-1.2341 1.2364-.6818 0-1.2344-.5526-1.2344-1.2364 0-.513-.4185-.9296-.9338-.9296-.5129 0-.9317.4165-.9317.9296 0 .6838-.5523 1.2364-1.234 1.2364-.6818 0-1.2344-.5526-1.2344-1.2364m14.0868 5.717c0 .6842-.5524 1.2363-1.2341 1.2363H6.3575c-.6818 0-1.2344-.552-1.2344-1.2363 0-.6837.5526-1.2363 1.2344-1.2363h11.4517c.6817 0 1.234.5526 1.234 1.2363m-5.351-5.0244c-.3814-.5657-.2323-1.3328.3334-1.7143l2.8628-1.9334c.5613-.3902 1.3329-.2324 1.7144.3289.3815.5654.2323 1.3329-.3334 1.7144l-2.8628 1.9333c-.5442.3831-1.3348.2379-1.7144-.3289zm7.8393 7.6018a.8815.8815 0 0 1-.258.6227l-2.1277 2.1277a.8822.8822 0 0 1-.623.258H5.4772a.8822.8822 0 0 1-.623-.258l-2.1277-2.1277a.8815.8815 0 0 1-.258-.6227V5.4818a.8797.8797 0 0 1 .258-.6228l2.1277-2.1282a.8816.8816 0 0 1 .623-.2578h13.0456a.8816.8816 0 0 1 .623.2578l2.1277 2.1282a.8797.8797 0 0 1 .258.6228V18.519zm1.811-15.0835L20.5644.6577A2.2454 2.2454 0 0 0 18.9775 0H5.0207A2.2445 2.2445 0 0 0 3.433.658L.657 3.4359A2.2449 2.2449 0 0 0 0 5.0228v13.9547c0 .5953.2366 1.1667.6575 1.5872l2.778 2.7779c.421.421.9918.6573 1.5871.6573h13.9548a2.2448 2.2448 0 0 0 1.5872-.6573l2.7779-2.7779A2.2436 2.2436 0 0 0 24 18.9775V5.023a2.2451 2.2451 0 0 0-.6575-1.5875z'/></svg>">
|
|
8
|
+
<!-- Flash prevention: apply stored theme before CSS renders -->
|
|
9
|
+
<script>(function(){var t=localStorage.getItem('clarity-theme');if(t==='dark'||(!t&&window.matchMedia('(prefers-color-scheme:dark)').matches)){document.documentElement.setAttribute('data-theme','dark');}else{document.documentElement.setAttribute('data-theme','light');}})();</script>
|
|
10
|
+
<style>{% include 'style.css' %}</style>
|
|
11
|
+
<style>{{ pygments_css | safe }}</style>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
{% set suite = suites if suites else None %}
|
|
15
|
+
|
|
16
|
+
{# ------------------------------------------------------------
|
|
17
|
+
Template helpers
|
|
18
|
+
------------------------------------------------------------ #}
|
|
19
|
+
{% macro suite_icon(is_folder) -%}
|
|
20
|
+
{%- if is_folder -%}
|
|
21
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h5l2 2h7a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7z"/></svg>
|
|
22
|
+
{%- else -%}
|
|
23
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4.9565 10.2246c0-1.8766 1.5257-3.4023 3.4-3.4023 1.8766 0 3.4024 1.5257 3.4024 3.4023 0 .6838-.5526 1.2364-1.2341 1.2364-.6818 0-1.2344-.5526-1.2344-1.2364 0-.513-.4185-.9296-.9338-.9296-.5129 0-.9317.4165-.9317.9296 0 .6838-.5523 1.2364-1.234 1.2364-.6818 0-1.2344-.5526-1.2344-1.2364m14.0868 5.717c0 .6842-.5524 1.2363-1.2341 1.2363H6.3575c-.6818 0-1.2344-.552-1.2344-1.2363 0-.6837.5526-1.2363 1.2344-1.2363h11.4517c.6817 0 1.234.5526 1.234 1.2363m-5.351-5.0244c-.3814-.5657-.2323-1.3328.3334-1.7143l2.8628-1.9334c.5613-.3902 1.3329-.2324 1.7144.3289.3815.5654.2323 1.3329-.3334 1.7144l-2.8628 1.9333c-.5442.3831-1.3348.2379-1.7144-.3289zm7.8393 7.6018a.8815.8815 0 0 1-.258.6227l-2.1277 2.1277a.8822.8822 0 0 1-.623.258H5.4772a.8822.8822 0 0 1-.623-.258l-2.1277-2.1277a.8815.8815 0 0 1-.258-.6227V5.4818a.8797.8797 0 0 1 .258-.6228l2.1277-2.1282a.8816.8816 0 0 1 .623-.2578h13.0456a.8816.8816 0 0 1 .623.2578l2.1277 2.1282a.8797.8797 0 0 1 .258.6228V18.519zm1.811-15.0835L20.5644.6577A2.2454 2.2454 0 0 0 18.9775 0H5.0207A2.2445 2.2445 0 0 0 3.433.658L.657 3.4359A2.2449 2.2449 0 0 0 0 5.0228v13.9547c0 .5953.2366 1.1667.6575 1.5872l2.778 2.7779c.421.421.9918.6573 1.5871.6573h13.9548a2.2448 2.2448 0 0 0 1.5872-.6573l2.7779-2.7779A2.2436 2.2436 0 0 0 24 18.9775V5.023a2.2451 2.2451 0 0 0-.6575-1.5875z"/></svg>
|
|
24
|
+
{%- endif -%}
|
|
25
|
+
{%- endmacro %}
|
|
26
|
+
|
|
27
|
+
<!-- ============================================================
|
|
28
|
+
TOP HEADER BAR
|
|
29
|
+
============================================================ -->
|
|
30
|
+
<header class="topbar">
|
|
31
|
+
<div class="topbar-left">
|
|
32
|
+
<button class="sidebar-toggle" id="sidebarToggle" aria-label="Toggle sidebar">
|
|
33
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
34
|
+
<line x1="3" y1="6" x2="21" y2="6"/>
|
|
35
|
+
<line x1="3" y1="12" x2="21" y2="12"/>
|
|
36
|
+
<line x1="3" y1="18" x2="21" y2="18"/>
|
|
37
|
+
</svg>
|
|
38
|
+
</button>
|
|
39
|
+
<div class="topbar-brand">
|
|
40
|
+
<svg class="topbar-logo" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-label="Robot Framework">
|
|
41
|
+
<path d="M4.9565 10.2246c0-1.8766 1.5257-3.4023 3.4-3.4023 1.8766 0 3.4024 1.5257 3.4024 3.4023 0 .6838-.5526 1.2364-1.2341 1.2364-.6818 0-1.2344-.5526-1.2344-1.2364 0-.513-.4185-.9296-.9338-.9296-.5129 0-.9317.4165-.9317.9296 0 .6838-.5523 1.2364-1.234 1.2364-.6818 0-1.2344-.5526-1.2344-1.2364m14.0868 5.717c0 .6842-.5524 1.2363-1.2341 1.2363H6.3575c-.6818 0-1.2344-.552-1.2344-1.2363 0-.6837.5526-1.2363 1.2344-1.2363h11.4517c.6817 0 1.234.5526 1.234 1.2363m-5.351-5.0244c-.3814-.5657-.2323-1.3328.3334-1.7143l2.8628-1.9334c.5613-.3902 1.3329-.2324 1.7144.3289.3815.5654.2323 1.3329-.3334 1.7144l-2.8628 1.9333c-.5442.3831-1.3348.2379-1.7144-.3289zm7.8393 7.6018a.8815.8815 0 0 1-.258.6227l-2.1277 2.1277a.8822.8822 0 0 1-.623.258H5.4772a.8822.8822 0 0 1-.623-.258l-2.1277-2.1277a.8815.8815 0 0 1-.258-.6227V5.4818a.8797.8797 0 0 1 .258-.6228l2.1277-2.1282a.8816.8816 0 0 1 .623-.2578h13.0456a.8816.8816 0 0 1 .623.2578l2.1277 2.1282a.8797.8797 0 0 1 .258.6228V18.519zm1.811-15.0835L20.5644.6577A2.2454 2.2454 0 0 0 18.9775 0H5.0207A2.2445 2.2445 0 0 0 3.433.658L.657 3.4359A2.2449 2.2449 0 0 0 0 5.0228v13.9547c0 .5953.2366 1.1667.6575 1.5872l2.778 2.7779c.421.421.9918.6573 1.5871.6573h13.9548a2.2448 2.2448 0 0 0 1.5872-.6573l2.7779-2.7779A2.2436 2.2436 0 0 0 24 18.9775V5.023a2.2451 2.2451 0 0 0-.6575-1.5875z"/>
|
|
42
|
+
</svg>
|
|
43
|
+
<div class="topbar-title">
|
|
44
|
+
<div class="topbar-title-main">{{ title }}</div>
|
|
45
|
+
<div class="topbar-title-sub">Test Documentation</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="topbar-right">
|
|
50
|
+
{% if suite %}
|
|
51
|
+
<div class="topbar-stat">
|
|
52
|
+
<span class="topbar-stat-value">{{ suite.test_count }}</span>
|
|
53
|
+
<span class="topbar-stat-label">Tests</span>
|
|
54
|
+
</div>
|
|
55
|
+
{% endif %}
|
|
56
|
+
<button class="theme-toggle" id="themeToggle" aria-label="Toggle theme">
|
|
57
|
+
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
58
|
+
<circle cx="12" cy="12" r="5"/>
|
|
59
|
+
<line x1="12" y1="1" x2="12" y2="3"/>
|
|
60
|
+
<line x1="12" y1="21" x2="12" y2="23"/>
|
|
61
|
+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
|
62
|
+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
|
63
|
+
<line x1="1" y1="12" x2="3" y2="12"/>
|
|
64
|
+
<line x1="21" y1="12" x2="23" y2="12"/>
|
|
65
|
+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
|
66
|
+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
|
67
|
+
</svg>
|
|
68
|
+
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
69
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
70
|
+
</svg>
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</header>
|
|
74
|
+
|
|
75
|
+
<!-- ============================================================
|
|
76
|
+
APP BODY: Sidebar + Content
|
|
77
|
+
============================================================ -->
|
|
78
|
+
<div class="app-body" id="appBody">
|
|
79
|
+
|
|
80
|
+
<!-- SIDEBAR -->
|
|
81
|
+
<aside class="nav" id="sidebar">
|
|
82
|
+
<div class="nav-tree">
|
|
83
|
+
<ul class="tree-list">
|
|
84
|
+
{# Root suite entry #}
|
|
85
|
+
{% if suite %}
|
|
86
|
+
<li class="tree-item">
|
|
87
|
+
<a href="#suite-{{ suite.id }}" class="tree-suite active"
|
|
88
|
+
data-target="suite-{{ suite.id }}" data-suite-id="{{ suite.id }}">
|
|
89
|
+
<span class="tree-icon {% if suite.is_folder %}suite-folder{% else %}suite-file{% endif %}">
|
|
90
|
+
{{ suite_icon(suite.is_folder) }}
|
|
91
|
+
</span>
|
|
92
|
+
<span class="tree-main-label">{{ suite.name }}</span>
|
|
93
|
+
</a>
|
|
94
|
+
|
|
95
|
+
{# Recursive tree macro #}
|
|
96
|
+
{% macro render_suite_tree(current) %}
|
|
97
|
+
{% if current.suites or current.tests %}
|
|
98
|
+
<ul class="tree-children">
|
|
99
|
+
{% for s in current.suites %}
|
|
100
|
+
<li class="tree-item">
|
|
101
|
+
<a href="#suite-{{ s.id }}" class="tree-suite"
|
|
102
|
+
data-target="suite-{{ s.id }}" data-suite-id="{{ s.id }}">
|
|
103
|
+
<span class="tree-icon {% if s.is_folder %}suite-folder{% else %}suite-file{% endif %}">
|
|
104
|
+
{{ suite_icon(s.is_folder) }}
|
|
105
|
+
</span>
|
|
106
|
+
<span class="tree-main-label">{{ s.name }}</span>
|
|
107
|
+
</a>
|
|
108
|
+
{{ render_suite_tree(s) }}
|
|
109
|
+
</li>
|
|
110
|
+
{% endfor %}
|
|
111
|
+
|
|
112
|
+
{% if current.tests %}
|
|
113
|
+
{% for t in current.tests %}
|
|
114
|
+
<li class="tree-item">
|
|
115
|
+
<a href="#test-{{ current.id }}-{{ loop.index0 }}" class="tree-test"
|
|
116
|
+
data-target="test-{{ current.id }}-{{ loop.index0 }}" data-suite-id="{{ current.id }}">
|
|
117
|
+
<span class="tree-icon test">T</span>
|
|
118
|
+
<span class="tree-main-label">{{ t.name }}</span>
|
|
119
|
+
</a>
|
|
120
|
+
</li>
|
|
121
|
+
{% endfor %}
|
|
122
|
+
{% endif %}
|
|
123
|
+
</ul>
|
|
124
|
+
{% endif %}
|
|
125
|
+
{% endmacro %}
|
|
126
|
+
|
|
127
|
+
{{ render_suite_tree(suite) }}
|
|
128
|
+
</li>
|
|
129
|
+
{% endif %}
|
|
130
|
+
</ul>
|
|
131
|
+
</div>
|
|
132
|
+
</aside>
|
|
133
|
+
|
|
134
|
+
<!-- MAIN CONTENT -->
|
|
135
|
+
<main class="content" id="mainContent">
|
|
136
|
+
{# ------------------------------------------------------------
|
|
137
|
+
PoC: Keyword documentation metadata
|
|
138
|
+
|
|
139
|
+
We keep the lexer + Pygments highlighting unchanged.
|
|
140
|
+
Instead, we embed resolved keyword docs (already available in the
|
|
141
|
+
parsed model) as NDJSON per test block. The frontend can then add
|
|
142
|
+
a small info button next to each keyword call line.
|
|
143
|
+
------------------------------------------------------------ #}
|
|
144
|
+
{% macro emit_kw_doc_ndjson(items) %}
|
|
145
|
+
{% for item in (items or []) %}
|
|
146
|
+
{% if item.type == 'KEYWORD' and item.keyword_doc %}
|
|
147
|
+
{{ {'name': item.name, 'owner': item.keyword_owner, 'doc': item.keyword_doc, 'args': item.args} | dump_json }}
|
|
148
|
+
{% endif %}
|
|
149
|
+
{% if item.body %}
|
|
150
|
+
{{ emit_kw_doc_ndjson(item.body) }}
|
|
151
|
+
{% endif %}
|
|
152
|
+
{% endfor %}
|
|
153
|
+
{% endmacro %}
|
|
154
|
+
|
|
155
|
+
{% macro render_suite_block(s, level) %}
|
|
156
|
+
<section class="suite-block" data-suite-id="{{ s.id }}">
|
|
157
|
+
|
|
158
|
+
<!-- Per-suite sticky header -->
|
|
159
|
+
<header class="content-header" id="suite-{{ s.id }}">
|
|
160
|
+
<div class="content-header-main">
|
|
161
|
+
<div class="content-breadcrumb">
|
|
162
|
+
<span class="breadcrumb-type">{% if s.is_folder %}Directory{% else %}Suite{% endif %}</span>
|
|
163
|
+
</div>
|
|
164
|
+
<h1 class="content-title-main">{{ s.name }}</h1>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="content-header-meta">
|
|
167
|
+
<div class="stat-pill">
|
|
168
|
+
<span class="stat-pill-value">{{ s.test_count }}</span>
|
|
169
|
+
<span class="stat-pill-label">Total</span>
|
|
170
|
+
</div>
|
|
171
|
+
{% if s.tests %}
|
|
172
|
+
<div class="stat-pill secondary">
|
|
173
|
+
<span class="stat-pill-value">{{ s.tests | length }}</span>
|
|
174
|
+
<span class="stat-pill-label">Direct</span>
|
|
175
|
+
</div>
|
|
176
|
+
{% endif %}
|
|
177
|
+
</div>
|
|
178
|
+
</header>
|
|
179
|
+
|
|
180
|
+
<div class="content-body">
|
|
181
|
+
|
|
182
|
+
<!-- Suite Details -->
|
|
183
|
+
<section class="section">
|
|
184
|
+
<div class="section-header">
|
|
185
|
+
<span class="section-title">Suite Details</span>
|
|
186
|
+
<span class="section-subtitle">General information about this test suite</span>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="key-value-grid">
|
|
189
|
+
<div class="kv-label">Name</div>
|
|
190
|
+
<div class="kv-value">{{ s.name }}</div>
|
|
191
|
+
|
|
192
|
+
<div class="kv-label">Source</div>
|
|
193
|
+
<div class="kv-value mono">
|
|
194
|
+
{% if s.custom_source %}
|
|
195
|
+
<a href="{{ s.custom_source }}" target="_blank" rel="noopener noreferrer">{{ s.custom_source }}</a>
|
|
196
|
+
{% else %}
|
|
197
|
+
{{ s.source }}
|
|
198
|
+
{% endif %}
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div class="kv-label">Tests (total)</div>
|
|
202
|
+
<div class="kv-value">{{ s.test_count }}</div>
|
|
203
|
+
|
|
204
|
+
<div class="kv-label">Tests (direct)</div>
|
|
205
|
+
<div class="kv-value">{{ s.tests | length }}</div>
|
|
206
|
+
</div>
|
|
207
|
+
</section>
|
|
208
|
+
|
|
209
|
+
<!-- Suite Documentation -->
|
|
210
|
+
{% if s.doc %}
|
|
211
|
+
<section class="section">
|
|
212
|
+
<div class="section-header">
|
|
213
|
+
<span class="section-title">Documentation</span>
|
|
214
|
+
</div>
|
|
215
|
+
<pre class="rf-doc">{{ s.doc }}</pre>
|
|
216
|
+
</section>
|
|
217
|
+
{% endif %}
|
|
218
|
+
|
|
219
|
+
<!-- Metadata -->
|
|
220
|
+
{% if s.metadata %}
|
|
221
|
+
<section class="section">
|
|
222
|
+
<div class="section-header">
|
|
223
|
+
<span class="section-title">Metadata</span>
|
|
224
|
+
<span class="section-subtitle">Additional suite information</span>
|
|
225
|
+
</div>
|
|
226
|
+
<div class="key-value-grid">
|
|
227
|
+
<div class="kv-label">Entries</div>
|
|
228
|
+
<div class="kv-value">
|
|
229
|
+
<div class="metadata">
|
|
230
|
+
{% for meta in s.metadata %}
|
|
231
|
+
<span class="metadata-item">{{ meta }}</span>
|
|
232
|
+
{% endfor %}
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
</section>
|
|
237
|
+
{% endif %}
|
|
238
|
+
|
|
239
|
+
<!-- User Keywords -->
|
|
240
|
+
{% if s.user_keywords %}
|
|
241
|
+
<section class="section">
|
|
242
|
+
<div class="section-header">
|
|
243
|
+
<span class="section-title">User Keywords</span>
|
|
244
|
+
<span class="section-subtitle">Defined in this suite</span>
|
|
245
|
+
</div>
|
|
246
|
+
<div class="code-wrapper">
|
|
247
|
+
<button class="code-toggle">
|
|
248
|
+
<span>Show / Hide Code</span>
|
|
249
|
+
<span class="code-toggle-icon" aria-hidden="true">
|
|
250
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
|
251
|
+
</span>
|
|
252
|
+
</button>
|
|
253
|
+
<div class="code-toggle-body">
|
|
254
|
+
{% set code -%}
|
|
255
|
+
*** Keywords ***
|
|
256
|
+
{{ s.user_keywords | join('\n') }}
|
|
257
|
+
{%- endset %}
|
|
258
|
+
{{ code | highlight_robot_in_pre | safe }}
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
</section>
|
|
262
|
+
{% endif %}
|
|
263
|
+
|
|
264
|
+
{% if s.tests %}
|
|
265
|
+
<!-- Test Case Overview -->
|
|
266
|
+
<section class="section">
|
|
267
|
+
<div class="section-header">
|
|
268
|
+
<span class="section-title">Test Case Overview</span>
|
|
269
|
+
<span class="section-subtitle">All {{ s.tests | length }} tests in this suite</span>
|
|
270
|
+
</div>
|
|
271
|
+
<div class="code-always-visible">
|
|
272
|
+
{% set code -%}
|
|
273
|
+
*** Test Cases ***
|
|
274
|
+
{{ s.tests | map(attribute='name') | join('\n') }}
|
|
275
|
+
{%- endset %}
|
|
276
|
+
{{ code | highlight_robot_in_pre | safe }}
|
|
277
|
+
</div>
|
|
278
|
+
</section>
|
|
279
|
+
|
|
280
|
+
<!-- Test Case Details -->
|
|
281
|
+
<section class="section">
|
|
282
|
+
<div class="section-header">
|
|
283
|
+
<span class="section-title">Test Case Details</span>
|
|
284
|
+
<span class="section-subtitle">Per-test documentation and steps</span>
|
|
285
|
+
</div>
|
|
286
|
+
<div class="tests-list">
|
|
287
|
+
{% for test in s.tests %}
|
|
288
|
+
<section id="test-{{ s.id }}-{{ loop.index0 }}" class="test-block collapsed">
|
|
289
|
+
<div class="test-header">
|
|
290
|
+
<div class="test-name">{{ test.name }}</div>
|
|
291
|
+
<span class="test-collapse-icon" aria-hidden="true">
|
|
292
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
|
293
|
+
</span>
|
|
294
|
+
</div>
|
|
295
|
+
<div class="test-body-collapsible">
|
|
296
|
+
<div class="test-subsection">
|
|
297
|
+
<div class="kv-label">Documentation</div>
|
|
298
|
+
{% if test.doc %}
|
|
299
|
+
<pre class="rf-doc">{{ test.doc }}</pre>
|
|
300
|
+
{% else %}
|
|
301
|
+
<span class="empty">No documentation.</span>
|
|
302
|
+
{% endif %}
|
|
303
|
+
</div>
|
|
304
|
+
<div class="test-subsection">
|
|
305
|
+
<div class="kv-label">Tags</div>
|
|
306
|
+
{% if test.tags %}
|
|
307
|
+
<div class="tag-row">
|
|
308
|
+
{% for tag in test.tags %}
|
|
309
|
+
{% if tag is mapping %}
|
|
310
|
+
<span class="tag">{{ tag.name or tag }}</span>
|
|
311
|
+
{% else %}
|
|
312
|
+
<span class="tag">{{ tag }}</span>
|
|
313
|
+
{% endif %}
|
|
314
|
+
{% endfor %}
|
|
315
|
+
</div>
|
|
316
|
+
{% else %}
|
|
317
|
+
<span class="empty">No tags.</span>
|
|
318
|
+
{% endif %}
|
|
319
|
+
</div>
|
|
320
|
+
<div class="test-subsection">
|
|
321
|
+
<div class="kv-label">Body</div>
|
|
322
|
+
{% if test.body or test.setup or test.teardown %}
|
|
323
|
+
<script type="application/x-ndjson" class="kw-doc-ndjson" data-test-target="test-{{ s.id }}-{{ loop.index0 }}">
|
|
324
|
+
{% if test.setup and test.setup.keyword_doc %}
|
|
325
|
+
{{ {'name': test.setup.name, 'owner': test.setup.keyword_owner, 'doc': test.setup.keyword_doc, 'args': test.setup.args, 'fixture': 'setup'} | dump_json }}
|
|
326
|
+
{% endif %}
|
|
327
|
+
{% if test.teardown and test.teardown.keyword_doc %}
|
|
328
|
+
{{ {'name': test.teardown.name, 'owner': test.teardown.keyword_owner, 'doc': test.teardown.keyword_doc, 'args': test.teardown.args, 'fixture': 'teardown'} | dump_json }}
|
|
329
|
+
{% endif %}
|
|
330
|
+
{{ emit_kw_doc_ndjson(test.body) }}
|
|
331
|
+
</script>
|
|
332
|
+
<div class="code-wrapper">
|
|
333
|
+
<button class="code-toggle">
|
|
334
|
+
<span>Show / Hide Code</span>
|
|
335
|
+
<span class="code-toggle-icon" aria-hidden="true">
|
|
336
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
|
337
|
+
</span>
|
|
338
|
+
</button>
|
|
339
|
+
<div class="code-toggle-body">
|
|
340
|
+
{% set setup_line = [test.setup] | format_test_body | join('') if test.setup else '' %}
|
|
341
|
+
{% set teardown_line = [test.teardown] | format_test_body | join('') if test.teardown else '' %}
|
|
342
|
+
{% set code -%}
|
|
343
|
+
*** Test Cases ***
|
|
344
|
+
{{ test.name }}
|
|
345
|
+
{% if test.setup %} [Setup] {{ setup_line }}
|
|
346
|
+
{% endif %}{% if test.body %} {{ test.body | format_test_body | join('\n ') }}
|
|
347
|
+
{% endif %}{% if test.teardown %} [Teardown] {{ teardown_line }}
|
|
348
|
+
{% endif %}
|
|
349
|
+
{%- endset %}
|
|
350
|
+
{{ code | highlight_robot_in_pre | safe }}
|
|
351
|
+
</div>
|
|
352
|
+
</div>
|
|
353
|
+
{% else %}
|
|
354
|
+
<span class="empty">No keywords.</span>
|
|
355
|
+
{% endif %}
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|
|
358
|
+
</section>
|
|
359
|
+
{% endfor %}
|
|
360
|
+
</div>
|
|
361
|
+
</section>
|
|
362
|
+
{% endif %}
|
|
363
|
+
|
|
364
|
+
<!-- Sub-suites -->
|
|
365
|
+
{% if s.suites %}
|
|
366
|
+
<section class="section">
|
|
367
|
+
<div class="section-header">
|
|
368
|
+
<span class="section-title">Sub-Suites</span>
|
|
369
|
+
<span class="section-subtitle">Nested suite structure</span>
|
|
370
|
+
</div>
|
|
371
|
+
|
|
372
|
+
{% macro render_suite_details(s2, level2) %}
|
|
373
|
+
<div class="subsuite-row" style="--indent: {{ level2 }}">
|
|
374
|
+
<a href="#suite-{{ s2.id }}"
|
|
375
|
+
class="subsuite-row-inner subsuite-link"
|
|
376
|
+
data-target="suite-{{ s2.id }}"
|
|
377
|
+
data-suite-id="{{ s2.id }}"
|
|
378
|
+
title="Jump to {{ s2.name }}">
|
|
379
|
+
<div class="subsuite-info">
|
|
380
|
+
<span class="subsuite-icon">
|
|
381
|
+
{% if s2.is_folder %}
|
|
382
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h5l2 2h7a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7z"/></svg>
|
|
383
|
+
{% else %}
|
|
384
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><line x1="9" y1="3" x2="9" y2="21"/></svg>
|
|
385
|
+
{% endif %}
|
|
386
|
+
</span>
|
|
387
|
+
<span class="subsuite-name">{{ s2.name }}</span>
|
|
388
|
+
<span class="subsuite-count">{{ s2.test_count }} tests</span>
|
|
389
|
+
</div>
|
|
390
|
+
<div class="subsuite-row-right">
|
|
391
|
+
<span class="subsuite-source mono">{{ s2.source }}</span>
|
|
392
|
+
<span class="subsuite-chevron" aria-hidden="true">
|
|
393
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
|
394
|
+
</span>
|
|
395
|
+
</div>
|
|
396
|
+
</a>
|
|
397
|
+
</div>
|
|
398
|
+
{% for child in s2.suites %}
|
|
399
|
+
{{ render_suite_details(child, level2 + 1) }}
|
|
400
|
+
{% endfor %}
|
|
401
|
+
{% endmacro %}
|
|
402
|
+
|
|
403
|
+
{{ render_suite_details(s, 0) }}
|
|
404
|
+
</section>
|
|
405
|
+
{% endif %}
|
|
406
|
+
|
|
407
|
+
</div>{# /content-body #}
|
|
408
|
+
</section>
|
|
409
|
+
|
|
410
|
+
{% for child in s.suites %}
|
|
411
|
+
{{ render_suite_block(child, level + 1) }}
|
|
412
|
+
{% endfor %}
|
|
413
|
+
{% endmacro %}
|
|
414
|
+
|
|
415
|
+
{% if suites %}
|
|
416
|
+
{{ render_suite_block(suites, 0) }}
|
|
417
|
+
{% else %}
|
|
418
|
+
<div class="content-body">
|
|
419
|
+
<p class="empty">No suites available.</p>
|
|
420
|
+
</div>
|
|
421
|
+
{% endif %}
|
|
422
|
+
|
|
423
|
+
<!-- Inline footer -->
|
|
424
|
+
<footer class="content-footer">
|
|
425
|
+
<span>Generated at: {{ generated_at }}</span>
|
|
426
|
+
<span class="content-footer-sep">·</span>
|
|
427
|
+
<a href="https://marvkler.github.io/robotframework-testdoc/" target="_blank" rel="noopener noreferrer">robotframework-testdoc</a>
|
|
428
|
+
<span class="content-footer-sep">·</span>
|
|
429
|
+
<a href="https://github.com/MarvKler/robotframework-testdoc" target="_blank" rel="noopener noreferrer">Contribute on GitHub</a>
|
|
430
|
+
</footer>
|
|
431
|
+
</main>
|
|
432
|
+
</div>
|
|
433
|
+
|
|
434
|
+
<script>{% include 'script.js' %}</script>
|
|
435
|
+
</body>
|
|
436
|
+
</html>
|