I've been testing JavaScript code using unit testing frameworks like jasmine and Qunit. But all these testing framework works only at load time, but I want to initiate the test cases at run time, for instance I want to test an object's value on a button click like below test case in Jasmine,
function btnClick() {
var temp++;
describe("Test Suite Inside Button Click", function () {
it("To test true value", function () {
expect(temp).not.toEqual(-1);
});
});
};
How to run the test cases dynamically ?
Here is how you do it.
Invoke the jasmineEnv at run time and run the test
Note that I'm clearing out the reporter div just to clean up the
output- which may not to necessary in your case.
My setTimeout is only to load the div onto the page
See it in action here
var testFunc = function() {
//this is optional- I'm just clearing the reporter out to run it on fiddle.
$('.jasmine_html-reporter').remove();
var jasmineEnv = jasmine.getEnv();
describe('test', function() {
it('sample test', function() {
console.log('test ran');
expect(true).toBe(true);
});
});
jasmineEnv.execute()
}
setTimeout(function() {
$('#myElement').click(testFunc);
}, 0);
Related
How to unit test your code if it's heavily belongs to external library and within each of its methods it calls some external library function.
If everything to mock, than code coverage like Istanbul don't count those lines mocked. Who has experience in unit testing with involvement of external dependencies and libraries, what is the best practice?
For instance, we have 2 internal functions and 3 external library functions.
If mock those external ones, than Istanbul doesn't count those lines as covered.
function internalFoo1(input) {
var result = internalFoo2(input*2);
var finalResult = externalLibraryBar1(result);
return result;
};
function internalFoo2(value) {
var operation = externalLibraryBar2(value*2);
var response = externalLibraryBar3(operation);
return response;
}
How to write a test for internalFoo1() so unit test will cover all its code lines, as well internalFoo2() one.
Ideally you shouldn't be testing external libraries, it's not your job.
In this case, you could just use a spy and see if that library has been called. http://jasmine.github.io/2.2/introduction.html#section-Spies
e.g. taken from Jasmine documentation:
describe("A spy, when configured with an alternate implementation", function() {
var foo, bar, fetchedBar;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
},
getBar: function() {
return bar;
}
};
spyOn(foo, "getBar").and.callFake(function() {
return 1001;
});
foo.setBar(123);
fetchedBar = foo.getBar();
});
it("tracks that the spy was called", function() {
expect(foo.getBar).toHaveBeenCalled();
});
it("should not affect other functions", function() {
expect(bar).toEqual(123);
});
it("when called returns the requested value", function() {
expect(fetchedBar).toEqual(1001);
});
});
I have a javascript below, which appends a DIV on page load and hides it after 3 sec.
var testObj = {
initialize: function() {
var that = this;
$(window).on("load", function() {
(function ($) { //Append Div
$('body').append("<div>TEST</div>");
})(jQuery);
that.hideAppendedDiv();
});
},
hideAppendedDiv: function() { //Hide appended Div after 3s
setTimeout(function(){
$("div").hide();
}, 3000);
}
};
//call Initialize method
testObj.initialize();
How to write Jasmine test cases for the methods in the code.
I'm guessing that you don't really want to test a Javascript function such as $(window).on('load')... , but that your own function hideAppendedDiv() get's called from $(window).on('load'). Furthermore, you want to make sure that the function hideAppendedDiv() works as well.
IMO, you need two expects.
Somewhere in your setup beforeEach function:
beforeEach(function () {
spyOn(testObj , 'hideAppendedDiv').and.callThrough();
});
Expectations
it('expects hideAppendedDiv() to have been called', function () {
// make the call to the initialize function
testObj.initialize ();
// Check internal function
expect(testObj.hideAppendedDiv).toHaveBeenCalled();
});
it('expects hideAppendedDiv() to hide div', function () {
// make the call to the hideAppendedDiv function
testObj.hideAppendedDiv();
// Check behavior
expect(... check the div ...)
});
Edit
Just to be clear, Jasmine executes all the expects in order. Now, if you have two functions fn_1(), and fn_2() and you want to test that they were called in order you can setup yet another spi function that returns a specific value, or a sequential and incremental set of values every time it is called.
beforeEach(function () {
spyOn(testObj , 'fn_1').and.returnValues(1, 2, 3);
spyOn(testObj , 'fn_2').and.returnValues(4, 5, 6);
});
The first time fn_1 is called it will return 1, respectively fn_2 will return 4.
That is just one of the ways, but you have to get creative when testing.
Now if you want to test that a function was called after x amount of time here is a post that already explains it.
You don't need to test the window load event, if you move the append code out of the anonymous function call and pass it into the event handler instead you can test the functionality in exactly the same way you would anything else and your code will be better structured.
Have problem under beforeEach function in my test class.
Click on the usersTab sometimes works fine, and sometimes returns StaleElementReferenceException.
Have tried protractor.ExpectedConditions like presenceOf or visibilityOf or elementToBeClickable but none worked in 100%.
I think that is caused by asynchronous and sometimes browser firstly want to click and afterwards wait - is it possible ?
Any idea how to handle it ?
var OnePage = require('../pages/one_page.js');
var SecondPage = require('../pages/second_page.js');
describe('Test', function () {
var onePage;
var secondPage;
var EC = protractor.ExpectedConditions;
beforeEach(function () {
browser.ignoreSynchronization = true;
onePage = new OnePage();
browser.wait(EC.presenceOf(onaPage.userLogin), 5000);
onePage.setUser('login#login');
onePage.setPassword('password');
onePage.login();
secondPage = new SecondPage();
browser.wait(EC.visibilityOf(secondPage.usersTab), 10000);
usersPage.usersTab.click();
});
I am using jasmine:2 and protractor:2.2.0 .
When I first started to build my Test Suite I ran into a similar issue and it took me a while to track down a solution. When you initialize the Page Object using a standard var in your beforeEach function it can hold on to an old instance when the 2nd or higher test is run. No idea how long it typically takes or what really triggered the hiccup in my tests, it was always random for me. The only way I could solve this was to use the this keyword in my beforeEach function like the example below. When the beforeEach function is executed the instance is correctly renewed in each test.
NOTE: In my conf.js file under onPrepare I have the following function setup to tell Protractor if the page that follows is an Angular page or not:
global.isAngularSite = function(flag) {
browser.ignoreSynchronization = !flag;
};
var OnePage = require('../pages/one_page.js');
var SecondPage = require('../pages/second_page.js');
describe('Test', function () {
beforeEach(function () {
isAngularSite(true);
this.onePage = new OnePage();
this.secondPage = new SecondPage();
this.ec = protractor.ExpectedConditions;
browser.wait(this.ec.presenceOf(this.onePage.userLogin), 5000);
this.onePage.setUser('login#login');
this.onePage.setPassword('password');
this.onePage.login();
browser.wait(this.ec.visibilityOf(this.secondPage.usersTab), 10000);
usersPage.usersTab.click();
});
it('', function() {
});
});
Try chaining the actions with each other so that they execute serially once the first one is completed resolving its promise. Here's how -
beforeEach(function () {
browser.ignoreSynchronization = true;
onePage = new OnePage();
browser.wait(EC.presenceOf(onaPage.userLogin), 5000).then(function(){
onePage.setUser('login#login');
onePage.setPassword('password');
onePage.login();
});
secondPage = new SecondPage();
browser.wait(EC.visibilityOf(usersPage.usersTab), 10000).then(function(){
usersPage.usersTab.click().then(function(){
//If you want to verify something after click, do it here.
browser.sleep(500);
});
});
});
If you want the second page actions to be done only after first one, then chain them together.
browser.wait(EC.presenceOf(onaPage.userLogin), 5000).then(function(){
//Actions of OnePage
}).then(function(){
//Actions of second page
secondPage = new SecondPage();
browser.wait(EC.visibilityOf(usersPage.usersTab), 10000).then(function(){
usersPage.usersTab.click().then(function(){
//If you want to verify something after click, do it here.
browser.sleep(500);
});
});
});
Hope this helps.
I'm trying to write a plugin for Jasmine that allows you to return a promise from a spec and will pass or fail that spec depending on whether or not the promise is fulfilled or rejected.
Of course, I want to write tests to make sure that my plugin works correctly, and to be thorough, I need to make sure that tests fail when the promise is rejected... so how do I make a test pass when I need to make sure that a test "successfully fails"?
After a conversation with the developers who work on Jasmine, we've come up with this:
var FAILED = 'failed'
var PASSED = 'passed'
describe('My Test Suite', function () {
var env
beforeEach(function () {
// Create a secondary Jasmine environment to run your sub-specs in
env = new jasmine.Env()
})
it('should work synchronously', function () {
var spec
// use the methods on `env` rather than the global ones for sub-specs
// (describe, it, expect, beforeEach, etc)
env.describe('faux suite', function () {
spec = env.it('faux test', function (done) {
env.expect(true).toBe(true)
})
})
// this will fire off the specs in the secondary environment
env.execute()
// put your expectations here if the sub-spec is synchronous
// `spec.result` has the status information we need
expect(spec.result.status).toBe(FAILED)
})
// don't forget the `done` argument for asynchronous specs
it('should work asynchronously', function (done) {
var spec
// use the methods on `env` rather than the global ones.
env.describe('faux suite', function () {
// `it` returns a spec object that we can use later
spec = env.it('faux test', function (done) {
Promise.reject("FAIL").then(done)
})
})
// this allows us to run code after we know the spec has finished
env.addReporter({jasmineDone: function() {
// put your expectations in here if the sub-spec is asynchronous
// `spec.result` has the status information we need
expect(spec.result.status).toBe(FAILED)
// this is how Jasmine knows you've completed something asynchronous
// you need to add it as an argument to the main `it` call above
done()
}})
// this will fire off the specs in the secondary environment
env.execute()
})
})
Going off Joe's answer, I moved the fake test context into a single function. Since the code under test is making use of jasmine expectations, I load the inner Env into jasmine.currentEnv_ and call it explicitly with jasmine.currentEnv_.expect(). Note that currentEnv_ is an internal variable set by jasmine itself, so I can't guarantee that this won't be broken in a future jasmine version.
function internalTest(testFunc) {
var outerEnvironment = jasmine.currentEnv_;
var env = new jasmine.Env();
jasmine.currentEnv_ = env;
var spec;
env.describe("fake suite", function () {
spec = env.it("fake test", function () {
func();
});
});
env.execute();
jasmine.currentEnv_ = outerEnvironment;
return spec.result;
}
Then each test looks like
it("does something", function () {
//Arrange
//Act
var result = internalTest(function () {
//Perform action
});
//Assert
expect(result.status).toBe("failed"); //Or "success"
expect(result.failedExpectations.length).toBe(1);
expect(result.failedExpectations[0].message).toBe("My expected error message");
});
I have the following code:
describe("Player", function() {
var player;
beforeEach(function(){
player = new Player({
name: "Mark"
});
});
it("has a name", function() {
expect(player.name).toEqual("Mark");
});
it("has a score"), function() {
expect(player.score).toEqual(0);
};
});
Jasmine says it's passing 2 specs, even though player.score is undefined
If I do...
it("has a score"), function() {
console.log("hello")
expect(player.score).toEqual(0);
};
I can see the second test is never run. Any ideas why? (this is my first time using Jasmine).
There is a misplaced closing parenthesis in the second spec (it() call). It should read:
it("has a score", function() {
expect(player.score).toEqual(0);
});
I run into this issue a lot: syntax errors in Jasmine specs result in tests not even running, rather than failing as they should. (I believe there may be an outstanding bug against Jasmine for this.)