I have a method which uses an ElementRef which is defined below.
#ViewChild('idNaicsRef') idNaicsRef: ElementRef;
ElementRef then sets the focus using .nativeElement.focus().
The method fails while running the spec, saying 'undefined is an object'
Although httpNick's answer should work, I ended up asking an architect on my team about this and he led me to a slightly different solution that may be a bit simpler.
describe(MyComponent.name, () => {
let comp: MyComponent;
describe('myFunction', () => {
it('calls focus', () => {
comp.idNaicsRef = {
nativeElement: jasmine.createSpyObj('nativeElement', ['focus'])
}
comp.myFunction();
expect(comp.idNaicsRef.nativeElement.focus).toHaveBeenCalled();
});
});
This particular example would just test to see if the focus method has been called or not. That's the test that I was interested in when I was testing my method, but you could of course test whatever you wanted. The key is the setup beforehand (which was elusive before it was shown to me).
this should work. this just creates a spy object and then you can populate it with whatever you want, so you could even check if it was called in your unit test.
import createSpyObj = jasmine.createSpyObj;
comp.idNaicsRef = createSpyObj('idNaicsRef', ['nativeElement']);
comp.idNaicsRef.nativeElement = { focus: () => { }};
comp is the reference to the component you are testing.
createSpyObj comes from a jasmine import
Related
I want to set a unit test on a very simple Vue Component with the default Vue Test Utils plugin coupled to Jest Framework.
On a click of a button, the handler calls 2 methods:
emitEvent(): to emit an event (actual target of my test),
effectUI(): for UI effect (using the Web Animations API). This animation is applied on each 'particle' of a 'particles' array. I do not wish to test this part (yet), but this is the one which is problematic.
I works fine when I run the component. No warnings, no errors.
But when I run the test, it passes... with console.error stating that 'particle.animate' is not a function.
I have tried:
first, to do nothing special: since the EffectUI() method has nothing to do with the click event (except they are called by the same handler) so maybe they do...
then, to mock the "animate" function: with no result so far. I assume the issue comes from the Web API method not being recognized. I may be completely wrong.
Code of method called from component click's handler:
effectUI() {
let particles = this.$el.querySelectorAll('span.particle')
particles.forEach(particle => { particle.animate(...) }
}
Code of test file:
import { mount } from '#vue/test-utils'
import ButtonParticles from '#/components/ButtonParticles.vue'
describe('ButtonParticles.vue', () => {
const wrapper = mount(ButtonParticles)
const animStub = jest.fn()
it('should trigger `clicked` event when user clicks on button', () => {
let particles = wrapper.findAll('.particle')
particles.wrappers.forEach(particle => {
particle.animate = animStub
})
wrapper.find('button').trigger('click')
expect(wrapper.emitted().clicked).toBeTruthy()
})
})
Expected results would be to get no console.error
Actual results are: [Vue warn]: Error in v-on handler: "TypeError: particle.animate is not a function" (+ stack trace)
Anyone can help me understand what's happening?
Thanks!
In your test, particle is a wrapper. Try particle.element.animate = animStub
I'm having a rough time trying to test if some function is bound to a component after the component has been initialized.
This is my ngOnInit() function:
ngOnInit() {
this.someFunction = this.someFunction.bind(this);
}
And this is the function that I want to bind to the component::
someFunction() {
// this empty function is not called yet but should be bound to the component
}
And this is my before each:
beforeEach(async(() => {
fixture = TestBed.createComponent(ComponentName);
component = fixture.componentInstance;
fixture.detectChanges();
}));
And this is my describe function:
describe('ngOnInit', () => {
it('someFunction has been bound to the component.', () => {
let bindFunctionSpy = spyOn(component.someFunction, 'bind').and.callThrough();
component.ngOnInit();
expect(bindFunctionSpy).toHaveBeenCalledWith(component);
});
});
The problem that I'm facing here is that there is a typescript error in the spyOn function preventing me from compiling the test cases, it says :
error TS2345: Argument of type '"bind"' is not assignable to parameter of type 'never'.
So what exactly am I not doing right here?
The same thing happens if I try spying on any of the prototype functions for a component function like apply or call for example.
Yet if I tried to spy on a prototype function for a component variable like length or toLowerCase it doesn't throw such error!
Another note is that this test actually sometimes gets compiled successfully and actually passes, and sometimes it throws the error while compilingm, but it happens only when I make any random changes like adding a space then saving them so that Karma can detect that a change happened and recompile the tests, but if I closed the terminal and then started it again and ran ng test I get the error again.
The best way to do this is just casting your function to the CallableFunction type.
let bindFunctionSpy = spyOn(component.someFunction as CallableFunction, 'bind').and.callThrough();
You could try
let bindFunctionSpy = spyOn(component.someFunction.prototype, 'bind').and.callThrough();
Try spying on Function.prototype like this -
spyOn(Function.prototype, 'bind');
it worked for me.
I am new to JavaScript testing and currently trying to write some test cases for a store (just an ES6 class) I created. I am using Jest as this is what we usually use for React projects, although here I am not testing a React Component but just a class wrapping a functionality.
The class I am testing extends another class, and has various methods defined in it. I want to test these methods (whether they are called or not), and also whether the properties declared in the class change as and when the corresponding class methods are called.
Now I have read about mocking functions, but from what I understand, they can only do checks like how many times a function is called, but can't replicate the functionality. But in my case, I need the functionality of the methods because I will be checking the class member values these methods change when called.
I am not sure if this is the right approach. Is it wrong to test functions in Jest without mocking? And inferentially, to test the internal workings of functions? When do we mock functions while testing?
The issue I am facing is that the project I am working on is a large one where there are multiple levels of dependencies of classes/functions, and it becomes difficult to test it through Jest as it will need to go through all of them. As I am using alias for file paths in the project, Jest throws errors if it doesn't find any module. I know its possible to use Webpack with Jest, but many of the dependent classes/functions in the code are not in React, and their alias file paths are not maintained by Webpack.
import { getData } from 'service/common/getData';
class Wrapper extends baseClass {
someVariable = false;
payload = null;
changeVariable() {
this.someVariable = true;
}
async getData() {
super.start();
response = await fetchData();
this.payload = response;
super.end();
}
}
This is a small representation of the actual code I have. Can't post the entire class here as I am working on a remote machine. Basically, I want to test whether changeVariable gets called when invoked, and whether it successfully changes someVariable to true when called; and similarly, check the value of payload after network request is complete. Note that fetchData is defined in some other file, but is critical to testing getData method. Also the path used here (service/common/getData) for importing getData is not the absolute path but an alias NOT defined in Webpack, but somewhere else. Jest can't resolve getData because of this. I will not have to worry about this if I mock getData, but then I will not be able to test its functionality I believe.
#maverick It's perfectly okay to test your class methods using jest. Check the code example in the link -
https://repl.it/repls/ClumsyCumbersomeAdware
index.js
class Wrapper {
constructor(){
this.someVariable = false;
}
changeVariable(){
this.someVariable = true;
}
getData(){
return new Promise(resolve => resolve('some data'));
}
}
module.exports = Wrapper;
index.test.js
const Wrapper = require('./index');
const wrapper = new Wrapper();
describe('Wrapper tests', () => {
it('should changeVariable', () => {
wrapper.changeVariable();
expect(wrapper.someVariable).toBe(true);
});
it('should get some data', () => {
wrapper.getData().then( res => expect(res).toBe('some data'));
});
});
This is a very simplistic example and in real life the async calls are much more complicated and dependent of 3rd party libraries or other project modules. In such cases it makes sense to have all the dependencies injected in out class and then mocked individually. For Example -
class GMapService {
constructor(placesApi, directionApi){
this.placesApi = placesApi;
this.directionApi = directionApi;
}
getPlaceDetails(){
this.placesApi.getDetails('NYC');
}
getDirections(){
this.directionApi.getDirections('A', 'B');
}
}
Now you can easily mock placesApi and directionApi, and test them individually without actually requiring Google Map dependencies.
Hope this helps ! 😇
I have the following test:
const mockedObject = {
mockedMethod: jest.fn((someKey, someValue) => {
return {someKey: 'someValue'}
})
};
jest.doMock('../myObject', () => {
return mockedObject;
});
testedObject.testedMethod();
expect(mockedObject.mockedMethod).toHaveBeenCalled();
Here, in the testedObject, I am importing myObject. I would like to mock that import and pass mockedObject instead.
After looking at this question and this question, I think the above code should be good, however mockedObject.mockedMethod is never called even though testedObject is making the call.
So what is wrong with the mocking done in this test?
You call
testedObject.testedMethod()
but expect
mockedObject.mockedMethod)
try this code:
const mockedObject = {
testedMethod: jest.fn((someKey, someValue) => {
return {someKey: 'someValue'}
})
};
jest.doMock('../myObject', () => {
return mockedObject;
});
testedObject.testedMethod();
expect(mockedObject.testedMethod).toHaveBeenCalled();
I can think of some choices.
One thing that could be happening is that you are mocking the import after your tested object has required it and you cannot modify that. If that is your case, then make sure you make the instance of the object only after you have modified the package.
Another option is to create a folder mocks and create a file .js called exactly like your module or import and then return whatever you need. This works best for global dependencies.
Lastly, what you also can do is to make your tested object receive the dependency as a parameter, so you can override the import inside the file.
Hope it helps
I'm experiencing with the whole React and I have a hard time clearly understanding the issue I have right now in one of my Unit Test. I committed (and pushed) my whole project so it will be easier to get all the necessary details to understand the problem.
But basically, I can't make any assertion on updated DOM elements as it keep giving me the original DOM.
Here's the Unit Test :
jest.unmock('../display.js');
import React from 'react';
import ReactDOM from 'react-dom';
import sinon from 'sinon';
import TestUtils from 'react-addons-test-utils';
import EmoticonDisplay from "../display.js";
describe('Selector', () => {
var component, renderedDOM;
beforeEach(() => {
renderComponent(true);
});
afterEach(() => {});
it('is not displayed if IsLoggedIn returns false', () => {
expect(renderedDOM()).not.toBe(null);
//Why do I need to re-render? If I change the value of isLoggedIn and I try to access the DOM
//it is still the same value as before
renderComponent(false);
expect(renderedDOM()).toBe(null);
});
it('sets default states', () => {
expect(component.state.stack).toEqual([]);
expect(component.state.isAnimating).toEqual(false);
expect(component.state.currentItem).toEqual({emote: 'none', username: ''});
expect(TestUtils.findRenderedDOMComponentWithTag(component, 'img').src).toBe('images/none.svg');
});
it('animates a newly received emoticon', () => {
var data = {emote:'cool', username:'swilson'};
component.animate(data);
expect(component.state.stack).toEqual(jasmine.objectContaining(data));
//Same potential issue as explained earlier. Altough everything I find online tells me I should get the
//updated DOM, I still have images/none.svg even though the code changes the source of the picture
console.log(TestUtils.scryRenderedDOMComponentsWithTag(component, 'img')[0].src);
});
function renderComponent(isLoggedIn) {
component = TestUtils.renderIntoDocument(<EmoticonDisplay isLoggedIn={ isLoggedIn } />);
renderedDOM = () => ReactDOM.findDOMNode(component);
}
});
File in repo : https://github.com/jprivard/scrum-companion/blob/9436903050697be3eb15cb31075e832980eb0b9f/app/modules/emoting/tests/display.test.js
Somehow, when I look for an answer online, I can see the exact same code running and working. And some other times, I see other ways to do it, but it seems incompatible with my current version of React/Jest/Jasmine/...
Please help :)