sap-fiori-opa5-test-development — Claude Code skill: how to install
Generates and debugs OPA5 integration tests for SAP Fiori Elements apps. Guides test setup for both OData V4 and V2 without inventing fake API methods.
npx skills add SAP/open-ux-tools --skill sap-fiori-opa5-test-development -a claude-codeWhat sap-fiori-opa5-test-development does
This skill guides coding agents through writing OPA5 integration tests for SAP Fiori Elements applications. It starts by locating the project root from manifest.json, then detects the OData version. If manifest.json contains sap.fe.templates, it selects the sap.fe.test library for OData V4. If it finds sap.ui.generic.app, it switches to fioriElementsTestLibrary for OData V2. Mixing these two test libraries is strictly prevented.
The guide enforces strict rules against silent test failures. Every opaTest block must include at least one Then assertion, because missing assertions report zero checks and pass silently. Case sensitivity in OData property names is strictly maintained to prevent silent timeouts. For OData V4, the skill ensures that keys in the JourneyRunner pages map mirror page accessor names.
Freestyle UI5 applications are not supported by design. The instructions strictly assume a project generated by SAP Fiori tools with an existing test folder at webapp/test.
What it helps with
- write OPA5 integration journeys for SAP Fiori Elements
- configure JourneyRunner and page object accessors for OData V4
- diagnose silent test failures caused by missing Then assertions
- structure new journey files within the integration test directory
Example prompts for the agent
- Write an OPA5 journey for the list report in my Fiori Elements project
- Fix failing OPA tests in webapp/test/integration
- Add a new integration test journey for this OData V4 app
How to install sap-fiori-opa5-test-development
1Skills CLI (Vercel)
npx skills add SAP/open-ux-tools --skill sap-fiori-opa5-test-development -a claude-code2Manually: put the files in place
~/.claude/skills/sap-fiori-opa5-test-development/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/sap-fiori-opa5-test-development/
1Skills CLI (Vercel)
npx skills add SAP/open-ux-tools --skill sap-fiori-opa5-test-development -a codex2Manually: put the files in place
.agents/skills/sap-fiori-opa5-test-development/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add SAP/open-ux-tools --skill sap-fiori-opa5-test-development -a cursor2Manually: put the files in place
.cursor/skills/sap-fiori-opa5-test-development/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install SAP/open-ux-tools sap-fiori-opa5-test-development2Manually: put the files in place
.github/skills/sap-fiori-opa5-test-development/SKILL.md1Skills CLI (Vercel)
npx skills add SAP/open-ux-tools --skill sap-fiori-opa5-test-development -a gemini-cli2Platform CLI
gemini skills install https://github.com/SAP/open-ux-tools --path plugins-coding-agents/fiori/skills/sap-fiori-opa5-test-developmentManually: put the files in place
.devin/skills/sap-fiori-opa5-test-development/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add SAP/open-ux-tools --skill sap-fiori-opa5-test-development -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about sap-fiori-opa5-test-development
How do I install sap-fiori-opa5-test-development in Claude Code?
Run npx skills add SAP/open-ux-tools --skill sap-fiori-opa5-test-development -a claude-code in your terminal.
Can I use this skill with freestyle UI5 apps?
No. This skill targets SAP Fiori Elements generated with SAP Fiori tools. Freestyle UI5 apps require separate guidelines such as ui5-best-practices-opa5.
How does the skill distinguish between OData V4 and V2?
It inspects manifest.json for sap.fe.templates (V4) or sap.ui.generic.app (V2). If the manifest is inconclusive, it checks the <edmx:Edmx> root element in metadata.xml.
Source text
SKILL.md · Apache-2.0
---
name: sap-fiori-opa5-test-development
description: Use this skill when writing, fixing, extending, or reviewing OPA5 integration tests
for SAP Fiori Elements applications - whether the app uses OData V4 (sap.fe.test library)
or OData V2 (fioriElementsTestLibrary). Triggers on any request involving OPA5 journeys,
page objects, JourneyRunner setup, test structure, mock data, or debugging test failures
in a SAP Fiori Elements project generated by SAP Fiori tools. Use even when the user says
"write integration tests" or "add an OPA journey" without specifying the library, as long
as the project context is SAP Fiori Elements. Not applicable to freestyle UI5 apps.
metadata:
author: sap-fiori-tools
version: "1.0.4"
---
# SAP Fiori OPA5 Development Skill
A guide for writing, fixing, and extending OPA5 integration tests for SAP Fiori Elements applications.
Covers both OData V4 (`sap.fe.test`) and OData V2 (`fioriElementsTestLibrary`).
Not applicable to freestyle UI5 applications - for those, suggest the `ui5-best-practices-opa5` skill from the **UI5 Plugins for Coding Agents** `ui5`.
---
## Prerequisites
This skill requires an existing SAP Fiori Elements application generated by SAP Fiori tools with a test folder present (e.g. at `webapp/test`). If it is missing, follow the version-specific guide after detecting the OData version.
---
## Step 1: Locate the Project Root
When the user provides a project name or ID (e.g. `fin.test.rap.lr3`) instead of a file path:
1. Search for `manifest.json` files under common project roots (e.g. `webapp/manifest.json`).
2. Match the `"id"` field in `sap.app` to the given name, or look for a folder whose name contains the given ID.
3. Once found, treat the folder containing `webapp/manifest.json` as the project root for all subsequent steps.
---
## Step 2: Detect OData Version
Before writing any test code, determine whether the app is OData V4 or V2. The two test libraries are completely different and must never be mixed.
### Primary check: `manifest.json`
| What you find | Version | Test library |
|---|---|---|
| `"sap.fe.templates"` key inside `sap.ui5.dependencies.libs` | **V4** | `sap.fe.test` |
| `"sap.ui.generic.app"` as a root key | **V2** | `fioriElementsTestLibrary` |
### Fallback check: `metadata.xml`
If `manifest.json` is inconclusive, check the `<edmx:Edmx>` root element in the service metadata file (typically at `webapp/localService/mainService/metadata.xml`, or wherever `metadataPath` points in `ui5-mock.yaml`):
| Attribute value | Version |
|---|---|
| `xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"` or `Version="4.0"` | **V4** |
| `xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"` or `Version="1.0"` | **V2** |
These attributes appear on line 1 or 2 of the file.
If neither signal is present, ask the user to confirm the OData version before proceeding.
---
## Step 3: Follow the Matching Guide
Once the version is confirmed:
1. Read the shared sections further below ("Test Endpoint and Running Tests", "Mock Server") - they apply to both V4 and V2.
2. Then read the version-specific guide for all test library decisions:
- **OData V4** - read `references/v4-instructions.md`
- **OData V2** - read `references/v2-instructions.md`
---
## Adding a New Journey
When the user asks to add an additional journey (not just a new `opaTest` inside an existing journey):
1. **Find the test root** - search for files matching `*Journey.js`, `*Journey.ts`, `*Journey.gen.js`, or `*Journey.gen.ts` in the project. The folder containing those files is the integration test root. These files typically live in a folder named `integration` within the test directory, e.g. `webapp/test/integration`.
2. **Understand the wiring** - read the existing journey files and any entry point files to understand how journeys are registered. Three setups are possible:
- **Virtual endpoint** (V4) - no registration needed; the middleware picks up any file matching the configured pattern (default: ends in `Journey.js` or `Journey.ts`)
- **Physical entry point** (V4) - add the new journey's module path to the `sap.ui.require` array in `OpaTests.qunit.js`
- **Custom wiring** (e.g. S/4 apps with `AllJourneys.js` or `AllJourneys.json`) - follow the existing pattern
3. **Create the journey file** following the same naming pattern as existing journeys.
4. **Confirm** to the user which file was created and how it is registered (or that registration is automatic).
---
## General Anti-Patterns (V4 and V2)
These apply regardless of OData version or test library.
**Never invent method names.** Only use methods that are confirmed to exist in the test library.
If a method is not shown in the quick-reference patterns, do NOT guess or construct a name - look it up first:
- **V4**: check `references/v4-standard-patterns.md` for common patterns. If the method is not there, check `references/v4-custom-selectors.md` for custom selector patterns. If still not found, read `references/v4-sap-fe-test-api-guide.md` and consult the official `sap.fe.test` API documentation it points to. A method that "sounds right" is not sufficient — it must be confirmed to exist.
- **V2**: check `references/fiori-elements-v2-test-library.md` which contains the full API reference for all V2 page objects.
Invented methods fail silently with a "not a function" runtime error that is hard to diagnose.
**Every `opaTest` must have at least one `Then` assertion.** A test with only `Given`/`When` steps reports 0 assertions and fails silently.
```javascript
// ❌ No Then = no assertions, test fails
opaTest("Click button", function(Given, When, Then) {
When.onThePage.iClickButton();
});
// ✅ Always end with at least one Then
opaTest("Click button", function(Given, When, Then) {
When.onThePage.iClickButton();
Then.onThePage.iSeeThisPage();
});
```
**OData property names are case-sensitive** - always match the exact casing from `metadata.xml`. Wrong casing causes a timeout, not an error message.
**OPA5 state carries over between `opaTest` blocks within a journey.** Tests run sequentially and share the same browser session - do not assume the app is in a clean state at the start of each `opaTest`. Always navigate and assert explicitly rather than relying on state left by the previous test block.
**The `pages` map key in JourneyRunner (V4) must exactly match the accessor name used in journeys.** A mismatch causes a silent runtime error - the page object is simply undefined when the journey tries to call it. (V2 registers page objects globally via module loading and has no `pages` map.)
```javascript
// ❌ Wrong - key is "onTheList" but journey calls "onTheListReport"
pages: { onTheList: ListReportPage }
// journey: When.onTheListReport.onTable()... → undefined
// ✅ Fixed - key matches accessor name exactly
pages: { onTheListReport: ListReportPage }
```
**Keep journeys focused - split at around 10 `opaTest` blocks.** Large journey files are slow to debug and hard to maintain. One journey file per feature or user flow is a good rule of thumb. Do not add tests for standard Fiori Elements behavior already covered by the test library itself.
**Teardown method name differs by version.** Always call teardown on `Given`, never on a page object:
- V4: `Given.iTearDownMyApp()` (capital D - overridden in `sap.fe.test.BaseArrangements`)
- V2: `Given.iTeardownMyApp()` (lowercase d - base `Opa5` method)
QUnit requires assertions to validate tests. Teardown is not an assertion - always assert something before tearing down.
❌ Incorrect - teardown with no prior assertion:
```javascript
// V4
opaTest("Should clean up", function(Given, When, Then) {
Given.iTearDownMyApp();
});
// V2
opaTest("Should clean up", function(Given, When, Then) {
Given.iTeardownMyApp();
});
```
❌ Incorrect - teardown chained on a page object instead of `Given`:
```javascript
// V4
opaTest("Should assert state and clean up", function(Given, When, Then) {
Then.onTheListPage.iSeeThisPage()
.and.onTheListPage.iTearDownMyApp();
});
```
✅ Correct:
```javascript
// V4
opaTest("Should assert state and clean up", function(Given, When, Then) {
Then.onTheListPage.iSeeThisPage(); // assertion first
Given.iTearDownMyApp(); // teardown on Given, separate step
});
// V2
opaTest("Should assert state and clean up", function(Given, When, Then) {
Then.onTheGenericListReport.theResultListIsVisible(); // assertion first
Given.iTeardownMyApp(); // teardown on Given, separate step
});
```
---
## Test Endpoint and Running Tests
These apply to both V4 and V2 projects.
### Virtual Test Endpoint (fiori-tools-preview or preview-middleware)
When `@sap/ux-ui5-tooling` or `@sap-ux/preview-middleware` is configured with a `test` block in `ui5.yaml` or `ui5-mock.yaml`, the HTML and JS entry point files are **generated on the fly** - no physical `opaTests.qunit.html` or `OpaTests.qunit.js` are needed on disk.
Example `ui5-mock.yaml` configuration:
```yaml
server:
customMiddleware:
- name: fiori-tools-preview
configuration:
test:
- framework: OPA5
path: /test/opaTests.qunit.html # default, omit if unchanged
init: /test/opaTests.qunit.js # default, omit if unchanged
pattern: /test/**/*Journey{,.gen}.{js,ts} # default, omit if unchanged
```
If a physical file already exists at the configured path, the middleware serves that instead (with a warning). When working in a virtual-endpoint project, do not create `opaTests.qunit.html` or `OpaTests.qunit.js` manually - new journey files are picked up automatically as long as their filename matches the configured pattern.
### Physical Files (classic setup)
Without the virtual endpoint, the full structure is present on disk:
```
webapp/test/integration/
├── opaTests.qunit.html <- test suite entry point (opened in browser)
├── OpaTests.qunit.js <- imports journeys and calls QUnit.start()
├── FirstJourney.js
└── pages/
└── ...
```
Registering a new journey requires adding its module path to the `sap.ui.require` array in `OpaTests.qunit.js`.
### Running Tests
**Via npm script:**
```bash
npm run int-test
```
Check `package.json` for the exact script name. This runs `fiori run --config ./ui5-mock.yaml --open 'test/integration/opaTests.qunit.html'`.
**Manually (CAP-based apps):**
```bash
npm start # or: cds watch
```
Then open in a browser: `http://localhost:<port>/<app-name>/webapp/test/integration/opaTests.qunit.html`
---
## Mock Server
These apply to both V4 and V2 projects.
### `@sap-ux/ui5-middleware-fe-mockserver` (recommended)
Runs in the UI5 tooling layer - no backend process needed - making it the recommended choice for OPA5 tests. Supports both V4 and V2 apps.
Set it up with:
```bash
npx --yes @sap-ux/create@latest add mockserver-config
```
Two data modes - choose based on what your tests assert:
| Mode | Config | Use when |
|---|---|---|
| Static mock data | `generateMockData: false` | Tests assert **specific values** (exact counts, field contents, IDs). JSON files in `mockdataPath` (default: `./webapp/localService/mainService/data/`). Deterministic across runs. |
| Dynamic mock data | `generateMockData: true` | Tests only assert **structure** (a field is visible, a table has rows). No JSON files to maintain, but you cannot assert exact values. |
> If a journey deletes a record (e.g., via `iExecuteDelete()`), restart the server before re-running to restore the data.
### `sap.ui.core.util.MockServer` (older V2 apps)
Older V2 apps generated by earlier tooling may use the UI5 framework's built-in mock server instead. It is configured via `localService/mockserver.js` and runs in the browser rather than the tooling layer. See the UI5 docs: `https://ui5.sap.com/#/topic/3a9728ec31f94ca18a7d543ce419d85d`
### CAP backend
For CAP-based projects, `cds watch` / `npm start` can serve as the data backend. Reserve this for dedicated integration or end-to-end suites that need to test CAP logic - prefer the mockserver for OPA5 tests.
---
## Debugging Failing Tests
These apply to both V4 and V2 projects.
When a test fails, enable pause-on-failure so the app stays live in the browser at the point of failure for direct inspection. Add this line to your test entry point before the runner or any `Opa5.extendConfig` call:
```javascript
sap.ui.test.qunitPause.pauseRule = "assert,timeout";
```
When the test pauses, inspect the live app in the browser to see what the UI actually shows vs. what the test expected. Remove this line once all journeys pass.
For UI5 version 1.147 and above, the **TestRecorder** tool (`sap.ui.testrecorder` library) can be added to the app temporarily to inspect the live control tree and generate reliable OPA5 snippets for non-trivial selectors. Remove the library again once done.
**Flaky tests on CI** - the default OPA5 timeout (15s) is often too low for CI environments. Increase it to 60 in your runner config (`opaConfig.timeout` for V4, `Opa5.extendConfig({ timeout: 60 })` for V2).
---
## Reference Files
| File | When to read |
|---|---|
| `references/v4-instructions.md` | V4 app: test structure, JourneyRunner, page objects, anti-patterns, debugging, patterns and fixes by UI area |
| `references/v4-journeyrunner.md` | V4: full JourneyRunner config reference, tile name lookup, portable journey pattern |
| `references/v4-sap-fe-test-api-guide.md` | V4: how to navigate the sap.fe.test API docs, naming conventions, identifier patterns |
| `references/v4-standard-patterns.md` | V4: quick-reference example catalogue by UI area (App Startup, FilterBar, Table, Header, Form, Footer, Dialog, Section, Value Help, Chart, Shell) |
| `references/v4-custom-selectors.md` | V4: custom selectors (last resort), OpaBuilder, CustomFilterField IDs, ComboBox, suffix pitfalls |
| `references/v2-instructions.md` | V2 app: setup, page objects, V2 gotchas |
| `references/fiori-elements-v2-test-library.md` | V2: full API reference for List Report, Object Page, ALP, and FCL page objects — method signatures, common pitfalls, complete example |
© sap-fiori-tools · Apache-2.0 · SAP/open-ux-tools