Just got done doing some testing and I want to write about the important aspects of it.
ucabGoSlice.js
The ucabGoSlice handles all the functions that update the state of the ucabGo store. Functions like onSetActiveProduct
, onUpdateProduct
, etc. It also holds the state of the store like stores, orders, clients, etc.
To test this, you can create a folder of fixtures in the test suite.
As you can see, you can create 'test subjects' or some states than can be used to test your slice.
Since I am lazy and I don't feel like explaining all the code, I'll just show the tests below.
import { onAddNewProduct, onDeleteProduct, onLoadProducts, onSetActiveProduct, onUpdateProduct, ucabGoSlice } from "../../../src/store/ucabGo/ucabGoSlice"
import { appWithActiveProductState, appWithProductsState, initialState, products } from "../../__fixtures__/ucabGoStates";
describe('tests in ucabGoSlice', () => {
test('should return default state', () => {
expect(ucabGoSlice.getInitialState()).toEqual(initialState)
});
test('onSetActiveProduct should activate a product', () => {
const state = ucabGoSlice.reducer(appWithProductsState, onSetActiveProduct(products[0]))
expect(state).toEqual(appWithActiveProductState);
});
test('should add a new product to the state', () => {
const newProduct = {
id: '4',
name: 'Arroz con Pollo',
desc: 'Hecho en casa',
img: 'http://res.clouiwerwesdfojoidf',
active: true,
}
const state = ucabGoSlice.reducer(appWithProductsState, onAddNewProduct(newProduct))
expect(state.products).toEqual([...products, newProduct]);
})
test('should update the product', () => {
const updatedProduct = {
id: '1',
name: 'Arroz con Pollo',
desc: 'Hecho en casa',
img: 'http://res.clouiwerwesdfojoidf',
active: true,
}
const state = ucabGoSlice.reducer(appWithProductsState, onUpdateProduct(updatedProduct));
expect(state.products).toContain(updatedProduct);
})
test('should delete a product', () => {
const state = ucabGoSlice.reducer(appWithActiveProductState, onDeleteProduct());
expect(state.products).not.toContain(products[0])
expect(state.activeProduct).toBe(null)
})
test('should load products', () => {
const state = ucabGoSlice.reducer(initialState, onLoadProducts(products));
expect(state.isLoadingProducts).toBeFalsy();
expect(state.products).toEqual(products)
})
})
FabAddNew
I also started a test in a react Component, where I used the React Testing Library.
The test is very minimal but it shows something important.
render(
<Provider store={store}>
<FabAddNew />
</Provider>
);
expect(fireEvent.click(screen.getByRole("button"))).toBeTruthy();
This is the component I am testing:
export const FabAddNew = () => {
const { openProductModal } = useUiStore();
const handleClickNew = () => {
openProductModal();
};
return (
<button
className="btn btn-success fab"
onClick={handleClickNew}
style={{ boxShadow: "rgba(149, 157, 165, 0.2) 0px 8px 24px" }}
>
<i className="fas fa-plus"></i>
</button>
);
};
The render method allows us to simulate the rendering of a React component. But the FabAddNew is a component that affects the store. So we wrap it on <Provider>
tags.
Then the fireEvent.click(screen.getByRole("button"))
simulates the click of an element.
Sadly, I wanted to test that handleClickNew
was being executed when the component is clicked, but I don't know how at the moment. 😢
UseUiStore
Now here it gets weird. UseUiStore holds 2 functions for handling the isProductModalOpen
state. And we want to test that these functions work.
First off, we must create a 'mockStore' that kinda simulates our store.
const getMockStore = ( initialState ) => {
return configureStore({
reducer: {
ui: uiSlice.reducer
},
preloadedState: {
ui: {...initialState}
}
})
}
To make sure that we are getting the default state and it is what we expect:
const mockStore = getMockStore({ isProductModalOpen: false });
const { result } = renderHook( () => useUiStore(), {
wrapper: ({children}) =>
<Provider store={ mockStore }>
{children}
</Provider>
});
expect(result.current).toEqual({
isProductModalOpen: false,
openProductModal: expect.any(Function),
closeProductModal: expect.any(Function),
});
As you can see, we must wrap this in a wrapper because it affects the store.
Now to check if the states are being changed correctly:
const { openProductModal } = result.current;
act( () => {
openProductModal()
});
We copy the mockStore
and {result}
lines of the first test and use act()
to update the state.
🥶🥶🥶🥶🥶🥶🥶