I am new to Jest, I mostly use cypress to test but I want to learn how to use jest/react-testing-library, and I am getting the following warning. I have tried searching about how to solve it and the warning remains there. As a note, I am testing an already finished component.
In Home.test.tsx
describe("Testing static content", () => {
test('renders Good Morning text', async () => {
await act(async () => {
await supabase
.from('habits')
.select(`*, habit_types (*)`)
.eq("userId", 1);
render(<StartingPageContent />);
});
const header = await screen.findByTestId('header');
expect(header.textContent).toContain("Good Morning");
});
});
I also tried just leaving render(<StartingPageContent />); without any of the supabase stuff and without the await/async in the act(() => {}); and it did not work either.
Since it is talking about updates I though that it might have to do something with setState() and the useEffect, but I am unsure.
useEffect and setStates() in StartingPageContent
useEffect(() => {
fetchProfile();
fetchHabits();
fetchDays();
return () => {
setProfile({});
setHabits([]);
setHabitDays([]);
};
}, [user]);
async function fetchProfile() {
const profileData = await supabase.auth.user()
if (!profileData) {
router?.push('/signin')
} else {
setProfile(profileData!);
}
}
async function fetchHabits() {
const { data, error } = await supabase
.from<Habits>('habits')
.select(`*, habit_types (*)`)
.eq("userId", user ? user!.id : "");
setHabits(data);
}
async function fetchDays() {
const { data, error } = await supabase
.from<HabitDay>('habit_days')
.select('*')
// if(data == null || data == undefined) {
// return data;
// }
setHabitDays(data);
}
Entire component, if necessary
import React, { useState, useEffect } from 'react';
// import { useDispatch, useSelector } from 'react-redux';
// import { getAllHabits, updateSingleHabitCompletion } from '../../store/habit';
// import { getAllHabitDays } from '../../store/habitDay';
import styles from './starting-page.module.css';
import BasicModal from '../modal/modal';
import Habit from '../habit/habit';
import CloseIcon from '@mui/icons-material/Close';
import CircleRoundedIcon from '@mui/icons-material/CircleRounded';
import UpdateHabit from '../habit/update-habit';
import Delete from '../habit/delete';
import { supabase } from '../../pages/api/client';
import { useRouter } from 'next/router';
// import ProgressBar from 'react-bootstrap/ProgressBar'
// import useSWR from 'swr';
// import { useSession } from 'next-auth/react';
// import { Container, Row, Col } from 'react-bootstrap';
type User = {
id?: string;
email?: string;
user_metadata?: {
name?: string;
}
}
const nullUser: User = {
id: "1",
email: "null",
};
type Habits = {
id: string;
title: string;
description: string;
color: string;
habitTypeId: string;
userId: string;
habit_types: {
data: null;
id: number;
name: string;
}
}
type HabitDay = {
id: number;
dayId: number;
habitId: string;
isCompleted: boolean;
userId: string;
}
function StartingPageContent() {
// const dispatch = useDispatch();
// Getting session user for user.id
// const { data: session, loading: status } = useSession();
// Obtaining global state thanks to redux store
// const habits = useSelector(state => state.habits);
// const habitDay = useSelector(state => state.habitDays);
// modal configuration state
const router = useRouter();
const [showModal, setShowModal] = useState(false);
const [showUpdateHabitModal, setShowUpdateHabitModal] = useState<boolean>(false);
const [habitId, setHabitId] = useState<string>('1');
const [profile, setProfile] = useState<User>(nullUser);
const [habits, setHabits] = useState<Habits[] | null >(null);
const [habitDays, setHabitDays] = useState<HabitDay[] | null>(null);
const user = supabase.auth.user();
// handleChange is in charge of obtaining an array with the dayId, and completed bool value to be used on the updateSingleHabitCompletion dispatch
const [handleChange, setHandleChange] = useState<any[]>([]);
// filter out values that have been completed
// const completedHabitsArray = Object.values(habitDay)?.filter(day => (day.isCompleted) && day.userId === session.id);
// calculate the number of completed habits, this will be used as the current value
/*
let numberOfCompletedHabits be the number of completed habits
let maxValue be the total number of habits per user
let percentagePerHabit be the percentage that each habit will cover
let initialValue be the initial value of the progress bar
numberOfCompletedHabits = 1
maxValue = 4
percentagePerHabit = 100 / 4 = 25
initialValue = 25 * 1 = 25
The remaining 75% will be used by the rest of the 3 habits, since each completed habit takes 25% of the progress bar
*/
// const numberOfCompletedHabits = completedHabitsArray?.length;
// const maxValue = Object.values(habitDay)?.filter(day => day.userId === session.id).length
// let percentagePerHabit = 100 / maxValue;
// let initialValue = (percentagePerHabit && numberOfCompletedHabits) ? percentagePerHabit * numberOfCompletedHabits : 0;
// useEffect(() => {
// dispatch(getAllHabitDays());
// dispatch(getAllHabits());
// }, [dispatch])
useEffect(() => {
fetchProfile();
fetchHabits();
fetchDays();
return () => {
setProfile({});
setHabits([]);
setHabitDays([]);
};
}, []);
async function fetchProfile() {
const profileData = await supabase.auth.user()
if (!profileData) {
router?.push('/signin')
} else {
setProfile(profileData!);
}
}
async function fetchHabits() {
const { data, error } = await supabase
.from<Habits>('habits')
.select(`*, habit_types (*)`)
.eq("userId", user ? user!.id : "");
setHabits(data);
}
async function fetchDays() {
const { data, error } = await supabase
.from<HabitDay>('habit_days')
.select('*')
// if(data == null || data == undefined) {
// return data;
// }
setHabitDays(data);
}
async function onSubmit(e: React.FormEvent) {
e.preventDefault();
const [dayId, completed] = handleChange;
const id = dayId;
const isCompleted = completed
const { data, error } = await supabase
.from<HabitDay>('habit_days')
.update({
isCompleted: !isCompleted
})
.eq('id', id)
window.location.reload();
// await dispatch(updateSingleHabitCompletion(id, isCompleted));
// window.location.reload(true);
}
/*
since today returns a datetime object, I first converted it to a string and
then I used the split method to obtain the day, month, date of the current day(for example 17) and time
and set those 4 values into variables that are dynamically used in an <h1></h1>
I did the same thing for a date that it is always 6 days ahead of the current date
*/
const today = new Date().toString();
const arrayDate = today.split(" ");
const firstDay = arrayDate[0];
const firstMonth = arrayDate[1];
const firstDate = arrayDate[2];
const time = arrayDate[4];
const endOfWeek = new Date(Date.now() + 6 * 24 * 60 * 60 * 1000).toString();
const arrayEndOfWeek = endOfWeek.split(" ");
const lastDay = arrayEndOfWeek[0];
const lastMonth = arrayEndOfWeek[1];
const lastDate = arrayEndOfWeek[2];
// currentDay obtains a number from 0-6 where 0 is Sunday and 6 is Saturday, but since my ids in db go from 1-7, I added a +1
const currentDay = new Date().getDay() + 1;
// array to be used to determine if we are in morning or afternoon time, then set greetings to be Good Morning if the time starts with any of those elements in the morningTimesArray
const morningTimesArray = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11"];
let greetings = "";
/*
function to allow the completion of a habit if we are on the current day and previous days, future days should be disabled
So if my weekly frequency was Monday, Wednesday and Friday, buttons for completion should be enabled form Monday and Wednesday(if today is Wednesday)
assuming that I forgot to set the habit as complete on Monday, but Friday cannot be set as complete as we are on Wednesday
the id is the id of the day. So, Sun has an id of 1, Mon has an id of 2, etc.
*/
let dayValue: string;
function isDisabled(id: number) {
if (id === 1) {
dayValue = "Sun";
}
else if (id === 2) {
dayValue = "Mon";
}
else if (id === 3) {
dayValue = "Tue";
}
else if (id === 4) {
dayValue = "Wed";
}
else if (id === 5) {
dayValue = "Thu";
}
else if (id === 6) {
dayValue = "Fri";
}
else {
dayValue = "Sat";
}
return id > currentDay;
}
/*
Components to rendered X icon if the habit type is Not-To-Do, and a circle if it is To-Do
The color depends on what the user said he/she wanted the color to be, just like how Google Calendar does it
*/
interface Props {
color: string;
title: string;
}
const ToDo: React.FC<Props> = ({ color, title }) => {
return (
<>
<CircleRoundedIcon style={{ color: color }}></CircleRoundedIcon>
<p>{title}</p>
</>
)
}
const NotToDo: React.FC<Props> = ({ color, title }) => {
return (
<>
<CloseIcon style={{ color: color }}></CloseIcon>
<p>{title}</p>
</>
)
}
return (
<div className={styles.dashboard}>
<div className={styles.dashboard__content}>
<section className={styles.content__left}>
<div className={styles.meet}>
<h1 data-testid="header" className={styles.meet__title}>{morningTimesArray.map(day => {
if (time.startsWith(day)) {
greetings = `Good Morning, ${profile ? profile?.user_metadata?.name : ""}`
}
})
}{greetings ? greetings : `Good Afternoon, ${profile?.user_metadata?.name}`}</h1>
<h5 className={styles.meet__subtitle}>Add your Bedtime</h5>
</div>
<div className={styles.filters}>
<div className={styles.filters__buttons}>
<button className={`${styles.button__action} ${styles.button__active}`}>Week</button>
<button className={styles.button__action}>Month</button>
<button className={styles.button__action}>Year</button>
<button className={styles.button__action}>All time</button>
</div>
<button id="modal-btn" className={styles.button__ghost} onClick={() => setShowModal(true)} >+ Add Habit</button>
<BasicModal show={showModal} setShow={setShowModal} title={"Add Habit"}>
<Habit />
</BasicModal>
</div>
<div className={styles.calendar}>
<div className={styles.calendar__filterData}>
<div className={styles.calendar__selectorDay}>
<button className={styles.arrow__left}>
<svg role="img" viewBox="0 0 320 512" className={styles.arrow__svg} width="10px">
<path d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z" className="">
</path></svg>
</button>
<button className={styles.arrow__right}>
<svg role="img" viewBox="0 0 320 512" className={styles.arrow__svg} width="10px">
<path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z">
</path>
</svg>
</button>
<h1 className={styles.calendar__day}>{firstDay}, {firstMonth} {firstDate} - {lastDay}, {lastMonth} {lastDate}</h1>
</div>
<div className={styles.icon__filters}>
<div className={`${styles.bars} ${styles.bars__active}`}>
<svg role="img" viewBox="0 0 512 512" className={styles.grid__svg} width="20px">
<path d="M488 351H24c-13.3 0-24 10.7-24 24v80c0 13.3 10.7 24 24 24h464c13.3 0 24-10.7 24-24v-80c0-13.3-10.7-24-24-24zm-24 80H289v-32h175v32zm24-240H24c-13.3 0-24 10.7-24 24v80c0 13.3 10.7 24 24 24h464c13.3 0 24-10.7 24-24v-80c0-13.3-10.7-24-24-24zm-24 80H161v-32h303v32zm24-240H24C10.7 31 0 41.7 0 55v80c0 13.3 10.7 24 24 24h464c13.3 0 24-10.7 24-24V55c0-13.3-10.7-24-24-24zm-24 80H353V79h111v32z">
</path>
</svg>
</div>
<div className={styles.grid}>
<svg className={styles.grid__svg} role="img" viewBox="0 0 512 512" width="20px">
<path d="M96 288H32c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zM96 96H32c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32zm160 0h-64c-17.67 0-32 14.33-32 32v64c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-64c0-17.67-14.33-32-32-32z">
</path>
</svg>
</div>
</div>
</div>
</div>
{/* <div className={styles.container__progress}>
<ProgressBar animated now={initialValue} label={`${Number(initialValue.toFixed(1))}`} />
</div> */}
<hr />
{/* <Container>
<Row>
<Col xs={2}></Col>
<Col>Sun</Col>
<Col>Mon</Col>
<Col>Tue</Col>
<Col>Wed</Col>
<Col>Thu</Col>
<Col>Fri</Col>
<Col>Sat</Col>
<Col xs={2}></Col>
</Row>
</Container> */}
{habits?.map(habit => (
<div className={styles.habit__container} key={habit.id}>
{profile.id === habit.userId && (
<>
{/* <Container className={styles.container}> */}
{/* <Row> */}
{/* <Col xs={2}> */}
{habit?.habit_types?.name === "To-Do" ? <ToDo color={habit.color} title={habit.title} /> : <NotToDo color={habit.color} title={habit.title} />}
{/* </Col> */}
{/* <Col className={styles.habit__container}> */}
{habitDays?.map(day => {
return (
<div key={day.id}>
{habit.id === day.habitId && (
<>
<form onSubmit={onSubmit}>
{!day.isCompleted ?
<button className={styles.btn__containers} disabled={isDisabled(day.dayId)} type="submit" onClick={() => setHandleChange([day.id, day.isCompleted])}>{dayValue}</button>
: <button className={styles.btn__containers} disabled={isDisabled(day.dayId)} style={{ color: habit.color }} type="submit" onClick={() => setHandleChange([day.id, day.isCompleted])}>{dayValue}</button>}
</form>
</>
)}
</div>
)
}
)}
{/* </Col> */}
{/* // <Col xs={2}></Col> */}
{/* </Row> */}
{/* </Container> */}
{habits?.map((data, index) => {
if (data.id === habit.id) {
return (
<div className={styles.habit__container} key={index}>
<button id="habit-edit-btn" onClick={() => {
setShowUpdateHabitModal(true);
setHabitId(data.id);
}}>Edit</button>
<Delete id={data.id} />
{data.id === habitId ?
<>
<BasicModal show={showUpdateHabitModal} setShow={setShowUpdateHabitModal} title={"Edit Habit"}>
<UpdateHabit idValue={data.id} titleValue={data.title} descriptionValue={data.description} colorValue={data.color} typeIdValue={data.habitTypeId} />
</BasicModal>
</>
: null}
</div>
)
}
})}
</>
)}
</div>
))}
<div className={styles.chars}>
</div>
</section>
{/* <section className={styles.content__right}>
right
</section> */}
</div>
</div>
)
}
export default StartingPageContent;
I have tried many things, and even though it passes the tests, I want to understand the meaning of the warning and how to fix it. Thanks in advance!