@testing-library/user-event
Version:
Fire events the same way the user does
128 lines (123 loc) • 4.74 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
require('../utils/click/isClickableInput.js');
require('../utils/dataTransfer/Clipboard.js');
require('../event/eventMap.js');
require('../event/behavior/click.js');
require('../event/behavior/cut.js');
require('../event/behavior/keydown.js');
require('../event/behavior/keypress.js');
require('../event/behavior/keyup.js');
require('../event/behavior/paste.js');
require('@testing-library/dom');
var selection = require('./selection.js');
var interceptor = require('./interceptor.js');
require('../utils/edit/maxLength.js');
require('../utils/edit/isEditable.js');
var isElementType = require('../utils/misc/isElementType.js');
var getWindow = require('../utils/misc/getWindow.js');
require('../utils/keyDef/readNextDescriptor.js');
require('../utils/misc/level.js');
require('../options.js');
const UIValue = Symbol('Displayed value in UI');
const InitialValue = Symbol('Initial value to compare on blur');
const TrackChanges = Symbol('Track programmatic changes for React workaround');
function valueInterceptor(v) {
const isUI = typeof v === 'object' && v[UIValue];
if (isUI) {
this[UIValue] = String(v);
startTrackValue(this);
}
return {
applyNative: !!isUI,
realArgs: sanitizeValue(this, v),
then: isUI ? undefined : ()=>trackOrSetValue(this, String(v))
};
}
function sanitizeValue(element, v) {
// Workaround for JSDOM
if (isElementType.isElementType(element, 'input', {
type: 'number'
}) && String(v) !== '' && !Number.isNaN(Number(v))) {
// Setting value to "1." results in `null` in JSDOM
return String(Number(v));
}
return String(v);
}
function prepareValueInterceptor(element) {
interceptor.prepareInterceptor(element, 'value', valueInterceptor);
}
function setUIValue(element, value) {
if (element[InitialValue] === undefined) {
element[InitialValue] = element.value;
}
element.value = {
[UIValue]: UIValue,
toString: ()=>value
};
}
function getUIValue(element) {
return element[UIValue] === undefined ? element.value : String(element[UIValue]);
}
/** Flag the IDL value as clean. This does not change the value.*/ function setUIValueClean(element) {
element[UIValue] = undefined;
}
function clearInitialValue(element) {
element[InitialValue] = undefined;
}
function getInitialValue(element) {
return element[InitialValue];
}
// When the input event happens in the browser, React executes all event handlers
// and if they change state of a controlled value, nothing happens.
// But when we trigger the event handlers in test environment with React@17,
// the changes are rolled back before the state update is applied.
// This results in a reset cursor.
// There might be a better way to work around if we figure out
// why the batched update is executed differently in our test environment.
function isReact17Element(element) {
return Object.getOwnPropertyNames(element).some((k)=>k.startsWith('__react')) && getWindow.getWindow(element).REACT_VERSION === 17;
}
function startTrackValue(element) {
if (!isReact17Element(element)) {
return;
}
element[TrackChanges] = {
previousValue: String(element.value),
tracked: []
};
}
function trackOrSetValue(element, v) {
var ref, ref1;
(ref = element[TrackChanges]) === null || ref === void 0 ? void 0 : (ref1 = ref.tracked) === null || ref1 === void 0 ? void 0 : ref1.push(v);
if (!element[TrackChanges]) {
setUIValueClean(element);
selection.setUISelection(element, {
focusOffset: v.length
});
}
}
function commitValueAfterInput(element, cursorOffset) {
var ref;
const changes = element[TrackChanges];
element[TrackChanges] = undefined;
if (!(changes === null || changes === void 0 ? void 0 : (ref = changes.tracked) === null || ref === void 0 ? void 0 : ref.length)) {
return;
}
const isJustReactStateUpdate = changes.tracked.length === 2 && changes.tracked[0] === changes.previousValue && changes.tracked[1] === element.value;
if (!isJustReactStateUpdate) {
setUIValueClean(element);
}
if (selection.hasUISelection(element)) {
selection.setUISelection(element, {
focusOffset: isJustReactStateUpdate ? cursorOffset : element.value.length
});
}
}
exports.clearInitialValue = clearInitialValue;
exports.commitValueAfterInput = commitValueAfterInput;
exports.getInitialValue = getInitialValue;
exports.getUIValue = getUIValue;
exports.prepareValueInterceptor = prepareValueInterceptor;
exports.setUIValue = setUIValue;
exports.setUIValueClean = setUIValueClean;