1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-25 03:20:23 +01:00
metamask-extension/test/lib/react-trigger-change.js

162 lines
5.1 KiB
JavaScript

// Trigger React's synthetic change events on input, textarea and select elements
// https://github.com/vitalyq/react-trigger-change
/******************IMPORTANT NOTE******************/
/* This file is a modification of the */
/* 'react-trigger-change' library linked above. */
/* That library breaks when 'onFocus' events are */
/* added to components under test because it */
/* dispatches focus events to ensure changes are */
/* triggered in some versions of IE. */
/* This modification removes the accomodations */
/* 'react-trigger-change' makes for IE to ensure */
/* our tests can pass in chrome and firefox. */
/**************************************************/
'use strict';
// Constants and functions are declared inside the closure.
// In this way, reactTriggerChange can be passed directly to executeScript in Selenium.
module.exports = function reactTriggerChange(node) {
var supportedInputTypes = {
color: true,
date: true,
datetime: true,
'datetime-local': true,
email: true,
month: true,
number: true,
password: true,
range: true,
search: true,
tel: true,
text: true,
time: true,
url: true,
week: true
};
var nodeName = node.nodeName.toLowerCase();
var type = node.type;
var event;
var descriptor;
var initialValue;
var initialChecked;
var initialCheckedRadio;
// Do not try to delete non-configurable properties.
// Value and checked properties on DOM elements are non-configurable in PhantomJS.
function deletePropertySafe(elem, prop) {
var desc = Object.getOwnPropertyDescriptor(elem, prop);
if (desc && desc.configurable) {
delete elem[prop];
}
}
function getCheckedRadio(radio) {
var name = radio.name;
var radios;
var i;
if (name) {
radios = document.querySelectorAll('input[type="radio"][name="' + name + '"]');
for (i = 0; i < radios.length; i += 1) {
if (radios[i].checked) {
return radios[i] !== radio ? radios[i] : null;
}
}
}
return null;
}
function preventChecking(e) {
e.preventDefault();
if (!initialChecked) {
e.target.checked = false;
}
if (initialCheckedRadio) {
initialCheckedRadio.checked = true;
}
}
if (nodeName === 'select' ||
(nodeName === 'input' && type === 'file')) {
// IE9-IE11, non-IE
// Dispatch change.
event = document.createEvent('HTMLEvents');
event.initEvent('change', true, false);
node.dispatchEvent(event);
} else if ((nodeName === 'input' && supportedInputTypes[type]) ||
nodeName === 'textarea') {
// React 16
// Cache artificial value property descriptor.
// Property doesn't exist in React <16, descriptor is undefined.
descriptor = Object.getOwnPropertyDescriptor(node, 'value');
// Update inputValueTracking cached value.
// Remove artificial value property.
// Restore initial value to trigger event with it.
initialValue = node.value;
node.value = initialValue + '#';
deletePropertySafe(node, 'value');
node.value = initialValue;
// React 0.14: IE10-IE11, non-IE
// React 15: non-IE
// React 16: IE10-IE11, non-IE
event = document.createEvent('HTMLEvents');
event.initEvent('input', true, false);
node.dispatchEvent(event);
// React 16
// Restore artificial value property descriptor.
if (descriptor) {
Object.defineProperty(node, 'value', descriptor);
}
} else if (nodeName === 'input' && type === 'checkbox') {
// Invert inputValueTracking cached value.
node.checked = !node.checked;
// Dispatch click.
// Click event inverts checked value.
event = document.createEvent('MouseEvents');
event.initEvent('click', true, true);
node.dispatchEvent(event);
} else if (nodeName === 'input' && type === 'radio') {
// Cache initial checked value.
initialChecked = node.checked;
// Find and cache initially checked radio in the group.
initialCheckedRadio = getCheckedRadio(node);
// React 16
// Cache property descriptor.
// Invert inputValueTracking cached value.
// Remove artificial checked property.
// Restore initial value, otherwise preventDefault will eventually revert the value.
descriptor = Object.getOwnPropertyDescriptor(node, 'checked');
node.checked = !initialChecked;
deletePropertySafe(node, 'checked');
node.checked = initialChecked;
// Prevent toggling during event capturing phase.
// Set checked value to false if initialChecked is false,
// otherwise next listeners will see true.
// Restore initially checked radio in the group.
node.addEventListener('click', preventChecking, true);
// Dispatch click.
// Click event inverts checked value.
event = document.createEvent('MouseEvents');
event.initEvent('click', true, true);
node.dispatchEvent(event);
// Remove listener to stop further change prevention.
node.removeEventListener('click', preventChecking, true);
// React 16
// Restore artificial checked property descriptor.
if (descriptor) {
Object.defineProperty(node, 'checked', descriptor);
}
}
};