diff --git a/docs/webapi/rightClick.mustache b/docs/webapi/rightClick.mustache index 2595b4863..7fb0e8838 100644 --- a/docs/webapi/rightClick.mustache +++ b/docs/webapi/rightClick.mustache @@ -1,3 +1,13 @@ -Performs right click on an element matched by CSS or XPath. +Performs right click on a clickable element matched by semantic locator, CSS or XPath. -@param locator element located by CSS|XPath|strict locator. \ No newline at end of file +```js +// right click element with id el +I.rightClick('#el'); +// right click link or button with text "Click me" +I.rightClick('Click me'); +// right click button with text "Click me" inside .context +I.rightClick('Click me', '.context'); +``` + +@param locator clickable element located by CSS|XPath|strict locator. +@param context (optional) element located by CSS|XPath|strict locator. diff --git a/lib/helper/Nightmare.js b/lib/helper/Nightmare.js index 4d87dfd9f..428c5e728 100644 --- a/lib/helper/Nightmare.js +++ b/lib/helper/Nightmare.js @@ -604,6 +604,18 @@ class Nightmare extends Helper { .wait(this.options.waitForAction); } + + /** + * {{> ../webapi/rightClick }} + */ + async rightClick(locator, context = null) { + const el = await findClickable.call(this, locator, context); + assertElementExists(el, locator, 'Clickable'); + return this.browser.evaluate(el => window.codeceptjs.rightClickEl(el), el) + .wait(this.options.waitForAction); + } + + /** * {{> ../webapi/moveCursorTo }} */ diff --git a/lib/helper/Protractor.js b/lib/helper/Protractor.js index cdadaa90e..97cf602af 100644 --- a/lib/helper/Protractor.js +++ b/lib/helper/Protractor.js @@ -473,10 +473,13 @@ class Protractor extends Helper { if (locator === undefined) { return this.browser.actions().click(Button.RIGHT).perform(); } - - const els = await this._locate(locator, true); - assertElementExists(els); - const el = els[0]; + let matcher = this.browser; + if (context) { + const els = await this._locate(context, true); + assertElementExists(els, context); + matcher = els[0]; + } + const el = await findClickable.call(this, matcher, locator); await this.browser.actions().mouseMove(el).perform(); return this.browser.actions().click(Button.RIGHT).perform(); diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js index 6db6c76d1..f82db3119 100644 --- a/lib/helper/WebDriver.js +++ b/lib/helper/WebDriver.js @@ -643,19 +643,28 @@ class WebDriver extends Helper { * * * *Appium*: supported, but in apps works as usual click */ - async rightClick(locator) { - // just press button if no selector is given - if (locator === undefined) { - return this.browser.buttonDown('right'); + async rightClick(locator, context) { + const locateFn = prepareLocateFn.call(this, context); + + const res = await findClickable.call(this, locator, locateFn); + if (context) { + assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`); + } else { + assertElementExists(res, locator, 'Clickable element'); } - const res = await this._locate(locator, true); - assertElementExists(res, locator, 'Clickable element'); - const elem = usingFirstElement(res); - const elementId = getElementId(elem); - if (this.browser.isMobile) return this.browser.touchClick(elementId); - await this.browser.moveTo(elementId); - this.browser.buttonDown('right'); + const el = usingFirstElement(res); + + await el.moveTo(); + + if (this.browser.isW3C) { + // W3C version + return this.browser.performActions([ + { type: 'pointerDown', button: 2 }, + ]); + } + // JSON Wire version + await this.browser.buttonDown(2); } /** @@ -2262,9 +2271,9 @@ function prepareLocateFn(context) { return (l) => { l = new Locator(l, 'css'); if (el) return this.browser.findElementsFromElement(el, l.type, l.value); - return this._locate(context, true).then((res) => { + return this._locate(context, true).then(async (res) => { assertElementExists(res, context, 'Context element'); - return this.browser.findElementsFromElement(el = getElementId(res[0]), l.type, l.value); + return res[0].$$(l.simplify()); }); }; } diff --git a/lib/helper/clientscripts/nightmare.js b/lib/helper/clientscripts/nightmare.js index 78cf6d057..c5ce5a0c1 100644 --- a/lib/helper/clientscripts/nightmare.js +++ b/lib/helper/clientscripts/nightmare.js @@ -118,6 +118,18 @@ if (!window.codeceptjs) { this.fetchElement(el).dispatchEvent(event); }; + + codeceptjs.rightClickEl = function (el) { + const event = new MouseEvent('contextmenu', { + bubbles: true, + cancelable: true, + view: window, + buttons: 2, + }); + + this.fetchElement(el).dispatchEvent(event); + }; + codeceptjs.checkEl = function (el) { const element = this.fetchElement(el); const event = document.createEvent('HTMLEvents'); diff --git a/test/data/app/view/form/rightclick.php b/test/data/app/view/form/rightclick.php new file mode 100644 index 000000000..beaa7c4a0 --- /dev/null +++ b/test/data/app/view/form/rightclick.php @@ -0,0 +1,24 @@ + +
+ + + + ++ + Lorem Ipsum + +
+ +