|
| 1 | +# TestRecorder Tooling |
| 2 | + |
| 3 | +The `sap.ui.testrecorder` library provides the module `sap.ui.testrecorder.ControlTree` that allows to: |
| 4 | +- inspect the live control tree in the browser |
| 5 | +- retrieve reliable OPA5 snippets for interacting with any part of the control tree |
| 6 | + |
| 7 | +## Prerequisites to Use `sap.ui.testrecorder.ControlTree` |
| 8 | + |
| 9 | +- **UI5 version ≥ 1.147** |
| 10 | +- Tool to load the OPA5 test in the browser and evaluate javascript in the browser window (e.g. MCP Playwright) |
| 11 | +- **`sap.ui.testrecorder` library loaded** — temporarily add to the app's library declarations in the places listed below (**ORDERED BY PRIORITY**): |
| 12 | + 1. `ui5.yaml` → `framework.libraries`: `- name: sap.ui.testrecorder` |
| 13 | + 2. `manifest.json` → `sap.ui5.dependencies.libs`: `"sap.ui.testrecorder": {}` |
| 14 | + 3. `index.html` → `data-sap-ui-libs` bootstrap attribute: append `,sap.ui.testrecorder` |
| 15 | + |
| 16 | + > After adding to `ui5.yaml` ensure the server is serving the added library before proceeding: |
| 17 | + > ```bash |
| 18 | + > curl -s -o /dev/null -w "%{http_code}" \ |
| 19 | + > http://localhost:8080/resources/sap/ui/testrecorder/ControlTree.js |
| 20 | + > ``` |
| 21 | + > If 404, **ALWAYS** start a fresh server on the next free port (8081, 8082, …) and use that port |
| 22 | + > for all subsequent browser navigation |
| 23 | +
|
| 24 | + > Remove `sap.ui.testrecorder` after use — not needed at runtime. |
| 25 | + > Kill after use any started fresh server instance. |
| 26 | +
|
| 27 | +## `sap.ui.testrecorder.ControlTree` API |
| 28 | +
|
| 29 | +**`ControlTree.search(query)`** — Search the live UI5 control tree. |
| 30 | +- Returns `Promise<string>` — a tree snapshot with matching controls and their parents |
| 31 | +- `query=""` returns the full tree; `query="anchorBar"` returns filtered results |
| 32 | +- Matches against control type short names, non-default property values, and accessibility attributes |
| 33 | +- Each node carries a `nodeId="N_M"` (snapshot N, node M) — use these in `ControlTree` methods that require a `nodeId` parameter |
| 34 | +
|
| 35 | +**`ControlTree.getControlData(nodeId)`** — Get selector and full control state. |
| 36 | +- Returns `Promise<{ selectorSnippet, properties, aggregations, associations, bindings }>` |
| 37 | +- `selectorSnippet` — OPA5 `waitFor` code to locate the control (use as the base selector) |
| 38 | +- Other fields provide live control state for customizing assertions |
| 39 | +
|
| 40 | +**`ControlTree.press(nodeId, settings?)`** — Press a control and get its OPA5 action snippet. |
| 41 | +- Returns `Promise<string>` — an OPA5 `waitFor` snippet with `actions: new Press()` |
| 42 | +- Also **replays the press** on the running app, advancing the UI state for the next search |
| 43 | +- Optional `settings`: `altKey`, `ctrlKey`, `shiftKey`, `xPercentage`, `yPercentage` |
| 44 | +
|
| 45 | +**`ControlTree.enterText(nodeId, settings)`** — Type into a control and get its OPA5 action snippet. |
| 46 | +- Returns `Promise<string>` — an OPA5 `waitFor` snippet with `actions: new EnterText()` |
| 47 | +- Also **replays the text entry** on the running app |
| 48 | +- `settings`: `text`, `clearTextFirst` (default `true`), `submitText` (default `true`) |
| 49 | +
|
| 50 | +## Example Usage |
| 51 | +
|
| 52 | +```javascript |
| 53 | +sap.ui.require(["sap/ui/testrecorder/ControlTree"], async (ControlTree) => { |
| 54 | + "use strict"; |
| 55 | + // Navigate to the state where the anchor bar is visible, then: |
| 56 | + await ControlTree.search("anchorBar"); // When resolved, inspect the returned markdown snapshot and pick nodeId, e.g. Button nodeId="1_8" text="Methods" |
| 57 | +
|
| 58 | + // Use the picked nodeId to interact with the corresponding control |
| 59 | + await ControlTree.press("1_8"); // When resolved, save the returned OPA5 snippet; UI has now navigated |
| 60 | +
|
| 61 | + await ControlTree.search("selectedSection"); // When resolved, parse returned snapshot and pick nodeId, e.g. ObjectPageLayout nodeId="2_3" |
| 62 | +
|
| 63 | + await ControlTree.getControlData("2_3"); // When resolved, save result.selectorSnippet + result.associations → build assertion |
| 64 | +}); |
| 65 | +``` |
0 commit comments