یه برنامه نویس معمولی لینوکس کار
نوشتن تست در ReactJs برای هوک ها
![](https://files.virgool.io/upload/users/17959/posts/jogwdkkyhbdp/yrrsj2limjaj.jpeg)
داخل یکی از مقاله های قبلیم در مورد نوشتنن تست برای Reactjs صحبت کردیم .
مشکلی که داشتم چی بود؟ اینکه من میخواستم داخل یک functional component که هوک داره ، یک تست بنویسم . من داخل کامپوننت هم از Material-ui استفاده کردم چون کار باهاش برام لذت بخشه . ( سلیقه ای دیگه . منم بد سلیقم ).
هرکار میکردم نمیتونستم به سلکتورها برسم . به هر دری زدم و متوجه شدم که برای هوک ها باید کارهای دیگه ای کرد و به شکل دیگه نوشت . موضوع اینه که وقتی ما Functional Component داریم مینویسیم ، Enzyme نمیتونه کامپوننت رو رندر کنه . چون باید حتما کامپوننت یک instance از کلاس باشه . اما ما Function داریم مینویسیم .
بعد از کلی زیر و رو کردن فهمیدم باید از یک کتابخانه دیگه استفاده کنیم .
کتابخانه react-testing-library همونیه که میتونه کمک کنه به ما .
حالا با یک مثال ساده نگاه میندازیم به موضوع :
import React, {useState} from 'react'
import {withStyles} from '@material-ui/core/styles';
import PropTypes from 'prop-types';
import InputAdornment from '@material-ui/core/InputAdornment';
import TextField from '@material-ui/core/TextField';
import classNames from 'classnames';
import Grid from "@material-ui/core/Grid";
import {isNumber} from "persian-regex";
import Fab from '@material-ui/core/Fab';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
},
margin: {
margin: theme.spacing.unit,
height: 39
},
textField: {
flexBasis: 200,
},
rootGrid: {
padding: 0,
height: '100%',
overflow: 'hidden'
},
rootGridItem: {
textAlign: 'left'
},
adornment: {
'& p':
{
color: '#ffffff',
fontSize: 12,
display: 'inherit',
width: 85,
paddingRight: 5
}
},
inputLabel: {
color: '#ffffff'
},
extendedIcon: {
marginRight: theme.spacing.unit,
},
fabButton: {
width: '100%',
margin: '0 auto',
textAlign: 'center',
borderRadius: 5
},
fabButtons: {
padding: 6
},
buyFab: {
backgroundColor: '#12b886',
color: '#ffffff'
},
sellFab: {
backgroundColor: '#fa5252',
color: '#ffffff'
}
});
function Limit(props) {
const [buyAmount, setBuyAmount] = useState(0);
const [alert, setAlert] = useState("");
function handleBuy() {
setAlert("")
if (buyAmount === 0 || buyAmount === "")
setAlert("missing inputs")
setTimeout(() => {
setAlert("");
}, 2000)
}
function handleChange(event, name) {
const amount = event.target.value;
if (amount !== undefined)
if (isNumber(amount))
switch (name) {
case 'buyAmount':
setBuyAmount(amount);
break;
}
}
const {classes} = props;
return (
<React.Fragment>
<Grid container classes={{container: classes.rootGrid}}>
<Grid item xs={6} className={classes.rootGridItem}>
<TextField
id="filled-adornment-amount"
className={classNames(classes.margin, classes.textField)}
variant="filled"
InputLabelProps={{
classes: {root: classes.inputLabel}
}}
value={buyAmount > 0 ? buyAmount : ""}
={(e) => handleChange(e, 'buyAmount')}
InputProps={{
inputProps: {'data-testid': "buyAmount"},
classes: {root: classes.inputLabel},
startAdornment: <InputAdornment position="start" classes={{root: classes.adornment}}>
Amount (IRR)
</InputAdornment>,
}}
/>
</Grid>
<Grid item xs={6} className={classNames(classes.rootGridItem, classes.fabButtons)}>
<Fab
data-testid="buy"
classes={{
root: classes.buyFab
}}
={handleBuy}
variant="extended"
size="large"
color="primary"
aria-label="Buy"
className={classes.fabButton}
>
Buy
</Fab>
</Grid>
<div data-testid="alert">{alert}</div>
</Grid>
</React.Fragment>
)
}
Limit.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(Limit);
داخل این مثال از material-ui و یکی از پکیج هایی که خودم نوشتم به اسم persian-regex استفاده کردم .
حالا میخوام تستم رو درست کنم . میرم داخل پوشه __tests__ و یک فایل به اسم Limit.js میسازم . تست ما از این پوشه پیروی میکنه .
داخل ترمینال پکیجمون رو نصب میکنیم :
npm i react-testing-library --save-dev
حالا داخل Limit.js که ساختیم برای تست کد زیر رو میزنیم :
import React from 'react';
import Limit from "../Components/Limit"; // limit component we made above
import 'react-testing-library/cleanup-after-each'
import {render, fireEvent} from 'react-testing-library'
import {isNumber} from "persian-regex";
describe('Test Limit Component', () => {
describe('Click on Buy Buttons and check validation', () => {
describe('should click on Buy Button ', () => {
it('should return false , cause inputs are empty', () => {
const {getByTestId} = render(<Limit/>)
const buyButton = getByTestId('buy');
const buyAmountInput = getByTestId('buyAmount');
const alert = getByTestId('alert');
fireEvent.change(buyAmountInput, {target: {buyAmount: ""}});
fireEvent.click(buyButton)
if (buyAmountInput.buyAmount === "") {
expect(alert).toContain('missing inputs')
}
})
it('write into buy Amount input and it should get value : 123456789', () => {
const {getByTestId} = render(<Limit/>)
const number = '123456789';
const buyAmountInput = getByTestId('buyAmount');
fireEvent.change(buyAmountInput, {target: {buyAmount: isNumber(number) ? number : ''}})
expect(buyAmountInput.buyAmount).toEqual(number)
})
it('write into buy Amount input and it should get empty value because input is not valid', () => {
const {getByTestId} = render(<Limit/>)
const number = 'hi there';
const buyAmountInput = getByTestId('buyAmount');
fireEvent.change(buyAmountInput, {target: {buyAmount: isNumber(number) ? number : ''}})
expect(buyAmountInput.buyAmount).toEqual('')
})
})
})
})
داخل کد بالا سه شرط نوشتم . یکی کلیک کردن روی دکمه خرید ، بدون وارد کردن مقدار ، یکی کلیک با مقدار درست یکی هم با مقدار اشتباه و validate کدن input . حالا بعد از اجرای دستور npm run test ، تست یکی یکی اجرا میشه و درست بودنشون چک میشه .
مطلبی دیگر از این انتشارات
کتابخانه ی ReactJS چیست و چه کارهایی می توان با آن انجام داد؟
مطلبی دیگر از این انتشارات
نحوه ی استفاده از Context در React
مطلبی دیگر از این انتشارات
خروجی apk از اپ ریکت نیتیو(Release apk from ReactNative)