|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Zeuz Node is a cross-platform test automation client that connects to Zeuz Server to receive and execute test cases. It supports Web (Selenium/Playwright), Mobile (Appium), Desktop (PyAutoGUI), Database, REST/SOAP APIs, and Performance testing. |
| 8 | + |
| 9 | +## Build & Development Commands |
| 10 | + |
| 11 | +### Python (uv package manager) |
| 12 | +```bash |
| 13 | +uv sync # Install dependencies |
| 14 | +uv run pytest tests/ # Run tests |
| 15 | +uv run pytest tests/test_cases.py::test_name # Run single test |
| 16 | +uv run mypy Framework/ # Type checking |
| 17 | +uv run ruff check Framework/ # Linting |
| 18 | +uv run ruff format Framework/ # Format code |
| 19 | +``` |
| 20 | + |
| 21 | +### AI Recorder Extension (React) |
| 22 | +```bash |
| 23 | +cd Apps/Web/AI_Recorder_2/ |
| 24 | +npm install |
| 25 | +npm run dev # Development |
| 26 | +npm run build # Production (TSC + Vite) |
| 27 | +npm run lint # ESLint |
| 28 | +``` |
| 29 | + |
| 30 | +### Node Runner CLI (Go) |
| 31 | +```bash |
| 32 | +cd Apps/node_runner/ |
| 33 | +make all # Build all platforms |
| 34 | +make windows # Windows only |
| 35 | +make mac # macOS only |
| 36 | +make linux # Linux only |
| 37 | +``` |
| 38 | + |
| 39 | +### Running Zeuz Node |
| 40 | +```bash |
| 41 | +python node_cli.py --help # Show available flags |
| 42 | +python node_cli.py --login # Authenticate with server |
| 43 | +python node_cli.py --logout # Clear credentials |
| 44 | +``` |
| 45 | + |
| 46 | +## Architecture |
| 47 | + |
| 48 | +### Execution Flow |
| 49 | +``` |
| 50 | +Zeuz Server → long_poll_handler.py → adapter.py → MainDriverApi.py |
| 51 | + ↓ |
| 52 | + sequential_actions.py |
| 53 | + ↓ |
| 54 | + ┌──────────────┬──────────────┬──────────────┐ |
| 55 | + ↓ ↓ ↓ ↓ |
| 56 | + Selenium Playwright Appium Desktop |
| 57 | + BuiltInFunctions BuiltInFunctions BuiltInFunctions ... |
| 58 | +``` |
| 59 | + |
| 60 | +### Key Files |
| 61 | +- `node_cli.py` - Entry point |
| 62 | +- `Framework/MainDriverApi.py` - Test orchestration |
| 63 | +- `Framework/Built_In_Automation/Sequential_Actions/sequential_actions.py` - Action dispatcher |
| 64 | +- `Framework/Built_In_Automation/Shared_Resources/LocateElement.py` - Universal element location |
| 65 | +- `Framework/Built_In_Automation/Shared_Resources/BuiltInFunctionSharedResources.py` - Shared variables |
| 66 | +- `Framework/Utilities/CommonUtil.py` - Logging and exceptions |
| 67 | +- `Framework/Utilities/decorators.py` - @logger, @deprecated decorators |
| 68 | + |
| 69 | +### Module Structure |
| 70 | +Each automation module follows this pattern: |
| 71 | +``` |
| 72 | +Built_In_Automation/<Platform>/ |
| 73 | +├── BuiltInFunctions.py # Action implementations |
| 74 | +├── utils.py # Platform-specific utilities |
| 75 | +└── ... |
| 76 | +``` |
| 77 | + |
| 78 | +Action declarations are in `Sequential_Actions/action_declarations/`: |
| 79 | +- `info.py` - Master registry that loads all declarations |
| 80 | +- `selenium.py`, `playwright.py`, `appium.py`, etc. - Module-specific action definitions |
| 81 | + |
| 82 | +## Code Patterns |
| 83 | + |
| 84 | +### Action Function Template |
| 85 | +All actions must follow this pattern: |
| 86 | +```python |
| 87 | +@logger |
| 88 | +def Action_Name(step_data): |
| 89 | + sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME |
| 90 | + try: |
| 91 | + # 1. Parse parameters from step_data (list of 3-tuples) |
| 92 | + for left, mid, right in step_data: |
| 93 | + left = left.strip().lower() |
| 94 | + # Extract values... |
| 95 | + |
| 96 | + # 2. Get element if needed |
| 97 | + Element = LocateElement.Get_Element(step_data, driver) |
| 98 | + if Element in failed_tag_list: |
| 99 | + CommonUtil.ExecLog(sModuleInfo, "Element not found", 3) |
| 100 | + return "zeuz_failed" |
| 101 | + |
| 102 | + # 3. Perform action |
| 103 | + # ... |
| 104 | + |
| 105 | + CommonUtil.ExecLog(sModuleInfo, "Success", 1) |
| 106 | + return "passed" |
| 107 | + except Exception: |
| 108 | + return CommonUtil.Exception_Handler(sys.exc_info()) |
| 109 | +``` |
| 110 | + |
| 111 | +### Return Status Values |
| 112 | +All actions must return one of: |
| 113 | +- `"passed"` - Success |
| 114 | +- `"zeuz_failed"` - Failure |
| 115 | +- `"skipped"` - Skipped |
| 116 | + |
| 117 | +### Step Data Format |
| 118 | +Actions receive data as a list of 3-tuples: |
| 119 | +```python |
| 120 | +step_data = [ |
| 121 | + ("id", "element parameter", "submit-btn"), |
| 122 | + ("use js", "optional parameter", "true"), |
| 123 | + ("click", "selenium action", "click"), |
| 124 | +] |
| 125 | +``` |
| 126 | + |
| 127 | +### Logging |
| 128 | +```python |
| 129 | +CommonUtil.ExecLog(sModuleInfo, "message", log_level) |
| 130 | +# Levels: 0=Trace, 1=Info/Pass, 2=Warning, 3=Error, 4=Debug |
| 131 | +``` |
| 132 | + |
| 133 | +### Shared Variables |
| 134 | +```python |
| 135 | +from Framework.Built_In_Automation.Shared_Resources import BuiltInFunctionSharedResources as sr |
| 136 | +sr.Set_Shared_Variables("key", value) |
| 137 | +value = sr.Get_Shared_Variables("key") |
| 138 | +sr.Test_Shared_Variables("key") # Check if exists |
| 139 | +``` |
| 140 | + |
| 141 | +### Variable References in Test Data |
| 142 | +Variables use `%|variable_name|%` syntax: |
| 143 | +```python |
| 144 | +"%|my_var|%" # Basic reference |
| 145 | +"%|my_list[0]|%" # Index access |
| 146 | +"%|user["name"]|%" # Dictionary access |
| 147 | +``` |
| 148 | + |
| 149 | +### Element Location |
| 150 | +The unified `LocateElement.Get_Element()` supports: |
| 151 | +- Selenium WebDriver |
| 152 | +- Playwright Page objects |
| 153 | +- Appium drivers |
| 154 | +- Auto-detects driver type from string representation |
| 155 | + |
| 156 | +Parameter types: `element parameter`, `parent parameter`, `child parameter`, `sibling parameter`, `unique parameter` |
| 157 | + |
| 158 | +Selector modifiers: |
| 159 | +- `*` prefix = partial match (contains) |
| 160 | +- `**` prefix = case-insensitive partial match |
| 161 | +- `|*|` separator = platform-specific (Android|iOS) |
| 162 | + |
| 163 | +## Loop Handling |
| 164 | + |
| 165 | +Loops are handled in `sequential_actions.py` with two main mechanisms: |
| 166 | + |
| 167 | +### For Loop (`for_loop_action()`) |
| 168 | +Iterates through data sets or shared variable lists: |
| 169 | +```python |
| 170 | +# Loop settings parameter format: |
| 171 | +("for each_item in %|MyList|%", "loop action", "action to loop") |
| 172 | +``` |
| 173 | + |
| 174 | +**Control options** (via `optional loop control`): |
| 175 | +- **Exit Loop and Fail** - Terminate loop and fail test case |
| 176 | +- **Exit Loop and Continue** - Terminate loop, continue test case |
| 177 | +- **Continue to Next Iteration** - Skip current iteration |
| 178 | + |
| 179 | +**Data structures** track pass/fail conditions per step: |
| 180 | +```python |
| 181 | +exit_loop_and_fail = {"pass": [[]], "fail": [[]], "cond": []} |
| 182 | +exit_loop_and_cont = {"pass": [[]], "fail": [[]], "cond": []} |
| 183 | +continue_next_iter = {"pass": [[]], "fail": [[]], "cond": []} |
| 184 | +``` |
| 185 | + |
| 186 | +### While Loop (`While_Loop_Action()`) |
| 187 | +Conditional looping based on dataset results: |
| 188 | +```python |
| 189 | +# Parameters: |
| 190 | +max_no_of_loop # Maximum iterations (via "repeat" setting) |
| 191 | +loop_this_data_sets # Dataset indices to loop |
| 192 | +# Operators: |==|, !=, <=, >=, >, <, |in| |
| 193 | +``` |
| 194 | + |
| 195 | +**Exit conditions**: |
| 196 | +- Pass/fail condition match on specified dataset |
| 197 | +- Operator comparison between variables |
| 198 | +- Max iteration count reached |
| 199 | + |
| 200 | +### Loop Parameter Types |
| 201 | +- `loop action` - Main loop designation |
| 202 | +- `optional loop settings` - Loop configuration |
| 203 | +- `optional loop condition` - Conditional expressions |
| 204 | +- `optional loop control` - Pass/fail control directives |
| 205 | + |
| 206 | +## Reporting System |
| 207 | + |
| 208 | +### Report Structure |
| 209 | +Reports are stored in `CommonUtil.all_logs_json` as a hierarchical JSON: |
| 210 | +``` |
| 211 | +all_logs_json = [{ |
| 212 | + "run_id": "<run_id>", |
| 213 | + "objective": "<test_objective>", |
| 214 | + "execution_detail": {"duration", "teststarttime", "status"}, |
| 215 | + "test_cases": [{ |
| 216 | + "testcase_no": "<tc_id>", |
| 217 | + "title": "<tc_name>", |
| 218 | + "execution_detail": {"status", "duration", "failreason"}, |
| 219 | + "steps": [{ |
| 220 | + "step_sequence": <seq>, |
| 221 | + "step_id": "<id>", |
| 222 | + "execution_detail": {"status", "duration", "stepstarttime", "stependtime"}, |
| 223 | + "log": [{"status", "modulename", "details", "tstamp", "loglevel"}] |
| 224 | + }] |
| 225 | + }] |
| 226 | +}] |
| 227 | +``` |
| 228 | + |
| 229 | +### Key Reporting Functions |
| 230 | + |
| 231 | +**`CommonUtil.CreateJsonReport()`** - Builds JSON report structure dynamically |
| 232 | +- Extracts log_id components: `run_id|testcase_no|step_id|step_no` |
| 233 | +- Updates test case and step entries in `all_logs_json` |
| 234 | +- Appends log entries to step logs |
| 235 | + |
| 236 | +**`MainDriverApi.upload_step_report()`** - Uploads individual step results |
| 237 | +- POST to `/create_step_report/` |
| 238 | +- 5 retry attempts with 4-second delays |
| 239 | + |
| 240 | +**`MainDriverApi.upload_reports_and_zips()`** - Uploads complete report + artifacts |
| 241 | +- POST to `/create_report_log_api/` (execution report) |
| 242 | +- POST to `/save_log_and_attachment_api/` (ZIP files) |
| 243 | +- Failed uploads saved to `failed_uploads/<run_id>/` for retry |
| 244 | + |
| 245 | +### Test Case Result Calculation |
| 246 | +`calculate_test_case_result()` aggregates step results (priority order): |
| 247 | +1. `testcase_exit` flag if set |
| 248 | +2. "BLOCKED" → Blocked |
| 249 | +3. "CANCELLED" → Cancelled |
| 250 | +4. "zeuz_failed" → Failed or Blocked (based on verify_point) |
| 251 | +5. "WARNING" or "NOT RUN" → Failed |
| 252 | +6. All "SKIPPED" → Skipped |
| 253 | +7. "PASSED" → Passed |
| 254 | +8. Default → Unknown |
| 255 | + |
| 256 | +### Artifact Directory Structure |
| 257 | +``` |
| 258 | +<run_id>/<session_name>/<test_case>/ |
| 259 | +├── Log/ # Browser console error logs |
| 260 | +├── screenshots/ # Test screenshots |
| 261 | +├── performance_report/ # Performance metrics |
| 262 | +├── json_report/ # Step-level JSON reports |
| 263 | +├── zeuz_download_folder/ # Downloaded files |
| 264 | +└── attachments/ # Test case attachments |
| 265 | +``` |
| 266 | + |
| 267 | +### JUnit Report |
| 268 | +Generated via `reporting/junit_report.py` after test completion: |
| 269 | +- Output: `<zip_dir>/junitreport.xml` |
| 270 | +- Standard JUnit XML format with test suite and test case elements |
| 271 | + |
| 272 | +## Adding New Modules |
| 273 | + |
| 274 | +1. Create `Framework/Built_In_Automation/<Category>/<Module>/BuiltInFunctions.py` |
| 275 | +2. Add action declarations in `Sequential_Actions/action_declarations/<module>.py` |
| 276 | +3. Register in `action_declarations/info.py` |
| 277 | +4. Add module loading in `sequential_actions.py:load_sa_modules()` |
| 278 | + |
| 279 | +See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for complete guide. |
| 280 | + |
| 281 | +## Local Server |
| 282 | + |
| 283 | +FastAPI server runs on port 18100+ (auto-increments if in use): |
| 284 | +- `/api/v1/status` - Health check |
| 285 | +- `/api/v1/connect` - Connection management |
| 286 | +- `/api/v1/mobile` - Mobile UI dump |
| 287 | + |
| 288 | +## Key Directories |
| 289 | + |
| 290 | +- `~/.zeuz/` - User artifacts |
| 291 | +- `~/.zeuz/zeuz_node_downloads/` - Driver/app downloads |
| 292 | +- `AutomationLog/` - Test execution logs |
| 293 | +- `AutomationLog/attachments/` - Captured files |
0 commit comments