diff --git a/lib/elements/checkBox.js b/lib/elements/checkBox.js index 9a0c17070..d6c257bef 100644 --- a/lib/elements/checkBox.js +++ b/lib/elements/checkBox.js @@ -19,6 +19,7 @@ class CheckBox extends Element { return result.value; } async check() { + await this.registerNativeValueSetter(); const navigationOptions = setNavigationOptions({}); await doActionAwaitingNavigation(navigationOptions, async () => { const objectId = this.get(); @@ -49,7 +50,7 @@ class CheckBox extends Element { } function setChecked(value) { - this.checked = value; + this.setNativeValue(this, 'checked', value); ['change', 'input', 'click'].forEach((ev) => { let event = new Event(ev, { bubbles: true }); try { diff --git a/lib/elements/element.js b/lib/elements/element.js index b54aa4f27..2c3931e6b 100644 --- a/lib/elements/element.js +++ b/lib/elements/element.js @@ -1,8 +1,8 @@ -const { setNativeValue } = require('./elementHelper'); /** * Abstract Element present on the web page. Extra methods are available based on the element type. * @see {ElementWrapper} for methods available */ + class Element { constructor(objectId, description, runtimeHandler) { this.objectId = objectId; @@ -126,13 +126,35 @@ class Element { } async registerNativeValueSetter() { - return await this.runtimeHandler.runtimeEvaluate( - `if (typeof globalThis.setNativeValue === 'undefined') { - globalThis.setNativeValue = ` + - setNativeValue.toString() + - ` - }`, - ); + function defineNativeSetterProperty() { + const setNativeValue = function (element, propName, value) { + const { set: valueSetter } = Object.getOwnPropertyDescriptor(element, propName) || {}; + const prototype = Object.getPrototypeOf(element); + const { set: prototypeValueSetter } = + Object.getOwnPropertyDescriptor(prototype, propName) || {}; + + if (prototypeValueSetter && valueSetter !== prototypeValueSetter) { + prototypeValueSetter.call(element, value); + } else if (valueSetter) { + valueSetter.call(element, value); + } else { + throw new Error('The given element does not have a value setter'); + } + }; + + if (typeof this.setNativeValue === 'undefined') { + Object.defineProperty(this.constructor.prototype, 'setNativeValue', { + configurable: true, + enumerable: false, + value: setNativeValue, + }); + } + } + + await this.runtimeHandler.runtimeCallFunctionOn(defineNativeSetterProperty, null, { + objectId: this.get(), + }); } } + module.exports = Element; diff --git a/lib/elements/elementHelper.js b/lib/elements/elementHelper.js index cb69c4f1e..e86218e05 100644 --- a/lib/elements/elementHelper.js +++ b/lib/elements/elementHelper.js @@ -17,17 +17,4 @@ const highlightElement = async (element) => { } }; -const setNativeValue = function (element, propName, value) { - const { set: valueSetter } = Object.getOwnPropertyDescriptor(element, propName) || {}; - const prototype = Object.getPrototypeOf(element); - const { set: prototypeValueSetter } = Object.getOwnPropertyDescriptor(prototype, propName) || {}; - if (prototypeValueSetter && valueSetter !== prototypeValueSetter) { - prototypeValueSetter.call(element, value); - } else if (valueSetter) { - valueSetter.call(element, value); - } else { - throw new Error('The given element does not have a value setter'); - } -}; - -module.exports = { highlightElement, setNativeValue }; +module.exports = { highlightElement }; diff --git a/lib/elements/radioButton.js b/lib/elements/radioButton.js index 13d83a966..d6e60cf8d 100644 --- a/lib/elements/radioButton.js +++ b/lib/elements/radioButton.js @@ -19,6 +19,7 @@ class RadioButton extends Element { return result.value; } async select() { + await this.registerNativeValueSetter(); const navigationOptions = setNavigationOptions({}); await doActionAwaitingNavigation(navigationOptions, async () => { const objectId = this.get(); @@ -49,7 +50,7 @@ class RadioButton extends Element { } function setChecked(value) { - this.checked = value; + this.setNativeValue(this, 'checked', value); ['change', 'input', 'click'].forEach((ev) => { let event = new Event(ev, { bubbles: true }); try { diff --git a/lib/elements/range.js b/lib/elements/range.js index 90b11b168..30509ee8f 100644 --- a/lib/elements/range.js +++ b/lib/elements/range.js @@ -2,7 +2,7 @@ const { setNavigationOptions } = require('../config'); const { descEvent } = require('../eventBus'); const Element = require('./element'); const { defaultConfig } = require('../config'); -const { highlightElement, setNativeValue } = require('./elementHelper'); +const { highlightElement } = require('./elementHelper'); const { doActionAwaitingNavigation } = require('../doActionAwaitingNavigation'); class Range extends Element { @@ -31,7 +31,7 @@ class Range extends Element { } function setRange(value) { - setNativeValue(this, 'value', value); + this.setNativeValue(this, 'value', value); let rangeValues = {}; rangeValues['min'] = this.min || 0; @@ -39,7 +39,7 @@ class Range extends Element { rangeValues['current'] = this.value; let selectAndDispatchEvent = function (self, value) { - setNativeValue(self, 'value', value); + self.setNativeValue(self, 'value', value); ['change', 'input'].forEach((ev) => { let event = new Event(ev, { bubbles: true }); diff --git a/test/functional-tests/specs/ElementsAPI.spec b/test/functional-tests/specs/ElementsAPI.spec index 18893e728..b5f532b09 100644 --- a/test/functional-tests/specs/ElementsAPI.spec +++ b/test/functional-tests/specs/ElementsAPI.spec @@ -25,6 +25,12 @@ Radio Button without for tags: knownIssue * Radio Button "Y" +Range +------ +* Ensure Range "Age" exists +* Select the value of Range "Age" to "51" + + File field ---------- diff --git a/test/functional-tests/specs/ElementsAPIIFrame.spec b/test/functional-tests/specs/ElementsAPIIFrame.spec index d4bc71458..eb7a8109a 100644 --- a/test/functional-tests/specs/ElementsAPIIFrame.spec +++ b/test/functional-tests/specs/ElementsAPIIFrame.spec @@ -25,6 +25,12 @@ Radio Button without for tags: knownIssue * Radio Button "Y" + +Range +------ +* Ensure Range "Age" exists +* Select the value of Range "Age" to "51" + Attach file ----------- diff --git a/test/functional-tests/specs/browserActions.spec b/test/functional-tests/specs/browserActions.spec index 0a90930db..93e0313cc 100644 --- a/test/functional-tests/specs/browserActions.spec +++ b/test/functional-tests/specs/browserActions.spec @@ -2,11 +2,11 @@ ## Switch To - * Navigate to "http://localhost:3001/" * Click "Multiple Windows" * Assert page navigated to "/windows" * Click "Click Here" +* Switch to tab with url "http://localhost:3001/windows/new" * Assert page navigated to "/windows/new" * Switch to tab with url "http://localhost:3001/windows" * Assert page navigated to "/windows" @@ -17,7 +17,6 @@ |text|Opening a new window| ## Switch to with name - * Open Tab with name "newTab" * Open Tab "http://localhost:3001/" * Switch to tab with name "newTab" @@ -36,6 +35,7 @@ * Open Tab "http://localhost:3001/dropdown" * Open Tab "http://localhost:3001/" * Close Tab +* Switch to tab with url "http://localhost:3001/dropdown" * Close Tab * Assert title to be "Document" @@ -101,7 +101,7 @@ * Set timezone "America/Jamaica" * Assert page has set timezome -## Click & Release To Element +## Click & Release To Element * Navigate to relative path "./specs/data/MouseMoveTest.html" * Press & Release To Element with element1 and "0","100" co-ordinates * Assert text "button2" exists on the page. diff --git a/test/functional-tests/specs/data/HTMLElements.html b/test/functional-tests/specs/data/HTMLElements.html index a7274cd19..9703789dc 100644 --- a/test/functional-tests/specs/data/HTMLElements.html +++ b/test/functional-tests/specs/data/HTMLElements.html @@ -51,6 +51,10 @@ +
+ + +
Some text inside a div element.

diff --git a/test/functional-tests/tests/htmlElementAPI.ts b/test/functional-tests/tests/htmlElementAPI.ts index 6bab8f43c..57bdafa12 100644 --- a/test/functional-tests/tests/htmlElementAPI.ts +++ b/test/functional-tests/tests/htmlElementAPI.ts @@ -10,6 +10,7 @@ import { dropDown, checkBox, radioButton, + range, click, write, attach, @@ -86,6 +87,19 @@ export default class HtmlElementAPI { assert.ok(await button.isSelected()); } + @Step('Ensure Range exists') + public async rangeExists(rangeName: string) { + const rangeInput = range(rangeName); + assert.ok(await rangeInput.exists()); + } + + @Step('Select the value of Range to ') + public async rangeValue(rangeName: string, rangeValue: string) { + const rangeInput = range(rangeName); + await rangeInput.select(rangeValue); + assert.equal(await rangeInput.value(), rangeValue); + } + @Step('Attach file to file field ') public async attachFile(fileName: string, FileFieldName: SearchElement) { const field = fileField(FileFieldName); diff --git a/test/unit-tests/elements/checkBox.test.js b/test/unit-tests/elements/checkBox.test.js index 4be623e79..65f367059 100644 --- a/test/unit-tests/elements/checkBox.test.js +++ b/test/unit-tests/elements/checkBox.test.js @@ -20,6 +20,9 @@ describe('CheckBox', () => { }, }; }, + async runtimeEvaluate(exp, executionContextId, opt = {}) { + return true; + }, }; beforeEach(() => { @@ -48,10 +51,21 @@ describe('CheckBox', () => { }, }, }; + + Object.defineProperty(Object.prototype, 'checked', { + configurable: true, + get: function () { + return this.checked; + }, + set: function (val) { + this.checked = val; + }, + }); }); afterEach(() => { CheckBox = rewire('../../../lib/elements/checkBox'); dispatchedEvent = null; + delete Object.prototype.checked; }); it('should be element', () => { @@ -76,6 +90,7 @@ describe('CheckBox', () => { describe('check', () => { it('should check an uncheckedd checkbox', async () => { let objectId = 28; + const checkBox = new CheckBox(objectId, 'description', runtimeHandler); expect(nodes[objectId].checked).to.be.false; diff --git a/test/unit-tests/elements/radioButton.test.js b/test/unit-tests/elements/radioButton.test.js index ec293b328..d27302541 100644 --- a/test/unit-tests/elements/radioButton.test.js +++ b/test/unit-tests/elements/radioButton.test.js @@ -20,6 +20,9 @@ describe('RadioButton', () => { }, }; }, + async runtimeEvaluate(exp, executionContextId, opt = {}) { + return true; + }, }; beforeEach(() => { RadioButton = rewire('../../../lib/elements/radioButton'); @@ -47,10 +50,20 @@ describe('RadioButton', () => { }, }, }; + Object.defineProperty(Object.prototype, 'checked', { + configurable: true, + get: function () { + return this.checked; + }, + set: function (val) { + this.checked = val; + }, + }); }); afterEach(() => { RadioButton = rewire('../../../lib/elements/radioButton'); dispatchedEvent = null; + delete Object.prototype.checked; }); it('should be element', () => {