React&Jest,如何测试变化的状态

时间:2020-04-12 03:28:17

标签: reactjs unit-testing jestjs

我是开玩笑的新手,我正在尝试为单页应用程序编写单元测试。我已经完成了对除根目录之外的所有其他无状态组件的单元测试。我一点都不知道,如果有人可以告诉我下一步该怎么做,我将不胜感激。 这是我卡住的组件。

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());
    })
});

0 个答案:

没有答案
相关问题