Issue while testing component that uses `createSelector`
I have a weird issue which is causing some of my tests to fail. I am not sure if this is a problem with reselect or with redux-mock-store (or with me)
I created a simplified version of my problem on CodeSandbox: https://codesandbox.io/s/wizardly-wave-nkuvw?file=/src/Component.js
Here is the problem:
I have a component (Component.js) which uses createSelector to get a value from the store:
const itemSelector = (state) => state.items;
const itemForId = createSelector(
[itemSelector, (state, id) => id],
(items, id) => items.find((item) => item.id === id)
);
export default function Component() {
const item = useSelector((state) => itemForId(state, 1));
return <div>{item.value}</div>;
}To test this component I created 2 different tests (Component.test.js) in which I use react-mock-store to mock my store.
Case 1: Mock item with ID 1 and value 1
Case 2: Mock item with ID 1 and value 2
When I create a store by calling mockStore with these items directly everything works as expected.
it("Case 1 - renders value 1 for item 1 when offering new object to mockStore", async () => {
const store = mockStore({
items: [
{
id: 1,
value: "Value 1"
}
]
});
render(
<Provider store={store}>
<Component />
</Provider>
);
expect(await screen.findByText("Value 1"));
});
it("Case 2 - renders value 2 for item 1 when offering new object to mockStore", async () => {
const store = mockStore({
items: [
{
id: 1,
value: "Value 2"
}
]
});
render(
<Provider store={store}>
<Component />
</Provider>
);
expect(await screen.findByText("Value 2"));
});Case 1 returns value 1 and Case 2 returns value 2
Now, in my real app I have other parts of my state that I have to mock so I start from a common object (initialState) and append these items to it. I recreated that here as Case 3 and 4:
const initialState = {
items: []
};
it("Case 3 - renders value 1 for item 1 when offering copied object to mockStore", async () => {
let state = initialState;
state.items = [
{
id: 1,
value: "Value 1"
}
];
const store = mockStore(state);
render(
<Provider store={store}>
<Component />
</Provider>
);
expect(await screen.findByText("Value 1"));
});
it("Case 4 - renders value 2 for item 1 when offering copied object to mockStore", async () => {
let state = initialState;
state.items = [
{
id: 1,
value: "Value 2"
}
];
const store = mockStore(state);
render(
<Provider store={store}>
<Component />
</Provider>
);
expect(await screen.findByText("Value 2"));
});Now Case 4 fails because the selector returns the value from Case 3 (value 1). Some observations:
- running only the last test does succeed
- initialState is const so it should not be able to carry over data from Case 3 to Case 4
- if I print out the state of the failing test before creating the mockStore it show the correct item (value 2)
- if I skip
createSelectorand just useuseSelectorit does work correctly:
const item = useSelector((state) =>
state.items.find((item) => item.id === 1)
);This last observation leads me to believe this might be an issue with Reselect.
I would appreciate some help. Thank you.
Source: reduxjs/reselect