Skip to content

renderHook does not work with React Magnetic DI wrapper #917

Open
@haskellcamargo

Description

@haskellcamargo
  • react-hooks-testing-library version: 8.0.1
  • react version: 16.13.1
  • react-dom version: 16.13.1

React Magnetic DI is a library that allows dependency injection in React components and functions for testing purposes.

It looks like the wrappers for renderHook and render (from @testing-library/react) behave quite differently. While render works with custom providers other than the React context, somehow renderHook fails to do so.

renderHook does not work when a React Magnetic DI provider is used as a wrapper.

Reproducible example

import React, { type ReactElement, type ComponentType, type ReactNode } from 'react';
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { injectable, di, DiProvider, type Dependency } from 'react-magnetic-di';

const createRtlDiWrapper =
    (use: Dependency[]): ComponentType<{ children: ReactNode }> =>
    (props: { children: ReactNode }) =>
        <DiProvider use={use}>{props.children}</DiProvider>;

const renderHookWithDi = <TProps, TResult>(
    callback: (props: TProps) => TResult,
    dependencies: Dependency[] = [],
) =>
    renderHook<TProps, TResult>(callback, {
        wrapper: createRtlDiWrapper(dependencies) as unknown as ComponentType<TProps>,
    });

const renderWithDi = (element: ReactElement, dependencies: Dependency[] = []) =>
    render(element, {
        wrapper: createRtlDiWrapper(dependencies),
    });

const exampleDependency = () => 1;

describe('renderHook vs render', () => {
    const deps = [injectable(exampleDependency, () => 2)];

    it('should inject dependency using renderHook (but fails)', () => {
        const useExample = () => {
            di(exampleDependency);
            return { value: exampleDependency() };
        };

        const { result } = renderHookWithDi(() => useExample(), deps);

        expect(result.current).toEqual({ value: 2 });
    });

    it('should inject dependency using render', () => {
        const Example = () => {
            di(exampleDependency);
            return <span>{exampleDependency()}</span>;
        };

        const { asFragment } = renderWithDi(<Example />, deps);

        expect(asFragment()).toMatchInlineSnapshot(`
            <span>
              2
            </span>
        `);
    });
});

Expectation

Both tests would pass as the dependency should be properly injected using the DI wrapper.

Actual Behaviour

Only the second test, using render, passes, as the dependency is properly injected. The first one fails because it uses the actual implementation instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions