Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions .github/workflows/build-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,23 @@ jobs:
- name: Install Build Dependencies
run: |
python -m pip install --upgrade pip
pip install build ruff
pip install build ruff pytest

- name: Lint with ruff
- name: Lint with Ruff
run: ruff check .

- name: Build package
- name: Build Package
run: python -m build

- name: Test CLI command
- name: Test CLI Command
run: |
pip install .
testdoc --help

# - name: Publish to TestPyPI (only on main)
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
- name: Run Unit Tests
run: pytest atest/

# - name: Publish to TestPyPI
# env:
# TWINE_USERNAME: __token__
# TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
Expand Down
49 changes: 49 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Release on Tag

on:
push:
tags:
- 'v*.*.*'

jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install build twine tomli

- name: Check Tag Matches pyproject.toml Version
run: |
VERSION_IN_FILE=$(python -c "import tomli; print(tomli.load(open('pyproject.toml', 'rb'))['project']['version'])")
TAG_VERSION=${GITHUB_REF#refs/tags/v}
echo "Version in pyproject.toml: $VERSION_IN_FILE"
echo "Git Tag Version: $TAG_VERSION"
if [ "$VERSION_IN_FILE" != "$TAG_VERSION" ]; then
echo "Version mismatch between createdxtag and pyproject.toml"
exit 1
fi

- name: Build Package
run: python -m build

- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: twine upload dist/*

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ src/robotframework_testdoc.egg-info/**
.vscode/launch.json
.vscode/
dist/
*.egg-info/
*.egg-info/
output_doc.html
output.html
src/testdoc/html/templates/jinja_template_02.html
image.png
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,52 @@ For using this config file, just call the following command:
# Generate docu with options defined in TOML file
testdoc -c path/to/config.toml tests/ TestDocumentation.html
```

## Theme Selection / Color Configuration

You can select between several themes (color configurations) for your HTML document to create!

> [!CAUTION]
> This is only possible via toml-configuration file, but not via cmd args directly!

### Default Themes

There are a few predefined default themes available that you can choose via the toml-configuration file.
Therefore, please use the following syntax:
```toml
[colors]
# Use the default theme
default = "default"
default = 0
# Use the default theme
default = "dark"
default = 1
# Use the default theme
default = "blue"
default = 2
# Use the default theme
default = "robot"
default = 3
```

> [!TIP]
> You can select the default theme using either a string value or an integer value.

### Custom Themes

You can apply your own custom theme to modify the colors of the created HTML document.
Use the following syntax & parameters in your toml-configuration file, to overwrite the predefined themes:
```toml
[colors]
background = "#000028"
inner_color = "#000028"
button_active_color = "#193966"
button_hover_color = "#193966"
border_color = "#CCCCCC"
text_color = "#CCCCCC"
title_color = "#00ffb9"
robot_icon = "#00ffb9"
```^

> [!TIP]
> Please make sure to configure all available color values from this example — missing values may cause layout or rendering issues in the generated HTML document!
16 changes: 16 additions & 0 deletions atest/config/config_with_colors.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
sourceprefix = "gitlab::https://gitlab.com/myrepo/repo_path"
hide_suite_doc = true
verbose_mode = true

[colors]
# DEFAULT THEME:
default = "robot"
# OR CUSTOM THEME:
# background = "#000028"
# inner_color = "#000028"
# button_active_color = "#193966"
# button_hover_color = "#193966"
# border_color = "#CCCCCC"
# text_color = "#CCCCCC"
# title_color = "#00ffb9"
# robot_icon = "#00ffb9"
34 changes: 34 additions & 0 deletions atest/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import os
from click.testing import CliRunner
from testdoc.cli import main

def test_cli_help():
runner = CliRunner()
result = runner.invoke(main, ["--help"])
assert result.exit_code == 0
assert "Usage" in result.output
assert "Welcome" in result.output

def test_cli_cmd():
current_dir = os.path.dirname(os.path.abspath(__file__))
robot = os.path.join(current_dir, "test_cli.robot")
output = os.path.join(current_dir, "output.html")
runner = CliRunner()
result = runner.invoke(main, [robot, output])
assert result.exit_code == 0
assert "Generated" in result.output
assert "output.html" in result.output
assert os.path.exists(output)


def test_cli_cmd_verbose():
current_dir = os.path.dirname(os.path.abspath(__file__))
robot = os.path.join(current_dir, "test_cli.robot")
output = os.path.join(current_dir, "output.html")
runner = CliRunner()
result = runner.invoke(main, [robot, output, "-v"])
assert result.exit_code == 0
assert "Generated" in result.output
assert "output.html" in result.output
assert "test_cli.robot" in result.output
assert os.path.exists(output)
12 changes: 12 additions & 0 deletions atest/test_cli.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
*** Settings ***
Documentation Basic Console Logging - Suite Doc
Metadata Author=Marvin Klerx
Metadata Creation=March 2025
Test Tags Global-Tag


*** Test Cases ***
Log Message
[Documentation] Basic Console Logging
[Tags] RobotTestDoc
Log RobotFramework Test Documentation Generator!
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ build-backend = "setuptools.build_meta"

[project]
name = "robotframework-testdoc"
version = "0.1.0"
version = "0.1.1"
description = "A CLI Tool to generate a Test Documentation for your RobotFramework Test Scripts."
readme = "README.md"
requires-python = ">=3.7"
authors = [{ name = "Marvin Klerx", email = "[email protected]" }]
license = { text = "MIT" }

dependencies = [
"setuptools",
"click",
"robotframework",
"jinja2",
Expand All @@ -24,6 +23,6 @@ testdoc = "testdoc.cli:main"

[tool.ruff]
line-length = 150
lint.select = ["E", "F"] # z. B. nur Pyflakes & pycodestyle
lint.select = ["E", "F"] # Pyflakes & pycodestyle
lint.ignore = ["E722"]
exclude = ["build", "dist"]
1 change: 0 additions & 1 deletion src/testdoc/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from testdoc.cli import main

if __name__ == "__main__":
main()
1 change: 0 additions & 1 deletion src/testdoc/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ def main(
args.suite_file = path
args.output_file = output

# If CLI arg was set -> set / overwrite toml arg value
for key, value in cli_params.items():
if value is not None:
setattr(args, key, value)
Expand Down
4 changes: 4 additions & 0 deletions src/testdoc/helper/cliargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CommandLineArgumentsData:
verbose_mode: bool = False
suite_file: str = None
output_file: str = None
colors: dict = None

class CommandLineArguments:
_instance = None
Expand All @@ -34,6 +35,9 @@ def load_from_config_file(self, file_path: str):
with open(file_path, "rb") as f:
config = tomli.load(f)

if "colors" in config:
self.data.colors = config["colors"]

for key, value in config.items():
if hasattr(self.data, key):
setattr(self.data, key, value)
45 changes: 26 additions & 19 deletions src/testdoc/html/templates/jinja_template_01.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,35 @@
{% macro render_suite(suite, index, first) %}
<div class="accordion-item">
<h2 class="accordion-header" id="heading{{ index }}">
{% if not suite.is_folder %}
<div class="custom-line" style="height: 3px; margin-bottom: 5px; border-radius: 2px;"></div>
{% endif %}
<button class="accordion-button {% if not first %}collapsed{% endif %}" type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse{{ index }}"
aria-expanded="{% if first %}true{% else %}false{% endif %}"
aria-controls="collapse{{ index }}">

{% if suite.is_folder %}
<button class="accordion-button {% if not first %}collapsed{% endif %}" type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse{{ index }}"
aria-expanded="{% if first %}true{% else %}false{% endif %}"
aria-controls="collapse{{ index }}">
<span class="custom-chevron">
</span>
{% if suite.is_folder %}
📁 Suite Directory:&nbsp;<strong>{{ suite.name }}</strong>
{% else %}
<svg class="svg-icon" width="20" height="20" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<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>
&nbsp;Suite File:&nbsp;<strong>{{ suite.name }}.robot</strong>
{% endif %}
</button>
📁 Suite Directory:&nbsp;<strong>{{ suite.name }}</strong>
</button>
{% else %}
<button class="accordion-button {% if not first %}collapsed{% endif %}" type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse{{ index }}"
aria-expanded="{% if first %}true{% else %}false{% endif %}"
aria-controls="collapse{{ index }}"
style="border: 2px solid {{ colors.robot_icon }};">
<span class="custom-chevron">
</span>
<svg class="svg-icon" width="20" height="20" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<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>
&nbsp;Suite File:&nbsp;<strong>{{ suite.name }}.robot</strong>
</button>
{% endif %}
</h2>
<div id="collapse{{ index }}" class="accordion-collapse collapse"
aria-labelledby="heading{{ index }}">
Expand Down Expand Up @@ -230,7 +238,6 @@ <h2 class="accordion-header" id="headingTest{{ index }}-{{ loop.index }}">
.accordion-button:active {
background-color: {{ colors.button_active_color }} !important;
box-shadow: none !important;
border-color: gray !important;
color: {{ colors.text_color }} !important;
}

Expand Down
65 changes: 25 additions & 40 deletions src/testdoc/html/themes/theme_config.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,27 @@
# default
DEFAULT_THEME = {
"background": "#f8f9fa",
"inner_color": "#f8f9fa",
"button_active_color": "#f8f9fa",
"button_hover_color": "#C2C2C2",
"border_color": "#353535",
"text_color": "#353535",
"title_color": "#343a40",
"robot_icon": "#00c0b5",
}
from ...helper.cliargs import CommandLineArguments
from .themes import DEFAULT_THEME, ROBOT_THEME, DARK_THEME, BLUE_THEME

ROBOT_THEME = {
"background": "#f8f9fa",
"accordion_background": "#00c0b5", # Offizielles Türkis
"accordion_hover": "#e83e8c", # Offizielles Pink
"border_color": "#353535", # Dunkelgrau für Kontraste
"text_color": "white",
"table_text_color": "#000000",
"alert_background": "#d1ecf1", # Helles Blau für Infoboxen
}
class ThemeConfig():

def __init__(self):
self.args = CommandLineArguments().data

DARK_THEME = {
"background": "#343a40",
"inner_color": "#495057",
"button_hover_color": "#6c757d",
"border_color": "white",
"text_color": "white",
"robot_icon": "#00c0b5"
}

CUSTOM_THEME_01 = {
"background": "#000028",
"inner_color": "#000028",
"button_active_color": "#193966",
"button_hover_color": "#193966",
# "border_color": "#f8f9fa",
"border_color": "#CCCCCC",
"text_color": "#CCCCCC",
"title_color": "#00ffb9",
"robot_icon": "#00ffb9",
}
def theme(self):
_theme = self.args.colors
if _theme:
if "default" in _theme:
return self._get_predefined_theme(_theme.get("default"))
return _theme
return DARK_THEME

def _get_predefined_theme(self, theme: str):
theme = theme.strip()
if theme == "default" or theme == 0:
return DEFAULT_THEME
if theme == "dark" or theme == 1:
return DARK_THEME
if theme == "robot" or theme == 2:
return ROBOT_THEME
if theme == "blue" or theme == 3:
return BLUE_THEME

Loading