All skills
secondsky avatar

/sapui5

@620a19a
by Eddiesecondsky/sap-skills456 stars
120

This skill should be used when developing SAP UI5 applications, including creating freestyle apps, Fiori Elements apps, custom controls, testing, data binding, OData integration, routing, and troubleshooting. Use when building enterprise web applications with SAP UI5 framework, implementing MVC patterns, configuring manifest.json, creating XML views, writing controllers, setting up data models (JSON, OData v2/v4), implementing responsive UI with sap.m controls, building Fiori Elements apps, writing unit tests with QUnit, integration tests with OPA5, setting up mock servers, handling security (XSS, CSP), optimizing performance, implementing accessibility features, or debugging UI5 applications. Also covers sap.ui.mdc controls and TypeScript control libraries.

Use this Skill: https://skilld.dev/gh/secondsky/sap-skills/sapui5

This session only. Nothing lands on disk.

referencestesting.md

≈5.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

SAPUI5 Testing Guide

Source: Official SAP SAPUI5 Documentation Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials Last Updated: 2025-11-21


Testing Strategy

SAPUI5 applications should include:

  1. Unit Tests (QUnit): Test individual functions and modules
  2. Integration Tests (OPA5): Test user interactions and flows
  3. Mock Server: Simulate backend for testing without real services

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: testing, qunit, opa)


QUnit Testing

Unit testing framework for JavaScript code.

Setup

test/unit/unitTests.qunit.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Unit Tests</title>

    <script
        id="sap-ui-bootstrap"
        src="../../resources/sap-ui-core.js"
        data-sap-ui-theme="sap_horizon"
        data-sap-ui-resourceroots='{
            "com.mycompany.myapp": "../../"
        }'
        data-sap-ui-async="true">
    </script>

    <link rel="stylesheet" type="text/css" href="../../resources/sap/ui/thirdparty/qunit-2.css">
    <script src="../../resources/sap/ui/thirdparty/qunit-2.js"></script>
    <script src="../../resources/sap/ui/qunit/qunit-junit.js"></script>
    <script src="../../resources/sap/ui/qunit/qunit-coverage.js"></script>

    <script src="unitTests.qunit.js"></script>
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>
</body>
</html>

test/unit/unitTests.qunit.js:

QUnit.config.autostart = false;

sap.ui.require([
    "com/mycompany/myapp/test/unit/model/formatter"
], function() {
    "use strict";
    QUnit.start();
});

Writing Unit Tests

test/unit/model/formatter.js:

sap.ui.define([
    "com/mycompany/myapp/model/formatter",
    "sap/ui/model/resource/ResourceModel"
], function(formatter, ResourceModel) {
    "use strict";

    QUnit.module("Formatter Tests");

    QUnit.test("Should format price correctly", function(assert) {
        // Arrange
        var fPrice = 123.456;

        // Act
        var sResult = formatter.formatPrice(fPrice);

        // Assert
        assert.strictEqual(sResult, "123.46 EUR", "Price formatted correctly");
    });

    QUnit.test("Should return empty string for null price", function(assert) {
        // Arrange & Act
        var sResult = formatter.formatPrice(null);

        // Assert
        assert.strictEqual(sResult, "", "Empty string for null");
    });

    QUnit.test("Should format status text", function(assert) {
        // Arrange
        var sStatus = "A";

        // Act
        var sResult = formatter.formatStatus(sStatus);

        // Assert
        assert.strictEqual(sResult, "Approved", "Status formatted correctly");
    });

    QUnit.test("Should calculate total", function(assert) {
        // Arrange
        var iQuantity = 5;
        var fPrice = 10.5;

        // Act
        var fTotal = formatter.calculateTotal(iQuantity, fPrice);

        // Assert
        assert.strictEqual(fTotal, 52.5, "Total calculated correctly");
    });
});

Async Tests

QUnit.test("Should load data asynchronously", function(assert) {
    // Indicate async test
    var done = assert.async();

    // Arrange
    var oModel = new JSONModel();

    // Act
    oModel.loadData("test/data/products.json");

    // Assert after data loaded
    oModel.attachRequestCompleted(function() {
        var aProducts = oModel.getProperty("/products");
        assert.ok(aProducts.length > 0, "Data loaded successfully");
        done(); // Mark test complete
    });
});

Testing Controllers

sap.ui.define([
    "com/mycompany/myapp/controller/Main.controller",
    "sap/ui/thirdparty/sinon",
    "sap/ui/thirdparty/sinon-qunit"
], function(MainController) {
    "use strict";

    QUnit.module("Main Controller", {
        beforeEach: function() {
            this.oController = new MainController();
        },
        afterEach: function() {
            this.oController.destroy();
        }
    });

    QUnit.test("Should initialize correctly", function(assert) {
        // Arrange - spy on method
        var oSpy = sinon.spy(this.oController, "_loadData");

        // Act
        this.oController.onInit();

        // Assert
        assert.ok(oSpy.calledOnce, "Load data called on init");
    });
});

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: qunit)


OPA5 Testing

One Page Acceptance testing for integration tests.

Setup

test/integration/opaTests.qunit.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Integration Tests</title>

    <script
        id="sap-ui-bootstrap"
        src="../../resources/sap-ui-core.js"
        data-sap-ui-theme="sap_horizon"
        data-sap-ui-resourceroots='{
            "com.mycompany.myapp": "../../"
        }'
        data-sap-ui-async="true">
    </script>

    <link rel="stylesheet" type="text/css" href="../../resources/sap/ui/thirdparty/qunit-2.css">
    <script src="../../resources/sap/ui/thirdparty/qunit-2.js"></script>
    <script src="../../resources/sap/ui/qunit/qunit-junit.js"></script>

    <script src="opaTests.qunit.js"></script>
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>
</body>
</html>

test/integration/opaTests.qunit.js:

QUnit.config.autostart = false;

sap.ui.require([
    "sap/ui/test/Opa5",
    "com/mycompany/myapp/test/integration/arrangements/Startup",
    "com/mycompany/myapp/test/integration/WorklistJourney"
], function(Opa5, Startup) {
    "use strict";

    Opa5.extendConfig({
        arrangements: new Startup(),
        viewNamespace: "com.mycompany.myapp.view.",
        autoWait: true
    });

    QUnit.start();
});

Page Objects

test/integration/pages/Worklist.js:

sap.ui.define([
    "sap/ui/test/Opa5",
    "sap/ui/test/actions/Press",
    "sap/ui/test/actions/EnterText",
    "sap/ui/test/matchers/AggregationLengthEquals",
    "sap/ui/test/matchers/PropertyStrictEquals"
], function(Opa5, Press, EnterText, AggregationLengthEquals, PropertyStrictEquals) {
    "use strict";

    var sViewName = "Worklist";

    Opa5.createPageObjects({
        onTheWorklistPage: {
            actions: {
                iPressOnTheFirstListItem: function() {
                    return this.waitFor({
                        id: "table",
                        viewName: sViewName,
                        actions: new Press(),
                        errorMessage: "The table is not visible"
                    });
                },

                iEnterSearchTerm: function(sSearchTerm) {
                    return this.waitFor({
                        id: "searchField",
                        viewName: sViewName,
                        actions: new EnterText({ text: sSearchTerm }),
                        errorMessage: "Search field not found"
                    });
                },

                iPressTheAddButton: function() {
                    return this.waitFor({
                        id: "addButton",
                        viewName: sViewName,
                        actions: new Press(),
                        errorMessage: "Add button not found"
                    });
                }
            },

            assertions: {
                theTableShouldHaveAllEntries: function() {
                    return this.waitFor({
                        id: "table",
                        viewName: sViewName,
                        matchers: new AggregationLengthEquals({
                            name: "items",
                            length: 10
                        }),
                        success: function() {
                            Opa5.assert.ok(true, "Table has 10 entries");
                        },
                        errorMessage: "Table does not have expected entries"
                    });
                },

                theTableShouldBeVisible: function() {
                    return this.waitFor({
                        id: "table",
                        viewName: sViewName,
                        success: function(oTable) {
                            Opa5.assert.ok(oTable.getVisible(), "Table is visible");
                        },
                        errorMessage: "Table is not visible"
                    });
                },

                iShouldSeeTheCorrectTitle: function() {
                    return this.waitFor({
                        id: "page",
                        viewName: sViewName,
                        matchers: new PropertyStrictEquals({
                            name: "title",
                            value: "Worklist"
                        }),
                        success: function() {
                            Opa5.assert.ok(true, "Page title is correct");
                        },
                        errorMessage: "Page title is incorrect"
                    });
                }
            }
        }
    });
});

Journeys (Test Scenarios)

test/integration/WorklistJourney.js:

sap.ui.define([
    "sap/ui/test/opaQunit",
    "./pages/Worklist",
    "./pages/Object"
], function(opaTest) {
    "use strict";

    QUnit.module("Worklist Journey");

    opaTest("Should see the table with all entries", function(Given, When, Then) {
        // Arrangements
        Given.iStartMyApp();

        // Actions
        // (none - just checking initial state)

        // Assertions
        Then.onTheWorklistPage.theTableShouldBeVisible();
        Then.onTheWorklistPage.theTableShouldHaveAllEntries();

        // Cleanup
        Then.iTeardownMyApp();
    });

    opaTest("Should be able to search for items", function(Given, When, Then) {
        // Arrangements
        Given.iStartMyApp();

        // Actions
        When.onTheWorklistPage.iEnterSearchTerm("Product");

        // Assertions
        Then.onTheWorklistPage.theTableShouldHaveAllEntries();

        // Cleanup
        Then.iTeardownMyApp();
    });

    opaTest("Should navigate to object page when item is pressed", function(Given, When, Then) {
        // Arrangements
        Given.iStartMyApp();

        // Actions
        When.onTheWorklistPage.iPressOnTheFirstListItem();

        // Assertions
        Then.onTheObjectPage.iShouldSeeTheObjectPage();

        // Cleanup
        Then.iTeardownMyApp();
    });
});

Startup Arrangements

test/integration/arrangements/Startup.js:

sap.ui.define([
    "sap/ui/test/Opa5"
], function(Opa5) {
    "use strict";

    return Opa5.extend("com.mycompany.myapp.test.integration.arrangements.Startup", {
        iStartMyApp: function() {
            this.iStartMyUIComponent({
                componentConfig: {
                    name: "com.mycompany.myapp",
                    async: true,
                    manifest: true
                },
                hash: "",
                autoWait: true
            });
        }
    });
});

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: opa5, integration-testing)


Mock Server

Simulate OData backend for testing.

Setup

localService/metadata.xml: Copy metadata from real service or create manually.

localService/mockdata/Products.json:

[
    {
        "ProductID": 1,
        "Name": "Product 1",
        "Price": "100.00",
        "CategoryID": 1
    },
    {
        "ProductID": 2,
        "Name": "Product 2",
        "Price": "200.00",
        "CategoryID": 2
    }
]

localService/mockserver.js:

sap.ui.define([
    "sap/ui/core/util/MockServer",
    "sap/base/util/UriParameters"
], function(MockServer, UriParameters) {
    "use strict";

    return {
        init: function() {
            // Create mock server
            var oMockServer = new MockServer({
                rootUri: "/sap/opu/odata/sap/SERVICE_SRV/"
            });

            // Configure mock server
            var sPath = sap.ui.require.toUrl("com/mycompany/myapp/localService");

            MockServer.config({
                autoRespond: true,
                autoRespondAfter: 1000 // 1 second delay
            });

            // Simulate backend
            oMockServer.simulate(sPath + "/metadata.xml", {
                sMockdataBaseUrl: sPath + "/mockdata",
                bGenerateMissingMockData: true
            });

            // Custom request handling
            var aRequests = oMockServer.getRequests();

            // Add custom response for specific request
            aRequests.push({
                method: "GET",
                path: new RegExp("Products\\?.*"),
                response: function(oXhr) {
                    oXhr.respondJSON(200, {}, JSON.stringify({
                        d: {
                            results: [
                                // Custom data
                            ]
                        }
                    }));
                    return true;
                }
            });

            oMockServer.setRequests(aRequests);

            // Start mock server
            oMockServer.start();

            return oMockServer;
        }
    };
});

test/initMockServer.js:

sap.ui.define([
    "com/mycompany/myapp/localService/mockserver"
], function(mockserver) {
    "use strict";

    // Initialize mock server
    mockserver.init();

    // Initialize application
    sap.ui.require([
        "sap/ui/core/ComponentSupport"
    ]);
});

Start with Mock Server:

<!-- In test HTML file -->
<script src="test/initMockServer.js"></script>

Conditional Mock Server (development only):

sap.ui.define([
    "sap/base/util/UriParameters"
], function(UriParameters) {
    "use strict";

    var oUriParameters = new UriParameters(window.location.href);
    var bUseMockServer = oUriParameters.get("useMockServer") === "true";

    if (bUseMockServer) {
        sap.ui.require([
            "com/mycompany/myapp/localService/mockserver"
        ], function(mockserver) {
            mockserver.init();
            initApp();
        });
    } else {
        initApp();
    }

    function initApp() {
        sap.ui.require(["sap/ui/core/ComponentSupport"]);
    }
});

Usage: index.html?useMockServer=true

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: mock-server)


Test Automation Best Practices

1. Test Structure (AAA Pattern)

QUnit.test("Test description", function(assert) {
    // Arrange - setup test data and conditions
    var oModel = new JSONModel({ value: 10 });

    // Act - execute the function being tested
    var iResult = myFunction(oModel.getProperty("/value"));

    // Assert - verify the result
    assert.strictEqual(iResult, 20, "Result is correct");
});

2. Use Descriptive Test Names

// Good
QUnit.test("Should format currency with two decimal places", function(assert) {});
QUnit.test("Should return empty string when price is null", function(assert) {});

// Bad
QUnit.test("Test 1", function(assert) {});
QUnit.test("Format test", function(assert) {});

3. Test One Thing Per Test

// Good - separate tests
QUnit.test("Should add item to cart", function(assert) {});
QUnit.test("Should calculate correct total", function(assert) {});

// Bad - testing multiple things
QUnit.test("Should add item and calculate total", function(assert) {});

4. Use Spies and Stubs (Sinon.js)

QUnit.test("Should call service method", function(assert) {
    // Arrange
    var oStub = sinon.stub(oService, "getData").returns([]);

    // Act
    oController.loadData();

    // Assert
    assert.ok(oStub.calledOnce, "Service called once");

    // Cleanup
    oStub.restore();
});

5. Clean Up After Tests

QUnit.module("Test Module", {
    beforeEach: function() {
        // Setup before each test
        this.oModel = new JSONModel();
    },
    afterEach: function() {
        // Cleanup after each test
        this.oModel.destroy();
    }
});

6. Use autoWait in OPA5

Opa5.extendConfig({
    autoWait: true // Automatically waits for UI to be ready
});

7. Organize Tests by Feature

test/
├── unit/
│   ├── model/
│   │   └── formatter.js
│   ├── controller/
│   │   └── Main.controller.js
│   └── unitTests.qunit.html
├── integration/
│   ├── pages/
│   │   ├── Worklist.js
│   │   └── Object.js
│   ├── WorklistJourney.js
│   ├── NavigationJourney.js
│   └── opaTests.qunit.html
└── localService/
    ├── mockserver.js
    ├── metadata.xml
    └── mockdata/

Code Coverage

Enable code coverage in QUnit:

test/unit/unitTests.qunit.html:

<script src="../../resources/sap/ui/qunit/qunit-coverage.js"></script>

View Coverage Report:

  1. Run tests in browser
  2. Click "Enable coverage" in QUnit toolbar
  3. View coverage report after tests complete

Coverage Goals:

  • Unit tests: 80%+ coverage
  • Integration tests: Cover all critical user flows

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: code-coverage)


Continuous Integration

Karma Runner

karma.conf.js:

module.exports = function(config) {
    config.set({
        frameworks: ["ui5"],
        ui5: {
            type: "application",
            configPath: "ui5.yaml",
            paths: {
                webapp: "webapp"
            }
        },
        browsers: ["ChromeHeadless"],
        reporters: ["progress", "coverage"],
        coverageReporter: {
            type: "html",
            dir: "coverage/"
        },
        singleRun: true
    });
};

package.json:

{
    "scripts": {
        "test": "karma start"
    },
    "devDependencies": {
        "karma": "^6.0.0",
        "karma-ui5": "^2.0.0",
        "karma-chrome-launcher": "^3.0.0",
        "karma-coverage": "^2.0.0"
    }
}

Run Tests:

npm test

Testing Tools

UI5 Inspector

Browser extension for debugging SAPUI5 apps:

  • View control tree
  • Inspect control properties
  • View bindings
  • Check performance

Installation: Available for Chrome and Firefox

Support Assistant

Built-in tool for quality checks:

// Enable in code
sap.ui.require(["sap/ui/support/RuleAnalyzer"], function(RuleAnalyzer) {
    RuleAnalyzer.analyze();
});

Or use keyboard: Ctrl+Alt+Shift+S

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: support-assistant)


Links to Official Documentation


Note: This document covers testing strategies and best practices for SAPUI5 applications. For specific testing scenarios and advanced techniques, refer to the official documentation links provided.

Source: SKILL.md on GitHub

No alerts1mo3 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    The sapui5 skill is a high-quality development assistant for building enterprise applications with the SAPUI5 framework. It provides extensive documentation, best practice checklists, and templates for components, controllers, and views. The skill also integrates with official SAP tools like the @ui5/mcp-server for advanced features like live code linting and project scaffolding. No security risks or malicious patterns were found; the skill even includes a dedicated guide on security best practices for developers.

  • Socket1mo

    No alerts

  • Snyk1mo

    Risk: LOW · No issues

Signed by skilld at 620a19a. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 2 months ago
Other metadata
metadata
{
  "maintainer": "Eduard Jiglau",
  "maintainer_email": "hello@sap-ai-skills.com",
  "website": "https://sap-ai-skills.com",
  "version": "2.4.1",
  "last_verified": "2026-05-31",
  "framework_version": "1.148.1 latest verified, 1.120.0+ baseline",
  "documentation_source": "https://github.com/SAP-docs/sapui5",
  "documentation_files_analyzed": 1416,
  "reference_files": 15,
  "mcp_integration": true,
  "mcp_tools": 9,
  "specialized_agents": 4,
  "slash_commands": 5,
  "status": "production",
  "keywords": [
    "sapui5",
    "ui5",
    "openui5",
    "sap ui5",
    "ui5 framework",
    "ui5 application",
    "ui5 development",
    "ui5 tooling",
    "ui5 cli",
    "Component.js",
    "manifest.json",
    "xml view",
    "data binding",
    "odata v2",
    "odata v4",
    "fiori elements",
    "sap.m controls",
    "mvc pattern",
    "routing",
    "navigation",
    "qunit",
    "opa5",
    "testing",
    "mock server",
    "sap.ui.mdc",
    "mdc table",
    "typescript",
    "accessibility",
    "security",
    "performance",
    "ui5 inspector"
  ]
}

README badge

README badge for secondsky/sap-skills/sapui5