I need to unit test the following method which takes one parameter. But I am unable to test.
Component Method:
resetAdd(qa: qaModel) {
const street = qa.children.find(temp => temp.token === 'street');
const zip = qa.children.find(temp => temp.token === 'zip');
const city = qa.children.find(temp => temp.token === 'city');
this.fGroup.controls[street.pathway].callReset();
this.fGroup.controls[zip.pathway].callReset();
this.fGroup.controls[city.pathway].callReset();
}
TestFile:
it('resetAdd Method is called', () => {
const param1= jest.fn();
expect(component.resetAdd).toHaveBeenCalledWith(param1);
});
I am not sure what's wrong and also please let me know what else test case I can write.
Here is the unit test solution, you can use jest.spyOn:
By default, jest.spyOn also calls the spied method. This is different behavior from most other test libraries.
That means when you can jest.spyOn to spy on a method of object without custom implementation, the original method of this object will be executed as usual. Beside, there is a spy on the method, so you can use assert of jest to check if it is executed or not. For your case, the method is callReset.
index.ts:
type qaModel = any;
export class SomeComponent {
private fGroup = {
controls: {
street: {
callReset() {}
},
zip: {
callReset() {}
},
city: {
callReset() {}
}
}
};
resetAdd(qa: qaModel) {
const street = qa.children.find(temp => temp.token === 'street');
const zip = qa.children.find(temp => temp.token === 'zip');
const city = qa.children.find(temp => temp.token === 'city');
this.fGroup.controls[street.pathway].callReset();
this.fGroup.controls[zip.pathway].callReset();
this.fGroup.controls[city.pathway].callReset();
}
}
index.spec.ts:
import { SomeComponent } from './';
describe('SomeComponent', () => {
it('should call resetAdd', () => {
const comp = new SomeComponent();
const streetCallResetSpy = jest.spyOn(comp['fGroup']['controls']['street'], 'callReset');
const zipCallResetSpy = jest.spyOn(comp['fGroup']['controls']['zip'], 'callReset');
const cityCallResetSpy = jest.spyOn(comp['fGroup']['controls']['city'], 'callReset');
const qaModel = {
children: [
{ token: 'street', pathway: 'street' },
{ token: 'zip', pathway: 'zip' },
{ token: 'city', pathway: 'city' }
]
};
comp.resetAdd(qaModel);
expect(streetCallResetSpy).toBeCalledTimes(1);
expect(zipCallResetSpy).toBeCalledTimes(1);
expect(cityCallResetSpy).toBeCalledTimes(1);
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/58818402/index.spec.ts
SomeComponent
✓ should call resetAdd (5ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.612s, estimated 8s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58818402
You are not calling resetAdd method in unit test, still expecting it should have been called.
Steps are :
Spy method which you want to be called,
call that method
then check for to have been called
it('resetAdd Method is called', () => {
const param: qaModel = null // define param of type which is expected. I dont know structure of qaModel, so for example put as null
spyOn(component, 'resetAdd') // spy first
component.resetAdd(param)
expect(component.resetAdd).toHaveBeenCalledWith(param);});
Related
I'm trying to learn unit testing for testing our react application. I'm starting with actions.
I have a function, the object that returned also has a nested function.
hello.actions.js
export function loadData(request){
return {
type: types.TEST_API,
coreApi: {
body: request,
success: (response) => [receiveData(response), update(response)]
}
}
}
export function receiveData(request){...}
export function update(request){...}
What I tried to do on returning success, it'll be () => jest.fn()
helloActions.test.js
describe("Action: hello", () => {
const payload = {
request: "request"
}
const expectedAction = {
type: types.TEST_API,
coreApi: {
body: request,
success: () => jest.fn()
}
}
expect(actions.loadData(payload.request)).toEqual(expectedAction);
});
});
If I remove the success line from both test and action, it works. So I've pin pointed it to be something wrong with the success line. Any insight would be greatly appreciated. I even tried to push success: (response) => [receiveData(response), update(response)] in the unit test but that fails as well.
The expect().toEqual() method can't compare two functions. See this anwser
You can use expect.any(constructor) matches anything that was created with the given constructor.
E.g.
hello.actions.js:
export const types = {
TEST_API: 'TEST_API',
};
export function loadData(request) {
return {
type: types.TEST_API,
coreApi: {
body: request,
success: (response) => [receiveData(response), update(response)],
},
};
}
export function receiveData(request) {}
export function update(request) {}
hello.actions.test.js:
import { loadData, types } from './hello.actions';
describe('67236356', () => {
it('should pass', () => {
const payload = {
request: 'request',
};
const expectedAction = {
type: types.TEST_API,
coreApi: {
body: payload.request,
success: expect.any(Function),
},
};
expect(loadData(payload.request)).toEqual(expectedAction);
});
});
unit test result:
PASS examples/67236356/hello.actions.test.js (9.468 s)
67236356
✓ should pass (3 ms)
------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------|---------|----------|---------|---------|-------------------
All files | 83.33 | 100 | 25 | 83.33 |
hello.actions.js | 83.33 | 100 | 25 | 83.33 | 9
------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.811 s
I'm trying to figure out how to perform unit tests, with Jest, on my code but I have been struggling with this. I want to be able to test the constructor and the method in my unit test but I can't understand how to do it in an efficient way.
class CommandOption {
constructor(commands) {
this.section = commands[0]
this.method = commands[1]
this.command1 = commands[2]
}
option(optionName) {
return require(`../commands/options/${optionName}`)(this)
}
}
I know that I can test the constructor fairly easily, in this case, but I don't know if it is good way or not.
const CommandOption = require('./command-option')
it('should equal "hardware", "get", and "byid"', () => {
let commandOption = new CommandOption(['hardware','get','byid'])
expect(commandOption.section).toBe('hardware')
expect(commandOption.method).toBe('get')
expect(commandOption.command1).toBe('byid')
}
I don't really know how to go about mocking the option method from there... I have read about using jest.spyOn() but I can't seem to wrap my head around it for my case... probably because I am trying to overthink it.
Unit test solution:
command-option.js:
class CommandOption {
constructor(commands) {
this.section = commands[0];
this.method = commands[1];
this.command1 = commands[2];
}
option(optionName) {
return require(`./commands/options/${optionName}`)(this);
}
}
module.exports = CommandOption;
command-option.test.js:
const CommandOption = require('./command-option');
describe('64327189', () => {
it('should equal "hardware", "get", and "byid"', () => {
let commandOption = new CommandOption(['hardware', 'get', 'byid']);
expect(commandOption.section).toBe('hardware');
expect(commandOption.method).toBe('get');
expect(commandOption.command1).toBe('byid');
});
it('should load option by name', () => {
const optionSetter = jest.fn();
jest.doMock('./commands/options/host', () => optionSetter);
let commandOption = new CommandOption(['hardware', 'get', 'byid']);
const optionName = 'host';
commandOption.option(optionName);
expect(optionSetter).toBeCalledWith(commandOption);
});
});
commands/options/host.js:
// whatever
unit test result with coverage report:
PASS src/stackoverflow/64327189/command-option.test.js
64327189
✓ should equal "hardware", "get", and "byid" (4ms)
✓ should load option by name (3ms)
-------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
command-option.js | 100 | 100 | 100 | 100 | |
-------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.848s, estimated 10s
I have a function, lets call it generateName, which as you’ve guessed it, generates a name. The problem is that a new name is generated each time time a test is ran.
In one of my tests, I assert that a function is called with an object containing this name. However, the name keeps on changing. I could just check that the object has property name, but I don’t really want to do that.
My idea is that I can mock the return value of the generateName function and do something like this
Import { generateName } from ‘libs/generateName’
jest.fn(generateName).mockResolvedValue ( ‘hello’ )
expect ( spy ).toHaveBeenCalledWith (
expect.objectContaining ( {
name: 'houses',
} )
)
You can use jest.mock(moduleName, factory, options) to mock libs/generateName module.
E.g.
generateName.ts:
export async function generateName() {
const name = Math.random() + '';
return name;
}
main.ts:
import { generateName } from './generateName';
export function main() {
return generateName();
}
main.test.ts:
import { main } from './main';
import { generateName } from './generateName';
jest.mock('./generateName', () => {
return {
generateName: jest.fn(),
};
});
describe('61350152', () => {
it('should pass', async () => {
(generateName as jest.MockedFunction<typeof generateName>).mockResolvedValueOnce('hello');
const actual = await main();
expect(actual).toBe('hello');
});
});
unit test results with coverage report:
PASS stackoverflow/61350152/main.test.ts (28.524s)
61350152
✓ should pass (6ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
main.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 31.98s
I have a function that looks roughly like this:
import {someLibraryMethod} from 'someLibrary';
function setFullWidth(el) {
someLibraryMethod(el);
el.setAttribute('width', '100%');
}
I'm testing this function by using Sinon to create a mock element that only supports setAttribute:
const fakeElement = {
setAttribute: sinon.spy()
};
setFullWidth(fakeElement);
assert(fakeElement.setAttribute.calledWithExactly('width', '100%'));
The problem is that someLibraryMethod assumets el is an HTML element and tries to call some other methods on it, such as hasAttribute. I could add these as stubs or spies to fakeElement too, but I was wondering if Sinon has a way to create an object that will spy on any method or property access on it?
Something like:
const fakeElement = sinon.spyOnAnyPropety();
fakeElement.setAttribute(); // valid
fakeElement.hasAttribute(); // valid
fakeElement.foo(); // also valid
// some way to check which methods were called
You can use sinon.stub(obj) to
Stubs all the object’s methods.
E.g.
index.ts:
export function setFullWidth(el) {
el.setAttribute('width', '100%');
el.hasAttribute('width');
el.foo();
}
index.spec.ts:
import { setFullWidth } from './';
import sinon, { SinonStubbedInstance } from 'sinon';
import { expect } from 'chai';
describe('58868361', () => {
const fakeElement = {
setAttribute(attr, value) {
console.log('setAttribute');
},
hasAttribute(attr) {
console.log('hasAttribute');
},
foo() {
console.log('foo');
},
};
afterEach(() => {
sinon.restore();
});
it('should spy all methods of el', () => {
const logSpy = sinon.spy(console, 'log');
const stub: SinonStubbedInstance<typeof fakeElement> = sinon.stub(fakeElement);
setFullWidth(fakeElement);
expect(stub.setAttribute.calledWithExactly('width', '100%')).to.be.true;
expect(stub.hasAttribute.calledWithExactly('width')).to.be.true;
expect(stub.foo.calledOnce).to.be.true;
expect(logSpy.callCount).to.be.equal(0);
logSpy.restore();
});
it('should restore to original methods of el', () => {
const logSpy = sinon.spy(console, 'log');
setFullWidth(fakeElement);
expect(logSpy.callCount).to.be.equal(3);
});
});
Unit test result with 100% coverage:
58868361
✓ should spy all methods of el
setAttribute
hasAttribute
foo
✓ should restore to original methods of el
2 passing (13ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.spec.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mongoose5.x-lab/tree/master/src/stackoverflow/58868361
this is the code I have to test:
myFunction: function(data) {
var file = new Blob(data, {type: 'text/plain'});
window.open(window.URL.createObjectURL(file));
}
In order to test it, I thought to test if the window.open function is called, applying a 'spy' on window.open , in the following way:
sandbox.spy(window, 'open');
but, even leaving previous line as the unique line in the test, what I only get is the test failure and the following message:
global leaks detected: consoleLogging, open
Thus, in order to avoid that, I tried to re-define the function in the test in this way:
global.window = {
open: function (url) {}
};
In this case an exception raised:
Attempted to assign to readonly property
Then I tried to mock the 'open' via the following:
sandbox.mock(window, 'open');
objectUnderTest.myFunction();
expect(window.open.callCount).to.equal(1);
this way, I get no global or readonly errors, but an exception on the 'expect', telling that:
expected undefined to equal 1
Does someone knows a way to successfully test window.open?
Here is the unit test solution based on Node.js environment:
index.js:
const obj = {
myFunction: function(data) {
var file = new Blob(data, { type: 'text/plain' });
window.open(window.URL.createObjectURL(file));
}
};
module.exports = obj;
index.spec.js:
const obj = require('./');
const sinon = require('sinon');
const { expect } = require('chai');
describe('53524524', () => {
before(() => {
class Blob {}
global.Blob = Blob;
global.window = {
open() {},
URL: {
createObjectURL() {}
}
};
});
it('should test myFunction correctly', () => {
const openStub = sinon.stub(window, 'open');
const createObjectURLStub = sinon.stub(global.window.URL, 'createObjectURL').returns('fake object url');
obj.myFunction('fake data');
expect(createObjectURLStub.calledOnce).to.be.true;
expect(openStub.calledWith('fake object url')).to.be.true;
});
});
Unit test result with coverage report:
53524524
✓ should test myFunction correctly
1 passing (11ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 66.67 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
index.spec.js | 100 | 100 | 60 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/53524524