How to test a callback of a mocked function with jasmine? - jasmine

A method of a third party service that I am using has a callback as the second argument. This callback is executed in real life when the response is received from the server.
I want to mock the third party method for unit testing, and supply different response arguments to the callback to ensure that its logic executes correctly. For example to check that the promise is rejected when the status is NOT 'success', or that on success just the saved record is returned and not the whole response.
I am using jasmine for testing.
function save() {
var deferred = $q.defer();
thirdPartyService.doSave(record, function callback(response) {
// How to test the code in here when doSave is mocked?
if(response.status === 'success') {
deferred.resolve(response.savedRecord);
} else {
deferred.reject(response);
}
});
return deferred.promise;
}
Example of a test I'd like to run:
// Setup
const successResponse = {
status: 'success',
savedRecord: { Id: 'test-id' }
};
// Somehow config the mocked thirdParty.doSave() to use successResponse for the callback.
// Test
myService.save()
.then(function(response) {
expect(response.Id).toBe('test-id');
});;

You could mock thirdParty.doSave using spyOn.and.callFake.
const successResponse = {
status: 'success',
savedRecord: { Id: 'test-id' }
};
spyOn(thirdParty, 'doSave').and.callFake((record, callback) => callback(successResponse));

Related

How to test emit event on ngSubmit within component subscribe method

On form submit getUsers() is called and if success message is received, the received data is emitted to the parent component.
child html
<form (ngSubmit)="getUsers()">
</form>
child component
getUsers(): void {
this.userService.getUsers().subscribe(users => {
if(users.status=="Success"{
this.listOfUsers = users;
this.user.emit(this.listOfUsers);
this.nextTab.emit(true);
}
});
}
i have written the test case to check emit event as follows
it('should emit data on success', () => {
spyOn(component.user,'emit');
component.getUsers();
expect(component.user.emit).toHaveBeenCalled(); // fails as never called what i am doing wrong
});
You have to make sure that userService.getUsers returns an observable.
import { of } from 'rxjs';
....
it('should emit data on success', () => {
// mock userService.getUsers to return { status: 'Success' } to go inside of the if block
spyOn(userService, 'getUsers').and.returnValue(of({ status: 'Success' }));
spyOn(component.user,'emit');
component.getUsers();
expect(component.user.emit).toHaveBeenCalled(); // fails as never called what i am doing wrong
});
Edit
To actually test ngSubmit, I would use triggerEventHandler. You can do some research on it.
const form = fixture.debugElement.query(By.css('form'));
// The 2nd argument is what you would like the $event value to be.
// In our case, null is fine.
form.triggerEventHandler('ngSubmit', null);
Doing the above will call getUsers.

Testing an Async function using Jest / Enzyme

Trying run a test case for the following:
async getParents() {
const { user, services, FirmId } = this.props;
let types = await Models.getAccounts({ user, services, firmId: FirmId });
let temp = types.map((type) => {
if(this.state.Parent_UID && this.state.Parent_UID.value === type.Account_UID) {
this.setState({Parent_UID: {label: type.AccountName, value: type.Account_UID}})
}
return {
label: type.AccountName,
value: type.Account_UID,
}
})
this.setState({ParentOptions: temp});
}
here is what i have so far for my test:
beforeEach(() => wrapper = mount(<MemoryRouter keyLength={0}><AccountForm {...baseProps} /></MemoryRouter>));
it('Test getParents function ',async() => {
wrapper.setProps({
user:{},
services:[],
FirmId:{},
})
wrapper.find('AccountForm').setState({
SourceOptions:[[]],
Parent_UID: [{
label:[],
value:[],
}],
});
wrapper.update();
await
expect(wrapper.find('AccountForm').instance().getParents()).toBeDefined()
});
If i try to make this ToEqual() it expects a promise and not anobject, what else could I add into this test to work properly.
Goal: Make sure the functions gets called correctly. The test is passing at the moment and has a slight increase on test coverage.
Using Jest and Enzyme for React Js
you can put the await before the async method, like:
await wrapper.find('AccountForm').instance().getParents()
and compare if the state was changed.
In another way, if can mock your API request, because this is a test, then you do not need the correct API, but know if the function calls the API correctly and if the return handling is correct.
And, you cand spy the function like:
const spy = jest.spyOn(wrapper.find('AccountForm').instance(), 'getParents');
and campare if the function was called if they are triggered by some action:
expect(spy).toBeCalled()

.then is not a function Angularjs factory

I just started learning Jasmine test cases for angularjs. I am unable to test below code.Kindly help
$scope.getConstants = function(lovName) {
ConstantService.getConstants(lovName).then(function(d) {
switch (lovName) {
case 'WORKFLOW':
$scope.workflowTypes = d;
$scope.loadCounterpartyTmp();
break;
--------Other Cases
}
My ConstantService is defined as
App.factory('ConstantService', [ '$http', '$q', function($http, $q) {
return {
getConstants : function(lovName) {
return $http.post('/sdwt/data/getConstants/', lovName).then(function(response) {
return response.data;
}, function(errResponse) {
return $q.reject(errResponse);
});
}
I want to test getConstants function.I need to create a mock of ConstantService and pass the data to it.
I have written below test case but the test case is not working.Please let me know how to test the above code
describe('getConstantsForMurexEntity', function() {
it('testing getConstantsForMurexEntity function', function() {
var d=[];
d.push(
{id:1,value:'ABC'},
{id:2,value:'DEF'},
{id:3,value:'IJK'},
{id:4,value:'XYZ'},
);
//defined controller
spyOn(ConstantService, 'getConstants').and.returnValue(d);
$scope.getConstants('WORKFLOW');
expect($scope.workflowTypes).toBe(d);
The above test case is not working as it is saying "ConstantService.getConstants(...).then is not a function".
Your ConstantService.getConstants() function returns a promise, which your actual code is using, with the .then() call. This means means that when you spy on it, you also need to return a promise, which you are not doing. Because you are not returning a promise, when your actual call tries to call .then(), it is undefined, which is the reason for the error message.
Also, you aren't using Array.push correctly.
Your test should probably look something like the following (note, this is untested):
describe('getConstantsForMurexEntity', function() {
it('should set workflowTypes to the resolved value when lovName is "WORKFLOW"', inject(function($q) {
var deferred = $q.defer();
spyOn(ConstantService, 'getConstants').and.returnValue(deferred.promise);
var d = [
{id:1,value:'ABC'},
{id:2,value:'DEF'},
{id:3,value:'IJK'},
{id:4,value:'XYZ'},
];
$scope.getConstants('WORKFLOW');
deferred.resolve(d);
$scope.$apply();
expect($scope.workflowTypes).toBe(d);
}));
});

custom async validation not working when returning a promise

I'm calling the web api to check if an urlalias is available, for this task I'm using a httpservice in my async validator.
The issue is that when the validator is called, all the correct code path is performed (all the console.log() run and behave as expected).
Whether the promise from the validation returns/resolves to null or an { 'isUrlAliasActivityMainAvailable': true }, the controller always shows an error object as following, thus keeping the form state as invalid, why (bloody hell!)?
I'm using: angular:2.1.0 and rxjs:5.0.0-beta.12
This is my formbuilder:
this.formBuilder.group({
//...
"urlAliasActivityMain":[null,[ ValidatorsZr.isUrlAliasActivityMainAvailableAsyncValidator(this.httpActivityService)]],
});
This is my validator:
public static isUrlAliasActivityMainAvailableAsyncValidator(httpActivityService: HttpActivityService) {
return function (control: FormControl): Promise<any> | Observable<any> {
const promise = new Promise<any>(
(resolve, reject) => {
httpActivityService.isUrlAliasActivityMainAvailable(control.value)
.subscribe(
(data: any) => {
console.log("isUrlAliasActivityMainAvailableAsyncValidator");
console.log(data);
if (data == false) {
console.log("data == false");
resolve({ 'isUrlAliasActivityMainAvailable': true });
}
else {
console.log("data == true");
resolve(null);
}
},
)
});
return promise;
}
}
Your async validator is listed in the synchronous validators location in the array and is being incorrectly evaluated.
[objectValue, synchronous validators, asynchronous validators]
control(formState: Object, validator?: ValidatorFn|ValidatorFn[],
asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]) : FormControl
Construct a new FormControl with the given formState,validator, and
asyncValidator.
formState can either be a standalone value for the form control or an
object that contains both a value and a disabled status.
To correct it, move your validator to the appropriate array location:
this.formBuilder.group({
//...
"urlAliasActivityMain":[null, null, ValidatorsZr.isUrlAliasActivityMainAvailableAsyncValidator(this.httpActivityService)],
});

Synchronous simple command stops test run

I've written tons of Nightwatch custom commands which use execute and everything has been fine except now I want to do something that doesn't use execute or any of the element API.
I've found that in it's simplest form like below, it breaks all my tests from running. The callback is triggered but no subsequent tests will run, and the after callback is not called. As soon as I do something that uses the element API in this command, everything is fine.
// getTest.js command
exports.command = function (callback) {
// this.execute(function () {}, [], function () {}); uncomment this and everything works
if (typeof callback === 'function') {
callback.call(this, 'test');
}
return this;
};
module.exports = {
'this test does run': client => {
client
.getTest((res) => {
console.log(res); // 'test'
});
},
'nope, this will not run': client => {
console.log('Please run!'); // NOPE
}
};

Resources