Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Beliagal/qa-report-automation/llms.txt

Use this file to discover all available pages before exploring further.

This page documents all public classes, methods, and utility functions that make up the Valoraclick QA Tool. Developers extending or embedding the tool should reference this page. Each section maps directly to a source module: gui.py, models.py, services.py, and logic.py.

TestingApp (gui.py)

TestingApp is the main application window. It extends ctk.CTk from the CustomTkinter library and owns the top-level lifecycle of a testing session — from UI construction and session persistence through to PDF export and Google Drive backup.
class TestingApp(ctk.CTk):
    def __init__(self) -> None: ...
The constructor instantiates a ReportData object (self.report_data), a PDFService (self.pdf_service), and a CSVService (self.csv_service). It sets self.session_file = "sesion_testing.json" and self.current_img = "". The window title is set to "QA Tool v1.0.0 Secure", the geometry is set to "1200x900", and the window is maximised by scheduling self.state('zoomed') via self.after(0, ...). A CTkScrollableFrame labelled "Panel de Control QA" is created as the main content area. Finally the constructor calls _setup_top_bar(), _setup_metadata_grid(), _setup_execution_form(), and _load_session() to build the complete UI and restore any in-progress session.

Key Methods

_on_export()

Triggers the full export pipeline: PDF generation followed by an automatic Google Drive CSV backup. Internally, _on_export():
  1. Calls _sync() to flush widget values into report_data.metadata.
  2. Validates the Fecha: field against ^\d{2}/\d{2}/\d{4}$. If validation fails, a warning dialog is shown and the export is aborted.
  3. Opens a Save As dialog restricted to .pdf files.
  4. Calls pdf_service.generate_report(report_data, path).
  5. Calls csv_service.export(report_data) for the automatic Drive backup.
  6. Displays a success dialog reporting whether the Drive backup succeeded.
On any unhandled exception during PDF generation, a Critical Error dialog is shown with the exception message.
The export is aborted silently if the user dismisses the Save As dialog without choosing a path. No error is raised in that case.

_on_add()

Appends a new test step to report_data.pruebas using the values currently in the step form. The step dict constructed by _on_add() has the following shape:
{
    "input": str,   # Acción field value (stripped)
    "esp":   str,   # Esperado field value
    "obt":   str,   # Obtenido field value
    "estado": str,  # ComboBox value: "Pass" or "Fail"
    "img":   str,   # self.current_img (absolute path or "")
}
If the Acción field is empty after stripping whitespace, _on_add() returns immediately without adding anything. After a successful append it calls _update_log(), _save_session(), and _clear_step().

_on_reset()

Displays a yes/no confirmation dialog. If confirmed:
  1. Calls report_data.reset_data() to restore all metadata to defaults and empty pruebas.
  2. Deletes sesion_testing.json from disk if it exists.
  3. Clears all metadata entry widgets and resets Fecha: to today’s date.
  4. Clears the Dependencias entry and the Resumen Ejecutivo textbox.
  5. Calls _update_log() to refresh the log preview.
This operation is irreversible. All unsaved steps are permanently discarded. Always use RESET TOTAL only between distinct test sessions.

_save_session()

Persists the current session to disk so it can be recovered on the next launch.
def _save_session(self) -> None: ...
Calls _sync() first, then writes the following JSON structure to sesion_testing.json in the working directory:
{
    "meta":    { },
    "pruebas": [ ]
}
Exceptions during the file write are silently swallowed so that a disk error never crashes the UI.

_load_session()

Reads sesion_testing.json on application startup and restores the previous session into the UI.
def _load_session(self) -> None: ...
If the file does not exist, _load_session() returns immediately. If it exists, it:
  1. Reads pruebas back into report_data.pruebas.
  2. Iterates over the meta dict and restores each value into the corresponding CTkEntry widget.
  3. Restores dep into the Dependencias entry and resumen into the Resumen Ejecutivo textbox.
  4. Calls _update_log() to populate the log preview.
Exceptions during loading are silently swallowed.
The session file uses the key "meta" (not "metadata") at the top level. This is intentional — see the Data Model page for the complete session JSON schema.

_sync()

Copies the current value of every UI widget into report_data.metadata.
def _sync(self) -> None: ...
Iterates over self.entries (a dict mapping metadata keys to CTkEntry widgets) and writes each .get() value back to report_data.metadata. Also pulls dep from self.ent_dep and resumen from self.txt_resumen. This method must be called before any operation that reads report_data — most notably _on_export() and _save_session().

_on_img()

Opens a file picker dialog so the analyst can attach a screenshot to the current step.
def _on_img(self) -> None: ...
Filters the dialog to *.png, *.jpg, and *.jpeg files. If the user selects a file, its absolute path is stored in self.current_img and the image button label changes to ✅ Imagen Ok. The path is consumed by _on_add() when the step is finalised.
self.current_img
str
Instance variable updated by _on_img(). Holds the absolute path to the selected screenshot, or an empty string if no image has been chosen for the current step.

_clear_step()

Resets all step-form fields and the image selection after a step has been added.
def _clear_step(self) -> None: ...
Clears the Acción, Esperado, and Obtenido entry widgets. Resets self.current_img to an empty string and restores the image button text to "📸 Imagen" with its default colour (#3b8ed0). Called automatically by _on_add() after each successful step append.

_update_log()

Refreshes the CTkTextbox preview panel with a colour-coded summary of the current session.
def _update_log(self) -> None: ...
Temporarily enables the read-only CTkTextbox (self.log), clears it, and rewrites its contents using the underlying _textbox widget’s tag system for colour highlighting:
  • Header lines (--- VISTA PREVIA DEL INFORME --- and --- PASOS (n) ---) are rendered in blue (#3498db, bold).
  • Each step line is coloured green (#2ecc71) for "Pass" steps or red (#e74c3c) for any other status.
  • Metadata key/value pairs from self.entries are printed in the default colour.
The textbox is set back to disabled state after the update and scrolled to the end.

_validate_date_input(P)

Validator registered with the Fecha: entry widget via Tkinter’s validatecommand mechanism.
def _validate_date_input(self, P: str) -> bool: ...
P
str
required
The proposed new value of the entry widget after the keypress. Provided automatically by the Tkinter validation framework.
Returns True (allowing the keypress) only when:
  • len(P) <= 10, and
  • every character in P is a digit (0–9) or a forward slash (/).

ReportData (models.py)

ReportData is the central, plain-Python data container for a testing session. It carries no UI logic and no I/O; its sole responsibility is holding structured test data that other services can read and write.
class ReportData:
    metadata: Dict[str, str]
    pruebas: List[Dict]

    def reset_data(self) -> None: ...

reset_data()

Restores the object to a clean initial state. Called automatically by __init__() and again by TestingApp._on_reset() at the user’s request.
def reset_data(self) -> None: ...
After reset_data() completes:
  • self.metadata is set to:
    {
        "Aplicación:":        "Valoraclick",
        "Tester:":            "",
        "Fecha:":             datetime.datetime.now().strftime('%d/%m/%Y'),
        "Historia de Usuario:": "",
        "Requisitos:":        "",
        "Versión:":           "",
        "dep":                "",
        "resumen":            ""
    }
    
  • self.pruebas is set to an empty list [].
Fecha: is always re-initialised to today’s date each time reset_data() is called, not to the date the object was first created.

PDFService (services.py)

PDFService generates a formatted PDF report from a ReportData object using fpdf2.
class PDFService:
    def generate_report(self, data: ReportData, output_path: str) -> None: ...

generate_report(data, output_path)

Creates the PDF document in memory and writes it to output_path. The generated document contains:
  1. A centred bold title — INFORME DE TESTING.
  2. A shaded INFORMACIÓN GENERAL section with a two-column grid of metadata fields: Aplicación, Tester, Fecha, Versión, and Resumen.
  3. A PASOS DE EJECUCIÓN table with columns: Acción / Entrada, Esperado, Obtenido, Estado. Pass rows are rendered in green text; Fail rows in red.
  4. For any step that has an attached image whose file still exists on disk, the image is embedded inline below its row at 100 mm width.
Auto page breaks are enabled with a margin=15 bottom margin.
data
ReportData
required
The test session data to render. The method reads data.metadata for the header section and iterates data.pruebas for the execution table.
output_path
str
required
Absolute or relative file path where the PDF will be written, including the .pdf extension. The directory must already exist and be writable.
If output_path points to a non-existent directory or a location where the process lacks write permission, fpdf2 will raise an exception. This exception propagates to TestingApp._on_export(), which catches it and displays a Critical Error dialog.

CSVService (services.py)

CSVService exports the test session to a timestamped CSV backup file, targeting a Google Drive folder via a Windows shell shortcut.
class CSVService:
    shortcut_path: str  # r"G:\Mi unidad\Informes.lnk"
    fallback_path: str  # r"G:\Mi unidad"

    def export(self, data: ReportData) -> Tuple[bool, str]: ...
    def _resolve_shortcut(self, path: str) -> Optional[str]: ...
The two path attributes are set in __init__() and are not configurable at runtime without subclassing.
shortcut_path
str
Hard-coded to r"G:\Mi unidad\Informes.lnk". This is the Windows shell shortcut that _resolve_shortcut() attempts to resolve to find the actual Drive folder.
fallback_path
str
Hard-coded to r"G:\Mi unidad". Used as the export destination when the shortcut cannot be resolved.

export(data)

Resolves the target directory, builds a unique filename, and writes the CSV.
def export(self, data: ReportData) -> Tuple[bool, str]: ...
data
ReportData
required
The test session data to export. Both data.metadata and data.pruebas are written to the CSV.
Return value: a two-element tuple.
[0]
bool
True if the CSV was written successfully; False if an exception was raised.
[1]
str
On success: the full absolute path to the written CSV file (e.g. G:\Mi unidad\Informes\backup_2025-07-15_143022_Ana_García.csv). On failure: the string representation of the exception.
The CSV filename follows the pattern backup_<YYYY-MM-DD_HHMMSS>_<Tester>.csv, where spaces in the tester name are replaced with underscores. The CSV is encoded as utf-8-sig (UTF-8 with BOM) for compatibility with Microsoft Excel. The CSV structure is:
CampoValor
Aplicación:Valoraclick
Tester:
(blank row)
AcciónEsperadoObtenidoEstadoRuta Imagen

_resolve_shortcut(path)

Resolves a Windows .lnk shortcut file to its target directory path using win32com.
def _resolve_shortcut(self, path: str) -> Optional[str]: ...
path
str
required
Absolute path to a .lnk Windows shortcut file, e.g. r"G:\Mi unidad\Informes.lnk".
return
Optional[str]
The TargetPath string from the shortcut if the file exists and can be parsed by WScript.Shell. Returns None if the file does not exist, if win32com raises any exception, or if the path is valid but the shortcut is broken.
This method relies on win32com.client from the pywin32 package, which is only available on Windows. Calling it on macOS or Linux will raise an ImportError at module import time, before any method is invoked.

Utility Functions (logic.py)

These module-level functions contain business logic shared across the application. They have no side effects and no dependency on the GUI.

validar_fecha(fecha_str)

Validates that a string represents a calendar date in DD/MM/YYYY format.
def validar_fecha(fecha_str: str) -> bool: ...
fecha_str
str
required
The date string to validate, e.g. "15/07/2025".
Returns True only when both of the following conditions hold:
  1. The string matches the regular expression ^\d{2}/\d{2}/\d{4}$.
  2. datetime.strptime(fecha_str, '%d/%m/%Y') does not raise a ValueError — meaning the day and month values are calendar-valid (e.g. "31/02/2025" would fail here).
Returns False otherwise.

obtener_color_estado(estado)

Maps a test step status string to an RGB colour tuple for use in rendered output.
def obtener_color_estado(estado: str) -> tuple: ...
estado
str
required
The status string. Expected values are "Pass" or "Fail".
return
tuple
(46, 204, 113) — a green shade — when estado == "Pass". (231, 76, 60) — a red shade — for any other value, including "Fail" and unexpected strings.

Build docs developers (and LLMs) love