sap-fiori-opa5-test-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSAP Fiori OPA5 Development Skill
SAP Fiori OPA5 Development Skill
A guide for writing, fixing, and extending OPA5 integration tests for SAP Fiori Elements applications.
Covers both OData V4 () and OData V2 ().
sap.fe.testfioriElementsTestLibraryNot applicable to freestyle UI5 applications - for those, suggest the skill from the UI5 Plugins for Coding Agents .
ui5-best-practices-opa5ui5本指南介绍如何为SAP Fiori Elements应用编写、修复和扩展OPA5集成测试。
涵盖OData V4()和OData V2()两种版本。
sap.fe.testfioriElementsTestLibrary不适用于自由风格UI5应用——对于此类应用,请推荐UI5 Plugins for Coding Agents 中的 Skill。
ui5ui5-best-practices-opa5Prerequisites
前提条件
This skill requires an existing SAP Fiori Elements application generated by SAP Fiori tools.
The folder must be present (e.g. at ). If it is missing, ask the user to regenerate it first using the Application Info command in SAP Fiori tools.
/testwebapp/test使用此Skill需要一个由SAP Fiori tools生成的现有SAP Fiori Elements应用。
必须存在文件夹(例如位于)。如果缺失,请先让用户使用SAP Fiori tools中的Application Info命令重新生成该文件夹。
/testwebapp/testStep 1: Locate the Project Root
步骤1:定位项目根目录
When the user provides a project name or ID (e.g. ) instead of a file path:
fin.test.rap.lr3- Search for files under common project roots (e.g.
manifest.json).webapp/manifest.json - Match the field in
"id"to the given name, or look for a folder whose name contains the given ID.sap.app - Once found, treat the folder containing as the project root for all subsequent steps.
webapp/manifest.json
当用户提供项目名称或ID(例如)而非文件路径时:
fin.test.rap.lr3- 在常见项目根目录下搜索文件(例如
manifest.json)。webapp/manifest.json - 将中的
sap.app字段与给定名称匹配,或查找名称包含给定ID的文件夹。"id" - 找到后,将包含的文件夹作为后续所有步骤的项目根目录。
webapp/manifest.json
Step 2: Detect OData Version
步骤2:检测OData版本
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.
在编写任何测试代码之前,确定应用使用的是OData V4还是V2。这两个测试库完全不同,绝不能混用。
Primary check: manifest.json
manifest.json主要检查:manifest.json
manifest.json| What you find | Version | Test library |
|---|---|---|
| V4 | |
| V2 | |
| 找到的内容 | 版本 | 测试库 |
|---|---|---|
| V4 | |
根键为 | V2 | |
Fallback check: metadata.xml
metadata.xml备用检查:metadata.xml
metadata.xmlIf is inconclusive, check the root element in the service metadata file (typically at , or wherever points in ):
manifest.json<edmx:Edmx>webapp/localService/mainService/metadata.xmlmetadataPathui5-mock.yaml| Attribute value | Version |
|---|---|
| V4 |
| 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.
如果无法确定版本,请检查服务元数据文件(通常位于,或中指向的位置)中的根元素:
manifest.jsonwebapp/localService/mainService/metadata.xmlui5-mock.yamlmetadataPath<edmx:Edmx>| 属性值 | 版本 |
|---|---|
| V4 |
| V2 |
这些属性出现在文件的第1或第2行。
如果两种信号都不存在,请在继续前让用户确认OData版本。
Step 3: Follow the Matching Guide
步骤3:遵循对应指南
Once the version is confirmed:
- Read the shared sections further below ("Test Endpoint and Running Tests", "Mock Server") - they apply to both V4 and V2.
- 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
- OData V4 - read
确认版本后:
- 阅读下方的共享章节(“测试端点与运行测试”、“模拟服务器”)——这些内容适用于V4和V2版本。
- 然后阅读对应版本的指南,以获取所有测试库相关的决策指导:
- OData V4 - 阅读
references/v4-instructions.md - OData V2 - 阅读
references/v2-instructions.md
- OData V4 - 阅读
Adding a New Journey
添加新Journey
When the user asks to add an additional journey (not just a new inside an existing journey):
opaTest- Find the test root - search for files matching ,
*Journey.js,*Journey.ts, or*Journey.gen.jsin the project. The folder containing those files is the integration test root. These files typically live in a folder named*Journey.gen.tswithin the test directory, e.g.integration.webapp/test/integration - 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 or
Journey.js)Journey.ts - Physical entry point (V4) - add the new journey's module path to the array in
sap.ui.requireOpaTests.qunit.js - Custom wiring (e.g. S/4 apps with or
AllJourneys.js) - follow the existing patternAllJourneys.json
- Virtual endpoint (V4) - no registration needed; the middleware picks up any file matching the configured pattern (default: ends in
- Create the journey file following the same naming pattern as existing journeys.
- Confirm to the user which file was created and how it is registered (or that registration is automatic).
当用户要求添加新的Journey(不仅仅是在现有Journey中添加新的)时:
opaTest- 找到测试根目录 - 在项目中搜索匹配、
*Journey.js、*Journey.ts或*Journey.gen.js的文件。包含这些文件的文件夹即为集成测试根目录。这些文件通常位于测试目录下名为*Journey.gen.ts的文件夹中,例如integration。webapp/test/integration - 了解关联配置 - 阅读现有Journey文件和任何入口点文件,了解Journeys的注册方式。可能存在三种配置:
- 虚拟端点(V4) - 无需注册;中间件会自动识别符合配置模式的文件(默认:以或
Journey.js结尾)Journey.ts - 物理入口点(V4) - 将新Journey的模块路径添加到的
OpaTests.qunit.js数组中sap.ui.require - 自定义关联(例如带有或
AllJourneys.js的S/4应用) - 遵循现有模式AllJourneys.json
- 虚拟端点(V4) - 无需注册;中间件会自动识别符合配置模式的文件(默认:以
- 创建Journey文件,遵循现有Journeys的命名模式。
- 告知用户创建了哪个文件以及注册方式(或说明注册是自动的)。
General Anti-Patterns (V4 and V2)
通用反模式(V4和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 for common patterns. If the method is not there, check
references/v4-standard-patterns.mdfor custom selector patterns. If still not found, readreferences/v4-custom-selectors.mdand consult the officialreferences/v4-sap-fe-test-api-guide.mdAPI documentation it points to. A method that "sounds right" is not sufficient — it must be confirmed to exist.sap.fe.test - V2: check which contains the full API reference for all V2 page objects.
references/fiori-elements-v2-test-library.md
Invented methods fail silently with a "not a function" runtime error that is hard to diagnose.
Every must have at least one assertion. A test with only / steps reports 0 assertions and fails silently.
opaTestThenGivenWhenjavascript
// ❌ 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 . Wrong casing causes a timeout, not an error message.
metadata.xmlOPA5 state carries over between 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 . Always navigate and assert explicitly rather than relying on state left by the previous test block.
opaTestopaTestThe 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 map.)
pagespagesjavascript
// ❌ 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 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.
opaTestTeardown method name differs by version. Always call teardown on , never on a page object:
Given- V4: (capital D - overridden in
Given.iTearDownMyApp())sap.fe.test.BaseArrangements - V2: (lowercase d - base
Given.iTeardownMyApp()method)Opa5
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 :
Givenjavascript
// 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
});这些规则适用于所有OData版本和测试库。
切勿自行发明方法名称。仅使用测试库中已确认存在的方法。
如果快速参考模式中未显示某个方法,请不要猜测或构造名称——先查找确认:
- V4:查看获取常见模式。如果未找到该方法,请查看
references/v4-standard-patterns.md获取自定义选择器模式。如果仍未找到,请阅读references/v4-custom-selectors.md并参考其指向的官方references/v4-sap-fe-test-api-guide.mdAPI文档。“听起来合理”的方法并不足够——必须确认其确实存在。sap.fe.test - V2:查看,其中包含所有V2页面对象的完整API参考。
references/fiori-elements-v2-test-library.md
自行发明的方法会静默失败,抛出难以诊断的“not a function”运行时错误。
每个必须至少包含一个断言。仅包含/步骤的测试会报告0个断言并静默失败。
opaTestThenGivenWhenjavascript
// ❌ 无Then = 无断言,测试失败
opaTest("Click button", function(Given, When, Then) {
When.onThePage.iClickButton();
});
// ✅ 始终以至少一个Then结尾
opaTest("Click button", function(Given, When, Then) {
When.onThePage.iClickButton();
Then.onThePage.iSeeThisPage();
});OData属性名称区分大小写 - 必须与中的大小写完全匹配。错误的大小写会导致超时,而非错误提示。
metadata.xmlOPA5状态会在同一个Journey的块之间延续。测试按顺序运行并共享同一个浏览器会话——不要假设每个开始时应用处于干净状态。始终显式导航和断言,不要依赖前一个测试块留下的状态。
opaTestopaTestJourneyRunner(V4)中的映射键必须与Journeys中使用的访问器名称完全匹配。不匹配会导致静默运行时错误——当Journey尝试调用页面对象时,该对象将是未定义的。(V2通过模块加载全局注册页面对象,没有映射。)
pagespagesjavascript
// ❌ 错误 - 键为"onTheList"但Journey调用"onTheListReport"
pages: { onTheList: ListReportPage }
// journey: When.onTheListReport.onTable()... → undefined
// ✅ 修正 - 键与访问器名称完全匹配
pages: { onTheListReport: ListReportPage }保持Journeys聚焦——大约每10个块拆分一次。大型Journey文件调试缓慢且难以维护。一个Journey文件对应一个功能或用户流程是不错的经验法则。不要添加测试库已覆盖的标准Fiori Elements行为的测试。
opaTestTeardown方法名称因版本而异。始终在上调用teardown,切勿在页面对象上调用:
Given- V4: (大写D - 在
Given.iTearDownMyApp()中重写)sap.fe.test.BaseArrangements - V2: (小写d - 基础
Given.iTeardownMyApp()方法)Opa5
QUnit需要断言来验证测试。Teardown不是断言——在teardown之前始终要进行断言。
❌ 错误 - 无前置断言的teardown:
javascript
// V4
opaTest("Should clean up", function(Given, When, Then) {
Given.iTearDownMyApp();
});
// V2
opaTest("Should clean up", function(Given, When, Then) {
Given.iTeardownMyApp();
});❌ 错误 - 在页面对象上链式调用teardown而非在上:
Givenjavascript
// V4
opaTest("Should assert state and clean up", function(Given, When, Then) {
Then.onTheListPage.iSeeThisPage()
.and.onTheListPage.iTearDownMyApp();
});✅ 正确:
javascript
// V4
opaTest("Should assert state and clean up", function(Given, When, Then) {
Then.onTheListPage.iSeeThisPage(); // 先断言
Given.iTearDownMyApp(); // 在Given上单独执行teardown
});
// V2
opaTest("Should assert state and clean up", function(Given, When, Then) {
Then.onTheGenericListReport.theResultListIsVisible(); // 先断言
Given.iTeardownMyApp(); // 在Given上单独执行teardown
});Test Endpoint and Running Tests
测试端点与运行测试
These apply to both V4 and V2 projects.
这些内容适用于V4和V2项目。
Virtual Test Endpoint (fiori-tools-preview or preview-middleware)
虚拟测试端点(fiori-tools-preview或preview-middleware)
When or is configured with a block in or , the HTML and JS entry point files are generated on the fly - no physical or are needed on disk.
@sap/ux-ui5-tooling@sap-ux/preview-middlewaretestui5.yamlui5-mock.yamlopaTests.qunit.htmlOpaTests.qunit.jsExample configuration:
ui5-mock.yamlyaml
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 unchangedIf 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 or manually - new journey files are picked up automatically as long as their filename matches the configured pattern.
opaTests.qunit.htmlOpaTests.qunit.js当或在或中配置了块时,HTML和JS入口点文件会动态生成——磁盘上不需要物理的或文件。
@sap/ux-ui5-tooling@sap-ux/preview-middlewareui5.yamlui5-mock.yamltestopaTests.qunit.htmlOpaTests.qunit.js示例配置:
ui5-mock.yamlyaml
server:
customMiddleware:
- name: fiori-tools-preview
configuration:
test:
- framework: OPA5
path: /test/opaTests.qunit.html # 默认值,无需修改可省略
init: /test/opaTests.qunit.js # 默认值,无需修改可省略
pattern: /test/**/*Journey{,.gen}.{js,ts} # 默认值,无需修改可省略如果配置路径下已存在物理文件,中间件会提供该文件(并给出警告)。在使用虚拟端点的项目中,不要手动创建或——只要新Journey文件的文件名符合配置模式,就会被自动识别。
opaTests.qunit.htmlOpaTests.qunit.jsPhysical 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 array in .
sap.ui.requireOpaTests.qunit.js没有虚拟端点时,磁盘上会存在完整的结构:
webapp/test/integration/
├── opaTests.qunit.html <- 测试套件入口点(在浏览器中打开)
├── OpaTests.qunit.js <- 导入Journeys并调用QUnit.start()
├── FirstJourney.js
└── pages/
└── ...注册新Journey需要将其模块路径添加到的数组中。
OpaTests.qunit.jssap.ui.requireRunning Tests
运行测试
Via npm script:
bash
npm run int-testCheck for the exact script name. This runs .
package.jsonfiori run --config ./ui5-mock.yaml --open 'test/integration/opaTests.qunit.html'Manually (CAP-based apps):
bash
npm start # or: cds watchThen open in a browser:
http://localhost:<port>/<app-name>/webapp/test/integration/opaTests.qunit.html通过npm脚本:
bash
npm run int-test查看获取确切的脚本名称。此命令运行。
package.jsonfiori run --config ./ui5-mock.yaml --open 'test/integration/opaTests.qunit.html'手动运行(基于CAP的应用):
bash
npm start # 或:cds watch然后在浏览器中打开:
http://localhost:<port>/<app-name>/webapp/test/integration/opaTests.qunit.htmlMock Server
模拟服务器
These apply to both V4 and V2 projects.
这些内容适用于V4和V2项目。
@sap-ux/ui5-middleware-fe-mockserver
(recommended)
@sap-ux/ui5-middleware-fe-mockserver@sap-ux/ui5-middleware-fe-mockserver
(推荐)
@sap-ux/ui5-middleware-fe-mockserverRuns 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-configTwo data modes - choose based on what your tests assert:
| Mode | Config | Use when |
|---|---|---|
| Static mock data | | Tests assert specific values (exact counts, field contents, IDs). JSON files in |
| Dynamic mock data | | 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), restart the server before re-running to restore the data.iExecuteDelete()
在UI5工具层运行——无需后端进程——是OPA5测试的推荐选择。支持V4和V2应用。
使用以下命令设置:
bash
npx --yes @sap-ux/create@latest add mockserver-config两种数据模式——根据测试断言内容选择:
| 模式 | 配置 | 使用场景 |
|---|---|---|
| 静态模拟数据 | | 测试断言特定值(精确数量、字段内容、ID)。JSON文件位于 |
| 动态模拟数据 | | 测试仅断言结构(字段可见、表格有行)。无需维护JSON文件,但无法断言精确值。 |
如果Journey删除了记录(例如通过),重新运行前请重启服务器以恢复数据。iExecuteDelete()
sap.ui.core.util.MockServer
(older V2 apps)
sap.ui.core.util.MockServersap.ui.core.util.MockServer
(旧版V2应用)
sap.ui.core.util.MockServerOlder V2 apps generated by earlier tooling may use the UI5 framework's built-in mock server instead. It is configured via and runs in the browser rather than the tooling layer. See the UI5 docs:
localService/mockserver.jshttps://ui5.sap.com/#/topic/3a9728ec31f94ca18a7d543ce419d85d早期工具生成的旧版V2应用可能使用UI5框架内置的模拟服务器。它通过配置,在浏览器中运行而非工具层。请查看UI5文档:
localService/mockserver.jshttps://ui5.sap.com/#/topic/3a9728ec31f94ca18a7d543ce419d85dCAP backend
CAP后端
For CAP-based projects, / 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.
cds watchnpm start对于基于CAP的项目, / 可作为数据后端。仅在需要测试CAP逻辑的专用集成或端到端套件中使用此方式——OPA5测试优先使用模拟服务器。
cds watchnpm startDebugging 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 call:
Opa5.extendConfigjavascript
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 ( 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.
sap.ui.testrecorderFlaky tests on CI - the default OPA5 timeout (15s) is often too low for CI environments. Increase it to 60 in your runner config ( for V4, for V2).
opaConfig.timeoutOpa5.extendConfig({ timeout: 60 })这些内容适用于V4和V2项目。
测试失败时,启用失败暂停功能,使应用在失败点保持浏览器中的实时状态以便直接检查。在测试入口点的运行器或任何调用之前添加以下代码:
Opa5.extendConfigjavascript
sap.ui.test.qunitPause.pauseRule = "assert,timeout";测试暂停时,在浏览器中检查实时应用,查看UI实际显示内容与测试预期的差异。所有Journeys通过后移除该行代码。
对于UI5 1.147及以上版本,可临时为应用添加TestRecorder工具(库),以检查实时控件树并为复杂选择器生成可靠的OPA5代码片段。完成后移除该库。
sap.ui.testrecorderCI上的不稳定测试 - 默认OPA5超时时间(15秒)在CI环境中通常太短。在运行器配置中将其增加到60秒(V4使用,V2使用)。
opaConfig.timeoutOpa5.extendConfig({ timeout: 60 })Reference Files
参考文件
| File | When to read |
|---|---|
| V4 app: test structure, JourneyRunner, page objects, anti-patterns, debugging, patterns and fixes by UI area |
| V4: full JourneyRunner config reference, tile name lookup, portable journey pattern |
| V4: how to navigate the sap.fe.test API docs, naming conventions, identifier patterns |
| V4: quick-reference example catalogue by UI area (App Startup, FilterBar, Table, Header, Form, Footer, Dialog, Section, Value Help, Chart, Shell) |
| V4: custom selectors (last resort), OpaBuilder, CustomFilterField IDs, ComboBox, suffix pitfalls |
| V2 app: setup, page objects, V2 gotchas |
| V2: full API reference for List Report, Object Page, ALP, and FCL page objects — method signatures, common pitfalls, complete example |
| 文件 | 阅读场景 |
|---|---|
| V4应用:测试结构、JourneyRunner、页面对象、反模式、调试、按UI区域划分的模式与修复方案 |
| V4:完整的JourneyRunner配置参考、磁贴名称查找、可移植Journey模式 |
| V4:如何浏览sap.fe.test API文档、命名约定、标识符模式 |
| V4:按UI区域划分的快速参考示例目录(应用启动、FilterBar、表格、页眉、表单、页脚、对话框、章节、值帮助、图表、Shell) |
| V4:自定义选择器(最后手段)、OpaBuilder、CustomFilterField ID、ComboBox、后缀陷阱 |
| V2应用:配置、页面对象、V2注意事项 |
| V2:List Report、Object Page、ALP和FCL页面对象的完整API参考——方法签名、常见陷阱、完整示例 |