Problem I'm writing an end-to-end test in Cypress for my React app. The app fetches posts from different Reddit api categories based on navigation clicks. However, in my test, after clicking on a navigation link, the expected API request for that category is made, but then the app incorrectly re-fetches the default category (popular) in the cypress test. (but not on the actual app itself)
Expected Behavior When the app first mounts, it should fetch the default category (popular).
When a navigation link is clicked (e.g., "CSS"), it should fetch that category (CSS).
In the test below it should not re-fetch popular again unless the user navigates back.
NOTE: THIS ONLY HAPPENS IN THE TEST AND NOT IN THE ACTUAL APP ITSELF.
Actual Behavior in Cypress Test The test result shows the following fetch sequence:
(fetch) GET 200 https://www.reddit.com/r/popular.json?limit=10 // Initial fetch on mount
click // Clicking on a category link (e.g., "CSS")
pause
(fetch) GET 200 https://www.reddit.com/r/CSS.json?limit=10 // Correctly fetching "CSS"
(fetch) GET 200 https://www.reddit.com/r/popular.json?limit=10 // Unexpected re-fetch of "popular"
The last fetch (popular
) should not happen after clicking on "CSS".
Here’s a simplified version of my component logic:
// Async thunk to fetch Reddit data based on category
export const fetchRedditData = createAsyncThunk(
'reddit/fetchRedditData',
async (category = 'popular') => {
try {
const response = await fetch(
`https://www.reddit.com/r/${category}.json?limit=10`
);
if (!response.ok) {
throw new Error('Failed to fetch Reddit data');
}
const data = await response.json();
return data.data.children.map((post) => post.data);
} catch (error) {
console.error(error);
throw error;
}
}
);
This code handles the click on the category title in the nav bar heading
import { subreddits } from '../data/subreddits';
import { useDispatch, useSelector } from 'react-redux';
import { fetchRedditData, setQuery } from '../store/redditSlice';
import { useLocation, useNavigate } from 'react-router-dom';
const handleSubRedditClick = (category) => {
// Only navigate when not already at root
if (location.pathname !== '/') {
navigate('/'); // Navigate to root if necessary
}
// Set the search query to the null when a subreddit is clicked
if (query !== null) {
dispatch(setQuery(null));
}
dispatch(fetchRedditData(category));
};
return (
<div className='subreddits'>
{subreddits.map((subreddit) => (
<SubReddit
key={subreddit.id}
subreddit={subreddit}
handleSubRedditClick={handleSubRedditClick}
/>
))}
</div>
);
};
The useEffect calls fetchRedditData() from the redditSlice when app mounts
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchRedditData } from '../store/redditSlice';
import { RedditPost } from './RedditPost';
import { createSelector } from 'reselect';
export const RedditPosts = () => {
// Input selectors
const selectPosts = (state) => state.reddit.posts;
const selectStatus = (state) => state.reddit.status;
const selectQuery = (state) => state.reddit.query;
// Memoized selector
const selectRedditState = createSelector(
[selectPosts, selectStatus, selectQuery],
(posts, status, query) => ({
posts,
status,
query,
})
);
// Use the memoized selector
const { posts, status, query } = useSelector(selectRedditState);
// Rename query to searchTerm for clarity
const searchTerm = query;
//dispatch function to dispatch actions
const dispatch = useDispatch();
useEffect(() => {
//fetch the Reddit data when the component mounts
if (status === 'idle') {
dispatch(fetchRedditData());
}
}, [status, dispatch]);
// Filter the posts based on the search term
const filteredPosts = posts.filter((post) =>
searchTerm ? post.title.toLowerCase().split(' ').includes(searchTerm) : true
);
return (
<div>
<h1>Reddit Posts</h1>
{status === 'loading' && <p>Loading...</p>}
{status === 'failed' && <p>Failed</p>}
{status === 'succeeded' &&
(posts.length === 0 ? (
<p>No posts available</p>
) : filteredPosts.length > 0 ? (
filteredPosts.map((post) => <RedditPost key={post.id} post={post} />)
) : (
<p>No posts found</p>
))}
</div>
);
};
Why is my app fetching the default category (popular
) again after switching categories in the test? How can I ensure it only fetches the selected category? Is there a possible re-render issue, or should I adjust my test approach?
Any insights or suggestions are appreciated!
I suspect it was something to do with either:
fetchdata from the redditSlice
useEffect when mounting
handling the click
I could be wrong, but I have tried making changing in these 3 mains areas without any luck
It looks like the cy.visit() was pointing to the wrong url: fixed