Expected and Actual Values in Failed Protractor Test Cases - jasmine

I have recently installed the jasmine-spec-reporter package in order to produce more verbose and helpful logging during execution of test suites.
I want to be able to log expected and actual values for failed test cases and was wondering if I needed to explicitly have a statement in the form of expect(someCondition).toEqual(true); in order for me to see these values.
For example, I have a function like the following:
it('should log in', function(done) {
var customerNameElement;
customerNameElement = element.all(by.xpath('some_xpath')).first();
core.infoMessage(browser, JSON.stringify(params, undefined, 4));
login.login(browser, undefined, undefined, getWaitTime())
.then(function() {
return browser.wait(protractor.ExpectedConditions.and(
function() { return core.isUnobscured(browser, customerNameElement);
}, protractor.ExpectedConditions.elementToBeClickable(customerNameElement)), getWaitTime());
})
.catch(fail)
.then(done);
});
I can still log the failure to the console but not in the form that I'd like. Does jasmine-spec-reporter handle this or do I have to add the statement from above in each test case?
Also, does the fail keyword in the .catch() have any properties I can use to my advantage? It comes from:
// Type definitions for Jasmine 2.5.2 // Project: http://jasmine.github.io/
Thanks

you can try adding the below in protractor_config file:
let SpecReporter = require('jasmine-spec-reporter').SpecReporter;
exports.config = {
// your config here ...
onPrepare: function () {
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
}));
}
}
Also, add the print function in the jasmineNodeOptssection
jasmineNodeOpts: {
...
print: function() {}
}

Related

Mocha .then(done) doesn't work as expected

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.

.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);
}));
});

How to send the success of a test to testingBot from a Protractor project?

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.

How to exit Protractor test from Spec on specific condition?

I have a suite which includes multiple specs. Each spec uses code on some libraries that return a rejected promise upon failure.
I can easily catch those rejected promises inside my spec. What I'm wondering about is that if I can make Protractor exit the whole suite inside that catch function, because the next specs inside the same suite are dependent on the success of the previous specs.
Pretend I have a suite called testEverything which has these specs openApp,signIn,checkUser,logout. If openApp fails, all next specs will fail due to dependency.
Consider this code for openApp:
var myLib = require('./myLib.js');
describe('App', function() {
it('should get opened', function(done) {
myLib.openApp()
.then(function() {
console.log('Successfully opened app');
})
.catch(function(error) {
console.log('Failed opening app');
if ( error.critical ) {
// Prevent next specs from running or simply quit test
}
})
.finally(function() {
done();
});
});
});
How would I exit the whole test?
There is a module for npm called protractor-fail-fast. Install the module npm install protractor-fail-fast. Here's an example from their site where you would place this code into your conf file:
var failFast = require('protractor-fail-fast');
exports.config = {
plugins: [{
package: 'protractor-fail-fast'
}],
onPrepare: function() {
jasmine.getEnv().addReporter(failFast.init());
},
afterLaunch: function() {
failFast.clean(); // Cleans up the "fail file" (see below)
}
}
Their url is here.
I have managed to come up with a workaround. Now the actual code that I used is way more complex, but the idea is the same.
I added a global variable inside protractor's config file called bail. Consider the following code at the top of config file:
(function () {
global.bail = false;
})();
exports.config: { ...
The above code uses an IIFE (Immediately Invoked Function Expression) which defines bail variable on protractor's global object (which would be available throughout the whole test).
I also have written asynchronous wrappers for the Jasmine matchers I need, which would execute an expect expression followed by a comparison, and return a promise (using Q module). Example:
var q = require('q');
function check(actual) {
return {
sameAs: function(expected) {
var deferred = q.defer();
var expectation = {};
expect(actual).toBe(expected);
expectation.result = (actual === expected);
if ( expectation.result ) {
deferred.resolve(expectation);
}
else {
deferred.reject(expectation);
}
return deferred.promise;
}
};
}
module.exports = check;
Then at the end of each spec, I set the bail value based on the spec's progress, which would be determined by the promise of those asynchronous matchers. Consider the following as first spec:
var check = require('myAsyncWrappers'); // Whatever the path is
describe('Test', function() {
it('should bail on next spec if expectation fails', function(done) {
var myValue = 123;
check(myValue).sameAs('123')
.then(function(expectation) {
console.log('Expectation was met'); // Won't happen
})
.catch(function(expectation) {
console.log('Expectation was not met'); // Will happen
bail = true; // The global variable
})
.finally(function() {
done();
});
});
});
Finally, on the beginning of next specs, I check for bail and return if necessary:
describe('Test', function() {
it('should be skipped due to bail being true', function(done) {
if ( bail ) {
console.log('Skipping spec due to previous failure');
done();
return;
}
// The rest of spec
});
});
Now I want to mention that there's one module out there called protractor-fail-fast which bails on the whole test whenever an expectation fails.
But in my case, I needed to set that bail global variable depending on which type of expectation has been failed. I ended up writing a library (really small) that distinguishes failures as critical and non-critical and then using that, specs would be stopped only if a critical failure has occurred.

How do I focus on one spec in jasmine.js?

I have a bunch of failing specs from a rather large architectural change. I'd like to work on fixing them one by one by tagging each one with 'focus'.
Does jasmine.js have a feature like this? I swore I read at one point that it does but I don't see it in the docs.
When using Karma, you can enable only one test with fit or fdescribe (iit and ddescribe in Jasmine before 2.1).
This only runs Spec1:
// or "ddescribe" in Jasmine prior 2.1
fdescribe('Spec1', function () {
it('should do something', function () {
// ...
});
});
describe('Spec2', function () {
it('should do something', function () {
// ...
});
});
This only runs testA:
describe('Spec1', function () {
// or "iit" in Jasmine prior 2.1
fit('testA', function () {
// ...
});
it('testB', function () {
// ...
});
});
In core since 2.1 with fit and fdescribe.
You can run a single spec by using the url for the spec
describe("MySpec", function() {
it('function 1', function() {
//...
})
it('function 2', function() {
//...
}
})
Now you can run just the whole spec by this url http://localhost:8888?spec=MySpec and a the first test with http://localhost:8888?spec=MySpec+function+1
There are a few ways you can do it.
There is: Jasmine's feature Focused Specs (2.2): http://jasmine.github.io/2.2/focused_specs.html
Focusing specs will make it so that they are the only specs that run. Any spec declared with fit is focused.
describe("Focused specs", function() {
fit("is focused and will run", function() {
expect(true).toBeTruthy();
});
it('is not focused and will not run', function(){
expect(true).toBeFalsy();
});
});
However, I don't really like the idea of editing my tests (fit and fdescribe) to run them selectively. I prefer to use a test runner like karma which can filter out tests using a regular expression.
Here's an example using grunt.
$ grunt karma:dev watch --grep=mypattern
If you're using gulp (which is my favourite task runner), you can pass args into gulp-karma with yargs and match patterns by setting karma's config.
Kinda like this:
var Args = function(yargs) {
var _match = yargs.m || yargs.match;
var _file = yargs.f || yargs.file;
return {
match: function() { if (_match) { return {args: ['--grep', _match]} } }
};
}(args.argv);
var Tasks = function() {
var test = function() {
return gulp.src(Files.testFiles)
.pipe(karma({ configFile: 'karma.conf.js', client: Args.match()}))
.on('error', function(err) { throw err; });
};
return {
test: function() { return test() }
}
}(Args);
gulp.task('default', ['build'], Tasks.test);
See my gist: https://gist.github.com/rimian/0f9b88266a0f63696f21
So now, I can run a single spec using the description:
My local test run: (Executed 1 of 14 (skipped 13))
gulp -m 'triggers the event when the API returns success'
[20:59:14] Using gulpfile ~/gulpfile.js
[20:59:14] Starting 'clean'...
[20:59:14] Finished 'clean' after 2.25 ms
[20:59:14] Starting 'build'...
[20:59:14] Finished 'build' after 17 ms
[20:59:14] Starting 'default'...
[20:59:14] Starting Karma server...
INFO [karma]: Karma v0.12.31 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
WARN [watcher]: All files matched by "/spec/karma.conf.js" were excluded.
INFO [Chrome 42.0.2311 (Mac OS X 10.10.3)]: Connected on socket hivjQFvQbPdNT5Hje2x2 with id 44705181
Chrome 42.0.2311 (Mac OS X 10.10.3): Executed 1 of 14 (skipped 13) SUCCESS (0.012 secs / 0.009 secs)
[20:59:16] Finished 'default' after 2.08 s
Also see: https://github.com/karma-runner/karma-jasmine
For anyone stumbling upon this, a better approach, which you can set up from the code itself, is to use this plugin: https://github.com/davemo/jasmine-only
It allows you set the spec exclusivity right on the code like this:
describe.only("MySpec", function() {
it('function 1', function() {
//...
})
it.only('function 2', function() {
//...
}
})
// This won't be run if there are specs using describe.only/ddescribe or it.only/iit
describe("Spec 2", function(){})
There has been a long discussion to get this added to Jasmine core, see: https://github.com/pivotal/jasmine/pull/309
If you happen to be using Jasmine via Karma/Testacular you should already have access to ddescribe() and iit()
You can create your all your specs up front but disable them with xdescribe and xit until you're ready to test them.
describe('BuckRogers', function () {
it('shoots aliens', function () {
// this will be tested
});
xit('rescues women', function () {
// this won't
});
});
// this whole function will be ignored
xdescribe('Alien', function () {
it('dies when shot', function () {
});
});
This is the most simplified answer with a practical example .Even in fdescribe you can run few it blocks using it. f means focus.
Also in a none fdescribe block which is just describe, you can select only specific it blocks by marking them as fit.
Please run the below code and observe the console log, also read the comments in the code.
Read this author's article it helps too . https://davidtang.io/2016/01/03/controlling-which-tests-run-in-jasmine.html
//If you want to run few describe only add f so using focus those describe blocks and it's it block get run
fdescribe("focus description i get run with all my it blocks ", function() {
it("1 it in fdescribe get executed", function() {
console.log("1 it in fdescribe get executed unless no fit within describe");
});
it("2 it in fdescribe get executed", function() {
console.log("2 it in fdescribe get executed unless no fit within describe");
});
//but if you and fit in fdescribe block only the fit blocks get executed
fit("3 only fit blocks in fdescribe get executed", function() {
console.log("If there is a fit in fdescribe only fit blocks get executed");
});
});
describe("none description i get skipped with all my it blocks ", function() {
it("1 it in none describe get skipped", function() {
console.log("1 it in none describe get skipped");
});
it("2 it in none describe get skipped", function() {
console.log("2 it in none describe get skipped");
});
//What happen if we had fit in a none fdescribe block will it get run ? yes
fit("3 fit in none describe get executed too eventhough it;s just describe ", function() {
console.log("3 fit in none describe get executed too");
});
});
With stand-alone Jasmine(2.0.0), on the spec_runner.htlm, I could click a specific spec and focus on that one spec. I should have noticed this feature earlier.
Not exactly what you've asked for but adding iit will test only that particular spec and ignore all others in the file, ddescribe works in the same way. So you can focus on a particular spec using iit or ddescribe

Resources