Mocha test order file-wise and webdriverjs instance persistence - javascript

I'm testing my web-app with Mocha and WebDriver. I'm struggling with the best practices regarding Mocha test-order and persistent state of the driver.
I want to separate tests to different files, e.g.
test\
index.js
selenium\
login.js
search.js
So in execution wise, login.js has to be first because it logs in to the app and gets authenticated. Only after that search.js is possible to do. But how? In login.js I now have this:
webdriverjs = require('webdriverjs');
describe 'UI/Selenium', ->
client = {}
before ->
client = webdriverjs.remote
desiredCapabilities:
browserName: 'chrome'
client.init()
client.windowHandleSize({width: 1920, height: 1080})
it 'should let us login', (done) ->
client.url('http://127.0.0.1:1337/login')
.setValue('#username', 'username')
.setValue('#password', 'password')
.buttonClick('button[type="submit"]')
.waitFor '#search_results_user', 5000, (err) -> throw err if err
.call done
How can I persist the state of client to other tests without having to re-init it every time? And how do I define the execution order of files with Mocha?

How can I persist the state of client to other tests without having to re-init it every time?
You setup whatever you want to share among tests in a before hook (and tear it down in an after hook). This would mean moving the code in your test for logging in into your before hook. Supposing you are testing the "foo" view, you could do:
describe("foo view", function () {
before(function () { /* create selenium driver */ });
describe("when used by a logged in user", function () {
before(function () { /* log in */ });
it(...
it(...
after(function () { /* log out */ });
});
describe("when used by a logged out user", function () {
it(...
it(...
});
after(function () { /* shut down the driver */ });
});
And how do I define the execution order of files with Mocha?
Mocha tests should not depend on one another and consequently should not depend on the order in which they are executed.
If you are in a situation where you must break this cardinal rule, you could just invoke Mocha from the command line with the list of test files, in the order you want. Or you could launch Mocha programmatically and use addFile to add the files in order.

Related

How to remove all cy.route from beforeEach in Cypress

I'm creating a lot of tests for application in my firm. Before each test I need to create a state to work on it, and it's always the same, so I created some routes in my own method and then in support/index.js file I created beforeEach that looks like this
beforeEach(() => {
cy.server();
cy.mockSearches(SHORTEN_SEARCHES); // this only creates mocks
cy.loginAdmin();
});
And in 99% percent of tests it's working fine, but there is one test, that needs to work on real data. What should I do? Is there a way to ignore global beforeEach? I guess I can move this part of code to each test before each, but that's code repetition? Or maybe I should override this cy.route with empty responses?
You can add a condition to your beforeEach() to exit before your setup:
beforeEach(() => {
if (shouldUseRealData) return;
cy.server();
cy.mockSearches(SHORTEN_SEARCHES); // this only creates mocks
cy.loginAdmin();
});
As stated in the docs about environment variables, you can set an environment variable in different ways. One way would be to set it in your command line when calling cypress run:
cypress run --env use_mock=true
And then you would use it with Cypress.env('use_mock').
beforeEach(() => {
if (Cypress.env('use_mock')) {
cy.server();
cy.mockSearches(SHORTEN_SEARCHES); // this only creates mocks
cy.loginAdmin();
}
});

beforeEach and AfterEach for every test case using Globals.js

So, I have a globals.js file where I have mentioned beforeEach and afterEach, but what I could understand from this link Nightwatch Globals, the beforeEach and afterEach are called once before and after a Test Suite (A single Js file). But in my framework I have multiple test cases in the a single js file (or Test Suite) and I want to call beforeEach and afterEach before and after every test case. Anyway to achieve that? Below is my globals.js file:
module.exports = {
asyncHookTimeout: 40000,
beforeEach: function (browser, done) {
// browser.maximizeWindow();
// browser.deleteCookies();
browser.perform(function () {
console.log('Inside BeforeEach');
done();
});
}
afterEach: function (browser, done) {
browser.end(function () {
console.log("Inside After Each");
done();
});
},
};
Of course there is! Just make use of the notorious Nightwatch test hooks.
If you want to filter your test-suites, then as you pointed out,
we'll use the global test
hooks.
If you want to filter your test-cases, then we'll use the test
hooks
Example (your test-file should look like this):
module.exports = {
before(browser) {
// > this will get run only ONCE, before all the tests <
},
beforeEach(browser) {
// > this will get run before every test case <
}
tags: ['your', 'tags', 'go', 'here'],
'Test Case No.1': (browser) => {
// > this test does something here <
},
'Test Case No.2': (browser) => {
// > this test does something else here <
},
'Test Case No.3': (browser) => {
// > this test does something else here <
},
afterEach(browser) {
// > this will get run after every test case <
},
after(browser) {
// > this will get run ONCE, after all tests have run <
}
};
Lastly, quoting the DOCs:
The before and after will run before and after the execution of the
test suite respectively (in our case, the test-file), while beforeEach and afterEach are ran before
and after each test case (test step).
LE: What #AlapanDas wants is to custom-tailor the way the Nightwatch test-runner handles test-level hooks. This is of course doable, but dirty. You have to re-write the hooking logic from the following files:
Nightwatch#v0.9.x:
testcase.js (path: /nightwatch/lib/runner/testcase.js);
testsuite.js (path: /nightwatch/lib/runner/testsuite.js);
Nightwatch#v1.0.x:
every {hookName}.js file from the /hooks folder (path: /nightwatch/lib/testsuite/hooks/*.js);
Still, a compromise can be made here! Just try to find the common, recurring steps/instructions from your before, after, etc. hooks and extract that logic inside a /custom_commands file. That would condense your test files, as well as decoupling the login from your hooks. On the long run, this will also grant the advantage of a single-point-of-change when maintaining the hooks.

close browser session after failed assertion with nightwatch

I implement a new testframework for automated tests in node.js with Nightwatch-Cucumber that based on Nightwatch.js. So, sometimes I use node.js Assertions to check some values. I work with the PageObject Pattern in my framework. My problem is that the browser session doen't close after a failed assertion and I don't know why and I don't know how to solve the problem.
Here is my StepDefinition:
const {
client
} = require('nightwatch-cucumber');
const {
defineSupportCode
} = require('cucumber');
const page = client.page.page();
defineSupportCode(({Given, When, Then}) => {
When(/^test$/, () => {
return page.test();
});
});
And that's my PageObject function:
module.exports = {
elements: {},
commands: [{
test() {
//here the assertion failed and the browser session still exist and doen't close
this.assert.equal(false, true);
return this.api;
}
}]
};
So, what can I do to realize it to close the browser and the session for ths test? It happened only if the node.js assertions fail.
Use an after or afterEach hook to always close the browser at the end of a test, regardless of outcome. See http://nightwatchjs.org/guide#using-before-each-and-after-each-hooks
after : function(browser) {
console.log('Closing down...');
browser.end();
},
To close your session after each test you have to add afterEach hook to your test file and use it like this:
afterEach : function(browser, done) {
browser.end(function(){
done();
});
}

How to stub a method that is called from an outer scope to the function under test?

I have a Redis client that is created thus using the node_redis library (https://github.com/NodeRedis/node_redis):
var client = require('redis').createClient(6379, 'localhost');
I have a method I want to test whose purpose is to set and publish a value to Redis, so I want to test to ensure the set and publish methods are called or not called according to my expectations. The tricky thing is I want this test to work without needing to fire up an instance of a Redis server, so I can't just create the client because it will throw errors if it cannot detect Redis. Therefore, I need to stub the createClient() method.
Example method:
// require('redis').createClient(port, ip) is called once and the 'client' object is used globally in my module.
module.exports.updateRedis = function (key, oldVal, newVal) {
if (oldVal != newVal) {
client.set(key, newVal);
client.publish(key + "/notify", newVal);
}
};
I've tried several ways of testing whether set and publish are called with the expected key and value, but have been unsuccessful. If I try to spy on the methods, I can tell my methods are getting called by running the debugger, but calledOnce is not getting flagged as true for me. If I stub the createClient method to return a fake client, such as:
{
set: function () { return 'OK'; },
publish: function () { return 1; }
}
The method under test doesn't appear to be using the fake client.
Right now, my test looks like this:
var key, newVal, oldVal, client, redis;
before(function () {
key = 'key';
newVal = 'value';
oldVal = 'different-value';
client = {
set: function () { return 'OK'; },
publish: function () { return 1; }
}
redis = require('redis');
sinon.stub(redis, 'createClient').returns(client);
sinon.spy(client, 'set');
sinon.spy(client, 'publish');
});
after(function () {
redis.createClient.restore();
});
it('sets and publishes the new value in Redis', function (done) {
myModule.updateRedis(key, oldVal, newVal);
expect(client.set.calledOnce).to.equal(true);
expect(client.publish.calledOnce).to.equal(true);
done();
});
The above code gives me an Assertion error (I'm using Chai)
AssertionError: expected false to equal true
I also get this error in the console logs, which indicates the client isn't getting stubbed out when the method actually runs.
Error connecting to redis [Error: Ready check failed: Redis connection gone from end event.]
UPDATE
I've since tried stubbing out the createClient method (using the before function so that it runs before my tests) in the outer-most describe block of my test suite with the same result - it appears it doesn't return the fake client when the test actually runs my function.
I've also tried putting my spies in the before of the top-level describe to no avail.
I noticed that when I kill my Redis server, I get connection error messages from Redis, even though this is the only test (at the moment) that touches any code that uses the Redis client. I am aware that this is because I create the client when this NodeJS server starts and Mocha will create an instance of the server app when it executes the tests. I'm supposing right now that the reason this isn't getting stubbed properly is because it's more than just a require, but the createClient() function is being called at app startup, not when I call my function which is under test. I feel there still ought to be a way to stub this dependency, even though it's global and the function being stubbed gets called before my test function.
Other potentially helpful information: I'm using the Gulp task runner - but I don't see how this should affect how the tests run.
I ended up using fakeredis(https://github.com/hdachev/fakeredis) to stub out the Redis client BEFORE creating the app in my test suite like so:
var redis = require('fakeredis'),
konfig = require('konfig'),
redisClient = redis.createClient(konfig.redis.port, konfig.redis.host);
sinon.stub(require('redis'), 'createClient').returns(redisClient);
var app = require('../../app.js'),
//... and so on
And then I was able to use sinon.spy in the normal way:
describe('some case I want to test' function () {
before(function () {
//...
sinon.spy(redisClient, 'set');
});
after(function () {
redisClient.set.restore();
});
it('should behave some way', function () {
expect(redisClient.set.called).to.equal(true);
});
});
It's also possible to mock and stub things on the client, which I found better than using the redisErrorClient they provide for testing Redis error handling in the callbacks.
It's quite apparent that I had to resort to a mocking library for Redis to do this because Sinon couldn't stub out the redisClient() method as long as it was being called in an outer scope to the function under test. It makes sense, but it's an annoying restriction.

How to reuse beforeEach/afterEach in Jasmine JS?

When writing tests with JasmineJS I have many tests that have similar beforeEach/afterEach code.
Is there a way to implement an inheritance model using JasmineJS test suites?
I can group all tests in a single describe but in this case I will end with a single HUGE JS file containing all tests.
I would like to split the tests for each page.
Here is an example:
describe('Services Page', function() {
beforeEach(function() {
login_as_admin()
})
beforeEach(function() {
browser().navigateTo('/services')
})
if('Some test for services page', function() {})
afterEach(function() {
logout()
})
})
describe('Administrators Page', function() {
beforeEach(function() {
login_as_admin()
})
beforeEach(function() {
browser().navigateTo('/administrators')
})
if('Some test for administrators page', function() {})
afterEach(function() {
logout()
})
})
I think this is partially examined in this blog post and also answered here but i'm adding an adapted answer for your example:
Reusable code:
function sharedSetup(startPage) {
beforeEach(function() {
login_as_admin();
browser().navigateTo(startPage);
});
afterEach(function() {
logout();
});
};
How to use it:
describe('Services Page', function() {
sharedSetup('/services');
it('Some test for services page', function() {});
});
describe('Administrators Page', function() {
sharedSetup('/administrators');
it('Some test for administrators page', function() {});
});
If you want to do this for all your suites, you can register a beforeEach or afterEach function in the topSuite:
jasmine.getEnv().topSuite().beforeEach({fn: function() {
//log in as admin
}});
If you only want to apply it on some suites, you can work with sub-suites:
describe("as_admin", function() {
beforeEach(function() {
//log in as admin
});
describe('Services Page',function() {...});
describe('Administrators Page',function() {...});
}
Jasmine does allow you to put beforeEach and afterEach outside of a describe call. In this way you can have setup and teardown that is global for all of your specs. Your logout() call seems like it might be a good candidate for global teardown, and if all of your specs login as an admin, you could move that out to global scope as well.
For things that are used in some, but not all, specs, having a method like your login_as_admin() seems like the best way to consolidate that logic in one place.
Reference: (Pivotal Labs Blog:Davis W. Frank)
He describes collecting shared functionality in a function that is called with parameters for the different individual suites. Calling this function within each suite will execute the common setup/configuration.
As to splitting tests across files; the file with the shared function can either be included within each page with a <script> tag if the tests are browser based, or by a require(...) near the top if the tests are node based. You can then run the tests independently but using that shared setup which is defined only once.
Found in the issues.
So in 3.7.0 afterEach along with other methods got moved out of Env namespace and into Globals.
the call in test.ts should be now:
afterEach(() => {});
that's it.

Categories

Resources