Testing tabaility with enzyme - reactjs

I have a simple checkbox input I want to test it when user wants to tab into the checkbox and expect something to happen.
const CheckBox = () => (
<input type="checkbox">
)
Test case:
describe("tabability", ()=> {
it("tab into the input",()=>{
const testForm = mount(
<div>
<input type="text" id="textInput" />
<CheckBox id="checkBox" />
</div>
);
const textInput = testForm.find("textInput");
textInput.simulate("keypress", {key: "Tab"});
})
})
But It seems to fail to find the text input. my textInput variable is pointing to testForm. What can I do to assigned input text to a variable and assign checkbox to a variable?

it should be
...
const textInput = testForm.find("#textInput");
...
same goes for the checkbox

Related

How to set radio button 'checked' based on value from database? - React

I have a radio button group in a component. I want to set which radio is selected based on it's value taken from the database in an Update/Edit scenario.
export default function updateRadioSelection(){
const [radioValue, setRadiovalue] = useState("");
useState(()=>{
setRadiovalue("pick"); // <-- Assume this value is taken from database, value may be either "delivery" or "pick"
}, [])
const changeSelection = (e)=>{
setRadiovalue(e.target.value);
}
return(
<div>
<input type="radio" id="delivery" name="orderType" value="delivery" required onChange={changeSelection} />
<label htmlFor="delivery">Delivery</label>
<input type="radio" id="pick" name="orderType" value="pick" onChange={changeSelection} />
<label htmlFor="pick">Pick Up</label>
</div>
)
}
To make a checkbox or radio checked you must use the checked prop for the input element, it receives a boolean value. And you can do something like this
export default function updateRadioSelection(){
const [radioValue, setRadiovalue] = useState("");
// useState will not execute any kind of callback function, for this case you need to use useEffect
useEffect(() => {
const dbResult = getRadioFromDb();
setRadiovalue(dbResult);
}, [])
const changeSelection = (e)=>{
setRadiovalue(e.target.value);
}
return(
<div>
<input type="radio" id="delivery" name="orderType" value="delivery" required onChange={changeSelection} checked={radioValue === 'delivery'} />
<label htmlFor="delivery">Delivery</label>
<input type="radio" id="pick" name="orderType" value="pick" onChange={changeSelection} checked={radioValue === 'pick'} />
<label htmlFor="pick">Pick Up</label>
</div>
)
}
You can read more about radio input in its documentation
Just a few minutes after posting this question I found the answer I was searching for. Turns out it's pretty easy.
Just add checked={radioValue === "pick"} for the Pick Up radio button & the same for other radio button by replacing "pick" with "delivery"
reference - react.tips/radio-buttons-in-reactjs

Multiple value / onChange values in a React form

I must be missing something very simple, but I can't figure out how to deal with having 2 value / onChange to pass to my component.
I tried changing the names, and that gets rid of errors and renders the app, but of course event.target.value does not work as if I change the second value to, for example to numval or something. event.target.numval doesn't recognize anything is happening.
Thank you so much in advance! And if this has been asked before I apologize, but I couldn't find it... which makes me think I'm overlooking a very simple solution.
return (
...
<PersonForm
onSubmit={addName}
value={newName}
onChange={handleName}
value={newNumber}
onChange={handleNumber}
/>
)
Here is the original code that worked fine before I tried to put the component into its own file:
return (
...
<form onSubmit={addName}>
<div>
name: <input value={newName} onChange={handleName} />
</div>
<div>
number: <input value={newNumber} onChange={handleNumber} />
</div>
<div>
<button type="submit">add</button>
</div>
</form>
your code sample is not clear but it seems you want to retrieve value from event.target object through event handler function triggered by onChange event on
an element. And you want to call event handler function available in a parent component from a child component.
You can try the following:
const App () => {
const [newNameValue, setName] = useState('');
const [newNumberValue, setNumber] = useState('');
const nameChangeHandler = (event) => {
setName(event.target.value);
};
const numberChangeHandler = (event) => {
setNumber(event.target.value);
};
const submitFormHandler = () => {
your code on form submit
};
return (
<PersonForm
submitForm={submitFormHandler}
newName={newNameValue}
handleName={nameChangeHandler}
newNumber={newNumberValue}
handleNumber={numberChangeHandler}
/>
);
}
const PersonForm (props) => {
return (
<form onSubmit={props.submitForm}>
<div>
name: <input value={props.newName} onChange={props.handleName} />
</div>
<div>
number: <input value={props.newNumber} onChange={props.handleNumber} />
</div>
<div>
<button type="submit">add</button>
</div>
</form>
);
}
onChange is a reserved attribute name which is available on few html elements
such as <input> and <select>. You should ideally not use it on other elements, like in your case custom html component <PersonForm>.
Since you're keeping form in separate component then you can trigger a function call received through attributes on props object.
You may call two different onChange event handler functions on two input elements.
I hope you got your answer, feel free to ask in case of any more doubts.
You may refer:
https://reactjs.org/docs/forms.html

How do I use "onfocus" &. "onblur" for input type date in React Functional Component?

Does anyone know how to make this code work in a React Functional Component?
onfocus="(this.type='date')" onblur="(this.type='text')"
I am trying to get placeholder text to appear prior to the user clicking on the input element. Then when clicked, the input will change to MM/DD/YYYY.
Trying to emulate something like this in my React project: https://stackoverflow.com/a/34565565/14677057
Would appreciate any help! Thank you!
Have a state variable for the type, then use it in what you render:
const Example = () => {
const [type, setType] = useState('text');
return (
<input
type={type}
onFocus={() => setType('date')}
onBlur={() => setType('text')}
/>
)
}
you can useRef for focusing. onBlur will work in camel case.
eg:
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it
const textInput = useRef(null);
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
Handling events with react elements is syntactically different from DOM elements.
events are named using camelCase, rather than lowercase.
We need to pass a JSX function, rather than a string.
`
function HandleInputField(){
const onChange=()=>{//your code}
const onFocus=()=>{//your code}
const onBlur=()=>{//your code}
return <input onChange={} onFocus={} onBlur={}/>
}
`

Child Component Making Use of Parents' Prop in ReactJS

I am creating a form Component that will have a Form component and an Input component. Something like this:
<Form>
<Input name="name" />
<Input name="email" />
</Form>
In my setup, labels are automatically get generated from the name prop. What I would like to do, though, is provide an option to not show labels. Now, I could do it on each <Input> component like this:
<Form>
<Input noLabel name="name" />
<Input noLabel name="email" />
</Form>
But what I would really like to do is add it to the <Form> component and have it automatically applied to each <Input> component. Something like this:
<Form noLabel>
<Input name="name" />
<Input name="email" />
</Form>
The way I envision it, when defining my <Input> component I could do a check if the noLabel prop is set on the <Form> component. Something like this:
export const Input = props => {
...
{!props.noLabel && <label>...}
<input.../>
...
}
But I can't figure out how to get access to the noLabel prop from the <Form> component so that I can check to see whether or not it is set.
Any ideas on how to do this?
I would choose the context approach, to overcome the problems I mentioned in my comment to Mohamed's solution, this would enable indirect nesting as well:
const FormContext = React.createContext();
const Form = ...;
Form.Context = FormContext; // or simply Form.Context = React.createContext();
export default ({noLabel, ...props}) => <FormContext.Provider value={{noLabel}}/>;
and then your input component will consume it either like this:
const Input = props => {
const {noLabel} = useContext(Form.Context);
return (... < your no label logic here > ...);
}
or like this:
const Input = ....;
export default props => () => {
const {noLabel} = useContext(Form.Context);
return <Input noLabel={noLabel}/>
}
In your Form component, you can use React.Children and React.cloneElement to pass the noLabel prop to the input components, something like this :
const children = React.Children.map(this.props.children, child =>
React.cloneElement(child, { noLabel: this.props.noLabel })
);
return (<form>{children}</form>);
One way to do it is manipulating form's children. Mapping over each one and inject noLabel prop. You still will need to check inside Input for a noLabel prop but it's definitely less work
const Form = ({children, noLabel}) =>{
return React.children.forEach(_, child =>{
return React.cloneElement(child, { noLabel })
})
}

how react programmatically focus input

I'm trying to implement a very simple use case, a UI feature, where:
There is a label with some content in it
If clicked, a text input replaces it with the content of label available
User can edit the content
When enter is pressed, the input hides and label is back with updated content
I could get finally all correct (in fact with a MongoBD backend, redux, etc.), and the only thing I couldn't ever do (paying a complete day in googling and reading S.O.F similar posts) was this:
When my text input appears, I can't transfer focus to it! First I tired this way:
<div className={((this.state.toggleWordEdit) ? '' : 'hidden')}>
<input id={this.props.word._id} className="form-control"
ref="updateTheWord"
defaultValue={this.state.word}
onChange={this.handleChange}
onKeyPress={this.handleSubmit}
autoFocus={this.state.toggleWordEdit}/></div>
<div className={((this.state.toggleWordEdit) ? 'hidden' : '')}>
<h3 onClick={this.updateWord}>
{this.state.word}</h3>
</div>
but autoFocus sure didn't work (I "guess" because the form is rendered, but in hidden state, making autoFocus useless).
Next I tried in my this.updateWor, many of suggestions I found on google and S.O.F.:
this.refs.updateTheWord.focus();
which together with similar suggestions all didn't work. Also I tried to fool React just to see if at all I can do something! I used real DOM:
const x = document.getElementById(this.props.word._id);
x.focus();
and it didn't work either. One thing I even could not understand to put into word is a suggestion like this:
having ref as a method (I "guess")
I didn't even try it because I have multiples of these components and I need ref to further get value of, per component, and I couldn't imagine if my ref is not named, how I could get the value of!
So could you please give an idea, helping me to understand that in case I'm not using a Form (because I need a single input box replacing a label) how I could set its focus when it's CSS (Bootstrap) class is losing 'hidden' please?
The way you have used refs is not the most preferred way or else its not the best practice anymore . try some thing like this
class MyClass extends React.Component {
constructor(props) {
super(props);
this.focus = this.focus.bind(this);
}
focus() {
this.textInput.current.focus();
}
render() {
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Set Focus"
onClick={this.focus}
/>
</div>
);
}
}
Update
From React 16.3 upwards you can use the React.createRef() API
class MyClass extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef();
this.focus = this.focus.bind(this);
}
focus() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();
}
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Set Focus"
onClick={this.focus}
/>
</div>
);
}
}
From React 18.xx upwards you can use the useRef Hook
import React, { useRef } from "react";
export const Form = () => {
const inputRef = useRef(null);
const focus = () => {
inputRef.current.focus();
};
return (
<div>
<input type="text" ref={inputRef} />
<input type="button" value="Set Focus" onClick={focus} />
</div>
);
};
Just add autofocus attribute to the input. (of course in JSX it is autoFocus)
<input autoFocus ...
useFocus hook
// General Focus Hook
const useFocus = (initialFocus = false, id = "") => {
const [focus, setFocus] = useState(initialFocus)
const setFocusWithTrueDefault = (param) => setFocus(isBoolean(param)? param : true)
return ([
setFocusWithTrueDefault, {
autoFocus: focus,
key: `${id}${focus}`,
onFocus: () => setFocus(true),
onBlur: () => setFocus(false),
},
])
}
const FocusDemo = () => {
const [labelStr, setLabelStr] = useState("Your initial Value")
const [setFocus, focusProps] = useFocus(true)
return (
<> {/* React.Fragment */}
<input
onChange={(e)=> setLabelStr(e.target.value)}
value={labelStr}
{...focusProps}
/>
<h3 onClick={setFocus}>{labelStr}</h3>
</>
)
}
For a more complete demo click here.
In addition to the previous answers, I've added setTimeout to make it work
handleClick() {
if (this.searchInput) {
setTimeout(() => {
this.searchInput.focus();
}, 100);
}
}
where searchInput is the jsx ref of the input
<input
type="text"
name="searchText"
ref={(input) => { this.searchInput = input; }}
placeholder="Search" />
and the handleClick() is an onClick handler to any element
#BenCarp's answer in typescript
Pass the inputRef to an input and just call setFocus to set the focus to it.
export const useInputFocus = (): [MutableRefObject<HTMLInputElement | undefined>, () => void] => {
const inputRef = useRef<HTMLInputElement>();
const setFocus = (): void => {
const currentEl = inputRef.current;
if (currentEl) {
currentEl.focus();
}
};
return [inputRef, setFocus];
};
Use componentDidUpdate method to every time update the component
componentDidUpdate(prevProps, prevState) {
this.input.focus();
}
You can use "useRef" hook and make a reference to your input control, then use your reference.current.focus()

Resources