Can anyone point me in the right direction to test both the success and .catch scenarios in this function? I don't know how to mock my resource properly to do this.
function loadData() {
cisVersionResource.get({ 'cisId': vm.cisId })
.$promise.then(function(data) {
vm.newContractSum = data.contractSum;
})
.catch(function(response) {
logger.warning('CIS Retrieve Warning', 'unable to retrieve CIS information', response.data);
});
}
Related
I have created Cypress e2e tests that use the following functions:
to mock the responses
export function getUserAndSupplier(): void {
cy.intercept('GET', `${Cypress.env('BaseUrl')}/users/me`,
{
fixture: 'shared/Users/me.json',
})
.as('users');
cy.intercept('GET', `${Cypress.env('BaseUrl')}/users/me/supplier`,
{
fixture: 'shared/Suppliers/supplier.json',
})
.as('supplier');
}
to check if responses are in accordance to the fixtures:
export function checkUserAndSupplier(): void {
cy.wait('#users')
.its('response.body')
.should('not.be.undefined')
.then((interception: any) => {
//assertions on each field
});
cy.wait('#supplier')
.its('response.body')
.should('not.be.undefined')
.then((interception: GetCurrentSupplierResponse) => {
//assertions on each field
});
}
Tests have Cucumber preprocessor implemented, the GIVEN and WHEN steps definition for given test are:
beforeEach(() => {
// intercept user and supplier api
getUserAndSupplier();
// intercept GET /paymentProviders
interceptPaymentProviders();
});
Given('User navigates to the {string} page', () => {
cy.visit('/sell/payment-providers');
// assert api calls on user and supplier
checkUserAndSupplier();
});
When('User clicks on {string} button', () => {
getActivationButton()
.scrollIntoView()
.contains('Activate')
.should('be.visible')
.and('not.be.disabled')
.click();
// Ensure Continue Button is disabled
getContinueButton()
.should('be.visible')
.and('be.disabled');
});
while the .feature file test is:
Scenario: Happy path - activate payment method
Given User navigates to the "sell/payment-providers" page
When User clicks on "activate" button
Then User is able to successfully activate payment provider
The problem is that sometimes, despite having responses mocked using fixtures (they're not null or empty), 'response.body' property is undefined, which makes tests flaky.
At the beginning I thought I have some asynchronous functions that lack await and make response.body being undefined, but this was not the case.
What may be the cause of this? And what makes it sometimes working, and sometimes not?
It's hard to tell what exactly is going on, the code looks ok.
Here's some general tips to try.
Cache
It's possible the browser cache is interfering with the intercept. To avoid caching, add this
beforeEach(() => {
Cypress.automation('remote:debugger:protocol', {
command: 'Network.clearBrowserCache'
})
...
})
Debug call sequence
To debug the network calls, combine the two intercepts and use callbacks to console.log what gets intercepted.
If something is changing the order of response, the problem may be caused by the sequence of cy.wait('#users') followed by cy.wait('#supplier') so combining the intercepts will catch that.
export function getUserAndSupplier(): void {
cy.intercept('/users*', (req) => {
if (req.url.endsWith('/me')) {
console.log('users request', req)
req.alias = 'users'
req.reply({fixture: 'shared/Users/me.json'})
}
if (req.url.endsWith('/me/supplier')) {
console.log('supplier request', req)
req.alias = 'supplier'
req.reply({fixture: 'shared/Suppliers/supplier.json'})
}
})
}
Or use a single alias for both paths and check inside the interception.
export function getUserAndSupplier(): void {
cy.intercept('/users*', (req) => {
if (req.url.endsWith('/me')) {
req.reply({fixture: 'shared/Users/me.json'})
}
if (req.url.endsWith('/me/supplier')) {
req.reply({fixture: 'shared/Suppliers/supplier.json'})
}
})
.as('both')
}
export function checkUserAndSupplier(): void {
const checkInterception = (interception) => {
if (interception.request.url.endsWith('/me')) {
console.log('users response', interception.response)
// assertions for users
}
if (interception.request.url.endsWith('/me/supplier')) {
console.log('supplier response', interception.response)
// assertions for supplier
}
}
cy.wait('#both').then(checkInterception); // first interception
cy.wait('#both').then(checkInterception); // second interception
}
Lastly, something in interceptPaymentProviders() is interfering with the other intercepts.
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));
This question is not about a problem which I can't solve, it is just a curiosity. I'm not very experienced with Mocha, but there's something interesting I've stumbled upon already.
What I want is to use done() to tell Mocha the promise has been resolved.
The following code DOESN'T work:
beforeEach((done) => {
user = new User({ name: 'Dummy' })
user.save()
.then(done)
})
I know I'm passing the result of the user.save() promise to done, but I think it shouldn't be a problem.
Instead this other code works:
beforeEach((done) => {
user = new User({ name: 'Dummy' })
user.save()
.then(() => done())
})
It seems to me that Mocha done() has some kind of control flow which leads to: Error: done() invoked with non-Error: {"_id":"5b65b9d2669f7b2ec0a3d503","name":"Dummy","__v":0}
Is it because done() wants strictly an error as its argument?
Why done() does even care about what I pass to it?
Can you make some example showing why done() argument to be an Error is useful?
Thanks in advance ;)
It is because done() in Mocha only accepts Error argument. In your case, your save() method returns json object not an Error ie new Error('failed save').
If we take a look at mocha test file, we can see that it won't accept other type of arguments.
// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L358
describe('when done() is invoked with a string', function () {
it('should invoke the callback', function (done) {
var test = new Runnable('foo', function (done) {
done('Test error'); // specify done with string/text argument
});
test.run(function (err) {
assert(err.message === 'done() invoked with non-Error: Test error');
done();
});
});
});
But if we see the test when the argument is Error, it works
// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L345
describe('when an error is passed', function () {
it('should invoke the callback', function (done) {
var test = new Runnable('foo', function (done) {
done(new Error('fail'));
});
test.run(function (err) {
assert(err.message === 'fail');
done();
});
});
});
Btw, I suggest that you avoid using done since mocha supports promise by specifying return statement. So, we change the code into
beforeEach(() => {
user = new User({ name: 'Dummy' })
return user.save().then(user => {
// antyhing todo with user
});
});
Hope it helps.
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);
}));
});
Following the testingBot example for protractor-based projects I got this code
var TestingBot = require('testingbot-api');
describe('Protractor Demo App', function () {
var tb;
beforeEach(function () {
tb = new TestingBot({
api_key: "master_key",
api_secret: "secret_007"
});
});
afterEach(function () {
browser.getSession().then(function (session) {
tb.updateTest({
'test[success]': true/*where do I get this 'test[success]' attribute? */
}, session.getId(), function () {
console.log("Hi! :D");
});
})
});
it('should have a title', function () {
browser.get('http://juliemr.github.io/protractor-demo/');
expect(browser.getTitle()).toEqual('Super Calculator');
});
});
I need to send the success of the test back through the tb.updateTest() but I don't know where I get the value of a passed or failed test. For now the value is a static true. I'd appreciate a jasmine approach too.
You can use a custom reporter with Jasmine.
There you can hook into specDone or suiteDone which has a result parameter, containing the test's success state.
You can then use this state to write a custom report or send it to somewhere else.