ui5-community / wdi5

official UI5 end-to-end test framework for UI5 web-apps. wdi5 = Webdriver.IO + UI5 Test API
https://ui5-community.github.io/wdi5/
Apache License 2.0
100 stars 42 forks source link

sap.ui.core.CustomData not returned as expected #621

Open metzing opened 1 month ago

metzing commented 1 month ago

Describe the bug I'm writing an E2E test for an application with complex data binding, based on 3 keys (currently). I want to verify that the right cell in the TreeTable receives the right text.

To access the three keys of the cell without scraping the UI, CustomData is added in the productive code, exposing their values. Reading this works as expected in OPA5 using the check function:

// OPA5
iSeeFieldValue(specificationVersionId, attributeFieldId, memberId, expectedValue) {
    this.waitFor({
        controlType: "sap.m.ObjectStatus",
        properties: {
            text: expectedValue
        },
        check: function (controls) {
            const specVersionIdMatch = controls.some(control => control.getCustomData()?.find(item => item.getKey() === "specificationVersionId" && item.getValue() === specificationVersionId));

            const attributeFieldIdMatch = controls.some(control => control.getCustomData()?.find(item => item.getKey() === "attributeFieldId" && item.getValue() === attributeFieldId));

            const memberIdMatch = controls.some(control => control.getCustomData()?.find(item => item.getKey() === "memberId" && item.getValue() === memberId));

            return specVersionIdMatch && attributeFieldIdMatch && memberIdMatch;
        },
        errorMessage: `Can't see field value '${expectedValue}' [specificationVersionId='${specificationVersionId}', attributeFieldId='${attributeFieldId}']`,
        success: function () {
            Opa5.assert.ok(true, `Saw field value: ${expectedValue} [specificationVersionId='${specificationVersionId}', attributeFieldId='${attributeFieldId}']`);
        }
    });
}  

Now I'm trying to achieve a similar verification in WDI5 as a higher-level smoke test, but the CustomData controls don't get initialised:

// WDI5
async iSeeCellValue(specificationVersionId, attributeFieldId, memberId, value) {
    const objectStatuses = await browser.allControls({
        forceSelect: true,
        selector: {
            controlType: "sap.m.ObjectStatus",
            properties: {
                text: value
            }
        }
    });
    expect(objectStatuses.length).toBeGreaterThan(0);
    const matching = await Promise.all(objectStatuses.map(async objectStatus => {
        // Here I receive 3 elements of type WDI5Control, but they are not initialised (isInitialised() === false)
        const customData = await objectStatus.getCustomData();

        const specVersionIdMatch = customData.some(item => item.getKey() === "specificationVersionId" && item.getValue() === specificationVersionId);
        const attributeFieldIdMatch = customData.some(item => item.getKey() === "attributeFieldId" && item.getValue() === attributeFieldId);
        const memberIdMatch = customData.some(item => item.getKey() === "memberId" && item.getValue() === memberId);
        return specVersionIdMatch && attributeFieldIdMatch && memberIdMatch;
    }));
    expect(matching.some(self => self)).toBeTruthy();
}

Expected behavior When I receive the result of await control.getCustomData() I expect that I can interact with the custom data objects.

Logs/Console Output

[wdi5] call of function allControls() returned: [{"aProtoFunctions":["getTitle","setTitle","getText","setText","getActive","setActive","getState","setState","getInverted","setInverted","getIcon","setIcon","getIconDensityAware","setIconDensityAware","getTextDirection","setTextDirection","getEmptyIndicatorMode","setEmptyIndicatorMode","getStateAnnouncementText","setStateAnnouncementText","getAriaDescribedBy","addAriaDescribedBy","removeAriaDescribedBy","removeAllAriaDescribedBy","getAriaLabelledBy","addAriaLabelledBy","removeAriaLabelledBy","removeAllAriaLabelledBy","attachPress","detachPress","firePress","getMetadata","exit","ontap","onsapenter","onsapspace","ontouchstart","getAccessibilityInfo","getBlocked","setBlocked","getBusy","setBusy","getBusyIndicatorDelay","setBusyIndicatorDelay","getBusyIndicatorSize","setBusyIndicatorSize","getVisible","setVisible","getFieldGroupIds","setFieldGroupIds","attachValidateFieldGroup","detachValidateFieldGroup","fireValidateFieldGroup","clone","addStyleClass","removeStyleClass","toggleStyleClass","hasStyleClass","isActive","invalidate","rerender","getDomRef","allowTextSelection","attachBrowserEvent","detachBrowserEvent","placeAt","onselectstart","getIdForLabel","destroy","isBusy","getControlsByFieldGroupId","checkFieldGroupIds","triggerValidateFieldGroup","exec","getTooltip","setTooltip","destroyTooltip","getCustomData","addCustomData","insertCustomData","removeCustomData","removeAllCustomData","indexOfCustomData","destroyCustomData","getLayoutData","setLayoutData","destroyLayoutData","getDependents","addDependent","insertDependent","removeDependent","removeAllDependents","indexOfDependent","destroyDependents","getDragDropConfig","addDragDropConfig","insertDragDropConfig","removeDragDropConfig","removeAllDragDropConfig","indexOfDragDropConfig","destroyDragDropConfig","register","deregister","getInterface","toString","prop","setProperty","getUIArea","addDelegate","removeDelegate","addEventDelegate","removeEventDelegate","getFocusDomRef","isFocusable","focus","getFocusInfo","applyFocusInfo","getTooltip_AsString","getTooltip_Text","data","findElements","bindElement","unbindElement","getElementBinding","getDomRefForSetting","attachValidationSuccess","detachValidationSuccess","fireValidationSuccess","attachValidationError","detachValidationError","fireValidationError","attachParseError","detachParseError","fireParseError","attachFormatError","detachFormatError","fireFormatError","attachModelContextChange","detachModelContextChange","fireModelContextChange","applySettings","getId","getProperty","validateProperty","isPropertyInitial","resetProperty","getOriginInfo","setAssociation","getAssociation","addAssociation","removeAssociation","removeAllAssociation","validateAggregation","setAggregation","indexOfAggregation","insertAggregation","addAggregation","removeAggregation","removeAllAggregation","destroyAggregation","isInvalidateSuppressed","setParent","getParent","isBinding","extractBindingInfo","getBindingInfo","bindObject","unbindObject","bindContext","unbindContext","bindProperty","unbindProperty","updateProperty","updateModelProperty","bindAggregation","unbindAggregation","updateAggregation","refreshAggregation","propagateMessages","isTreeBinding","updateBindings","isBound","getObjectBinding","getEventingParent","getBinding","getBindingPath","setBindingContext","setElementBindingContext","updateBindingContext","getBindingContext","setModel","addPropagationListener","removePropagationListener","getPropagationListeners","propagateProperties","getModel","getOwnModels","hasModel","findAggregatedObjects","onOwnerDeactivation","onOwnerActivation","isDestroyStarted","isDestroyed","attachEvent","attachEventOnce","detachEvent","hasListeners","isA","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","valueOf","toLocaleString"],"domElement":{"element-6066-11e4-a52e-4f735466cecf":"f.F41CD2FE2BDB9953603820D7EAF46195.d.3D1B505DE7FEFBE9B5DED3C1B0966F2B.e.5642"},"id":"__status2-__clone167"},{"aProtoFunctions":["getTitle","setTitle","getText","setText","getActive","setActive","getState","setState","getInverted","setInverted","getIcon","setIcon","getIconDensityAware","setIconDensityAware","getTextDirection","setTextDirection","getEmptyIndicatorMode","setEmptyIndicatorMode","getStateAnnouncementText","setStateAnnouncementText","getAriaDescribedBy","addAriaDescribedBy","removeAriaDescribedBy","removeAllAriaDescribedBy","getAriaLabelledBy","addAriaLabelledBy","removeAriaLabelledBy","removeAllAriaLabelledBy","attachPress","detachPress","firePress","getMetadata","exit","ontap","onsapenter","onsapspace","ontouchstart","getAccessibilityInfo","getBlocked","setBlocked","getBusy","setBusy","getBusyIndicatorDelay","setBusyIndicatorDelay","getBusyIndicatorSize","setBusyIndicatorSize","getVisible","setVisible","getFieldGroupIds","setFieldGroupIds","attachValidateFieldGroup","detachValidateFieldGroup","fireValidateFieldGroup","clone","addStyleClass","removeStyleClass","toggleStyleClass","hasStyleClass","isActive","invalidate","rerender","getDomRef","allowTextSelection","attachBrowserEvent","detachBrowserEvent","placeAt","onselectstart","getIdForLabel","destroy","isBusy","getControlsByFieldGroupId","checkFieldGroupIds","triggerValidateFieldGroup","exec","getTooltip","setTooltip","destroyTooltip","getCustomData","addCustomData","insertCustomData","removeCustomData","removeAllCustomData","indexOfCustomData","destroyCustomData","getLayoutData","setLayoutData","destroyLayoutData","getDependents","addDependent","insertDependent","removeDependent","removeAllDependents","indexOfDependent","destroyDependents","getDragDropConfig","addDragDropConfig","insertDragDropConfig","removeDragDropConfig","removeAllDragDropConfig","indexOfDragDropConfig","destroyDragDropConfig","register","deregister","getInterface","toString","prop","setProperty","getUIArea","addDelegate","removeDelegate","addEventDelegate","removeEventDelegate","getFocusDomRef","isFocusable","focus","getFocusInfo","applyFocusInfo","getTooltip_AsString","getTooltip_Text","data","findElements","bindElement","unbindElement","getElementBinding","getDomRefForSetting","attachValidationSuccess","detachValidationSuccess","fireValidationSuccess","attachValidationError","detachValidationError","fireValidationError","attachParseError","detachParseError","fireParseError","attachFormatError","detachFormatError","fireFormatError","attachModelContextChange","detachModelContextChange","fireModelContextChange","applySettings","getId","getProperty","validateProperty","isPropertyInitial","resetProperty","getOriginInfo","setAssociation","getAssociation","addAssociation","removeAssociation","removeAllAssociation","validateAggregation","setAggregation","indexOfAggregation","insertAggregation","addAggregation","removeAggregation","removeAllAggregation","destroyAggregation","isInvalidateSuppressed","setParent","getParent","isBinding","extractBindingInfo","getBindingInfo","bindObject","unbindObject","bindContext","unbindContext","bindProperty","unbindProperty","updateProperty","updateModelProperty","bindAggregation","unbindAggregation","updateAggregation","refreshAggregation","propagateMessages","isTreeBinding","updateBindings","isBound","getObjectBinding","getEventingParent","getBinding","getBindingPath","setBindingContext","setElementBindingContext","updateBindingContext","getBindingContext","setModel","addPropagationListener","removePropagationListener","getPropagationListeners","propagateProperties","getModel","getOwnModels","hasModel","findAggregatedObjects","onOwnerDeactivation","onOwnerActivation","isDestroyStarted","isDestroyed","attachEvent","attachEventOnce","detachEvent","hasListeners","isA","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","valueOf","toLocaleString"],"domElement":{"element-6066-11e4-a52e-4f735466cecf":"f.F41CD2FE2BDB9953603820D7EAF46195.d.3D1B505DE7FEFBE9B5DED3C1B0966F2B.e.5645"},"id":"__status3-__clone168"}]
Logger.js:22
[wdi5] call of function getCustomData returned: [{"id":"__data59-__clone168"},{"id":"__data60-__clone168"},{"id":"__data61-__clone168"}]
Logger.js:22
[wdi5] creating internal control with id __data60-__clone168
Logger.js:22
[wdi5] creating internal control with id __data61-__clone168
Logger.js:22
[wdi5] creating internal control with id __data59-__clone168
Logger.js:22
[wdi5] call of function getCustomData returned: [{"id":"__data56-__clone167"},{"id":"__data57-__clone167"},{"id":"__data58-__clone167"}]
Logger.js:22
[wdi5] creating internal control with id __data57-__clone167
Logger.js:22
[wdi5] creating internal control with id __data58-__clone167
Logger.js:22
[wdi5] creating internal control with id __data56-__clone167
Logger.js:22
[wdi5] call of _getControl() failed because of: Error: No DOM element found using the control selector {"id":"__data60-__clone168"}
Logger.js:22
[wdi5] error retrieving control: __data60-__clone168
Logger.js:22
[wdi5] _asControl() needed 464.6518330000108 for __data60-__clone168
Logger.js:22
[wdi5] call of _getControl() failed because of: Error: No DOM element found using the control selector {"id":"__data61-__clone168"}
Logger.js:22
[wdi5] error retrieving control: __data61-__clone168
Logger.js:22
[wdi5] _asControl() needed 1087.4870410000149 for __data61-__clone168
Logger.js:22
[wdi5] call of _getControl() failed because of: Error: No DOM element found using the control selector {"id":"__data59-__clone168"}
Logger.js:22
[wdi5] error retrieving control: __data59-__clone168
Logger.js:22
[wdi5] _asControl() needed 1528.7512080000015 for __data59-__clone168
Logger.js:22
[wdi5] call of _getControl() failed because of: Error: No DOM element found using the control selector {"id":"__data57-__clone167"}
Logger.js:22
[wdi5] error retrieving control: __data57-__clone167
Logger.js:22
[wdi5] _asControl() needed 1975.074500000017 for __data57-__clone167
Logger.js:22
[wdi5] call of _getControl() failed because of: Error: No DOM element found using the control selector {"id":"__data58-__clone167"}
Logger.js:22
[wdi5] error retrieving control: __data58-__clone167
Logger.js:22
[wdi5] _asControl() needed 2414.174541000015 for __data58-__clone167
Logger.js:22
[wdi5] call of _getControl() failed because of: Error: No DOM element found using the control selector {"id":"__data56-__clone167"}
Logger.js:22
[wdi5] error retrieving control: __data56-__clone167
Logger.js:22
[wdi5] _asControl() needed 2857.3215830000117 for __data56-__clone167
Logger.js:22
Saved screenshot for failed test case as {TEST_FAILED}_SPEC={BasicValidations.spec.js}_TEST={4._Validate_results_in_table}.png
wdi5.common.conf.js:155
[0-0] TypeError in "Compare Specifications - Basic Validations.4. Validate results in table"
TypeError: item.getKey is not a function
    at /Users/I565124/Documents/GitHub/epd-plmcore/specmgmt/app/ui-comparespecifications/webapp/test/wdi5/pages/CompareSpecifications.page.js:418:73
    at Array.some (<anonymous>)
    at /Users/I565124/Documents/GitHub/epd-plmcore/specmgmt/app/ui-comparespecifications/webapp/test/wdi5/pages/CompareSpecifications.page.js:418:55
    at async Promise.all (index 1)
    at async Object.iSeeCellValue (/Users/I565124/Documents/GitHub/epd-plmcore/specmgmt/app/ui-comparespecifications/webapp/test/wdi5/pages/CompareSpecifications.page.js:415:30)
    at async Context.<anonymous> (/Users/I565124/Documents/GitHub/epd-plmcore/specmgmt/app/ui-comparespecifications/webapp/test/wdi5/specs/BasicValidations.spec.js:93:17)

Screenshots image

Runtime Env (please complete the following information):

metzing commented 1 month ago

I was able to come up with a workaround: you can set the writeToDom property of the CustomData to true and access its value using control.$().getAttribute() (https://webdriver.io/docs/api/element/getAttribute).

github-actions[bot] commented 1 week ago

hey 👋 - silence for 30 days 🤐 ... anybody? 😀