$npx -y skills add totvs/engpro-advpl-tlpp-skills --skill tir-test-generatorGenerate TIR (TOTVS Interface Robot) end-to-end test scripts in Python for Protheus SmartClient/Webapp screens. Supports CRUD screen tests, MVC screen tests, grid interaction, report tests, field validation, and message box assertions. Use when a user says "TIR test", "interface
| 1 | # Protheus TIR Test Generator |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Generate end-to-end **interface test scripts** in Python for the TOTVS Protheus ERP using the **TIR** (TOTVS Interface Robot) framework. TIR automates Protheus screens through the SmartClient/Webapp interface, validating complete user workflows including screen navigation, field interaction, grid manipulation, button clicks, and result assertions. |
| 6 | |
| 7 | TIR tests use Python's `unittest` framework combined with the `tir.Webapp` class to: |
| 8 | 1. **Connect** to a running Protheus Webapp environment |
| 9 | 2. **Navigate** to specific routines via `Program()` |
| 10 | 3. **Interact** with screen elements (fields, grids, buttons, folders) |
| 11 | 4. **Assert** field values, screen states, and data integrity |
| 12 | 5. **Tear down** the session cleanly |
| 13 | |
| 14 | ## When to Use |
| 15 | |
| 16 | Use this skill when: |
| 17 | |
| 18 | - Creating end-to-end UI tests for Protheus screens (CRUD, workflows) |
| 19 | - Testing MVC-generated screens via the SmartClient/Webapp interface → use `Webapp` class |
| 20 | - Validating critical user journeys (complete business flows) |
| 21 | - Testing screen navigation, menu access, and dialog handling |
| 22 | - Validating field interactions (fill, check, read values) |
| 23 | - Testing grid operations (add rows, edit cells, scroll, select) |
| 24 | - Validating reports via parameter screens |
| 25 | - Needing visual/interface-level regression tests |
| 26 | |
| 27 | ### When NOT to Use |
| 28 | |
| 29 | - **TLPP unit tests** → Use ProBat (@TestFixture) |
| 30 | |
| 31 | --- |
| 32 | |
| 33 | ## Which TIR Class to Use? |
| 34 | |
| 35 | | Routine type | TIR class | Import | |
| 36 | |---|---|---| |
| 37 | | MVC (`ModelDef`/`ViewDef`/`MenuDef`) | `Webapp` | `from tir import Webapp` | |
| 38 | | Legacy Browse (`MBrowse`, `AxCadastro`) | `Webapp` | `from tir import Webapp` | |
| 39 | |
| 40 | --- |
| 41 | |
| 42 | ## TIR Three-File Architecture (MANDATORY) |
| 43 | |
| 44 | Every TIR test project requires **three files**: |
| 45 | |
| 46 | | File | Responsibility | |
| 47 | |------|---------------| |
| 48 | | `{ROUTINE}TESTCASE.py` | Test class with `unittest.TestCase`, `setUpClass`, test methods (`test_*`), `tearDownClass` | |
| 49 | | `{ROUTINE}TESTSUITE.py` | Runner: imports TESTCASE, builds `unittest.TestSuite`, executes with `TextTestRunner` | |
| 50 | | `config.json` | Environment configuration — URL, browser, credentials, Protheus environment name | |
| 51 | |
| 52 | **Without `config.json` in the same directory, TIR cannot connect to Protheus.** |
| 53 | |
| 54 | ``` |
| 55 | {test_directory}/ |
| 56 | ├── {ROUTINE}TESTCASE.py ← test class |
| 57 | ├── {ROUTINE}TESTSUITE.py ← runner (CI/CD entry point) |
| 58 | └── config.json ← environment config (REQUIRED) |
| 59 | ``` |
| 60 | |
| 61 | ### config.json — Webapp (MVC/Legacy) |
| 62 | |
| 63 | ```json |
| 64 | { |
| 65 | "Url": "http://{server}:{port}/", |
| 66 | "Browser": "Chrome", |
| 67 | "Environment": "{environment_name}", |
| 68 | "User": "{username}", |
| 69 | "Password": "{password}", |
| 70 | "Language": "pt-br" |
| 71 | } |
| 72 | ``` |
| 73 | |
| 74 | For the complete `config.json` parameter reference (all sections: Required, Additional, Logging, Database, Chrome), see [tir-setup-and-best-practices.md](references/tir-setup-and-best-practices.md). |
| 75 | |
| 76 | --- |
| 77 | |
| 78 | ## Complete File Templates |
| 79 | |
| 80 | ### TESTCASE Template — Webapp (MVC/Legacy) |
| 81 | |
| 82 | ```python |
| 83 | from tir import Webapp |
| 84 | import unittest |
| 85 | |
| 86 | class {ROUTINE}(unittest.TestCase): |
| 87 | """ |
| 88 | TIR E2E Tests for {ROUTINE} - {Description} |
| 89 | Module: {MODULE} |
| 90 | Tables: {TABLE_ALIASES} |
| 91 | """ |
| 92 | |
| 93 | @classmethod |
| 94 | def setUpClass(inst): |
| 95 | """Setup: Initialize Webapp, configure environment, open routine""" |
| 96 | inst.oHelper = Webapp() |
| 97 | inst.oHelper.Setup('{MODULE}', '{DATE}', 'T1', '{BRANCH}') |
| 98 | inst.oHelper.Program('{ROUTINE}') |
| 99 | |
| 100 | def test_{ROUTINE}_CT001(self): |
| 101 | """CT001 — Include record with required fields""" |
| 102 | self.oHelper.SetButton('Incluir') |
| 103 | self.oHelper.SetBranch('{BRANCH}') |
| 104 | self.oHelper.SetValue('{Field Label 1}', '{value1}') |
| 105 | self.oHelper.SetValue('{Field Label 2}', '{value2}') |
| 106 | self.oHelper.SetButton('Salvar') |
| 107 | self.oHelper.SearchBrowse(f'{BRANCH}{search_key}', key='Filial+{Search Column}') |
| 108 | self.oHelper.SetButton('Visualizar') |
| 109 | self.oHelper.CheckResult('{FIELD_NAME}', '{expected_value}') |
| 110 | self.oHelper.SetButton('Cancelar') |
| 111 | self.oHelper.AssertTrue() |
| 112 | |
| 113 | def test_{ROUTINE}_CT002(self): |
| 114 | """CT002 — Edit existing record""" |
| 115 | self.oHelper.SearchBrowse(f'{BRANCH}{search_key}', key='Filial+{Search Column}') |
| 116 | self.oHelper.SetButton('Alterar') |
| 117 | self.oHelper.SetValue('{Field Label}', '{new_value}') |
| 118 | self.oHelper.SetButton('Salvar') |
| 119 | self.oHelper.AssertTrue() |
| 120 | |
| 121 | def test_{ROUTINE}_CT003(self): |
| 122 | "" |