Dispatch an "oninput" event with a custom { target : { value } } data - javascript

I'm trying to use dispatchEvent on an <input> element in a unit test to trigger its "oninput" handler with a custom {target: {value: "data"}}
This guide only tells you how to trigger a CustomEvent. But I don't think that'll work as it only lets you specify a "details" property. I'm actually trying to trigger it with something like {target: {value: "data"}}
There's also InputEvent but it too seems to take the same "details" property only.
Here's my <input>:
<input
oninput={handleOnInput} // jsx
>
...
function handleOnInput(e){
const data = e.target.value; // << needs to be mocked
}
And this is my test code:
getThatInputEl().dispatchEvent(what can trigger "input" with {target: {value: "data"}} ?)
Is there a way you can dispatch an "input" event with a custom {target: value: "data"}?

When you dispatch input event on actual input element e.target is always set to the element, you can't override it - you can only pass object with additional data. To solve your problem you just have to set value of input before dispatching event or you can test event handler itself

Related

Manually triggering onChange callback in React 18+

The problem is that I'm unable to manually trigger onChange callback on input component in React. I have a custom 'file picker' which changes the input's value of new selected file path. I want to manually dispatch a 'change'/'input' event for this input.
Example case:
<input onChange={(e) => console.log(e.target.value)} />
const inputRef = /* ref of input above */
/* .. */
const newValue = 'path/test.ext';
inputRef.current.value = newValue;
// dispatch change event for inputRef.current to console log new value
I'd like to point out that I've already researched the subject. The newest solution I've could find is: https://stackoverflow.com/a/71340077/14175627
Sadly, this solution doesn't work anymore and I'm unable to find working one.

In jest/enzyme, how do you simulate a click on an element with eventListener bound by [element].addEventListener (not window.addEventListener)?

In react, when you have an element with an onClick prop, it's easy to use Enzyme's .simulate("click") method to click it. However, there's an example in my codebase where an element is referenced by React's "ref" prop, and then that element's .addEventListener is invoked to bind an event handler to it.
I've provided a code example:https://codesandbox.io/s/1z4xok048j
The key line is this:
if (this.refs.hey) {
this.refs.hey.addEventListener("click", this.handleClick);
}
In the code example, the eventHandler is not bound until componentDidUpdate is run, so if you click on the "click me to increment counter" div, the child element receives new props and its componentDidUpdate triggers. Then if you click on the Child element, its eventHandler triggers as expected. However, I can't reproduce this behavior in my Enzyme/Jest tests.
I've done the obvious .simulate("click") method from Enzyme and it does not work; when I change from using refs and the event listeners to using an onClick, .simulate("click") works as expected. However, removing the refs causes other bugs to surface and I haven't been able to figure out why, so I'd prefer to find out a way to simulate clicking the button.
The code for .simulate("click") actually looks for the onClick function and passes the params to it, there is no 'actual' click going on. You might have to mock the addEventListener functions with something like
// Set-up event listener mock
const map = {};
window.addEventListener = jest.genMockFn().mockImpl((event, callback) => {
map[event] = callback;
});
The answer is actually really simple. The general idea is to .find the node and get the underlying HTML DOM Node with .getDOMNode(). Once you have it, replace its .addEventListener like so:
const map ={};
const namedByRefComponent = component.find(".some-class-name");
const namedByRefDomNode = namedByRefComponent.getDOMNode();
namedByRefDomNode.addEventListener = jest.fn().mockImplementation((event, cb) => {
map[event] = cb;
});
after that, your DOM node's event handlers can be found in map and you can invoke them in the tests.

Setter is not triggered when object changed through ngModel

I have the following code:
set dynamicData(val) {
this.editableData.emit(val);
}
get dynamicData() {
return this.formsData;
}
If i set dynamicData value from my component, the setter is triggered.
But if i set dynamicData from input with [(ngModel)] the actual value of dynamicData is changed, but the setter is not triggered for some reason.
Here's the input:
<input type="text" name="dynamicDataSender"
*ngIf="someCondition"
[(ngModel)]="dynamicData.sender"/>
Am i missing something?
The [(ngModel)] syntax can only set a data-bound property. If you need to do something more or something different, you can write the expanded form.
<input type="text" name="dynamicDataSender" #ref
*ngIf="someCondition" [ngModel]="dynamicData.sender" (ngModelChange)="dynamicData(ref.value)"/>
The ngModel data property sets the element's value property and the ngModelChange event property listens for changes to the element's value
ngModelChange will be fired on every keystroke you need to debounce value else event will be emitted for every keystroke and To debounce values you can use a Subject. A subject is both an observable and an observer. This means you can treat it as an observable and pass values to it as well.
debouncer= new Subject();
constructor() {
this. debouncer
.debounceTime(1000)
.subscribe((val) =>{
console.log(val);
this.editableData.emit(val);
});
}
set dynamicData(val) {
this.debouncer.next(value);
}
You reference [(ngModel)]="dynamicData.sender" instead of dynamicData. You should reference the object.
If dynamicData needs to be an event emitter, then you should not use it as a property bind, but instead, use an (onChange)="modelChanged($event)" handler, where you can emit the new values to the dynamicData. ( modelChanged(value){this.dynamicData.emit(value);} ) and use some other property as ngModel.

simulating an onClick method with a parameter using Enzyme in React

I'm trying to simulate an onClick method in my unit tests using Enzyme for React. I've found many guides to simulating an onClick that takes some event e, such as:
handleClick(e) {
// Does something
}
....
<MyComponent
onClick = {handleClick}
></MyComponent>
However I want to be able to simulate my onClick which does not take the event as a parameter but takes something else instead, ie:
onClick = {() => handleClick(myParam)}
I've tried using .simulate('click', [myParam]); but it did not pass the parameter as I expected.
How would I go about simulating a click that sends a specific parameter to the handler?
according to the documentaton it states that:
.simulate(event[, mock]) => Self Simulate events
Arguments
event (String): The event name to be simulated mock (Object
[optional]): A mock event object that will be merged with the
event object passed to the handlers.
so you need to fix your code and pass an object:
.simulate('click', {myParam});
You can also take a look at the implementaion and see how it is passed to the event handler here:
simulate(event, ...args) {
const handler = this.prop(propFromEvent(event));
if (handler) {
withSetStateAllowed(() => {
// TODO(lmr): create/use synthetic events
// TODO(lmr): emulate React's event propagation
performBatchedUpdates(this, () => {
handler(...args);
});
this.root.update();
});
}
return this;
}

Dynamically added rows onchange event javascript

Im using javascript and jsp for creating rows dynamically. When value in a particular cell changes, onchange event will be fired and the message will be given.
When an onchange event is used in java script, first i tried to pass the id directly,
element1.onchange=checkInputValue(element1.id);
onchange event fired even when cell gets created. Later when i changed to
element1.onchange = function(evt){ testInputElement(this.id); };
and inside "testInputElement", the onchange event is called and the function worked fine. What is the use of this? Why we need to pass the function inside the function?
Is there any other way?
TIA
The onchange property allows you to specify a function that should be executed whenever that element changes. In your first example you are assigning the return value of checkInputValue to onchange, which the element can't execute.
What you want to do is assign a function that should be executed whenver the elemnent changes, which you correctly do in the second example.
If you don't want to pass a new function to onchange, you could instead modify checkInputValue to accept a change event. The change event contains information about where the event originated, including the elemnt.
function handleOnChange(event) {
var id = event.target.id;
// do some stuff
}
// pass a reference to the function, rather than executing it.
// when element1 changes it will call handleOnChange, and pass an
// event object
element1.onchange = handleOnChange;

Categories