diff --git a/client-side-js/dragAndDrop.js b/client-side-js/dragAndDrop.js new file mode 100644 index 00000000..9c8da48e --- /dev/null +++ b/client-side-js/dragAndDrop.js @@ -0,0 +1,18 @@ +async function clientSide_dragAndDrop(sourceWebElem, destWebElem) { + return await browser.executeAsync( + (sourceWebElem, destWebElem, done) => { + window.bridge.waitForUI5(window.wdi5.waitForUI5Options).then(() => { + const oSourceControl = window.wdi5.getUI5CtlForWebObj(sourceWebElem) + const oDestControl = window.wdi5.getUI5CtlForWebObj(destWebElem) + window.wdi5.simulateDragDrop(oSourceControl, oDestControl) + }) + done(["success"]) + }, + sourceWebElem, + destWebElem + ) +} + +module.exports = { + clientSide_dragAndDrop +} diff --git a/client-side-js/injectUI5.js b/client-side-js/injectUI5.js index 1c9e6d5a..7492c765 100644 --- a/client-side-js/injectUI5.js +++ b/client-side-js/injectUI5.js @@ -354,6 +354,14 @@ async function clientSide_injectUI5(config, waitForUI5Timeout, browserInstance) } } + window.wdi5.simulateDragDrop = (oSourceControl, oDestinationControl, sAggregationName = "items") => { + const oDrag = new Drag() + oDrag.executeOn(oSourceControl) + const oDrop = new Drop({ + aggregationName: sAggregationName + }) + oDrop.executeOn(oDestinationControl) + } window.wdi5.errorHandling = (done, error) => { window.wdi5.Log.error("[browser wdi5] ERR: ", error) done({ status: 1, message: error.toString() }) diff --git a/examples/ui5-js-app/webapp/controller/Other.controller.js b/examples/ui5-js-app/webapp/controller/Other.controller.js index 1726af5f..b015ec9c 100644 --- a/examples/ui5-js-app/webapp/controller/Other.controller.js +++ b/examples/ui5-js-app/webapp/controller/Other.controller.js @@ -1,27 +1,37 @@ sap.ui.define( - ['test/Sample/controller/BaseController', 'sap/m/MessageToast', 'sap/m/StandardListItem'], + ["test/Sample/controller/BaseController", "sap/m/MessageToast", "sap/m/StandardListItem"], function (Controller, MessageToast, StandardListItem) { - 'use strict'; + "use strict" - return Controller.extend('test.Sample.controller.Other', { + return Controller.extend("test.Sample.controller.Other", { onInit: function () {}, onItemPress(oEvent) { - this.getView().byId('idTextFieldClickResult').setText(oEvent.getParameter('listItem').data('key')); + this.getView().byId("idTextFieldClickResult").setText(oEvent.getParameter("listItem").data("key")) - MessageToast.show(oEvent.getParameter('listItem').data('key')); + MessageToast.show(oEvent.getParameter("listItem").data("key")) + }, + + onDragDrop: function (oEvent) { + const oDraggedItem = oEvent.getParameter("draggedControl") + const oDroppedItem = oEvent.getParameter("droppedControl") + const oPeopleList = this.getView().byId("PeopleList") + const iDroppedItemIndex = oPeopleList.indexOfItem(oDroppedItem) + + list.removeItem(oDraggedItem) + list.insertItem(oDraggedItem, iDroppedItemIndex) }, onAddLineItem(oEvent) { this.getView() - .byId('PeopleList') + .byId("PeopleList") .addItem( new StandardListItem({ - title: 'FirstName LastName', - type: 'Navigation' + title: "FirstName LastName", + type: "Navigation" }) - ); + ) } - }); + }) } -); +) diff --git a/examples/ui5-js-app/webapp/index.html b/examples/ui5-js-app/webapp/index.html index 673c6dcc..76830ad8 100644 --- a/examples/ui5-js-app/webapp/index.html +++ b/examples/ui5-js-app/webapp/index.html @@ -1,24 +1,29 @@ + + + + Sample UI5 Application - - - - Sample UI5 Application + - + + - - - - -
- - - \ No newline at end of file + +
+ + diff --git a/examples/ui5-js-app/webapp/test/e2e/dragAndDrop.test.js b/examples/ui5-js-app/webapp/test/e2e/dragAndDrop.test.js new file mode 100644 index 00000000..bd9f462b --- /dev/null +++ b/examples/ui5-js-app/webapp/test/e2e/dragAndDrop.test.js @@ -0,0 +1,43 @@ +const { wdi5 } = require("wdio-ui5-service") +const Other = require("./pageObjects/Other") +var dragAndDrop = require("html-dnd").codeForSelectors + +describe("list drag and drop", () => { + const listSelector = { + forceSelect: true, + selector: { + id: "PeopleList", + viewName: "test.Sample.view.Other" + } + } + + before(async () => { + await Other.open() + }) + + beforeEach(async () => { + await browser.screenshot("list-interaction-before") + }) + + afterEach(async () => { + await browser.screenshot("list-interaction-after") + }) + + it("should change the order of the list", async () => { + const elem = await browser.asControl(listSelector).getItems(2).getWebElement() + const target = await browser.asControl(listSelector).getItems(8).getWebElement() + + // wdio -> not working see https://github.com/webdriverio/webdriverio/issues/4134 + // also donw forget to comment wdi5 dragAndDrop method before testing + // #1. drag and drop to other element + // await elem.dragAndDrop(target) + + // #2. drag and drop relative from current position + // await elem.dragAndDrop({ x: 10, y: 300 }) + + const listItemsInNewOrder = await browser.asControl(listSelector).getItems(7) + const listItemTitle = await listItemsInNewOrder.getTitle() + + expect(listItemTitle).toEqual("Robert King") + }) +}) diff --git a/examples/ui5-js-app/webapp/view/Other.view.xml b/examples/ui5-js-app/webapp/view/Other.view.xml index 1592fcdf..117d7c6b 100644 --- a/examples/ui5-js-app/webapp/view/Other.view.xml +++ b/examples/ui5-js-app/webapp/view/Other.view.xml @@ -1,6 +1,7 @@ @@ -11,8 +12,15 @@ + + + diff --git a/src/lib/wdi5-control.ts b/src/lib/wdi5-control.ts index 23d7e3ef..0c9c6c38 100644 --- a/src/lib/wdi5-control.ts +++ b/src/lib/wdi5-control.ts @@ -5,6 +5,7 @@ import { clientSide_interactWithControl } from "../../client-side-js/interactWit import { clientSide_executeControlMethod } from "../../client-side-js/executeControlMethod" import { clientSide_getAggregation } from "../../client-side-js/_getAggregation" import { clientSide_fireEvent } from "../../client-side-js/fireEvent" +import { clientSide_dragAndDrop } from "../../client-side-js/dragAndDrop" import { clientSide_ui5Response, wdi5ControlMetadata, wdi5Selector } from "../types/wdi5.types" import { Logger as _Logger } from "./Logger" import { wdioApi } from "./wdioApi" @@ -267,6 +268,33 @@ export class WDI5Control { } /** + * + * @param dropTarget: WDI5 object representation of the drop target UI5 control. + * @returns + */ + async dragAndDrop(dropTarget) { + let sourceWebelement, destWebelement + + if (util.types.isProxy(this.getWebElement)) { + sourceWebelement = await Promise.resolve(this.getWebElement()) + } else { + sourceWebelement = (await this.getWebElement()) as unknown as WebdriverIO.Element + } + + if (util.types.isProxy(dropTarget)) { + destWebelement = await Promise.resolve(dropTarget.getWebElement()) + } else { + destWebelement = (await dropTarget.getWebElement()) as unknown as WebdriverIO.Element + } + + await clientSide_dragAndDrop(sourceWebelement, destWebelement) + return this + } + + /** + * used to update the wdio control reference + * this can be used to manually trigger an control reference update after a ui5 control rerendering + * this method is also used wdi5-internally to implement the extended forceSelect option * fire a named event on a UI5 control * @param {String} eventName * @param {any} oOptions