单元测试不会更新样式化输入的值
Unit test doesn't update value on styled input
我正在测试 React 组件
import React from 'react';
import styled from 'styled-components';
const Input = styled.input``;
export default function FormInput (props) {
const { name, type, value, label, placeholder, onChange} = props;
return (
<Input
id={name}
name={name}
type={type}
placeholder={placeholder}
onChange={onChange}
value={value}
/>
)
};
使用这个单元测试
test('it changes the value of the input', () => {
let currentValue = 'Initial value';
const setValue = (value) => {
currentValue = value;
}
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue}
onChange={(e) => setValue(e.target.value)} />
render(component);
const input = screen.getByPlaceholderText('Enter your first name');
fireEvent.change(input, {target: {value: 'New value'}});
expect(currentValue).toBe('New value');
expect(input.value).toBe('New value');
});
关于输入值的断言是假的,因为它仍然是初始值。该组件在应用程序中正常工作。我在测试中设置错了什么?
我发现使用 @testing-library/user-event
包很容易模拟用户的文本输入。
import userEvent from '@testing-library/user-event';
test('it changes the value of the input', () => {
let currentValue = 'Initial value';
const setValue = (value) => {
currentValue = value;
}
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue}
onChange={(e) => setValue(e.target.value)} />
render(component);
const input = screen.getByPlaceholderText('Enter your first name');
userEvent.type(input, 'New value');
expect(currentValue).toBe('New value');
expect(input.value).toBe('New value');
});
为什么不将 setValue 放在组件主体中?这个逻辑明明是属于组件的,你应该有:
import React, { useState } from 'react';
import styled from 'styled-components';
const Input = styled.input``;
export default function FormInput (props) {
const { name, type, label, placeholder} = props;
const [value, setValue] = useState('');
return (
<input
id={name}
name={name}
type={type}
placeholder={placeholder}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
)
};
然后在你的测试中:
import '@testing-library/jest-dom/extend-expect';
test('it changes the value of the input', () => {
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue} />
render(component);
const input = screen.getByPlaceholderText('Enter your first name');
fireEvent.change(input, { target : { value : 'New value' } });
expect(input).toHaveValue('New value');
});
请注意,我使用 https://github.com/testing-library/jest-dom 以获得更具可读性的匹配器。
单元测试失败,因为它没有被重新渲染。我使用 rerender
函数来渲染具有更新值的组件。这是必要的,因为此测试不包括父组件保持状态。
更新测试
test('it changes the value of the input', async () => {
let currentValue = 'Initial value';
const setValue = (value) => {
currentValue = value;
}
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue}
onChange={(e) => setValue(e.target.value)} />
const { rerender } = render(component);
const input = screen.getByPlaceholderText('Enter your first name');
fireEvent.change(input, {target: {value: 'New value'}});
rerender(<FormInput value={currentValue} />);
expect(input.value).toBe('New value');
});
我正在测试 React 组件
import React from 'react';
import styled from 'styled-components';
const Input = styled.input``;
export default function FormInput (props) {
const { name, type, value, label, placeholder, onChange} = props;
return (
<Input
id={name}
name={name}
type={type}
placeholder={placeholder}
onChange={onChange}
value={value}
/>
)
};
使用这个单元测试
test('it changes the value of the input', () => {
let currentValue = 'Initial value';
const setValue = (value) => {
currentValue = value;
}
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue}
onChange={(e) => setValue(e.target.value)} />
render(component);
const input = screen.getByPlaceholderText('Enter your first name');
fireEvent.change(input, {target: {value: 'New value'}});
expect(currentValue).toBe('New value');
expect(input.value).toBe('New value');
});
关于输入值的断言是假的,因为它仍然是初始值。该组件在应用程序中正常工作。我在测试中设置错了什么?
我发现使用 @testing-library/user-event
包很容易模拟用户的文本输入。
import userEvent from '@testing-library/user-event';
test('it changes the value of the input', () => {
let currentValue = 'Initial value';
const setValue = (value) => {
currentValue = value;
}
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue}
onChange={(e) => setValue(e.target.value)} />
render(component);
const input = screen.getByPlaceholderText('Enter your first name');
userEvent.type(input, 'New value');
expect(currentValue).toBe('New value');
expect(input.value).toBe('New value');
});
为什么不将 setValue 放在组件主体中?这个逻辑明明是属于组件的,你应该有:
import React, { useState } from 'react';
import styled from 'styled-components';
const Input = styled.input``;
export default function FormInput (props) {
const { name, type, label, placeholder} = props;
const [value, setValue] = useState('');
return (
<input
id={name}
name={name}
type={type}
placeholder={placeholder}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
)
};
然后在你的测试中:
import '@testing-library/jest-dom/extend-expect';
test('it changes the value of the input', () => {
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue} />
render(component);
const input = screen.getByPlaceholderText('Enter your first name');
fireEvent.change(input, { target : { value : 'New value' } });
expect(input).toHaveValue('New value');
});
请注意,我使用 https://github.com/testing-library/jest-dom 以获得更具可读性的匹配器。
单元测试失败,因为它没有被重新渲染。我使用 rerender
函数来渲染具有更新值的组件。这是必要的,因为此测试不包括父组件保持状态。
更新测试
test('it changes the value of the input', async () => {
let currentValue = 'Initial value';
const setValue = (value) => {
currentValue = value;
}
const component = <FormInput
name={'firstName'}
placeholder={'Enter your first name'}
value={currentValue}
onChange={(e) => setValue(e.target.value)} />
const { rerender } = render(component);
const input = screen.getByPlaceholderText('Enter your first name');
fireEvent.change(input, {target: {value: 'New value'}});
rerender(<FormInput value={currentValue} />);
expect(input.value).toBe('New value');
});