From fd4aff1e2cc3e691a82e61c7e550fb088ee47d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Sk=C3=B3rka?= Date: Fri, 11 Oct 2019 15:30:46 +0200 Subject: [PATCH] Add element property (#2189) Added W3C Webdriver related element property commands - "getElementProperty" and "elementIdProperty" protocol action. --- .../element-commands/getElementProperty.js | 35 +++++++++++++++++++ lib/api/protocol.js | 18 ++++++++++ lib/transport/jsonwire/actions.js | 4 +++ test/lib/nocks.js | 18 ++++++++++ .../api/commands/testGetElementProperty.js | 32 +++++++++++++++++ test/src/api/protocol/testElementCommands.js | 22 ++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 lib/api/element-commands/getElementProperty.js create mode 100644 test/src/api/commands/testGetElementProperty.js diff --git a/lib/api/element-commands/getElementProperty.js b/lib/api/element-commands/getElementProperty.js new file mode 100644 index 0000000000..3a2a7a9ee0 --- /dev/null +++ b/lib/api/element-commands/getElementProperty.js @@ -0,0 +1,35 @@ +const BaseElementCommand = require('./_baseElementCommand.js'); + +/** + * Retrieve the value of a property for a given DOM element. Uses `elementIdProperty` protocol command. + * + * @example + * this.demoTest = function (browser) { + * browser.getElementProperty("#main ul li a.first", "href", function(result) { + * this.assert.equal(typeof result, "object"); + * this.assert.equal(result.status, 0); + * this.assert.equal(result.value, 'https://nightwatchjs.org/'); + * }); + * }; + * + * + * @method getElementProperty + * @syntax .getElementProperty(selector, property, callback) + * @param {string} selector The CSS/Xpath selector used to locate the element. + * @param {string} property The property to inspect. + * @param {function} callback Callback function which is called with the result value. + * @see elementIdProperty + * @returns {*} The value of the property + * @api protocol.elementstate + */ +class GetElementProperty extends BaseElementCommand { + get extraArgsCount() { + return 1; + } + + get elementProtocolAction() { + return 'getElementProperty'; + } +} + +module.exports = GetElementProperty; diff --git a/lib/api/protocol.js b/lib/api/protocol.js index c12bc47bac..38432c8ed4 100644 --- a/lib/api/protocol.js +++ b/lib/api/protocol.js @@ -1145,6 +1145,24 @@ module.exports = class ProtocolActions { return this.TransportActions.getElementCSSValue(webElementId, cssPropertyName, callback); }, + /** + * Retrieve the computed value of the given property of the given element. + * + * The property to query should be specified using the CSS property name, not the JavaScript property name (e.g. background-color instead of backgroundColor). + * + * @link /#get-element-property + * @param {string} webElementId The [Web Element ID](https://www.w3.org/TR/webdriver1/#dfn-web-elements) of the element to route the command to. + * @param {string} propertyName + * @param {function} callback Callback function which is called with the result value. + * @api protocol.elementinternal + * @internal + */ + elementIdProperty(webElementId, propertyName, callback) { + ProtocolActions.validateElementId(webElementId, 'elementIdProperty'); + + return this.TransportActions.getElementProperty(webElementId, propertyName, callback); + }, + /** * Scrolls into view a submittable element excluding buttons or editable element, and then attempts to clear its value, reset the checked state, or text content. * diff --git a/lib/transport/jsonwire/actions.js b/lib/transport/jsonwire/actions.js index e7de688a6e..fcc120af6a 100644 --- a/lib/transport/jsonwire/actions.js +++ b/lib/transport/jsonwire/actions.js @@ -252,6 +252,10 @@ module.exports = { return `/element/${id}/css/${cssPropertyName}`; }, + getElementProperty(id, propertyName) { + return `/element/${id}/property/${propertyName}`; + }, + getElementTagName(id) { return `/element/${id}/name`; }, diff --git a/test/lib/nocks.js b/test/lib/nocks.js index 58f12e39b6..41bfcd6c07 100644 --- a/test/lib/nocks.js +++ b/test/lib/nocks.js @@ -137,6 +137,24 @@ module.exports = { return this; }, + property(value, times) { + var mock = nock('http://localhost:10195') + .get('/wd/hub/session/1352110219202/element/0/property/display'); + + if (times) { + mock.times(times); + } + + mock.reply(200, { + status: 0, + sessionId: '1352110219202', + value: value, + state: 'success' + }); + + return this; + }, + enabled(times) { var mock = nock('http://localhost:10195') .get('/wd/hub/session/1352110219202/element/0/enabled'); diff --git a/test/src/api/commands/testGetElementProperty.js b/test/src/api/commands/testGetElementProperty.js new file mode 100644 index 0000000000..b34c8a6b98 --- /dev/null +++ b/test/src/api/commands/testGetElementProperty.js @@ -0,0 +1,32 @@ +const assert = require('assert'); +const MockServer = require('../../../lib/mockserver.js'); +const CommandGlobals = require('../../../lib/globals/commands.js'); + +describe('getElementProperty', function() { + before(function(done) { + CommandGlobals.beforeEach.call(this, done); + }); + + after(function(done) { + CommandGlobals.afterEach.call(this, done); + }); + + it('client.getElementProperty()', function(done) { + MockServer.addMock({ + url : '/wd/hub/session/1352110219202/element/0/property/display', + method:'GET', + response : JSON.stringify({ + sessionId: '1352110219202', + status:0, + value : 'block' + }) + }); + + this.client.api.getElementProperty('#weblogin', 'display', function callback(result) { + assert.strictEqual(result.value, 'block'); + }); + + this.client.start(done); + }); + +}); diff --git a/test/src/api/protocol/testElementCommands.js b/test/src/api/protocol/testElementCommands.js index 202fd172d9..c7aa4d887b 100644 --- a/test/src/api/protocol/testElementCommands.js +++ b/test/src/api/protocol/testElementCommands.js @@ -243,6 +243,28 @@ describe('element actions', function () { }).then(result => assert.strictEqual(result, true)); }); + it('testElementIdProperty', function () { + return Globals.protocolTest.call(this, { + assertion: function (opts) { + assert.equal(opts.method, 'GET'); + assert.equal(opts.path, '/session/1352110219202/element/TEST_ELEMENT/property/test_property'); + }, + commandName: 'elementIdProperty', + args: ['TEST_ELEMENT', 'test_property'] + }); + }); + + it('testElementIdProperty invalid element ID', function () { + return Globals.protocolTest.call(this, { + commandName: 'elementIdProperty', + args: [false, 'test_property'] + }).catch(err => { + assert.equal(err.message, 'First argument passed to .elementIdProperty() should be a web element ID string. Received boolean.'); + + return true; + }).then(result => assert.strictEqual(result, true)); + }); + it('testElementIdDisplayed', function () { return Globals.protocolTest.call(this, { assertion: function (opts) {