DEV Community

Kinga
Kinga

Posted on • Edited on

1

Jest + React component

Test driven development

If you are new to TDD, or jest, please have a look at the Resources section at the end of this post.

The code

I have a React component, SiteBreadcrumbs.tsx that is using BreadcrumbsHelper class to generate site breadcrumbs.

SiteBreadcrumbs.tsx

import BreadcrumbsHelper from '../../../../utils/BreadcrumbsHelper';
import { BreadcrumbDataProvider } from '../../../../dal/BreadcrumbDataProvider';
import { PageContextDataProvider } from '../../../../dal/PageContextDataProvider';

React.useEffect(() => {
    //...
    const helper = new BreadcrumbsHelper(dataProvider, pageContextProvider);

    helper.getBreadcrumbs()
        .then((result) => {
             setLinkItems(result);
         })
         .catch((error) => {
             console.log(error);
          });
}, []);
Enter fullscreen mode Exit fullscreen mode

BreadcrumbsHelper.ts

export default class BreadcrumbsHelper {

constructor(protected dataProvider: BreadcrumbDataProvider, protected pageContextProvider: PageContextDataProvider) {}

    public getBreadcrumbs = async (): Promise<IBreadcrumbItem[]> => {
        const items: IBreadcrumbItem[] = [];
        //...
        return items;
    }
    //...
}
Enter fullscreen mode Exit fullscreen mode

Tests

Not so great approach

Jest allows mocking partials, so I could mock the BreadcrumbsHelper.getBreadcrumbs() method using the following code:

SiteBreadcrumbs.test.tsx
jest.mock('../../src/utils/BreadcrumbsHelper', () => {
    const originalModule = jest.requireActual('../../src/utils/BreadcrumbsHelper');
    return {
        __esModule: true, //<- required for ES modules
        ...originalModule,
        default: jest.fn().mockImplementation(() => {
            return {
                getBreadcrumbs: jest.fn().mockImplementation(() => {
                    return Promise.resolve([];
                })
            };
        }),
    };
});

Enter fullscreen mode Exit fullscreen mode

But in my tests, I want to cover different cases: breadcrumbs for site's welcome page, site's (other) page, subsite, etc. And I certainly won't be creating separate files just to cover them.

The right approach

You will find many examples on how to mock functions, but the complicated part here is that getBreadcrumbs is a class method and is not exported as a function.

Jest requires the jest.mock('../../src/utils/BreadcrumbsHelper') to be above the tests, but I can change the getBreadcrumbs mock for each test using.

(BreadcrumbsHelper as jest.Mock).mockReturnValueOnce({
    getBreadcrumbs: jest.fn().mockResolvedValue(BreadcrumbsConfig.TeamSiteWelcomePage)
})
Enter fullscreen mode Exit fullscreen mode
SiteBreadcrumbs.test.tsx
import BreadcrumbsHelper from '../../src/utils/BreadcrumbsHelper';
jest.mock('../../src/utils/BreadcrumbsHelper')

const BreadcrumbsConfig = {
    TeamSiteWelcomePage: [
        { "text": "Intranet", "key": "1", "href": "https://contoso.sharepoint.com/sites/Intranet"}
    ],
    TeamSiteInsightsPage: [
        { "text": "Intranet", "key": "1", "href": "https://contoso.sharepoint.com/sites/Intranet"},
        { "text": "Insights", "key": "2", "href": ""}
    ],
    //...
}

describe('SiteBreadcrumbs', () => {
    it('should render breadcrumbs on TeamSite WelcomePage', async () => {
        (BreadcrumbsHelper as jest.Mock).mockReturnValueOnce({
            getBreadcrumbs: jest.fn().mockResolvedValue(BreadcrumbsConfig.TeamSiteWelcomePage)
        })
        await act(async () => {
            siteBreadcrumbs = render(<SiteBreadcrumbs pageContext={mockPageContext} spfiContext={mockSPFI} />);
        });
        //...
    });

    it('should render breadcrumbs on TeamSite InsightsPage', async () => {
        (BreadcrumbsHelper as jest.Mock).mockReturnValueOnce({
            getBreadcrumbs: jest.fn().mockResolvedValue(BreadcrumbsConfig.TeamSiteInsightsPage)
        })

        await act(async () => {
            siteBreadcrumbs = render(<SiteBreadcrumbs pageContext={mockPageContext} spfiContext={mockSPFI} />);
        });
        //...
    });
}
Enter fullscreen mode Exit fullscreen mode

Resources

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay