DEV Community

beerpacks
beerpacks

Posted on

React Component Testing

I have a complicated question about React development, creating component and testing them.

I created an app using React and Typescript. It worked but now I'm interest in testing that app using Cypress. I can override my API Calls and test the software but as I'm reading, I try to separate the component from API for betting architecture.

Here's an example of fetching and show a data list.

Model

import { useEffect, useState } from "react"
import * as SquadsAPI from "../../servercalls/squadsdatafetcher";
import { ISquadPlayer } from "../../../../common/squads";
type UIState = 'show' | 'loading' | 'error'

export const useSquadsPageModel = (careerId: string): {
    isLoading: boolean,
    isReady: boolean,
    isOffline: boolean,
    squadList: ISquadPlayer[],
    nationnalities: INationnality[],
    avgPotentialPerPosition: IAvgPotentialPosition[]
    deletePlayer: (playerId: string) => void
} => {
    const [uiState, setUiState] = useState<UIState>('loading');
    const [playerList, setPlayerList] = useState<ISquadPlayer[]>([]);
    useEffect(() => {
        const loadSquads = async () => {
            setUiState('loading')
            try {
                const request = await SquadsAPI.fetchSquads({
                    careerId: careerId
                })
                if (!request.success) {
                    throw new Error('server request error')
                }
                setPlayerList(request.squadsPlayers.map(player => {
                    if (parseInt(player.potential) > 0)
                        return player;
                    return {
                        ...player,
                        potential: ((parseInt(player.maxPotential) - parseInt(player.minPotential)) / 2 + parseInt(player.minPotential)).toFixed(0)
                    }
                }))
                setUiState('show')
            } catch (err) {
                setUiState('error')
            }
        }
        loadSquads();
    }, [careerId]);

    const onDeletePlayer = async (playerId: string) => {
        const newList = playerList.filter(player => player.id !== playerId);
        setPlayerList(newList);
    }
    return {
        isLoading: uiState === 'loading',
        isReady: uiState === 'show',
        isOffline: uiState === 'error',
        squadList: playerList,
        deletePlayer: onDeletePlayer
    }
}
Enter fullscreen mode Exit fullscreen mode

View

const SquadsPageComponent = () => {
    const classes = useSquadsPageStyle();
    const buttonClass = useButtonStyle();
    const { selectedCareerId } = useContext(CareersContext);
    const {
        isLoading,
        squadList,
    } = useSquadsPageModel(selectedCareerId);

    if (isLoading) {
        return (
            <LoadingComponent />
        )
    }

    return (
        <div className={classes.mainContent}>
            <div className={classes.commandLayout}>
                <Link className={buttonClass.greenBorderedButton} to={SitesRoutes.NewRecruitPlayerPage.link}>Add Recruits</Link>
                <Link className={buttonClass.greenBorderedButton} to={SitesRoutes.NewSquadPlayerPage.link}>Add Player</Link>
            </div>
            <SquadsTable players={squadList} />
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

I would like some tips to refactor my code with the test using cypress.

Would it be a better approach to send my {UiState} from the model with the array of data to another component (2 parameters in) ?
-My page component would not have the if loading, it will only call my model and send everything as props to a single component.

Or inside my Page component, keep it with the if statement ?

It's easy to find on use a design pattern for that but how to bring all to together for the "frontend" unit testing, component testing and End to End testing while thinking in architecture for best scaling and maintaining the software.

Hope I'm as clear as possible for my question and my explanation.

Thank in advance.

Top comments (0)