zombie icon indicating copy to clipboard operation
zombie copied to clipboard

browser.fill is not compatible with React 15.6 controlled input components

Open Gekkio opened this issue 8 years ago • 2 comments

React 15.6 introduces some changes to input event handling, and browser.fill in zombie.js is incompatible with all React controlled inputs. The problem is that browser.fill sets the value directly using the DOM API:

// Switch focus to field, change value and emit the input event (HTML5)
field.focus();
field.value = value; // <--------- Danger! Might not be the raw DOM property
this.fire(field, 'input', false);
// Switch focus out of field, if value changed, this will emit change event
field.blur();

React 15.6 wraps the .value property in input fields using Object.defineProperty, and zombie.js ends up calling the setter defined by React, not the original DOM setter defined by jsdom. Here's the relevant closed React bug: https://github.com/facebook/react/issues/10003

While React could maybe do things differently, zombie.js is wrong here because a real browser doesn't call a custom .value property setter when you input text into a field. Zombie could use jsdom_patches.js to install some custom mechanism for private use to directly set the underlying property without invoking any possible custom property wrappers.

If we generalize a bit, Zombie.js shouldn't even use .value to read the property. With React it doesn't cause any issues, but some other framework or library could have a getter with side-effects. But to fix this main incompatibility it would be enough to handle the .value setter case.

Gekkio avatar Jun 19 '17 14:06 Gekkio

As a quick and dirty patch example, we can replace this:

field.value = value;

with this:

var descriptor = Object.getOwnPropertyDescriptor(field.constructor.prototype, 'value');
descriptor.set.call(field, value);

It works because we use the original constructor's property setter, ignoring any special stuff in the instance's property. In a proper patch this method would need to be used for all .value and .checked accesses and descriptors should probably be cached. And yes, it's unfortunately complicated and makes the code uglier :man_shrugging:

Gekkio avatar Jun 19 '17 15:06 Gekkio

Guys, this issue is fixed, we should close this.

arturog avatar Aug 08 '19 18:08 arturog