2017-08-26 130 views
1

我在学校学习Redux,因此我们正在使用测试来确保我们有基准测试通过,以帮助我们理解构建模块。Redux中的“Reducer”能否在默认情况下返回初始状态并且默认值?

我达到了创建Reducer函数的部分,而我几乎完成了\o/但是我无法通过一个测试。

1) returns the initial state by default

和下面的控制台来发回...

Reducer returns the initial state by default:

AssertionError: expected undefined to be an object at Context. (tests/redux.spec.js:103:49)

我想这是因为测试处理一些关注的问题之一将负责例如导入,创建动作类型等,但并不是所有的。所以也许我错过了测试没有提供的东西?

反正这是我的减速器文件:

import pet from "../components/PetPreview"; 
import { createStore } from "redux"; 

import { adoptPet, previewPet, addNewDog, addNewCat } from "./action-creators"; 
// ACTION TYPES 
const PREVIEW_PET = "PREVIEW_PET"; 
const ADOPT_PET = "ADOPT_PET"; 
const ADD_NEW_DOG = "ADD_NEW_DOG"; 
const ADD_NEW_CAT = "ADD_NEW_CAT"; 


// INTITIAL STATE 
const initialState = { 
    dogs: [ 
    { 
     name: "Taylor", 
     imgUrl: "src/img/taylor.png" 
    }, 
    { 
     name: "Reggie", 
     imgUrl: "src/img/reggie.png" 
    }, 
    { 
     name: "Pandora", 
     imgUrl: "src/img/pandora.png" 
    } 
    ], 
    cats: [ 
    { 
     name: "Earl", 
     imgUrl: "src/img/earl.png" 
    }, 
    { 
     name: "Winnie", 
     imgUrl: "src/img/winnie.png" 
    }, 
    { 
     name: "Fellini", 
     imgUrl: "src/img/fellini.png" 
    } 
    ] 
// These dogs and cats are on our intial state, 
// but there are a few more things we need! 
}; 


export default function reducer(prevState = initialState, action) { 
    var newState = Object.assign({}, prevState) 

    console.log('initialState', typeof initialState) 
    switch (action.type) { 

    case PREVIEW_PET: 
     // console.log('newState', newState) 
     return Object.assign({}, prevState, { 
     petToPreview: action.pet 
     }); 
     break 
    case ADOPT_PET: 
     return Object.assign({}, prevState, { 
     petToAdopt: action.pet 
     }); 
     break 
    case ADD_NEW_DOG: 
     // console.log('action', action.dog) 
     // console.log('prevState.dogs', prevState.dogs) 
     newState.dogs = prevState.dogs.concat([action.dog]) 
     return newState; 
     break 
    case ADD_NEW_CAT: 
     // console.log('action', action.dog) 
     // console.log('prevState.dogs', prevState.dogs) 
     newState.cats = prevState.cats.concat([action.cat]) 
     return newState; 
     break; 
    default: 
     return prevState; 

    } 
    return initialState 
} 

,你可以在switch块之后看到我返回initialState 应该不是吧?

下面是redux.spec.js文件:

import { expect } from "chai"; 
import { createStore } from "redux"; 

// You will write these functions 
import { 
    previewPet, 
    adoptPet, 
    addNewDog, 
    addNewCat 
} from "../src/store/action-creators"; 
import reducer from "../src/store/reducer"; 

const DOGS = [ 
    { 
    name: "Taylor", 
    imgUrl: "src/img/taylor.png" 
    }, 
    { 
    name: "Reggie", 
    imgUrl: "src/img/reggie.png" 
    }, 
    { 
    name: "Pandora", 
    imgUrl: "src/img/pandora.png" 
    } 
]; 

const CATS = [ 
    { 
    name: "Earl", 
    imgUrl: "src/img/earl.png" 
    }, 
    { 
    name: "Winnie", 
    imgUrl: "src/img/winnie.png" 
    }, 
    { 
    name: "Fellini", 
    imgUrl: "src/img/fellini.png" 
    } 
]; 

function getRandomPet(pets) { 
    return pets[Math.floor(Math.random() * pets.length)]; 
} 

describe("Action creators",() => { 
    describe("previewPet",() => { 
    it("returns properly formatted action",() => { 
     const pet = getRandomPet(DOGS); 

     expect(previewPet(pet)).to.be.deep.equal({ 
     type: "PREVIEW_PET", 
     pet: pet 
     }); 
    }); 
    }); 

    describe("adoptPet",() => { 
    it("returns properly formatted action",() => { 
     const pet = getRandomPet(DOGS); 

     expect(adoptPet(pet)).to.be.deep.equal({ 
     type: "ADOPT_PET", 
     pet: pet 
     }); 
    }); 
    }); 

    describe("addNewDog",() => { 
    it("returns properly formatted action",() => { 
     const pet = getRandomPet(DOGS); 

     expect(addNewDog(pet)).to.be.deep.equal({ 
     type: "ADD_NEW_DOG", 
     dog: pet 
     }); 
    }); 
    }); 

    describe("addNewCat",() => { 
    it("returns properly formatted action",() => { 
     const pet = getRandomPet(CATS); 

     expect(addNewCat(pet)).to.be.deep.equal({ 
     type: "ADD_NEW_CAT", 
     cat: pet 
     }); 
    }); 
    }); 
}); // end Action creators 

describe("Reducer",() => { 
    let store; 

    beforeEach("Create the store",() => { 
    // creates a store (for testing) using your (real) reducer 
    store = createStore(reducer); 
    }); 

    it("returns the initial state by default",() => { 
    // In addition to dogs and cats, we need two more fields 
    expect(store.getState().petToPreview).to.be.an("object"); 
    expect(store.getState().petToAdopt).to.be.an("object"); 
    }); 

    describe("reduces on PREVIEW_PET action",() => { 
    it("sets the action's pet as the petToPreview on state (without mutating the previous state)",() => { 
     const prevState = store.getState(); 

     const pet = getRandomPet(DOGS); 
     const action = { 
     type: "PREVIEW_PET", 
     pet: pet 
     }; 
     store.dispatch(action); 

     const newState = store.getState(); 

     // ensures the state is updated properly - deep equality compares the values of two objects' key-value pairs 
     expect(store.getState().petToPreview).to.be.deep.equal(pet); 
     // ensures we didn't mutate anything - regular equality compares the location of the object in memory 
     expect(newState.petToPreview).to.not.be.equal(prevState.petToPreview); 
    }); 
    }); 

    describe("reduces on ADOPT_PET action",() => { 
    it("sets the action's pet as the petToAdopt on state (without mutating the previous state)",() => { 
     const prevState = store.getState(); 

     const pet = getRandomPet(DOGS); 
     const action = { 
     type: "ADOPT_PET", 
     pet: pet 
     }; 
     store.dispatch(action); 

     const newState = store.getState(); 

     expect(newState.petToAdopt).to.be.deep.equal(pet); 
     expect(newState.petToAdopt).to.not.be.equal(prevState.petToAdopt); 
    }); 
    }); 

    describe("reduces on ADD_NEW_DOG action",() => { 
    it("adds the new dog to the dogs array (without mutating the previous state)",() => { 
     const prevState = store.getState(); 

     const pet = getRandomPet(DOGS); 
     const action = { 
     type: "ADD_NEW_DOG", 
     dog: pet 
     }; 
     store.dispatch(action); 

     const newState = store.getState(); 

     expect(newState.dogs.length).to.be.equal(prevState.dogs.length + 1); 
     expect(newState.dogs[newState.dogs.length - 1]).to.be.deep.equal(pet); 
     expect(newState.dogs).to.not.be.equal(prevState.dogs); 
    }); 
    }); 

    describe("reduces on ADD_NEW_CAT action",() => { 
    it("adds the new cat to the cats array (without mutating the previous state)",() => { 
     const prevState = store.getState(); 

     const pet = getRandomPet(CATS); 
     const action = { 
     type: "ADD_NEW_CAT", 
     cat: pet 
     }; 
     store.dispatch(action); 

     const newState = store.getState(); 

     expect(newState.cats.length).to.be.equal(prevState.cats.length + 1); 
     expect(newState.cats[newState.cats.length - 1]).to.be.deep.equal(pet); 
     expect(newState.cats).to.not.be.equal(prevState.cats); 
    }); 
    }); 

    describe("handles unrecognized actions",() => { 
    it("returns the previous state",() => { 
     const prevState = store.getState(); 

     const action = { 
     type: "NOT_A_THING" 
     }; 
     store.dispatch(action); 

     const newState = store.getState(); 

     // these should be the same object in memory AND have equivalent key-value pairs 
     expect(prevState).to.be.an("object"); 
     expect(newState).to.be.an("object"); 
     expect(newState).to.be.equal(prevState); 
     expect(newState).to.be.deep.equal(prevState); 
    }); 
    }); 
}); // end Reducer 

提前感谢!

+0

嘿,我无法理解确切的问题,你想默认返回初始状态?,如果是的话发生了什么,你能解释一下吗 – mindaJalaj

+0

@mindaJalaj发生了什么似乎有最后一个测试没有通过。本质上'默认返回初始状态'不通过。 –

+0

我认为@jaihindhreddy已经很好地回答了问题,它工作吗? – mindaJalaj

回答

1
在测试用例

,测试用例默认的一个说

it("returns the initial state by default",() => { 
    // In addition to dogs and cats, we need two more fields 
    expect(store.getState().petToPreview).to.be.an("object"); 
    expect(store.getState().petToAdopt).to.be.an("object"); 
    }); 

意味着必须有附着在inital本身商店petTpPreview和petToAdapt protery。这可以通过将这两个添加为状态如下来完成。

​​

希望它有帮助!

+0

这就是我的朋友!简直不敢相信!它实际上说的很多'//这些狗和猫都处于我们的初始状态,但是还有一些我们需要的东西!'就在那里作为提示! 另外,我认为这就像保存状态的心理过渡一样,像在正常情况下一样,在Reux中保存状态,就像你刚刚演示的那样!谢谢! –

+0

不客气。希望你喜欢答案,事情很清楚。 – mindaJalaj

+0

确实!水晶! –

1

switch语句中的所有路径导致return,这意味着倒数第二行上的return initialState无法访问。 此外,您的newState不过是prevState的克隆,并且不是必需的。 移除,并把帮助功能switchcase一些ES6传播爱的结合,你的代码变得

const switchcase = cases => defaultValue => key => 
    (key in cases ? cases[key] : defaultValue); 
const reducer = (state = initialState, action) => 
    switchcase({ 
    [PREVIEW_PET]: { ...state, petToPreview: action.pet }, 
    [ADOPT_PET]: { ...state, petToAdopt: action.pet }, 
    [ADD_NEW_DOG]: { ...state, dogs: [...state.dogs, action.dog] }, 
    [ADD_NEW_CAT]: { ...state, cats: [...state.cats, action.cat] }, 
    })(state)(action.type); 

随着走了所有的混乱,这是昭然若揭,问题是,你的代码返回initialState事实对象如果action.type === undefined。而您的initialState对象只包含dogscats属性,而您的测试期望有petToPreviewpetToAdopt属性。

您可以在initialState中添加这些属性,或者您可以根据所需的功能更改测试。

0

默认情况下不应该返回以前的状态吗?默认情况下,reducer不关心动作,只是简单地返回它的当前状态,这在你的情况下是prevState。