Simple Jasmine Async Test with Inverted waitsFor - javascript

I'm trying to write an async test, which I've never done before. In english the test says this:
create a timer object with a callback
if the timer were to be started, it'd trigger after 500ms
the timer shouldn't be started
confirm the callback isn't called by waiting 1000ms and checking if it was called
So, from reading the docs, and looking at some other code, I think this is how I should write it.
it("should create a timer not start", function (done) {
var fail = false, timer;
// if this test is passing, this should do nothing
runs(function(){
timer = new Timer(function () {
fail = true;
timer.pause();
}, 500);
});
// if this test is passing, fail should never be true
waitsFor(function(){
return fail;
}, 1000);
// this should be called after 1 second because the previous times out
runs(function(){
expect(fail).toBeFalsy();
});
});
However waitsFor is timing out, because fail should never be true. I need waitsFor to wait the full second, and then the expect statement can run, but I need the timeout to be a good thing, not a failure (which Jasmine reports it as).
How do I do this with Jasmine?

Edit 2017-07-24
Based on #Yavin5's comment, This answer is valid for Jasmine v1.
For upgrading to Jasmine v2 please reference the documentation. https://jasmine.github.io/2.0/upgrading.html#section-9
For Jasmine V2 Documentation visit https://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
You need to add a flag that that will become true when the async operation has completed. That is what the waitsFor is waiting for. I would suggest something like
it("should create a timer not start", function (done) {
var fail = false, timer, flag;
// if this test is passing, this should do nothing
runs(function(){
flag = false;
timer = new Timer(function () {
fail = true;
timer.pause();
}, 500);
setTimeout(function() {
flag = true;
}, 1000);
});
// if this test is passing, fail should never be true
waitsFor(function(){
return flag;
}, 1100);
// this should be called after 1 second because the previous times out
runs(function(){
expect(fail).toBeFalsy();
});
});

Related

Cucumber-Protractor tests skipping over assertions, falsely passing

So I am brand new at Javascript, my only language before this was Ruby. I have written API tests with Cucumber and Ruby for years, but now I am trying to figure out UI tests for an angular app using Protractor and Cucumber.js. I have the framework set up and the test steps run are passing, but falsely so.
Here is a snippet of my step definitions, with a few edits to change data in assertions and the string for the assertion is intentionally wrong to trigger a failure. They run and are passing, but only because it ignores the assertion. I don't see it actually doing anything in the browser, but if I put in console.log messages I do see them in the console. However, if I comment out the last callback, then I can see it run in the browser and it actually checks the assertions and fails as it should.
Cucumber doesn't require callbacks, and removing them results in it running in exactly the same way... only I can't comment out a callback of course and watch it run like I mentioned above.
And if I don't put that timeout in the first step, then the whole thing errors out at the first step with "Error: function timed out after 5000 milliseconds"
Why?!? Thanks!!
Protractor 5.3.0 with Cucumber 4.0.0 and protractor-cucumber-framework 4.2.0
Given('I am on the home page', {timeout: 30000}, (callback) => {
browser.waitForAngularEnabled(false);
browser.get(browser.params.env.int).then(callback);
});
Then('the log in form is displayed', callback => {
expect(element(by.id('email')).isPresent()).to.eventually.be.true;
expect(element(by.id('password')).isPresent()).to.eventually.be.true;
callback();
});
When('I enter my user name', callback => {
element(by.name('email')).sendKeys('my_addy#example.com');
expect(element(by.id('email')).getAttribute('value')).to.eventually.equal('something that does match');
callback();
});
When('I enter my password', callback => {
element(by.name('password')).sendKeys('blah');
callback();
});
When('I click the log in button', callback => {
element(by.buttonText('Log In')).click();
callback();
});
Then('I am on the X page', callback => {
expect(browser.getCurrentUrl()).to.eventually.contains('Y');
// callback();
});
1) For issue: "Error: function timed out after 5000 milliseconds
This is due to your step definition function execution time duration exceeds the default timeout: 5 secs.
You can change this time out globally by following my another post, or as you did
add timeout only on needed step definition functions individually.
2) For Cucumber callback issue,
You can choose to use callback, or choose to return a promise likely in each step definition function. I prefer the latter approach.
var { Given, Then, When } = require("cucumber");
Given(/^open cucumberjs github page$/, ()=> {
browser.get("https://github.com/cucumber/cucumber-js");
return expect(browser.getTitle()).to.eventually
.equal("cucumber/cucumber-js: Cucumber for JavaScript");
});
When('I enter my password', ()=> {
return element(by.name('password')).sendKeys('blah');
});
When('I click the log in button', ()=> {
return element(by.buttonText('Log In')).click();
});
More code example, you can find from my example project here

Protractor waits during ignore synchronization, browser implicitTimeout vs browser.wait timeout

I have an application that kicks off a $timeout when a button is clicked, so I must work with ignoreSynchronization set to true. During this time, I need to wait for elements to be added to the page, and I am experiencing some interesting behavior during the waits:
The wait timeout passed in during browser.wait(element, timeout, error message) does nothing. The only wait that matters is the implicitTimeout set on the browser. On top of that, the ENTIRE implicit timeout will be used. If the element is found to be present, it will continue checking until the end of the timeout. This means the tests will always run slowly, with the max time given.
describe('Cool Page', () =>{
beforeEach(function(){
browser.ignoreSynchronization = true;
return browser.sleep(250);
});
afterEach(function(){
browser.ignoreSynchronization = false;
return browser.sleep(250);
});
it('can open menu with timeout', function(){
// No timeout at this point
coolPage.wait.ellipsesIcons().then(() =>{
// Clicking the ellipses icons kicks off a $timeout of 100 seconds
coolPage.ellipsesIcons.click().then(() =>{
coolPage.wait.dropdownOptions().then(() => {
expect(coolPage.dropdownOptions.getText()).toContain('Option 1');
});
});
});
});
})
.
export = new CoolPage;
class CoolPageextends PageObject {
private elements;
constructor(){
super();
... // Lots of other stuff
this.initWait();
}
... // Initializing elements and other things
private initWait() {
this.wait = {
ellipsesIcons: () => {
// Timeout of 5 seconds will be used - regardless of isPresent resolving as true or false, the entire 5 seconds will be used
browser.manage().timeouts().implicitlyWait(5000);
// The 2 milliseconds passed in here does nothing at all
browser.wait(element(by.css('.fa-ellipses-h')).isPresent(), 2, 'Ellipses Icon(...) was not present in time');
// Must reset implicit wait back to the original 25 seconds it was set too in the conf
browser.manage().timeouts().implicitlyWait(25000);
return browser.sleep(150);
},
dropdownOptions: () => {
// This two seconds wait WILL be used
browser.manage().timeouts().implicitlyWait(2000);
// This five second wait WILL NOT be used
browser.wait(element(by.css('[name="change-status"]')).isPresent(), 5000, 'Options actions menu item was not present in time');
browser.manage().timeouts().implicitlyWait(25000);
return browser.sleep(150);
},
}
}
The timeouts passed in through browser.wait have no effect here. My questions are:
What does the browser.wait timeout do?
When is the implicit wait used? I thought it was only waiting for pages to load
Is there any way to pass in a timeout that will actually be used?
If not, is there any way for the wait to exit as soon as the condition is met, rather than using the entire timeout?
Try to use expected conditions with browser wait. Take a look at it('should wait for a series of periodic increments' for an example using function textToBePresentInElement. To check if an element is present, I might try out visibilityOf or presenceOf.

How can I make a function that calls another function every 60 seconds?

I have this function:
isAuthenticated = (): boolean => {
xxx
};
I am using AngularJS and I would like to know how can I make a function such as
keepCheckingAuthentication()
That will call the is Authenticated() function every 60 seconds?
There’s a setInterval function that will call any code with given time interval in ms:
var intervalID = setInterval(function() { console.log('Works!') }, 1000);
Later you can cancel the timer using clearInterval(intervalID).
If isAuthenticated can be modified to actually make a request to call the server in order to check authentication, and can return a promise that resolves or rejects when this is done, then I would do something like
var keepCheckingAuthentication = function() {
return isAuthenticated().catch(angular.noop).then(function(isAuth) {
// Can do something different if isAuth == false
return $timeout(keepCheckingAuthentication, 60 * 1000);
});
});
Note the call to catch. This effectively converts any rejections to a success, so the next then callback runs in every case.
Using something like this rather than $setInterval means there will always be 60 seconds between responses from the server, rather than requests made. On a slower connection, or an overloaded server, this means there is a lower chance of adding to the overloaded connection or server, as you're sure the previous request has finished before sending off another one.
you can probably use $interval function (wrapper of window.setInterval() in AngularJS)?
The documentation of $interval function is here
In your case keepCheckingAuthentication() is the function and you can adjust the other parameters accoding to your needs? Does this help?
example:
$interval(myFunctionAtInterval, 5000) // Scheduled for every 5 seconds, for instance
funtion myFunctionAtInterval() {...}
I tend to avoid setInterval whenever I can, i.e. always (Paul Irish talks about this in this video).
What I do is wrap a setTimeout in a function that recursively calls itself (with a condition that allows me to easily stop, or to let the data decide when it's not needed anymore).
var condition = true;
$scope.count = 1;
function myFunc(){
$scope.count += 1;
}
var timer = function(){
myFunc();
if( condition ){
$timeout(timer, 1000);
}
};
timer();
I am using angular built in $timeout here as it's always suggested.
A demo
use $interval.this code will help you:
var callefunc=function() {
console.log('hey i am calle');
}
$scope.caller=function(){
var stop = $interval(callefunc, 1000);
}
here you can call a caller function when you want to start function callefunc on interval of 1 second .

Conditional mocha test

I use mocha for some integration testing and have many test sets.
Each set has initialization tests. When such tests fail, the rest of the set should not run at all, because if one fails then each will fail.
The thing is that I can't avoid such initialization tests, because part of the code/environment is generated by some tool which does not guarantee any correct result.
Is it possible to implement this using mocha ?
Using the BDD interface, the normal way to do this with Mocha is to put anything that sets up the testing environment into before or beforeEach:
describe("foo", function () {
describe("first", function () {
before(function () {
// Stuff to be performed before all tests in the current `describe`.
});
beforeEach(function () {
// Stuff to perform once per test, before the test.
});
it("blah", ...
// etc...
});
describe("second", function () {
before(function () {
// Stuff to be performed before all tests in the current `describe`.
});
beforeEach(function () {
// Stuff to perform once per test, before the test.
});
it("blah", ...
// etc...
});
});
If the before or beforeEach that a test depends on fails, then the test is not run. Other tests that don't depend on it will still run. So in the example above if the callback passed to before in the describe named first fails, the tests in the describe named second won't be affected at all and will run, provided that their own before and beforeEach callbacks don't fail.
Other than this, Mocha is designed to run tests that are independent from each other. So if one it fails, then the others are still run.
I found mocha-steps which basically allow you to write a "chain" of it()s (called step()) and mocha will abort the suite if one of them breaks, thus avoiding the cascade of inevitable failures, and I found pull request 8 marks subsequent steps and subsuites as pending. So I can write:
describe("businessCode()", function() {
step("should be not null", function() {
assert(businessCode() != null)
});
step("should be a number", function() {
assert(typeof businessCode() === 'number');
});
step("should be greater than 10", function() {
assert(businessCode() > 10);
});
describe("thingThatCallsBusinessCode()", function() {
step("should be greater than 10", function() {
assert(thingThatCallsBusinessCode() != null);
});
});
});
If e.g. businessCode() returns a boolean, only the should be a number test will fail; the subsequent ones (and the subsuite will be marked as pending).

Unit testing nodejs events

I'm using a solution explained in this answer to unit test events in my node application.
However, the setTimeout function never calls and so my tests pass when they should fail.
Here is an example:
suite('myTests', function() {
test('myFunction_whenCalled_emitsEvent', function() {
var myClass = new MyClass();
var eventTimeout = setTimeout(function() {
assert(false);
}, 1000);
myClass.on('something', function() {
clearTimeout(eventTimeout);
});
myClass.doSomething(); // this does not emit the 'something' event
});
});
I would expect this to fail, after 1 second as long as the 'something' event is not raised.
I put a breakpoint in the assert(false) line and it is never hit.
Could someone point me in the right direction ? Thanks.
You must use the done callback to show that your test is finished. Something like this:
suite('myTests', function() {
test('myFunction_whenCalled_emitsEvent', function(done) {
var myClass = new MyClass();
myClass.on('something', function() {
done();
});
myClass.doSomething();
});
});
It looks like you are only testing whether the event is emitted. If this is the case, then the whole setTimeout thing is unnecessary. Mocha will itself timeout if it does not get done without the default timeout (2000ms, if I recall correctly).
The way your code was set, Mocha would just schedule your event and then exit the test. Since scheduling the event was successful, Mocha would call the test successful.

Categories