Skip to content

Commit

Permalink
Bug(range): Set range value on native element setter so that events a…
Browse files Browse the repository at this point in the history
…re triggered properly (#2370)

Signed-off-by: atulv <[email protected]>
  • Loading branch information
lethaldose committed Oct 25, 2021
1 parent dec13ae commit f33c9f4
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 8 deletions.
11 changes: 11 additions & 0 deletions lib/elements/element.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
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
Expand Down Expand Up @@ -123,5 +124,15 @@ class Element {
}
return await this._executeAndGetValue(isDraggable);
}

async registerNativeValueSetter() {
return await this.runtimeHandler.runtimeEvaluate(
`if (typeof globalThis.setNativeValue === 'undefined') {
globalThis.setNativeValue = ` +
setNativeValue.toString() +
`
}`,
);
}
}
module.exports = Element;
16 changes: 15 additions & 1 deletion lib/elements/elementHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,18 @@ const highlightElement = async (element) => {
console.warn('WARNING: Taiko cannot highlight hidden elements.');
}
};
module.exports = { highlightElement };

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 };
10 changes: 7 additions & 3 deletions lib/elements/range.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const { setNavigationOptions } = require('../config');
const { descEvent } = require('../eventBus');
const Element = require('./element');
const { defaultConfig } = require('../config');
const { highlightElement } = require('./elementHelper');
const { highlightElement, setNativeValue } = require('./elementHelper');
const { doActionAwaitingNavigation } = require('../doActionAwaitingNavigation');

class Range extends Element {
Expand Down Expand Up @@ -31,14 +31,16 @@ class Range extends Element {
}

function setRange(value) {
this.value = value;
setNativeValue(this, 'value', value);

let rangeValues = {};
rangeValues['min'] = this.min || 0;
rangeValues['max'] = this.max || 100;
rangeValues['current'] = this.value;

let selectAndDispatchEvent = function (self, value) {
self.value = value;
setNativeValue(self, 'value', value);

['change', 'input'].forEach((ev) => {
let event = new Event(ev, { bubbles: true });
try {
Expand All @@ -56,6 +58,8 @@ class Range extends Element {
selectAndDispatchEvent(this, this.value);
return rangeValues;
}

await this.registerNativeValueSetter();
const options = setNavigationOptions({});
let result;
await doActionAwaitingNavigation(options, async () => {
Expand Down
60 changes: 56 additions & 4 deletions test/unit-tests/range.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ let {
$,
} = require('../../lib/taiko');
let { createHtml, removeFile, openBrowserArgs, resetConfig } = require('./test-util');
const { assert } = require('chai');

describe('Range test', () => {
let filePath;

before(async () => {
let innerHtml =
`<script>
class ShadowButton extends HTMLElement {
constructor() {
super();
var shadow = this.attachShadow({mode: 'open'});
var button = document.createElement('input');
button.setAttribute('type', 'range');
button.setAttribute('id', 'Shadow Click');
Expand All @@ -41,7 +42,7 @@ describe('Range test', () => {
hiddenButton.setAttribute('id', 'HiddenShadowButton');
hiddenButton.setAttribute('style','display:none');
shadow.appendChild(hiddenButton);
}
}
customElements.define('shadow-button', ShadowButton);
Expand All @@ -50,14 +51,17 @@ describe('Range test', () => {
`
<div>
<p>RangeItem</p>
<input type="range" id="range-1" name="range"
<input type="range" id="range-1" name="range"
min="0" max="100" value='2'>
<label for="volume">Volume</label>
</div>
<div>
<p>RangeItem</p>
<input type="range" id="range-2" name="range" value='2'>
<label for="volume">Volume</label>
<p>Simulate Native Range Setter</p>
<input type="range" id="range-3" name="range" value='10'>
<label for="volume">Simulate Native Setter</label>
</div>
`;
filePath = createHtml(innerHtml, 'Range');
Expand Down Expand Up @@ -86,6 +90,54 @@ describe('Range test', () => {
});
});

describe('set native value', () => {
it('should set native value on element', async () => {
await evaluate(() => {
function trackValueOnElementPrototype(element) {
const valueField = 'value';
const descriptor = Object.getOwnPropertyDescriptor(
element.constructor.prototype,
valueField,
);

const { set } = descriptor;
Object.defineProperty(element.constructor.prototype, valueField, {
configurable: true,
set: function (val) {
document.nativeSetterCalled = true;
set.call(this, val);
},
});
}
function trackValueOnElement(element) {
const valueField = 'value';
const descriptor = Object.getOwnPropertyDescriptor(
element.constructor.prototype,
valueField,
);

const { get } = descriptor;
Object.defineProperty(element, valueField, {
configurable: true,
get: function () {
return get.call(this);
},
set: function () {
document.nativeSetterCalled = false;
},
});
}
trackValueOnElementPrototype(document.getElementById('range-3'));
trackValueOnElement(document.getElementById('range-3'));
});

expect(await evaluate(() => document.nativeSetterCalled)).to.be.undefined;
await range({ id: 'range-3' }).select(57);
expect(await evaluate(() => document.nativeSetterCalled)).to.be.true;
expect(await range({ id: 'range-3' }).value()).to.be.equal('57');
});
});

it('Set Range value with Integer', async () => {
await range({ id: 'range-1' }).select(10);
expect(await range({ id: 'range-1' }).value()).to.be.equal('10');
Expand Down

0 comments on commit f33c9f4

Please sign in to comment.