Conditional execution of mocha test cases - tdd

I am using Mocha with Sinon JS and Phantom Js to test the google analytics call from a particular page. Till now, i am able to execute static test cases for individual element by writing different test case for each element. Like :
describe("Site Home Page Test", function() {
it ("Global Search track", function() {
var link = $('button.search');
link.click();
});
});
Now the ask is, is it possible to execute test case if only $('elem') is found? something like this:
describe("Site Home Page Test", function() {
// if(condition) {
it ("Global Search track", function() {
var link = $('button.search');
link.click();
});
// }
});

I'm not sure if I've missed the question completly, but you can do conditional test cases exactly how you have it written:
describe("Some module", function() {
if(false) {
it ("should NOT run this test case", function() { });
}
it("should run this test case", function() { });
});
mocha will only run the unit-test that isn't in the if-statement.
Some module
✓ should run this test case
1 passing (5 ms)

Related

Nested it in Protractor/Jasmine

Can I create a nested it in Protractor/Jasmine.
it("outer it", function () {
it("inner it", function () {
expect(1).toBe(1);
});
});
I am trying to execute it test cases inside a loop, and in every iteration I want to run a test, for example:
it("outer it", function () {
for(var i=0;i<10;i++){
it("inner it", function () {
expect(1).toBe(1);
});
}
});
The reason I want to do it is that I want to initialize an array and then in a dynamically way to loop trough all the element and run a number of "it", for example:
describe ("[Components]", function() {
var grid = new Grid();
it("Initialize the grid for the history window", function () {
grid.init();
});
for(var i=0;i<grid.length;i++){
it("test 1", function () {
expect(1).toBe(1);
});
}
});
The grid.length is equal to 0 when the for loop execute, I want the for loop execute after the initialize "it".
Answering to your question, no you cannot nest it's one inside other. Though Jasmine framework doesn't throw any error, the code inside a nested it doesn't execute. Also, I don't see any use of nesting it's as they are specs or functions that run on their own to complete a particular test step. It also gives an overview of the function that is being executed currently. If you are trying to run something in a loop, you can create another function and then call it inside the for loop, something like this -
it("outer it", function () {
var newFunction = function(){
expect(1).toBe(1);
};
for(var i=0;i<10;i++){
newFunction();
};
});
Hope this helps. More on it's can be found here - Jasmine Framework - it's
As mentioned earlier - no, you can not place it inside of another it block, BUT you could place a whole describe block inside another one
You also have an ability to run it blocks inside of for loops, OR for example make it block conditional.
You can find a real example of a code below (I've added for loop just for demonstration purposes)
describe("E2E: Environment configuration test", function () {
beforeAll(function () {
logIn();
});
afterAll(function () {
logOut();
});
describe("Members page configuration test", function() {
for (let i=0; i<3; i++) {
it("Members page - columns", function () {
//code that verifies that all columns of the page are presented
});
}
it( "Members page - filters", function() {
//code that verifies that all filters of the UI are presented as expected
});
it( "Members page - eligibility feature", function() {
//code that verifies that if the feature is set to true then additional column must be displayed
});
});
describe("Providers page configuration test", function() {
// use of conditional it blocks
// if feature is turned on run one set it blocks
// otherwise execute another set of it blocks
if (envConfig.providerFeature) {
it( "Organizations tab configuration test", function() {
//code that verifies that all elements of the current tab are displayed according to configurations of all features of the application
});
it( "Practitioners tab configuration test", function() {});
//code that verifies that all elements of the current tab are displayed according to configurations of all features of the application
} else {
it( "Providers page - verification of the page being disabled", function() {
//code that verifies that both tabs are not present in the UI
console.log('Providers feature is set to FALSE for the environment by default configuration, the test case will be skipped');
});
}
});
it( "Users page configuration test", function() {
//code that verifies that all elements of the current page are displayed according to configurations of all features of the application
});
it( "Reports page configuration test", function() {
if (!envConfig.disabledReportsFeature) {
//code that verifies that all elements of the current page are displayed according to configurations of all features of the application
} else {
console.log('Reports DISABLED_REPORTS_FEATURE is set to TRUE for the environment by default configuration, the test case will be skipped');
}
});
});
The console output in this case will look well organized
P.S. Additionally I will attach an image of clean console

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(){
});
});
});

Running into Error while waiting for Protractor to sync with the page with basic protractor test

describe('my homepage', function() {
var ptor = protractor.getInstance();
beforeEach(function(){
// ptor.ignoreSynchronization = true;
ptor.get('http://localhost/myApp/home.html');
// ptor.sleep(5000);
})
describe('login', function(){
var email = element.all(protractor.By.id('email'))
, pass = ptor.findElement(protractor.By.id('password'))
, loginBtn = ptor.findElement(protractor.By.css('#login button'))
;
it('should input and login', function(){
// email.then(function(obj){
// console.log('email', obj)
// })
email.sendKeys('josephine#hotmail.com');
pass.sendKeys('shakalakabam');
loginBtn.click();
})
})
});
the above code returns
Error: Error while waiting for Protractor to sync with the page: {}
and I have no idea why this is, ptor load the page correctly, it seem to be the selection of the elements that fails.
TO SSHMSH:
Thanks, your almost right, and gave me the right philosophy, so the key is to ptor.sleep(3000) to have each page wait til ptor is in sync with the project.
I got the same error message (Angular 1.2.13). My tests were kicked off too early and Protractor didn't seem to wait for Angular to load.
It appeared that I had misconfigured the protractor config file. When the ng-app directive is not defined on the BODY-element, but on a descendant, you have to adjust the rootElement property in your protractor config file to the selector that defines your angular root element, for example:
// protractor-conf.js
rootElement: '.my-app',
when your HTML is:
<div ng-app="myApp" class="my-app">
I'm using ChromeDriver and the above error usually occurs for the first test. I've managed to get around it like this:
ptor.ignoreSynchronization = true;
ptor.get(targetUrl);
ptor.wait(
function() {
return ptor.driver.getCurrentUrl().then(
function(url) {
return targetUrl == url;
});
}, 2000, 'It\'s taking too long to load ' + targetUrl + '!'
);
Essentially you are waiting for the current URL of the browser to become what you've asked for and allow 2s for this to happen.
You probably want to switch the ignoreSynchronization = false afterwards, possibly wrapping it in a ptor.wait(...). Just wondering, would uncommenting the ptor.sleep(5000); not help?
EDIT:
After some experience with Promise/Deferred I've realised the correct way of doing this would be:
loginBtn.click().then(function () {
ptor.getCurrentUrl(targetUrl).then(function (newURL){
expect(newURL).toBe(whatItShouldBe);
});
});
Please note that if you are changing the URL (that is, moving away from the current AngularJS activated page to another, implying the AngularJS library needs to reload and init) than, at least in my experience, there's no way of avoiding the ptor.sleep(...) call. The above will only work if you are staying on the same Angular page, but changing the part of URL after the hashtag.
In my case, I encountered the error with the following code:
describe("application", function() {
it("should set the title", function() {
browser.getTitle().then(function(title) {
expect(title).toEqual("Welcome");
});
});
});
Fixed it by doing this:
describe("application", function() {
it("should set the title", function() {
browser.get("#/home").then(function() {
return browser.getTitle();
}).then(function(title) {
expect(title).toEqual("Welcome");
});
});
});
In other words, I was forgetting to navigate to the page I wanted to test, so Protractor was having trouble finding Angular. D'oh!
The rootElement param of the exports.config object defined in your protractor configuration file must match the element containing your ng-app directive. This doesn't have to be uniquely identifying the element -- 'div' suffices if the directive is in a div, as in my case.
From referenceConf.js:
// Selector for the element housing the angular app - this defaults to
// body, but is necessary if ng-app is on a descendant of <body>
rootElement: 'div',
I got started with Protractor by watching the otherwise excellent egghead.io lecture, where he uses a condensed exports.config. Since rootElement defaults to body, there is no hint as to what is wrong with your configuration if you don't start with a copy of the provided reference configuration, and even then the
Error while waiting for Protractor to sync with the page: {}
message doesn't give much of a clue.
I had to switch from doing this:
describe('navigation', function(){
browser.get('');
var navbar = element(by.css('#nav'));
it('should have a link to home in the navbar', function(){
//validate
});
it('should have a link to search in the navbar', function(){
//validate
});
});
to doing this:
describe('navigation', function(){
beforeEach(function(){
browser.get('');
});
var navbar = element(by.css('#nav'));
it('should have a link to home in the navbar', function(){
//validate
});
it('should have a link to search in the navbar', function(){
//validate
});
});
the key diff being:
beforeEach(function(){
browser.get('');
});
hope this may help someone.
I was getting this error:
Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details"
The solution was to call page.navigateTo() before page.getTitle().
Before:
import { AppPage } from './app.po';
describe('App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should have the correct title', () => {
expect(page.getTitle()).toEqual('...');
})
});
After:
import { AppPage } from './app.po';
describe('App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
page.navigateTo();
});
it('should have the correct title', () => {
expect(page.getTitle()).toEqual('...');
})
});
If you are using
browser.restart()
in your spec some times, it throws the same error.
Try to use
await browser.restart()

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