robotframework-testdoc 0.7.0__tar.gz → 0.8.1a1__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.
@@ -23,3 +23,7 @@ docs/mkdocs/site/**
23
23
  .DS_Store
24
24
  .vscode/mcp.json
25
25
  .vscode/settings.json
26
+ styles.css
27
+ app.js
28
+ atest/output_testdoc_custom_template.pdf
29
+ atest/output_testdoc.pdf
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: robotframework-testdoc
3
- Version: 0.7.0
3
+ Version: 0.8.1a1
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
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Programming Language :: Python :: 3.14
17
17
  Requires-Python: >=3.10
18
18
  Requires-Dist: click
19
+ Requires-Dist: fpdf2
19
20
  Requires-Dist: jinja2
20
21
  Requires-Dist: mkdocs-include-markdown-plugin
21
22
  Requires-Dist: mkdocs-macros-plugin
@@ -102,9 +103,12 @@ testdoc tests/ TestDocumentation.html
102
103
 
103
104
  # JSON — machine-readable suite tree
104
105
  testdoc -f json tests/ TestDocumentation.json
106
+
107
+ # PDF — release-ready export (overview + TOC + suites + test cases)
108
+ testdoc -f pdf tests/ TestDocumentation.pdf
105
109
  ```
106
110
 
107
- Available values: `html` (default), `json`.
111
+ Available values: `html` (default), `json`, `pdf`.
108
112
 
109
113
  ### Plugin Usage
110
114
 
@@ -115,6 +119,39 @@ You have two option to use it this way:
115
119
 
116
120
  For further details about the usage, please read the [official documentation](https://marvkler.github.io/robotframework-testdoc/usage).
117
121
 
122
+ ### Custom PDF Template
123
+
124
+ You can provide your own Jinja2 template for PDF rendering:
125
+
126
+ ```shell
127
+ testdoc -f pdf --custom-pdf-template path/to/pdf_template.html tests/ TestDocumentation.pdf
128
+ ```
129
+
130
+ This works out of the box. No code changes are required.
131
+
132
+ Required template contract:
133
+
134
+ 1. The template must contain a branch for `view == "overview"`.
135
+ 2. The template must contain a branch for `view == "suite"`.
136
+ 3. In the `overview` branch, these variables are available:
137
+ `title` (string), `generated_at` (string), `suite_count` (int), `test_count` (int).
138
+ 4. In the `suite` branch, these variables are available:
139
+ `suite_name` (string), `tests` (list of dicts).
140
+ 5. Each item in `tests` has:
141
+ `name` (string), `tags` (list of strings, can be empty).
142
+
143
+ Recommended usage pattern:
144
+
145
+ 1. Start with the minimal template above.
146
+ 2. Change only markup/styling first.
147
+ 3. Keep variable names exactly as documented.
148
+ 4. If a section is empty, always handle it with `{% if tests %}` / fallback text.
149
+
150
+ Notes:
151
+
152
+ 1. Title page and table of contents are rendered by the PDF engine, not by the custom HTML template.
153
+ 2. You can also set `custom_pdf_template` in your TOML config file.
154
+
118
155
  #### Use customized Jinja2 HTML Template
119
156
 
120
157
  ![Custom Jinja Template](./docs/gifs/customjinja.gif)
@@ -65,9 +65,12 @@ testdoc tests/ TestDocumentation.html
65
65
 
66
66
  # JSON — machine-readable suite tree
67
67
  testdoc -f json tests/ TestDocumentation.json
68
+
69
+ # PDF — release-ready export (overview + TOC + suites + test cases)
70
+ testdoc -f pdf tests/ TestDocumentation.pdf
68
71
  ```
69
72
 
70
- Available values: `html` (default), `json`.
73
+ Available values: `html` (default), `json`, `pdf`.
71
74
 
72
75
  ### Plugin Usage
73
76
 
@@ -78,6 +81,39 @@ You have two option to use it this way:
78
81
 
79
82
  For further details about the usage, please read the [official documentation](https://marvkler.github.io/robotframework-testdoc/usage).
80
83
 
84
+ ### Custom PDF Template
85
+
86
+ You can provide your own Jinja2 template for PDF rendering:
87
+
88
+ ```shell
89
+ testdoc -f pdf --custom-pdf-template path/to/pdf_template.html tests/ TestDocumentation.pdf
90
+ ```
91
+
92
+ This works out of the box. No code changes are required.
93
+
94
+ Required template contract:
95
+
96
+ 1. The template must contain a branch for `view == "overview"`.
97
+ 2. The template must contain a branch for `view == "suite"`.
98
+ 3. In the `overview` branch, these variables are available:
99
+ `title` (string), `generated_at` (string), `suite_count` (int), `test_count` (int).
100
+ 4. In the `suite` branch, these variables are available:
101
+ `suite_name` (string), `tests` (list of dicts).
102
+ 5. Each item in `tests` has:
103
+ `name` (string), `tags` (list of strings, can be empty).
104
+
105
+ Recommended usage pattern:
106
+
107
+ 1. Start with the minimal template above.
108
+ 2. Change only markup/styling first.
109
+ 3. Keep variable names exactly as documented.
110
+ 4. If a section is empty, always handle it with `{% if tests %}` / fallback text.
111
+
112
+ Notes:
113
+
114
+ 1. Title page and table of contents are rendered by the PDF engine, not by the custom HTML template.
115
+ 2. You can also set `custom_pdf_template` in your TOML config file.
116
+
81
117
  #### Use customized Jinja2 HTML Template
82
118
 
83
119
  ![Custom Jinja Template](./docs/gifs/customjinja.gif)
@@ -27,6 +27,7 @@ dependencies = [
27
27
  "click",
28
28
  "robotframework",
29
29
  "jinja2",
30
+ "fpdf2",
30
31
  "tomli",
31
32
  "mkdocs<2.0.0",
32
33
  "mkdocs-macros-plugin",
@@ -93,7 +94,8 @@ check = "mypy --install-types --non-interactive {args:src/Tables tests}"
93
94
  [tool.hatch.envs.dev]
94
95
  dependencies = [
95
96
  "ruff",
96
- "pytest"
97
+ "pytest",
98
+ "robotframework-tablelibrary"
97
99
  ]
98
100
  [tool.hatch.envs.dev.scripts]
99
101
  lint = "ruff check --force-exclude"
@@ -89,6 +89,16 @@
89
89
 
90
90
  <!-- SIDEBAR -->
91
91
  <aside class="nav" id="sidebar">
92
+ <nav class="primary-nav" aria-label="Main navigation">
93
+ <button class="primary-nav-item" id="sidebarDashboard" type="button">
94
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 13h6V4H4v9Zm0 7h6v-5H4v5Zm10 0h6V11h-6v9Zm0-16v5h6V4h-6Z"/></svg>
95
+ <span>Dashboard</span>
96
+ </button>
97
+ <button class="primary-nav-item active" id="sidebarRepository" type="button">
98
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h4.379a1.5 1.5 0 0 1 1.06.44L11 6.5H19.5A1.5 1.5 0 0 1 21 8v9.5A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5v-11Z"/></svg>
99
+ <span>Test Case Repository</span>
100
+ </button>
101
+ </nav>
92
102
  <div class="nav-tree">
93
103
  <ul class="tree-list">
94
104
  {# Root suite entry #}
@@ -330,38 +340,19 @@
330
340
  {% endif %}
331
341
 
332
342
  {% if s.tests %}
333
- <!-- Test Case Overview -->
334
- <section class="section">
335
- <div class="section-header">
336
- <span class="section-title">Test Case Overview</span>
337
- <span class="section-subtitle">All {{ s.tests | length }} tests in this suite</span>
338
- </div>
339
- <div class="code-always-visible">
340
- {% set code -%}
341
- *** Test Cases ***
342
- {{ s.tests | map(attribute='name') | join('\n') }}
343
- {%- endset %}
344
- {{ code | highlight_robot_in_pre | safe }}
345
- </div>
346
- </section>
347
-
348
- <!-- Test Case Details -->
343
+ <!-- Test Cases -->
349
344
  <section class="section">
350
345
  <div class="section-header">
351
- <span class="section-title">Test Case Details</span>
352
- <span class="section-subtitle">Per-test documentation and steps</span>
346
+ <span class="section-title">Test Cases</span>
347
+ <span class="section-subtitle">{{ s.tests | length }} test{% if s.tests | length != 1 %}s{% endif %} — click to view details</span>
353
348
  </div>
354
349
  <div class="tests-list">
355
350
  {% for test in s.tests %}
356
351
  {%- set _test_tags = [] -%}
357
352
  {%- for _t in (test.tags or []) -%}{%- if _test_tags.append((_t.name if _t is mapping else _t) | string) -%}{%- endif -%}{%- endfor -%}
358
- <section id="test-{{ s.id }}-{{ loop.index0 }}" class="test-block collapsed" data-tags="{{ _test_tags | dump_json | e }}" data-has-doc="{{ '1' if test.doc else '0' }}" data-suite-name="{{ s.name }}" data-test-name="{{ test.name }}">
359
- <div class="test-header">
360
- <div class="test-name">{{ test.name }}</div>
361
- <span class="test-collapse-icon" aria-hidden="true">
362
- <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>
363
- </span>
364
- </div>
353
+
354
+ {# Hidden data container used by showTestDetail #}
355
+ <section id="test-{{ s.id }}-{{ loop.index0 }}" class="test-block" data-tags="{{ _test_tags | dump_json | e }}" data-has-doc="{{ '1' if test.doc else '0' }}" data-suite-name="{{ s.name }}" data-test-name="{{ test.name }}" data-suite-id="{{ s.id }}" hidden>
365
356
  <div class="test-body-collapsible">
366
357
  <div class="test-subsection">
367
358
  <div class="kv-label">Documentation</div>
@@ -426,6 +417,26 @@
426
417
  </div>
427
418
  </div>
428
419
  </section>
420
+
421
+ {# Visible clickable row #}
422
+ <button class="test-list-row" data-target="test-{{ s.id }}-{{ loop.index0 }}" type="button">
423
+ <span class="tree-icon test">T</span>
424
+ <div class="test-list-main">
425
+ <span class="test-list-name">{{ test.name }}</span>
426
+ {% if test.doc %}
427
+ <span class="test-list-doc">{{ test.doc | truncate(100) }}</span>
428
+ {% endif %}
429
+ </div>
430
+ {% if _test_tags %}
431
+ <div class="test-list-tags">
432
+ {% for tag in _test_tags[:3] %}<span class="tag">{{ tag }}</span>{% endfor %}
433
+ {% if _test_tags | length > 3 %}<span class="tag tag-more">+{{ _test_tags | length - 3 }} more</span>{% endif %}
434
+ </div>
435
+ {% endif %}
436
+ <span class="test-list-chevron" aria-hidden="true">
437
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
438
+ </span>
439
+ </button>
429
440
  {% endfor %}
430
441
  </div>
431
442
  </section>
@@ -485,6 +496,9 @@
485
496
  <!-- Statistics Dashboard (hidden by default, built by JS) -->
486
497
  <div id="dashboardPanel" class="dashboard-panel" style="display:none" role="region" aria-label="Statistics Dashboard"></div>
487
498
 
499
+ <!-- Test Case Detail View (single-page per test case) -->
500
+ <div id="testDetailPanel" class="test-detail-panel" style="display:none" role="region" aria-label="Test Case Detail"></div>
501
+
488
502
  <div id="suiteContent">
489
503
  {% if suites %}
490
504
  {{ render_suite_block(suites, 0) }}
@@ -0,0 +1,55 @@
1
+ <html>
2
+ <body>
3
+ {% if view == "title" %}
4
+ <br /><br /><br /><br /><br />
5
+ <h1 align="center">{{ title }}</h1>
6
+ <p align="center">{{ generated_date }}</p>
7
+ {% elif view == "overview" %}
8
+ <h2 align="center">Overview</h2>
9
+
10
+ <table width="100%" border="1" cellspacing="0" cellpadding="7">
11
+ <tr>
12
+ <td bgcolor="#e2e8f0">Total .robot suites</td>
13
+ <td>{{ suite_count }}</td>
14
+ </tr>
15
+ <tr>
16
+ <td bgcolor="#e2e8f0">Total test cases</td>
17
+ <td>{{ test_count }}</td>
18
+ </tr>
19
+ </table>
20
+
21
+ <br />
22
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
23
+ <tr>
24
+ <td bgcolor="#eff6ff">Test Suites</td>
25
+ </tr>
26
+ </table>
27
+ {% else %}
28
+ <h1>{{ suite_name }}</h1>
29
+ <h3>Test Cases</h3>
30
+ {% if tests %}
31
+ <table width="100%" border="0" cellspacing="0" cellpadding="2">
32
+ {% for test in tests %}
33
+ {% if loop.first %}
34
+ <tr>
35
+ <td width="4%">-</td>
36
+ <td width="96%">{{ test.name }}</td>
37
+ </tr>
38
+ {% else %}
39
+ <tr>
40
+ <td>-</td>
41
+ <td>{{ test.name }}</td>
42
+ </tr>
43
+ {% endif %}
44
+ {% endfor %}
45
+ </table>
46
+ {% else %}
47
+ <table width="100%" border="0" cellspacing="0" cellpadding="6">
48
+ <tr>
49
+ <td bgcolor="#f1f5f9">No test cases in this suite.</td>
50
+ </tr>
51
+ </table>
52
+ {% endif %}
53
+ {% endif %}
54
+ </body>
55
+ </html>
@@ -26,20 +26,57 @@ Download the latest `.vsix` file from the [GitHub Releases](https://github.com/M
26
26
  code --install-extension testdoc-vscode-<version>.vsix
27
27
  ```
28
28
 
29
+ ## Build VSIX Locally
30
+
31
+ You can build the extension package (`.vsix`) on your machine.
32
+
33
+ ### Prerequisites
34
+
35
+ - Node.js (LTS recommended)
36
+ - npm
37
+
38
+ ### Steps
39
+
40
+ 1. Open a terminal in the extension folder:
41
+ ```bash
42
+ cd vscode-extension
43
+ ```
44
+ 2. Install dependencies:
45
+ ```bash
46
+ npm install
47
+ ```
48
+ 3. Build the `.vsix` package:
49
+ ```bash
50
+ npx @vscode/vsce package
51
+ ```
52
+ 4. The generated file will be in the same folder, for example:
53
+ ```
54
+ testdoc-vscode-0.1.7.vsix
55
+ ```
56
+
57
+ ### Install the locally built package
58
+
59
+ ```bash
60
+ code --install-extension testdoc-vscode-<version>.vsix
61
+ ```
62
+
63
+ If you want a new package version, update `version` in `vscode-extension/package.json` before running the package command.
64
+
29
65
  ## Usage
30
66
 
31
- Right-click any folder in the Explorer and choose one of the three commands:
67
+ Right-click any folder in the Explorer and choose one of the available commands:
32
68
 
33
69
  | Command | Description |
34
70
  |---|---|
35
71
  | **testdoc: Generate HTML Documentation** | Generates a self-contained `.html` test documentation file |
36
72
  | **testdoc: Generate JSON Documentation** | Generates a machine-readable `.json` suite tree |
73
+ | **testdoc: Generate PDF Documentation** | Generates a release-friendly `.pdf` report |
37
74
  | **testdoc: Generate MkDocs Output** | Generates a full MkDocs project into a selected output directory |
38
75
 
39
- ### HTML / JSON
76
+ ### HTML / JSON / PDF
40
77
 
41
78
  1. Right-click a folder containing your `.robot` files
42
- 2. Select **testdoc: Generate HTML Documentation** or **testdoc: Generate JSON Documentation**
79
+ 2. Select **testdoc: Generate HTML Documentation**, **testdoc: Generate JSON Documentation**, or **testdoc: Generate PDF Documentation**
43
80
  3. A save dialog opens — choose the output file location and name
44
81
  4. A terminal runs `testdoc` and the file is written to the chosen location
45
82