我是开玩笑的新手,我正在尝试为单页应用程序编写单元测试。我已经完成了对除根目录之外的所有其他无状态组件的单元测试。我一点都不知道,如果有人可以告诉我下一步该怎么做,我将不胜感激。 这是我卡住的组件。
class PizzaCreator extends React.Component{
constructor(props){
super(props);
this.state = {
atLeastOneTopping: true,
selectedSize:
{
name: "small",
price: 9.99
},
selectedToppings:[],
details: {
name:'Bella',
email:'',
confirmEmail:'',
address:'',
postcode:'',
contactNumber:'',
}
}
this.addSelectedToppingAmount = this.addSelectedToppingAmount.bind(this);
this.minusSelectedToppingAmount = this.minusSelectedToppingAmount.bind(this);
this.chooseSize = this.chooseSize.bind(this);
this.setDetails = this.setDetails.bind(this);
this.submitOrder = this.submitOrder.bind(this);
}
setDetails(key, value){
const { details } = this.state;
const newDetails = {
...details,
[key]: value
}
this.setState({
details: newDetails
}
);
}
getSelectedTopping(name){
const { selectedToppings } = this.state;
const selectedTopping = selectedToppings.find(({ name: selectedToppingName}) => name === selectedToppingName);
return selectedTopping;
}
getAmount(selectedTopping){
const amount = selectedTopping !== undefined ? selectedTopping.amount : 0;
return amount;
}
getPrice(name){
const { toppings } = this.state;
const { price } = toppings.find(({ name: toppingName}) => toppingName === name);
return price;
}
updateSelectedToppingAmount(name, price, delta){
const selectedTopping = this.getSelectedTopping(name);
const amount = this.getAmount(selectedTopping);
const newAmount = amount + delta;
this.getNewSelectedToppings(name, newAmount, price);
}
setSelectedToppings(newSelectedToppings){
this.setState({
selectedToppings: newSelectedToppings,
});
}
addNewToppingToSelectedToppings(newName, newAmount, price){
const { selectedToppings } = this.state;
const newSelectedToppings=[
...selectedToppings,
{
name: newName,
price: price,
amount: newAmount
}
];
return newSelectedToppings;
}
removeFromSelectedToppings(newName){
const { selectedToppings } = this.state;
const newSelectedToppings = selectedToppings.filter((element) => element.name !== newName);
return newSelectedToppings;
}
updateExistToppingAmount(newName, newAmount){
const { selectedToppings } = this.state;
const newSelectedToppings = selectedToppings.map((element) => {
if(element.name === newName){
const { name, price } = element;
return {
name,
price,
amount: newAmount
}
}
return element;
});
return newSelectedToppings;
}
getNewSelectedToppings(newName, newAmount, price){
const selectedTopping = this.getSelectedTopping(newName);
const amount = this.getAmount(selectedTopping);
let newSelectedToppings;
if(amount === 0 && newAmount > 0){
newSelectedToppings = this.addNewToppingToSelectedToppings(newName, newAmount, price);
}else if(amount === 0 && newAmount < 0 || amount === 1 && newAmount === 0){
newSelectedToppings = this.removeFromSelectedToppings(newName);
}else
{
newSelectedToppings = this.updateExistToppingAmount(newName, newAmount);
}
this.setSelectedToppings(newSelectedToppings);
}
addSelectedToppingAmount(name, price, value = 1){
this.updateSelectedToppingAmount(name, price,value);
}
minusSelectedToppingAmount(name, price, value = -1){
this.updateSelectedToppingAmount(name, price, value);
}
chooseSize(name, price){
this.getNewSelectedSize(name, price);
}
getNewSelectedSize(name, price){
const newSelectedSize = {
name: name,
price: price
};
this.setSelectedSize(newSelectedSize);
}
setSelectedSize(newSelectedSize){
this.setState({
selectedSize: newSelectedSize
})
}
setAtLeastOneTopping(newAtLeastOneTopping){
this.setState({
atLeastOneTopping:newAtLeastOneTopping,
})
}
render(){
const { selectedSize, selectedToppings, details, atLeastOneTopping } = this.state;
return(
<div className = "pizza-creator">
{!atLeastOneTopping && <ErrorMessage
content="Please select at least one topping"
></ErrorMessage>}
<Details
details={details}
onChange={this.setDetails}
></Details>
<Sizes
selectedSize={selectedSize}
chooseSize={this.chooseSize}
></Sizes>
<Toppings
selectedToppings={selectedToppings}
onAmountAdd = {this.addSelectedToppingAmount}
onAmountMinus = {this.minusSelectedToppingAmount}
></Toppings>
<Summary
selectedToppings={selectedToppings}
selectedSize={selectedSize}
></Summary>
<SubmitButton
submitOrder={this.submitOrder}
></SubmitButton>
</div>
);
}
这是另一个组件及其单元测试之一。
import React from 'react';
import Title from '../Title';
import Topping from '../Topping';
import './Toppings.css';
class Toppings extends React.Component{
constructor(props){
super(props);
this.toppings = [{
name : 'anchovy',
srcImg: 'src/assets/toppings/anchovy.svg',
price: 2,
},
{
name : 'bacon',
srcImg: 'src/assets/toppings/bacon.svg',
price: 2,
},
{
name : 'basil',
srcImg: 'src/assets/toppings/basil.svg',
price: 2,
},
{
name : 'chili',
srcImg: 'src/assets/toppings/chili.svg',
price: 2,
},
{
name : 'mozzarella',
srcImg: 'src/assets/toppings/mozzarella.svg',
price: 2,
},
{
name : 'mushroom',
srcImg: 'src/assets/toppings/mushroom.svg',
price: 2,
},
{
name : 'olive',
srcImg: 'src/assets/toppings/olive.svg',
price: 2,
},
{
name : 'onion',
srcImg: 'src/assets/toppings/onion.svg',
price: 2,
},
{
name : 'pepper',
srcImg: 'src/assets/toppings/pepper.svg',
price: 2,
},
{
name : 'pepperoni',
srcImg: 'src/assets/toppings/pepperoni.svg',
price: 2,
},
{
name : 'sweetcorn',
srcImg: 'src/assets/toppings/sweetcorn.svg',
price: 2,
},
{
name : 'tomato',
srcImg: 'src/assets/toppings/tomato.svg',
price: 2,
}];
}
render(){
const { selectedToppings, onAmountAdd, onAmountMinus } = this.props;
return (
<div className="toppings">
<Title>Choose Your Toppings</Title>
<div className="toppings__container">
{this.toppings.map(({ name, srcImg, price }) =>(
<Topping
key={name}
name={name}
srcImg={srcImg}
price={price}
selectedToppings={selectedToppings}
onAmountAdd={onAmountAdd}
onAmountMinus={onAmountMinus}
></Topping>
))}
</div>
</div>
);
}
}
export default Toppings;
import React from 'react';
import Topping from './Topping';
import sinon from 'sinon';
import { render, cleanup, fireEvent } from '@testing-library/react';
describe('Topping', () => {
afterEach(cleanup);
const name = 'pepper';
const price = 0.99;
const srcImg = '/src/assets/toppings/pepperoni.svg';
test("render topping", () =>{
const { getByTestId } = render((
<Topping
name={name}
srcImg={srcImg}
price={price}
selectedToppings={[]}
onAmountAdd={() => {}}
onAmountMinus={() => {}}
/>));
expect(getByTestId('topping-name').textContent).toBe(name);
expect(getByTestId('topping-srcImg').alt).toBe(name);
expect(getByTestId('topping-srcImg').src).toBe('http://localhost/src/assets/toppings/pepperoni.svg');
})
test("topping amount add and minus", () => {
const onAmountAddSpy = sinon.spy();
const onAmountMinusSpy = sinon.spy();
const { getByTestId } = render((
<Topping
name={name}
srcImg={srcImg}
price={price}
selectedToppings={[]}
onAmountAdd={onAmountAddSpy}
onAmountMinus={onAmountMinusSpy}
/>));
const toppingAmountAddBtn = getByTestId('topping-AmountAdd');
fireEvent.click(toppingAmountAddBtn);
sinon.assert.calledOnce(onAmountAddSpy);
sinon.assert.calledWith(onAmountAddSpy,name,price)
const toppingAmountMinusBtn = getByTestId('topping-AmountMinus');
fireEvent.click(toppingAmountMinusBtn);
sinon.assert.calledOnce(onAmountMinusSpy);
sinon.assert.calledWith(onAmountMinusSpy,name,price);
})
test("topping className", () =>{
const amount = 1;
const { getByTestId } = render((
<Topping
name={name}
srcImg={srcImg}
price={price}
selectedToppings={[{name, price,amount}]}
onAmountAdd={() => {}}
onAmountMinus={() => {}}
/>));
const topping = getByTestId('topping');
expect(topping.className).toBe("topping topping--active");
})
test("topping className", () =>{
const amount = 1;
const { getByTestId } = render((
<Topping
name={name}
srcImg={srcImg}
price={price}
selectedToppings={[{name, price,amount}]}
onAmountAdd={() => {}}
onAmountMinus={() => {}}
/>));
const toppingAmount = getByTestId('topping-amount');
expect(toppingAmount.textContent).toBe(amount.toString());
})
});