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

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.

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.

Async call in beforeAll

Here are 2 samples of the same test. The only difference is that first one uses a promise in beforeAll block to assign a value to the variable while the second one assigns the value directly.
I raised a similar question Running spec after promise has been resolved with one of the comments pointing to this issue https://github.com/jasmine/jasmine/issues/412 which says that this is not supported in Jasmine. Has somebody figured out any workaround?
This fails with TypeError: Cannot read property 'forEach' of undefined
describe('Async car test', function () {
var cars;
beforeAll(function (done) {
// getCars() is a promise which resolves to ['audi', 'bmw']
getCars().then(function (data) {
cars = data;
console.log(cars) // ['audi', 'bmw']
done();
});
});
cars.forEach(function (car) {
it('car ' + car, function () {
expect(car).toBe(car);
});
});
});
This works fine
describe('Car test', function () {
var cars = ['audi', 'bmw'];
cars.forEach(function (car) {
it('car ' + car, function () {
expect(car).toBe(car);
});
});
});
Posting it as an answer, because I can't see things properly in comments.
I'm actually generating tests in my spec as well, and I'm using https://www.npmjs.com/package/jasmine-data-provider , I think you probably cannot generate it directly from resolved promise. And wrapping in another it doesn't work for you. This should work:
var using = require('jasmine-data-provider');
using(cars.forEach, function (car) {
it(car + ' should be' + car, function () {
expect(car).toBe(car);
});
});
This is not an issue with jasmine, it is an issue with your code.
beforeAll does not block subsequent code below the statement. it blocks code that is defined in it('should ...', (done)=>{...});
it('should have cars', (done) => {
cars.forEach(function (car) {
expect(car).toBe(car);
});
});
Since Jasmine does not support adding tests at runtime, the trick is to request the asynchronous data before starting Jasmine, and then using the retrieved data during runtime instead. This can be achieved with a singleton and programmatically starting Jasmine.
See here for a working example.
// car-collection.js
class CarCollection {
static load() {
return this.request()
then((data) => this.cars = data);
}
static request() {
// in practice this function would do something cooler
return Promise.resolve(['audi', 'bmw']);
}
}
modules.export = CarCollection;
Since CarCollection has methods that are static they will be shared across imports and this.cars will persist.
// launcher.js
const Jasmine = require('jasmine');
const CarCollection = require('./car-collection');
CarCollection.load()
.then(() => {
console.log(`car count is ${CarCollection.cars.length}`); // prints: car count is 2
const jasmine = new Jasmine();
jasmine.loadConfigFile(...); // path to jasmine.json
jasmine.execute();
});
An important step here is configure jasmine to know where to look for the test files. Either by loading a config or passing specifics into the execute function.
// car.spec.js
const CarCollection = require('./car-collection');
describe('test', function () {
CarCollection.cars.forEach((car) => {
it('test' + car, () => {
expect(car).toBe(car);
});
});
});
Now run node ./launcher.js and the tests should run.

Jasmine avoid beforeEach for certain tests

Is there a way to NOT execute beforeEach function only for certain tests ('it' blocks). Lets say I have 10 it blocks, I do not want beforeEach to be executed for two of the blocks. Is it possible?
You can group specs which you want to run with beforeEach into a separate describe:
it('should 1...', function () {});
it('should 2...', function () {});
describe('group', function () {
beforeEach(function () {
// ...
});
it('should 3...', function () {});
it('should 4...', function () {});
// ...
});
I currently managed this with a work around as follows:
var executeBeforeEach = true;
function beforeEach() {
if(!executeBeforeEach) return;
//your before each code here.
}
describe('some test case 1', function(){
it('Start', function(){
//this is a dummy block to disable beforeeach for next test
})
it('The test that does not need beforeEach', function(){
//this test does not need before each.
})
it('Start', function(){
//this is a dummy block to enable beforeeach for next test
})
})
But, I am wondering if there is a more elegant way!?!

Using jasmine to test amplifyjs request call backs

I'm using amplifyjs for AJAX requests. That's working fine. I'm using jasmine to test the code. I'm wondering what the best method is to test the success and error call backs. The current unit test I've written doesn't work because the call back is executed after the jasmine expect. Here's my code under test:
function logout() {
ns.busy.show();
amplify.request({
resourceId: 'logout',
success: _logoutSuccess
});
};
function _logoutSuccess(response) {
ns.busy.hide();
};
Here's the unit test, where I want to validate that a function is called when the request is returned:
it('should hide busy when successful', function () {
// arrange
ns.busy = { show: function () { }, hide: function () { } };
spyOn(ns.busy, 'hide');
amplify.request.define('logout', function (settings) {
settings.success({});
});
// act
ns.accountLogoutViewModel.logout();
// assert
expect(ns.busy.hide).toHaveBeenCalled();
});
Note: ns is just a variable holding the application namespace. If I place break points on the expect and on the ns.busy.hide() in the _logoutSuccess function, jasmine hits the expect and then hits the _logoutSuccess, hence the spyOn fails.
As I say, the code is working, I just want to know how to write a test for it. I've looked into the jasmine done() function, but I'm not sure how to use it in this circumstance (or even if it is a solution).
Thanks
Isn't it always the way, when I finally get round to posting a question, I then immediately find the answer. Here's the test that passes, using the jasmine done() function:
it('should hide busy when successful', function (done) {
// arrange
ns.busy = { show: function () { }, hide: function () { } };
spyOn(ns.busy, 'hide');
amplify.request.define('logout', function (settings) {
settings.success({});
done();
});
// act
ns.accountLogoutViewModel.logout();
// assert
expect(ns.busy.hide).toHaveBeenCalled();
});

Jasmine Testing get the name of the full describes/it's

I was wondering, is it possible to get the full nested describe path for the tests?
Given:
describe('Smoke Testing - Ensuring all pages are rendering correctly and free of JS errors', function () {
describe('app', function () {
describe('app.home', function () {
it('should render this page correctly', function (done) {
//name here should be: Smoke Testing - Ensuring all pages are rendering correctly and free of JS errors app app.home should render this page correctly
done()
})
})
describe('app.dashboard', function () {
describe('app.dashboard.foobar', function () {
it('should render this page correctly', function (done) {
//name here should be: Smoke Testing - Ensuring all pages are rendering correctly and free of JS errors app app.dashboard app.dashboard.foobar should render this page correctly
done()
})
})
})
})
})
Both jasmine.Suite and jasmine.Spec have method getFullName(). Works as you'd expect:
describe("A spec within suite", function() {
it("has a full name", function() {
expect(this.getFullName()).toBe('A spec within suite has a full name.');
});
it("also knows parent suite name", function() {
expect(this.suite.getFullName()).toBe('A spec within suite');
});
});
<script src="http://searls.github.io/jasmine-all/jasmine-all-min.js"></script>
Notice: this answer is now bit dated and uses Jasmine 1.3.1 in the example.
When you are inside the describe callback function this is set to a "suite" object which has the description of the suite (the text you pass to describe) and a property for the parent suite.
The example below gets the concatenation of the description nested describe calls, I'm not sure about how to access the description of the "it". But this will get you part way there.
var getFullDesc = function(suite){
var desc = "";
while(suite.parentSuite){
desc = suite.description + " " + desc;
suite = suite.parentSuite;
}
return desc;
}
describe('Outer describe', function(){
describe('Inner describe', function(){
console.log(getFullDesc(this));
it('some test', function(){
});
});
});

Resources