Before, I simply mocked the API response since it had a custom hook inside that delivered the data, the "Loading..." message and, in case of failure, an error message. I used the "mockRejectedValue" method to simulate said rejection:
Information Panel Component:
function AgentInformationPanel({ agentID, renderPanel }) {
const { agent, loading, error } = useAgent(
'https://valorant-api.com/v1/agents/',
agentID
);
if (renderPanel)
return (
<div>
{
error && (
<div>
<p>Error: {error.message}</p>
</div>
)
}
</div>
// ...
)
Test:
import React from 'react';
import { render, screen } from '@testing-library/react';
import AgentInformationPanel from './AgentInformationPanel.js';
import agentsMock from '../../../agentsMock/agentsMock.js';
import axios from 'axios';
const agent = agentsMock[0];
const agentID = agent.uuid;
jest.mock('axios');
beforeEach(() => {
axios.get.mockResolvedValue({
data: { data: agent },
loading: true,
error: 'Something went wrong D:'
});
});
afterEach(() => {
axios.mockRestore();
});
test('Should render "Error" message when API call fails', async () => {
axios.get.mockRejectedValue(new Error('Something went wrong D:'));
render(<AgentInformationPanel agentID={agentID} renderPanel={true} />);
const errorElement = await screen.findByText(
'Error: Something went wrong D:'
);
expect(errorElement).toBeInTheDocument();
});
// Other tests...
But NOW that I refactored my code, and was making use of Context API, I also refactored all the test file for this same component. I was able to mock the Context data and all but when I try to run the test for mock a rejected call from the API then I don't really know how to make it work :/
App.js
import React from 'react';
import Header from './components/Header/Header.js';
import AgentsContainer from './components/AgentsContainer/AgentsContainer.js';
import AgentInformationPanel from './components/AgentInformationPanel/AgentInformationPanel.js';
import { PanelContextProvider } from './contexts/Panel.context.js';
import './App.css';
function App() {
return (
<main>
<Header />
<PanelContextProvider>
<AgentsContainer />
<AgentInformationPanel />
</PanelContextProvider>
</main>
);
}
export default App;
Panel Context:
import React, { useState, createContext } from 'react';
import { useAgent } from '../hooks/useAgent.js';
export const PanelContext = createContext();
export function PanelContextProvider({ children }) {
const [id, setId] = useState();
const [renderPanel, setRenderPanel] = useState(false);
const { agent, loading, error } = useAgent(
'https://valorant-api.com/v1/agents/',
id
);
// This and the "restartDataForPanel" are just for a few buttons in the app.
function setDataForPanel(agentId) {
setId(agentId);
setRenderPanel(true);
}
function restartDataForPanel() {
setId();
setRenderPanel(false);
}
return (
<PanelContext.Provider
value={{
agent,
loading,
error,
renderPanel
}}>
{children}
</PanelContext.Provider>
);
}
Information Panel Component (REF):
import { PanelContext } from '../../contexts/Panel.context.js';
function AgentInformationPanel() {
const { agent, loading, error, renderPanel } = useContext(PanelContext);
if (renderPanel)
return (
<div>
{
error && (
<div>
<p>Error: {error.message}</p>
</div>
)
}
</div>
// ...
Test (REF):
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import AgentInformationPanel from './AgentInformationPanel.js';
import agentsMock from '../../agentsMock/agentsMock.js';
import { PanelContext } from '../../contexts/Panel.context.js';
const agent = agentsMock[0];
// I used this object to run other tests, and it worked.
const Context = {
agent: agent,
loading: true,
error: 'Something went wrong! D:',
renderPanel: true
};
test('Should render "Error" message when API call fails', async () => {
const rejectContext = {
agent: null,
loading: true,
error: 'Something went wrong! D:',
renderPanel: true
};
render(
<PanelContext.Provider value={rejectContext}>
<AgentInformationPanel />
</PanelContext.Provider>
);
const errorElement = await screen.findByText(
'Error: Something went wrong D:'
);
expect(errorElement).toBeInTheDocument();
});
// Othe tests...
Also, the "useAgent" custom hook is the same for both versions, but if you want to know how the "useAgent" hook is built:
useAgent Custom Hook:
import { useState, useEffect } from 'react';
import axios from 'axios';
export function useAgent(url, id) {
const [agent, setAgent] = useState();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
useEffect(() => {
setAgent();
if (!id) return;
setLoading(true);
axios
.get(url + id)
.then(({ data: { data } }) => {
setAgent(data);
})
.catch(error => setError(error))
.finally(() => setLoading(false));
}, [id]);
return { agent, loading, error };
}
I already found the problem, it was the following: