GithubHelp home page GithubHelp logo

mikeborozdin / jest-react-hooks-shallow Goto Github PK

View Code? Open in Web Editor NEW
114.0 114.0 9.0 8.29 MB

Bringing React Hooks to shallow rendering

License: ISC License

JavaScript 75.53% TypeScript 20.06% HTML 4.24% Shell 0.16%

jest-react-hooks-shallow's People

Contributors

dependabot[bot] avatar kallebornemark avatar mikeborozdin avatar mrmicrowaveoven avatar newbornfrontender avatar raphaelhaettich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

jest-react-hooks-shallow's Issues

Doesn't seem to play well with ts-jest

I recently came across your package in hopes that it would solve my shallow + hooks testing hole I'm currently in. However I seem to be running into issues getting the mock hooks to actually stay in place.

I've created a fork and I'll make a PR to this repository adding a example into the samples-and-e2e-tests folder in this project.
PR: #33

useEffect cleanup function is not called on component unmount

I am using useEffect in my test component.

const Cmp = () => {
  React.useEffect(() => {
    console.log(1);
    return () => console.log(2);
  }, []);
  return <span>Test</span>;
};

And in test: shallow(<Cmp />).unmount().

And there is no log emitted in the cleanup function

Typescript example?

Looks good. I am struggling to make the jest import with Typescript though.

useEffect callbacks are not invoked for subsequent tests if there are more than one useEffect hooks

If a component has more than one useEffect hook, the callback will be invoked only for the very first test in a describe block.

A very simple reproduction:

function Component() {
  useEffect(() => {
    console.log('test 1');
  }, []);

  useEffect(() => {
    console.log('test 2');
  }, []);

  return null;
}

describe('test', () => {
  it('useEffect works', () => {
    shallow(<Component />);
  });

  it('useEffect does not work', () => {
    shallow(<Component />);
  });
})

Note that if I remove t he deps array everything will be back to normal.

enableHooks not sufficient if jest config contains "resetMocks: true"

Hello!

This is a really useful library. Thanks for making it. While trying to integrate this, I realized the steps suggested in the docs don't work as expected if the jest config as resetMocks set to true: https://jestjs.io/docs/en/configuration#resetmocks-boolean

My setupHooks.js file:

import enableHooks from 'jest-react-hooks-shallow';

enableHooks(jest);

It seems that the resetMocks option clears the mocks setup by this library before every test. I fixed it by using the now deprecated reenableHooks function in the following way:

import enableHooks, { reenableHooks } from 'jest-react-hooks-shallow';

enableHooks(jest);

beforeEach(() => {
  reenableHooks();
});

I also tried putting just the enableHooks in a beforeEach block, but didn't seem to work. The above combination is the only thing that worked for me.

I'm wondering if you would consider "re-introducing" the deprecated function since it seems to solve for a particular case? Also, do you mind sharing why it was deprecated?

Possible way to get around mount issues

i'm guessing you don't want to tie this library to enzyme, but if you did, you could spy on mount and basically change it to

withoutHooks(() => {
  originalMount(...)
});

useEffect run cleanup function in wrong trigger

Hello.

When I use this library to do the unit testing with the shallow object, I found that the cleanup function of the first effect will be triggered by the second effect. Is this under our expectations?

Experiment code below:

import React from 'react';
import { shallow } from 'enzyme';

const Cmp = () => {
    React.useEffect(() => {
        console.log(1);

        return () => console.log(2);
    }, []);

    React.useEffect(() => {
        console.log(3);

        return () => console.log(4);
    }, []);

    return <span>Test</span>;
};

it('test it', () => {
    shallow(<Cmp/>);
});

and the console will output "1", "2", and "3". But our expectation is only "1" and "3".

Could you help me check this situation? Thanks a lot.

Facing `Cannot read property 'refs' of undefined` for Tests with enzyme mount wrapper on component having material ui components

After including this library and adding the setup, able to pass tests fromuseEffect actions seamlessly which I couldn't do with other solutions.
But soon, all the other test components (where mount wrapper of enzyme is used and the components are usingmaterial-ui components) started throwing throwing the error Cannot read property 'refs' of undefined error.

Sample Test Component:

//TestComponent.js
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';

const TestComponent = () => {
  return (
    <TextField value="somedata" />
  }
}
export default TestComponent;

//TestComponent.test.js
import React from 'react';
import { mount } from 'enzyme';
import TestComponent from '../TestComponent';
describe('TestComponent', () => {
        Date.now = jest.fn(() => 123);
	it('matches snapshot', () => {
		const componentWrapper = mount(<TestComponent />);
		expect(componentWrapper).toMatchSnapshot();
	});
});

image

But, Not getting error when i try using useRef and ForwardRef's inside the component
Not getting error with material-ui components too when I exclude this package from setup..
Any work around for this would be welcomed?

Consider back documenting to enzyme's open issue

From what I gather (still processing, apologizes if my understanding is incorrect) this seems to be a stop-gap measure until React supports Enzyme with some sort of event regarding effect callbacks which is effectively tracked via enzymejs/enzyme#2086.

However the documentation for this package doesn't reference this issue which I think would be useful for additional context if people are interested... or if the issue does ever actually get resolved, as a back reference to what the official solution ends up being.

Just something to consider, thanks!

Clean up functions testing with jasmine integration

Thank you for this wonderfull piece of code, it's going to change my life !

I used the code to test it in a jasmine integration. For now I managed to make it work in a test like this.

        it('should enter use effect', () => {
            type FunctionBody = string;
            type CleanupFunction = () => void;

            const noDepsOrDifferent = (previousDependencies: unknown[], currentDependencies: unknown[]): boolean => {
                return (
                    previousDependencies === undefined ||
                    previousDependencies.some((prevDep, index) => prevDep !== currentDependencies[index])
                );
            };

            spyOn(React, 'useEffect').and.callFake(
                (effect: () => CleanupFunction | void, dependencies?: unknown[]): void => {
                    const previousCalls = new Map<FunctionBody, unknown[]>();
                    const cleanupFunctions = new Map<string, CleanupFunction>();

                    const effectBody = effect.toString();

                    const shouldCall = previousCalls.has(effectBody)
                        ? noDepsOrDifferent(previousCalls.get(effectBody), dependencies)
                        : true;

                    if (shouldCall) {
                        previousCalls.set(effectBody, dependencies);

                        if (cleanupFunctions.has(effectBody)) {
                            cleanupFunctions.get(effectBody)();
                        }

                        const cleanupFunction = effect();

                        if (typeof cleanupFunction === 'function') {
                            cleanupFunctions.set(effectBody, cleanupFunction);
                        }
                    }
                }
            );

            shallowMountTheComponent();
            expect(SpyingAFunctionInComponentUseEffectHook).toHaveBeenCalledTimes(1);
        });

But I cannot seem able to trigger the cleanup function. Since useEffect is not triggered when the shallow component unmounts, How would you trigger the cleanupFunction ?

Support for storybook

Hi,

We've recently installed this package and it's brilliant! However, we noticed that when running the package with storybook and creating storyshots there's an error: TypeError: Cannot read property '0' of undefined.

Skjermbilde 2021-09-24 kl  09 09 13

The origin of this error is this function, namely the third line:

const noDepsOrDifferent = (previousDependencies, currentDependencies) => { return previousDependencies === undefined || previousDependencies.some((prevDep, index) => prevDep !== currentDependencies[index]); };

Although currentDepdencies can be undefined, there is no check for it - therefore the index line throws an error. The storyshots passed with this check:
previousDependencies.some((prevDep, index) => prevDep !== (currentDependencies && currentDependencies[index]));

Is that an appropriate solution? I'm not entirely sure what dependencies are in this instance (with the exception of it being dependencies from useEffect?) or why it would be undefined here.

Thank you!

dontMockByDefault not working?

I've just installed jest-react-hooks-shallow and added enableHooks(jest, { dontMockByDefault: true }) in my test setup script, and I'm seeing countless test failures in tests that use mount(), multiple errors several similar to this:

Warning: React has detected a change in the order of Hooks called by Formik. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks

       Previous render            Next render
       ------------------------------------------------------
    1. useRef                     useRef
    2. useRef                     useRef
    3. useRef                     useRef
    4. useRef                     useRef
    5. useRef                     useRef
    6. useRef                     useRef
    7. useReducer                 useEffect
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I'm using react-scripts (create-react-app), so I had to add enableHooks in the setupTests.js script they provide (adding setupFilesAfterEnv directly to my package.json caused an error telling me to add to this file instead, as react-scripts loads their setup file automatically).

Am I missing something? Or is there a problem with dontMockByDefault and react-scripts?

Not working correctly with beforeAll

We're currently using this project with both shallow and mount renders. In some tests we use beforeAll with the render function:

  const renderComponent = () => {
    component = mount(<LinkEditor {...props} />);
  };

  beforeEach(renderComponent);

The issue here is that beforeAll is always executed before beforeEach. And the mocks are setup in a beforeEach call.
Changing the beforeEach in the library to beforeAll fixes this. But this seems not the best solution, as this might break things.
Would it be possible to also add a beforeAll to mock the methods? Or let the user specify which before-method they want to trigger the mocks on?

withHooks and withoutHooks do not support async tests / promises

Thanks for this package. I'm currently trying to get this to work with an async test, but that doesn't seem to be supported yet. Could this be added?

Example usage:

it('does something async', async () => {
    await withHooks(async () => {
        const wrapper = shallow(<App />);

        await something();
    });
});

I'm currently using this as a workaround:

export default function withHooksAsync(test: () => Promise<void>): Promise<void> {
    return new Promise<void>((resolve, reject) => {
        withHooks(() => {
            test().then(resolve).catch(reject);
        });
    });
}

Clash with mocking React to work around useRef problems

useRef() also doesn't work with shallow rendering if the ref.current value is handled by passing the ref to a DOM node or a component with ref forwarding. In this case, the ref will always be undefined with shallow rendering.

This can be worked around by mocking out useRef() and making it return a mock value that doesn't crash the component that's being tested. However, a mock list this:

jest.mock('react', () => ({
	...jest.requireActual('react'),
	useRef: arg => (typeof arg === 'undefined' ? { current: { getBoundingClientRect: () => ({ left: 0 }) } } : {current: arg}),
}));

will override jest-react-hooks-shallow's mock useEffect() and revert it to React's default implementation.

I've been able to work around the issue like this:

import React, {useEffect} from 'react';
import mockUseEffect from 'jest-react-hooks-shallow/lib/mock-use-effect/mock-use-effect';

jest.mock('react', () => ({
	...jest.requireActual('react'),
	useEffect: jest.fn(),
	useRef: arg => (typeof arg === 'undefined' ? { current: { getBoundingClientRect: () => ({ left: 0 }) } } : {current: arg}),
}));

then

useEffect.mockImplementation(mockUseEffect());

instead of withHooks() in every test case where withHooks() would normally be used.

It would be nice if the library would offer a more elegant solution for this, either by mocking out useRef() as well or re-exporting mock-use-effect so that we don't have to have an ugly import like above.

TypeError: Cannot read property '0' of undefined

When I test with mount It show "TypeError: Cannot read property '0' of undefined"

I looks length of previousDependencies and length of currentDependencies can be different.
For example,
if i have 2 unit tests which first one uses shallow, second one uses mount,

  • first unit test runs previousDependencies is undefined, currentDependencies's length is 3
  • second unit test runs previousDependencies'lengh is 3, currentDependencies is undefined

It throws TypeError: Cannot read property '0' of undefined

const noDepsOrDifferent = (previousDependencies: unknown[], currentDependencies: unknown[]): boolean => {
return previousDependencies === undefined ||
previousDependencies.some((prevDep, index) => prevDep !== currentDependencies[index]);
}

I looks

beforeEach is not defined

I am seeing this error:

ReferenceError: beforeEach is not defined
      at Object.mockUseEffect [as default] (node_modules/jest-react-hooks-shallow/lib/mock-use-effect/mock-use-effect.js:10:5)
      at enableHooks (node_modules/jest-react-hooks-shallow/lib/enable-hooks.js:17:67)
      at Object.<anonymous> (config/jest/setup.js:24:39)
import Adapter from 'enzyme-adapter-react-16'; // eslint-disable-line import/no-extraneous-dependencies
import jestFetchMock from 'jest-fetch-mock'; // eslint-disable-line import/no-extraneous-dependencies
import 'babel-polyfill'; // eslint-disable-line import/no-extraneous-dependencies
import enableHooks from 'jest-react-hooks-shallow';

global.fetch = jestFetchMock;
global.local = {
  baseurl: "ThisisiAbaseurl"
}

// pass an instance of jest to `enableHooks()`
enableHooks(jest);

Enzyme.configure({ adapter: new Adapter() });

test('Renders default message and updates it on clicking a button', () => {
  const component = shallow(<GenerateSecretForm />);
});

Npm7 & React 17 peer dependency error

Hi,

When trying to use this library with npm7 it fails in combination with react 17.

Is it possible to add rules in the deps to be ^16.8 || ห†17 in your react deps?

image

Support for React 18 ?

Currently, this library doesn't support react 18, is it possible to address this? Thanks in advance

Function returned from useEffect, testable?

Say you have the following code:

  useEffect(() => {
    dispatch(fetchData());
    return () => {
      dispatch(resetPaging());
    };
  }, [dispatch]);

Does this package allow you to test if resetPaging was called?

How to run useEffect cleanup - Help

The cleanup functions are only called before invoking the same effect again.

Thank you for this library! can you please demonstrate "cleanup functions are only called before invoking the same effect again." I've gone through the demo but was not able to achieve it. Below is the sample useEffect I've in my project

 useEffect(() => {
        dispatch({
            type: SET_RESOLUTION_STATUS_COUNT_BAR_CHART_FETCHING_DATA,
            payload: true,
        });
        dispatch(getResolutionStatusCount([]));
        return () => {
            const barChartPayload = {
                barChartData: [],
                barChartCategories: [],
                resolution_status_environment: [],
            };
            dispatch({
                type: SET_RESOLUTION_STATUS_COUNT_BAR_CHART,
                payload: barChartPayload,
            });
        };
    }, []);

and Below is the test cases what I have

const setup = (props = {}) => {
    return shallow(<ResolutionCount {...props} />)
}

test("dispatch actions on unmount ", () => {
        mockState({
            generalReducer: {
                dateRangePicker: {
                    startDate: "",
                    endDate: "",
                }
            }
        });

        setup({ componentUsedIn: "range picker" });

        expect(mockDispatch).toHaveBeenNthCalledWith(1, {
            type: "SET_RESOLUTION_STATUS_COUNT_BAR_CHART_FETCHING_DATA",
            payload: true
        });

        expect(mockDispatch).toHaveBeenNthCalledWith(2, expect.any(Function))

Could you please tell me how would I achieve component unmount here.

Thank you

Incompatible with Jest 26+

When running with Jest 26.6.0 (with Create-React-App v4), all of my tests now fail with the error 'Hooks cannot be defined inside tests. Hook of type "beforeEach" is nested within "Test Name"'. This was mentioned as one of the issues in this previous issue , of which the fix was to upgrade to v1.4.2 of jest-react-hooks-shallow. This, however, has not fixed it. Is there some other configuration that is required to make it work with Jest 26.6.0?

Stacktrace:

Error: Hooks cannot be defined inside tests. Hook of type "beforeEach" is nested within "toggles tigonMode and saves it in sessionStore".
    at eventHandler (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/eventHandler.js:105:11)
    at dispatchSync (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/state.js:65:5)
    at _addHook (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/index.js:125:27)
    at beforeEach (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/index.js:135:3)
    at Object.mockUseEffect [as default] (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-react-hooks-shallow/src/mock-use-effect/mock-use-effect.ts:14:3)
    at withHooks (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-react-hooks-shallow/src/enable-hooks.ts:47:49)
    at Object.<anonymous> (/Users/robwaddell/src/git/string-dashboard/client/src/app/App.test.jsx:54:7)
    at Promise.then.completed (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/utils.js:276:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/utils.js:216:10)
    at _callCircusTest (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/run.js:212:40)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at _runTest (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/run.js:149:3)
    at _runTestsForDescribeBlock (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/run.js:63:9)
    at _runTestsForDescribeBlock (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/run.js:57:9)
    at _runTestsForDescribeBlock (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/run.js:57:9)
    at run (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/Users/robwaddell/src/git/string-dashboard/client/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:176:21)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.