Calling prop callback in react test renderer doesn't update hooksReactJS - Does render get called any time “setState” is called?React “after render” code?What is the difference between state and props in React?Testing react form - AssertionErrorReact tests with jest, enzyme behave strangelyTesting React Components which Display Other Components in LoopPass form input values to another component ReactReact redux-form - error while testing - “TypeError: handleSubmit is not a function”How to test props that are updated by an onChange handler in react testing library?React-router <Link> doesn't work with react 16.8 correctly
When using the Proficiency Dice optional rule, how should they be used in determining a character's Spell Save DC?
Are the related objects in an SOQL query shared?
Why do rocket engines use nitrogen actuators to operate the fuel/oxidiser valves instead of electric servos?
How do the surviving Asgardians get to Earth?
C# TCP server/client class
What's "halachic" about "Esav hates Ya'akov"?
What could prevent players from leaving an island?
What does "autolyco-sentimental" mean?
Can attackers change the public key of certificate during the SSL handshake
Is the Infernal Healing spell actually worth it as a Wand?
What is the reason behind water not falling from a bucket at the top of loop?
Why should I "believe in" weak solutions to PDEs?
Variable doesn't parse as string
How can I perform a deterministic physics simulation?
Does the length of a password for Wi-Fi affect speed?
What are the limitations of the Hendersson-Hasselbalch equation?
How to design an effective polearm-bow hybrid?
How do I know when and if a character requires a backstory?
Need reasons why a satellite network would not work
Is space radiation a risk for space film photography, and how is this prevented?
Vectorised way to calculate mean of left and right neighbours in a vector
How easy is it to get a gun illegally in the United States?
Getting an entry level IT position later in life
How can I use commands with sudo without changing owner of the files?
Calling prop callback in react test renderer doesn't update hooks
ReactJS - Does render get called any time “setState” is called?React “after render” code?What is the difference between state and props in React?Testing react form - AssertionErrorReact tests with jest, enzyme behave strangelyTesting React Components which Display Other Components in LoopPass form input values to another component ReactReact redux-form - error while testing - “TypeError: handleSubmit is not a function”How to test props that are updated by an onChange handler in react testing library?React-router <Link> doesn't work with react 16.8 correctly
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I'm trying to figure out how to test a react function component that uses hooks to keep track of state. The problem I'm having is when I call the onChange
prop function passed to the input components, the value of my useState
hook isn't being updated, so when I trigger the form submit, the result doesn't reflect the state changes.
Here is the component I'm testing:
import React, useState, ChangeEvent, FormEvent from 'react';
import styled from '../styled';
import Column from './Column';
import BlockButton from './BlockButton';
import Input from './Input';
import Form from './Form';
import InputRow from './InputRow';
export type LoginFormOnSubmit = (result: LoginFormResult) => any;
export interface LoginFormResult
employeeId: string;
password: string;
export interface LoginFormProps
onSubmit?: LoginFormOnSubmit;
const LoginForm: React.FunctionComponent<LoginFormProps> = props =>
const onSubmit, ...rest = props;
const [employeeId, setEmployeeId] = useState('');
const [password, setPassword] = useState('');
function handleEmployeeIdChange(event: ChangeEvent<HTMLInputElement>)
setEmployeeId(event.currentTarget.value);
function handlePasswordChange(event: ChangeEvent<HTMLInputElement>)
setPassword(event.currentTarget.value);
function handleSubmit(event: FormEvent<HTMLFormElement>)
if(onSubmit)
onSubmit(
employeeId,
password,
);
return (
<Column ...rest>
<h1>SHIFT LEDGER LOGON</h1>
<Form onSubmit=handleSubmit>
<InputRow>
<label>Employee ID:</label>
<Input
type="text"
value=employeeId
onChange=handleEmployeeIdChange
data-testid="employee-id-input"
/>
</InputRow>
<InputRow>
<label>Password:</label>
<Input
type="password"
value=password
onChange=handlePasswordChange
data-test-id="password-input"
/>
</InputRow>
<BlockButton data-testid="submit-button">Enter</BlockButton>
</Form>
</Column>
);
;
export default styled(LoginForm)`
background-color: #F0EBDF;
justify-content: center;
flex: 1;
h1
text-align: center;
$Form
align-items: center;
label
width: 150px;
`;
And here is my test:
import React from 'react';
import sinon from 'sinon';
import TestRenderer, act from 'react-test-renderer';
import LoginForm from '../LoginForm';
import Form from '../Form';
describe('components/LoginForm', () =>
test('Should be able to edit employee id', async () =>
const onSubmit = sinon.fake();
const employeeId = 'test id';
const rendered = TestRenderer.create(<LoginForm onSubmit=onSubmit/>);
act(() =>
const wrapper = rendered.root;
const employeeIdInput = wrapper.findByProps( 'data-testid': 'employee-id-input' );
employeeIdInput.props!.onChange(
currentTarget:
value: employeeId,
,
);
wrapper.findByType(Form).props.onSubmit(
preventDefault: sinon.fake(),
);
);
expect(onSubmit.calledOnce).toBeTruthy();
expect(onSubmit.args).toEqual([[
employeeId,
password: '',
]]);
);
);
And the error I'm seeing:
● components/LoginForm › Should be able to edit employee id
expect(received).toEqual(expected)
Difference:
- Expected
+ Received
Array [
Array [
Object
- "employeeId": "test id",
+ "employeeId": "",
"password": "",
,
],
]
42 | });
43 |
> 44 | expect(onSubmit.calledOnce).toBeTruthy();
| ^
45 | expect(onSubmit.args).toEqual([[
46 | employeeId,
at react_test_renderer_1.act (src/components/__tests__/LoginForm.test.tsx:44:33)
at batchedUpdates (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12492:12)
at Object.act (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13146:18)
at Object.test (src/components/__tests__/LoginForm.test.tsx:29:5)
Some extra info:
- typescript 3.3.3
- react 16.8.2
- react-dom 16.8.2
- react-test-renderer 16.8.5
- jest 24.3.1
javascript reactjs typescript jestjs
I'm trying to figure out how to test a react function component that uses hooks to keep track of state. The problem I'm having is when I call the onChange
prop function passed to the input components, the value of my useState
hook isn't being updated, so when I trigger the form submit, the result doesn't reflect the state changes.
Here is the component I'm testing:
import React, useState, ChangeEvent, FormEvent from 'react';
import styled from '../styled';
import Column from './Column';
import BlockButton from './BlockButton';
import Input from './Input';
import Form from './Form';
import InputRow from './InputRow';
export type LoginFormOnSubmit = (result: LoginFormResult) => any;
export interface LoginFormResult
employeeId: string;
password: string;
export interface LoginFormProps
onSubmit?: LoginFormOnSubmit;
const LoginForm: React.FunctionComponent<LoginFormProps> = props =>
const onSubmit, ...rest = props;
const [employeeId, setEmployeeId] = useState('');
const [password, setPassword] = useState('');
function handleEmployeeIdChange(event: ChangeEvent<HTMLInputElement>)
setEmployeeId(event.currentTarget.value);
function handlePasswordChange(event: ChangeEvent<HTMLInputElement>)
setPassword(event.currentTarget.value);
function handleSubmit(event: FormEvent<HTMLFormElement>)
if(onSubmit)
onSubmit(
employeeId,
password,
);
return (
<Column ...rest>
<h1>SHIFT LEDGER LOGON</h1>
<Form onSubmit=handleSubmit>
<InputRow>
<label>Employee ID:</label>
<Input
type="text"
value=employeeId
onChange=handleEmployeeIdChange
data-testid="employee-id-input"
/>
</InputRow>
<InputRow>
<label>Password:</label>
<Input
type="password"
value=password
onChange=handlePasswordChange
data-test-id="password-input"
/>
</InputRow>
<BlockButton data-testid="submit-button">Enter</BlockButton>
</Form>
</Column>
);
;
export default styled(LoginForm)`
background-color: #F0EBDF;
justify-content: center;
flex: 1;
h1
text-align: center;
$Form
align-items: center;
label
width: 150px;
`;
And here is my test:
import React from 'react';
import sinon from 'sinon';
import TestRenderer, act from 'react-test-renderer';
import LoginForm from '../LoginForm';
import Form from '../Form';
describe('components/LoginForm', () =>
test('Should be able to edit employee id', async () =>
const onSubmit = sinon.fake();
const employeeId = 'test id';
const rendered = TestRenderer.create(<LoginForm onSubmit=onSubmit/>);
act(() =>
const wrapper = rendered.root;
const employeeIdInput = wrapper.findByProps( 'data-testid': 'employee-id-input' );
employeeIdInput.props!.onChange(
currentTarget:
value: employeeId,
,
);
wrapper.findByType(Form).props.onSubmit(
preventDefault: sinon.fake(),
);
);
expect(onSubmit.calledOnce).toBeTruthy();
expect(onSubmit.args).toEqual([[
employeeId,
password: '',
]]);
);
);
And the error I'm seeing:
● components/LoginForm › Should be able to edit employee id
expect(received).toEqual(expected)
Difference:
- Expected
+ Received
Array [
Array [
Object
- "employeeId": "test id",
+ "employeeId": "",
"password": "",
,
],
]
42 );
43 |
> 44 | expect(onSubmit.calledOnce).toBeTruthy();
| ^
45 | expect(onSubmit.args).toEqual([[
46 | improve this question
I'm trying to figure out how to test a react function component that uses hooks to keep track of state. The problem I'm having is when I call the onChange
prop function passed to the input components, the value of my useState
hook isn't being updated, so when I trigger the form submit, the result doesn't reflect the state changes.
Here is the component I'm testing:
import React, useState, ChangeEvent, FormEvent from 'react';
import styled from '../styled';
import Column from './Column';
import BlockButton from './BlockButton';
import Input from './Input';
import Form from './Form';
import InputRow from './InputRow';
export type LoginFormOnSubmit = (result: LoginFormResult) => any;
export interface LoginFormResult
employeeId: string;
password: string;
export interface LoginFormProps
onSubmit?: LoginFormOnSubmit;
const LoginForm: React.FunctionComponent<LoginFormProps> = props =>
const onSubmit, ...rest = props;
const [employeeId, setEmployeeId] = useState('');
const [password, setPassword] = useState('');
function handleEmployeeIdChange(event: ChangeEvent<HTMLInputElement>)
setEmployeeId(event.currentTarget.value);
function handlePasswordChange(event: ChangeEvent<HTMLInputElement>)
setPassword(event.currentTarget.value);
function handleSubmit(event: FormEvent<HTMLFormElement>)
if(onSubmit)
onSubmit(
employeeId,
password,
);
return (
<Column ...rest>
<h1>SHIFT LEDGER LOGON</h1>
<Form onSubmit=handleSubmit>
<InputRow>
<label>Employee ID:</label>
<Input
type="text"
value=employeeId
onChange=handleEmployeeIdChange
data-testid="employee-id-input"
/>
</InputRow>
<InputRow>
<label>Password:</label>
<Input
type="password"
value=password
onChange=handlePasswordChange
data-test-id="password-input"
/>
</InputRow>
<BlockButton data-testid="submit-button">Enter</BlockButton>
</Form>
</Column>
);
;
export default styled(LoginForm)`
background-color: #F0EBDF;
justify-content: center;
flex: 1;
h1
text-align: center;
$Form
align-items: center;
label
width: 150px;
`;
And here is my test:
import React from 'react';
import sinon from 'sinon';
import TestRenderer, act from 'react-test-renderer';
import LoginForm from '../LoginForm';
import Form from '../Form';
describe('components/LoginForm', () =>
test('Should be able to edit employee id', async () =>
const onSubmit = sinon.fake();
const employeeId = 'test id';
const rendered = TestRenderer.create(<LoginForm onSubmit=onSubmit/>);
act(() =>
const wrapper = rendered.root;
const employeeIdInput = wrapper.findByProps( 'data-testid': 'employee-id-input' );
employeeIdInput.props!.onChange(
currentTarget:
value: employeeId,
,
);
wrapper.findByType(Form).props.onSubmit(
preventDefault: sinon.fake(),
);
);
expect(onSubmit.calledOnce).toBeTruthy();
expect(onSubmit.args).toEqual([[
employeeId,
password: '',
]]);
);
);
And the error I'm seeing:
● components/LoginForm › Should be able to edit employee id
expect(received).toEqual(expected)
Difference:
- Expected
+ Received
Array [
Array [
Object
- "employeeId": "test id",
+ "employeeId": "",
"password": "",
,
],
]
42 );
43 |
> 44 | expect(onSubmit.calledOnce).toBeTruthy();
| ^
45 | expect(onSubmit.args).toEqual([[
46 | {
47 | employeeId,
at react_test_renderer_1.act (src/components/__tests__/LoginForm.test.tsx:44:33)
at batchedUpdates (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12492:12)
at Object.act (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13146:18)
at Object.test (src/components/__tests__/LoginForm.test.tsx:29:5)
Some extra info:
- typescript 3.3.3
- react 16.8.2
- react-dom 16.8.2
- react-test-renderer 16.8.5
- jest 24.3.1
javascript reactjs typescript jestjs
javascript reactjs typescript jestjs
asked Mar 26 at 19:55
SimpleJSimpleJ
6,4714 gold badges23 silver badges49 bronze badges
6,4714 gold badges23 silver badges49 bronze badges
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
It looks like the issue is that the state doesn't update during an act
function, it only updates after the act
completes.
Here is a simple example:
import React, useState from 'react';
import TestRenderer, act from 'react-test-renderer';
function Example(props)
const [count, setCount] = useState(0);
return (
<div>
<p>count</p>
<button onClick=() => setCount(count + 1) data-test-id="increment">
Increment
</button>
<button onClick=() => props.submit(count) data-test-id="submit">
Submit
</button>
</div>
);
test('Example', () =>
const submitSpy = jest.fn();
const rendered = TestRenderer.create(<Example submit=submitSpy />);
act(() =>
rendered.root.findByProps( 'data-test-id': 'increment' ).props.onClick(); // increment
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit
expect(rendered.root.findByType('p').props.children).toBe(0); // <= still 0
expect(submitSpy).toHaveBeenLastCalledWith(0); // <= still 0
);
expect(rendered.root.findByType('p').props.children).toBe(1); // <= NOW it's 1
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit again
expect(submitSpy).toHaveBeenLastCalledWith(1); // Success!
);
So it looks like submitting the form after the act
instead of during the act
might fix the problem.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55365287%2fcalling-prop-callback-in-react-test-renderer-doesnt-update-hooks%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
It looks like the issue is that the state doesn't update during an act
function, it only updates after the act
completes.
Here is a simple example:
import React, useState from 'react';
import TestRenderer, act from 'react-test-renderer';
function Example(props)
const [count, setCount] = useState(0);
return (
<div>
<p>count</p>
<button onClick=() => setCount(count + 1) data-test-id="increment">
Increment
</button>
<button onClick=() => props.submit(count) data-test-id="submit">
Submit
</button>
</div>
);
test('Example', () =>
const submitSpy = jest.fn();
const rendered = TestRenderer.create(<Example submit=submitSpy />);
act(() =>
rendered.root.findByProps( 'data-test-id': 'increment' ).props.onClick(); // increment
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit
expect(rendered.root.findByType('p').props.children).toBe(0); // <= still 0
expect(submitSpy).toHaveBeenLastCalledWith(0); // <= still 0
);
expect(rendered.root.findByType('p').props.children).toBe(1); // <= NOW it's 1
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit again
expect(submitSpy).toHaveBeenLastCalledWith(1); // Success!
);
So it looks like submitting the form after the act
instead of during the act
might fix the problem.
add a comment |
It looks like the issue is that the state doesn't update during an act
function, it only updates after the act
completes.
Here is a simple example:
import React, useState from 'react';
import TestRenderer, act from 'react-test-renderer';
function Example(props)
const [count, setCount] = useState(0);
return (
<div>
<p>count</p>
<button onClick=() => setCount(count + 1) data-test-id="increment">
Increment
</button>
<button onClick=() => props.submit(count) data-test-id="submit">
Submit
</button>
</div>
);
test('Example', () =>
const submitSpy = jest.fn();
const rendered = TestRenderer.create(<Example submit=submitSpy />);
act(() =>
rendered.root.findByProps( 'data-test-id': 'increment' ).props.onClick(); // increment
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit
expect(rendered.root.findByType('p').props.children).toBe(0); // <= still 0
expect(submitSpy).toHaveBeenLastCalledWith(0); // <= still 0
);
expect(rendered.root.findByType('p').props.children).toBe(1); // <= NOW it's 1
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit again
expect(submitSpy).toHaveBeenLastCalledWith(1); // Success!
);
So it looks like submitting the form after the act
instead of during the act
might fix the problem.
add a comment |
It looks like the issue is that the state doesn't update during an act
function, it only updates after the act
completes.
Here is a simple example:
import React, useState from 'react';
import TestRenderer, act from 'react-test-renderer';
function Example(props)
const [count, setCount] = useState(0);
return (
<div>
<p>count</p>
<button onClick=() => setCount(count + 1) data-test-id="increment">
Increment
</button>
<button onClick=() => props.submit(count) data-test-id="submit">
Submit
</button>
</div>
);
test('Example', () =>
const submitSpy = jest.fn();
const rendered = TestRenderer.create(<Example submit=submitSpy />);
act(() =>
rendered.root.findByProps( 'data-test-id': 'increment' ).props.onClick(); // increment
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit
expect(rendered.root.findByType('p').props.children).toBe(0); // <= still 0
expect(submitSpy).toHaveBeenLastCalledWith(0); // <= still 0
);
expect(rendered.root.findByType('p').props.children).toBe(1); // <= NOW it's 1
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit again
expect(submitSpy).toHaveBeenLastCalledWith(1); // Success!
);
So it looks like submitting the form after the act
instead of during the act
might fix the problem.
It looks like the issue is that the state doesn't update during an act
function, it only updates after the act
completes.
Here is a simple example:
import React, useState from 'react';
import TestRenderer, act from 'react-test-renderer';
function Example(props)
const [count, setCount] = useState(0);
return (
<div>
<p>count</p>
<button onClick=() => setCount(count + 1) data-test-id="increment">
Increment
</button>
<button onClick=() => props.submit(count) data-test-id="submit">
Submit
</button>
</div>
);
test('Example', () =>
const submitSpy = jest.fn();
const rendered = TestRenderer.create(<Example submit=submitSpy />);
act(() =>
rendered.root.findByProps( 'data-test-id': 'increment' ).props.onClick(); // increment
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit
expect(rendered.root.findByType('p').props.children).toBe(0); // <= still 0
expect(submitSpy).toHaveBeenLastCalledWith(0); // <= still 0
);
expect(rendered.root.findByType('p').props.children).toBe(1); // <= NOW it's 1
rendered.root.findByProps( 'data-test-id': 'submit' ).props.onClick(); // submit again
expect(submitSpy).toHaveBeenLastCalledWith(1); // Success!
);
So it looks like submitting the form after the act
instead of during the act
might fix the problem.
answered Mar 27 at 2:41
brian-lives-outdoorsbrian-lives-outdoors
15k1 gold badge16 silver badges41 bronze badges
15k1 gold badge16 silver badges41 bronze badges
add a comment |
add a comment |
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55365287%2fcalling-prop-callback-in-react-test-renderer-doesnt-update-hooks%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown