Testing ScrollIntoView in Jest - jestjs

With the function which uses scrollIntoView
export const scrollDown = () => {
document.querySelector('.bottom').scrollIntoView({
behavior: 'smooth'
});
}
I have a test here that goes like this
describe('scrollDown', () => {
let scrollIntoViewMock = jest.fn();
window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
scrollDown()
expect(scrollIntoViewMock).toBeCalled();
})
But the test is failing with the TypeError: Cannot set property 'scrollIntoView' of undefined
The test was from another SO answer for scrollIntoView testing question. Any help would be appreciated.

You need to add an HTMLElement with class bottom to the document:
const scrollDown = () => {
document.querySelector('.bottom').scrollIntoView({
behavior: 'smooth'
});
}
test('scrollDown', () => {
document.body.innerHTML = '<div class="bottom"></div>';
const scrollIntoViewMock = jest.fn();
HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
scrollDown();
expect(scrollIntoViewMock).toBeCalledWith({ behavior: 'smooth' }); // Success!
})

Related

jest change mocked value at later stage

I have a mock where it sets up a return value before all my tests. But I was wondering if you could update a value in the test itself. As you can see I want to just update the boolean value of mockedIsloading, without calling the entire mockedLoadStatus.mockReturnValue({...}) again in my test with a new isLoading value of true this time around.
Would be nice to just be able to call mockedIsloading.mockReturnValueOnce(true) but this does not seem to work.
import {
loadStatus,
} from 'pathToMyFile'
jest.mock('pathToMyFile')
const mockedLoadStatus jest.mocked(loadStatus)
const mockedMutate = jest.fn()
const mockedIsLoading = jest.fn().mockReturnValue(false)
beforeAll(() => {
mockedLoadStatus.mockReturnValue({
mutate: mockedMutate,
isLoading: mockedIsloading,
})
})
test('my test', () => {
mockedIsloading.mockReturnValueOnce(true)
render(<Wrapper />)
})
What do you mean "doesn't work"? I mean this works OK:
const mockedLoadStatus = jest.fn();
const mockedMutate = jest.fn()
const mockedIsLoading = jest.fn().mockReturnValue(false)
beforeAll(() => {
mockedLoadStatus.mockReturnValue({
mutate: mockedMutate,
isLoading: mockedIsLoading,
})
})
test('some test', () => {
expect(mockedLoadStatus().isLoading()).toBeFalsy();
})
test('my test', () => {
mockedIsLoading.mockReturnValueOnce(true)
expect(mockedLoadStatus().isLoading()).toBeTruthy();
expect(mockedLoadStatus().isLoading()).toBeFalsy();
})
Or am I missing something :) ?

jest.spyOn not calling mocked implementation but rather actual function instead

I'm trying to write a unit test for a function that calls some helper functions in the same file. I'm using jest.spyOn to mock away those helper functions as it appears that it can do that.
myModule.js
export const getUserName = () => {
return "mjordan"
}
export const getItem = () => {
return 'basketball'
}
export const getUserWithItem = () => {
const userName = getUserName()
const item = getItem()
return userName + " " + item
}
myModule.test.js
import * as myModule from 'path/to/module'
describe('getUserWithItem', () => {
beforeEach(() => {
jest.restoreAllMocks()
})
it('Returns user with item', () => {
jest.spyOn(myModule, 'getUserName').mockImplementation(() => 'tigerwoods')
jest.spyOn(myModule, 'getItem').mockImplementation(() => 'golf ball')
const result = myModule.getUserWithItem()
expect(result).toEqual("tigerwoods golf ball")
})
})
However, the jest.spyOn function does not appear to be mocking the implementation of the spied on functions but the test is calling the original functions instead which results in an output of mjordan basketball instead.
Am I missing something with how spyOn is supposed to work?
The easiest way I have found to do what you want is to explicitly call the exported version of the function in your module, i.e.
export const getUserName = () => {
return "mjordan"
}
export const getItem = () => {
return 'basketball'
}
export const getUserWithItem = () => {
const userName = exports.getUserName()
const item = exports.getItem()
return userName + " " + item
}

How to mock different value, of useLocation, for each test?

My react component should do some change to the state according to the current location.
There is custom hook, that is called upon component loading.
In the hook there is a check of useLocation().pathname and the result in switch/case for the correct change.
Can this be Jest tested in one file/describe?
I tried to jest.mock useLocation but I just can't do it inside Jest describe...
This is the mock, currently out of the describe - and this works, but can't be changed from test to test:
const mockUseLocation = () => {
jest.mock('react-router-dom', () => ({
useLocation: jest.fn().mockReturnValue({
pathname: '/val1'
})
}))
};
How can I test all the switch/case branches?
switch (pathname) {
case 'val1':
return 100;
case 'val2':
return 200;
...
...
}
To go off of #skyboyer answer I got this working well using renderHook
The first argument is your hook you want to test and the second argument is your wrapper which I wraps <MemoryRouter>, <Route> around children prop.
// test.js
import React, { FC } from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
import { renderHook } from '#testing-library/react-hooks';
it('returns value from url query', () => {
const wrapper: FC = ({ children }) => (
<MemoryRouter initialEntries={[`/?user=authorized`]}>
<Route path="*" />
{children}
</MemoryRouter>
);
const { result } = renderHook(() => useLocation(), { wrapper });
expect(result.current).toBe('authorized');
});
easiest way is use MemoryRouter instead mocking useLocation. Also this would be helpful if your component has <Link>(otherwise you will get the error "Link cannot be used outside the Router"). Also it allows you to check if navigation happens. So with such many benefits mocking useLocation directly does not have any value.
Take a look into examples in official docs. It would be something alike:
test("current user is active in sidebar", () => {
const wrapper = mount(
<MemoryRouter initialEntries={["/users/2"]}>
<YourComp />
</MemoryRouter>
);
expected(wrapper.find(User)).toHaveLength(2);
});
You can change the value of pathname by changing the value of this variable in the appropriate places in the tests.
For example:
let mockPATH = 'val1';
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useLocation: () => ({
pathname: mockPATH
})
}));
test('1st', () => {
mockPATH = 'val2';
//...
})
try:
const locationMock = jest.fn();
const mockUseLocation = () => {
jest.mock('react-router-dom', () => ({
useLocation: () => locationMock()
}))
};
it('test1', () => {
locationMock.mockReturnValue({
pathname: '/val1'
})
expect()
})
it('test2', () => {
locationMock.mockReturnValue({
pathname: '/val2'
})
expect()
})
Hope it work for u ^^

mock a toPromise function in jest - got .toPromise is not a function

I have an httpService from nestjs/common
and I am using like the following:
const response = await this.httpService.post(`${this.api}/${action}`, data).toPromise();
and in my jest spec file ( unit testing) . i am trying to mock this service
httpServiceMock = {
post: jest.fn()
};
it('should start', async () => {
const serviceResult = await service.start(data);
});
and I have got this error :
TypeError: this.httpService.post(...).toPromise is not a function
I am also trying to add a promise result like :
const promise = Promise.resolve('result');
httpServiceMock.post.mockResolvedValue(promise);
tried also :
it('should start', async () => {
const mockObservable = Promise.resolve({
toPromise: () => {
console.log('toPromise called');
}
})
httpServiceMock.post.mockImplementation(() => mockObservable);
const serviceResult = await service.start();
});
My question is how can I mock the promise and return a response or exception
The return value httpService.post needs to return an Observable<AxiosResponse<T>> which includes a property toPromise, which is a function. Your mock returns a resolved promise, whereas it needs to return a fake Observable.
The Observable is returned immediately, so the post implementation can just return a raw value, but the toPromise needs to return a promise.
Return the correct shaped object to get rid of this error:
const mockObservable = {
toPromise: () => Promise.resolve('result')
}
httpServiceMock.post.mockImplementation(() => mockObservable);
I had a similar problem that could not be solved by accepted answer. So I bring here another solution just in case it could help someone else.
If you have jasmine, just use jasmine.createSpyObj(). If not, here is what I needed to do :
First, I implemented a jasmine.createSpyObj() equivalent (based on this answer with little modifications) :
export class TestUtilsService {
static createSpyObj (baseName:string, methodNames:string[]): SpyObject {
let obj: any = {};
for (let i = 0; i < methodNames.length; i++) {
obj[methodNames[i]] = jest.fn();
}
return {[baseName]:()=>obj};
};
}
export class SpyObject {
[key: string]: ()=>{[key:string]:jest.Mock} ;
}
Then I used it in my unit test :
const spyHttpClient: SpyObject = TestUtilsService.createSpyObj('get',['toPromise']);
Add it in test module providers :
{provide: HttpClient, useValue: spyHttpClient}
Finally, mock the toPromise implementation in order to return a mocked response :
const mockedResponse = {...};
spyHttpClient.get().toPromise.mockImplementationOnce(()=>Promise.resolve(mockedResponse));
await service.myRealMethodThatCallsHttpClient();
expect(service.someUpdatedProp).toBeTruthy();
Please notice parenthesis after method get.
"A Jar of Clays" solution didn't work for me (I got mockImplementation is not a function), but this worked:
const mockPromise = {
toPromise: () => Promise.resolve(ical)
}
mockHttpService.get = jest.fn( () => {return mockPromise});

testing an actual returning value on javascript using jest

I have the following js function:
const modelUtils = {
modelingObj(obj, stringVal = ‘RE’) {
let newObj;
//my logic for setting value of newObj
return newObj;
};
export default modelUtils;
I want to test and see that based on a specific params I get a particular result, the issue is I’m always returning back an empty object.
Test.js
import modelUtils from '../modelUtils';
jest.unmock('../modelUtils');
describe(' testing modelUtils', () => {
let test;
const mockData = {
myProperty: [],
};
describe('testing modelingObj function', () => {
it('For my first test’, () => {
test = modelUtils.mockData, ‘TR’);
expect(test).toEqual({ myProperty: [] });
});
});
});

Resources