0

I'm struggling a bit to find a solution on how to test this exported function with jest.

export const scrollToError = () => {
  setTimeout(() => {
    const hasErrorElement = jQuery('.has-error');
    if (!hasErrorElement.length) return;
    jQuery('html,body').animate({
      scrollTop: hasErrorElement.offset().top - 50,
    }, 'slow');
  }, 400);
};

I imported it in my test file and tried to start it:

import { scrollToError } from './utils';

describe('Utils', () => {
  it('should scroll to error', () => {
    const result = scrollToError();
    expect(result).toBe(true); //added this just to force an error and got result as undefined 
  });
});

Could anyone give me any tips on how to test code with these dependencies?

3 Answers 3

1

scrollToError() is asynchronous function and you can't invoke it and expect the result to be there immediately. You need to wait that amount of ms (400 in your case), before testing for it.

Asynchronous code is tested a bit differently in Jest: Testing Asynchronous Code. You can also take control over the timers or combine it all with the manual mocks and override jQuery itself.

Sign up to request clarification or add additional context in comments.

1 Comment

but what about the jquery.. I was trying to figure out a way to mock it..
1

How are you using jQuery?

I mean, did you get it using npm or yarn? to mock node_modules you can follow this link: https://jestjs.io/docs/en/manual-mocks#mocking-node-modules

Otherwise, you will have to create a manual mock. You can see how to do it here: https://jestjs.io/docs/en/manual-mocks

Updated:

the simplest way is to override it, is while settting up your test at beforeXXX method.

You can simply put something like window.JQuery = jest.fn();

this is the simplest mock ever but you will have to create the methods like animate and other jquery related methods.

Having second thoughts here and looking to your function, if you mock jQuery what else left to be tested?

If you mock, you will be testing if your fn are doing the steps you defined here. Like check if the jQuery fn was called with .has-error class or if animate received the correct parameters.

This kind of test doesn't help you at all, it's just checking if it's following line by line your algorithm. The problem here, that you could do some refactorings like changing the .has-error class name or the animate method by other improved one.

What you really need to change, if it's doing at the end what should be doing. Displaying the div or whatever that should be displayed. If you test that, regardless the way you refactor your code the test will check if the final solution still works and that what matters.

Was I clear? English is not my first language so, it may be a little bit confusing

1 Comment

the difficulty here is to create a manual mock for it... I'm not using it from node_modules...
1

I finally managed to find a proper solution. I wrote three test cases for it:

jest.useFakeTimers();
describe('utils', () => {
  afterEach(() => {
    document.body.innerHTML = '';
  });
  it('ScrollToError - should run the settimeout for 400 ms', () => {
    scrollToError();
    expect(setTimeout).toHaveBeenCalledTimes(1);
    expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 400);
  });
  it('ScrollToError - should scroll to error', () => {
    document.body.innerHTML = formStep1ErrorMock;
    window.setTimeout = fn => fn();
    const result = scrollToError();
    expect(result).toBe(true);
  });
  it('ScrollToError - should do nothing as has no errors', () => {
    document.body.innerHTML = formStep1Mock;
    window.setTimeout = fn => fn();
    const result = scrollToError();
    expect(result).toBe(true);
  });
});

So basically, first I check if the setTimeout was called with the proper amount of seconds (not that it's important).

Then I mock the setTimeout by doing this window.setTimeout = fn => fn(); so it runs without waiting for the delay. I also mock the html with the proper details I need it to have.

And finally, I just cover another scenario.

PS: I added a return true statement to the scrollToError method to make it simpler to have an expected result.

This way I achieved 100% coverage for this method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.