I've been writing a suite of tests in Protractor, and am almost finished. I'm having difficulty figuring out how to do something fairly common though. I want to be able to check if a textbox contains a value, and if so, exit the testcase with a failure. (If the textbox contains a value, I know there's no chance the test case can pass anyway)
I'm currently trying something like this:
tasksPage.generalInformationDateOfBirthTextbox.getAttribute('value').then(function(attr){
//attr contains the correct value in the textbox here but how do I return it to parent scope so I can exit the test case?
console.log("attr length is " + attr.length);
expect(attr.length).toBe(0);
},function(err){
console.log("An error was caught while evaluating Date of Birth text value: " + err);
});
The expect statement fails as I'd expect it to, but the testcase keeps going, which seems to be the intended behavior of expect. So I tried returning a true/false from within the 'then' block, but I can't seem to figure out how to return that value to the parent scope to make a determination on. In other words, if I change the above to:
var trueFalse = tasksPage.generalInformationDateOfBirthTextbox.getAttribute('value').then(function(attr){
if(attr === ""){
return true;
}else{
return false;
}
},function(err){
console.log("An error was caught while evaluating Date of Birth text value: " + err);
});
//This is the 'it' block's scope
if(trueFalse == true){
return;
}
I know my inexperience with promises is probably to blame for this trouble. Basically, I just want a way of saying, 'if such and such textbox contains text, stop the test case with a failure'.
Thanks,
This is not a protractor issue, it is a testing framework issue (jasmine, mocha etc).
Though, there was an issue on protractor's issue tracker:
--fail-fast CLI option
which was closed with a reference to an opened issue in jasmine issue tracker:
Feature Request - fail-fast option
While this is not implemented, there is a workaround (originally mentioned here):
jasmine-bail-fast package
After installing the module with npm, when you want your test to fail and exit, add:
jasmine.getEnv().bailFast();
(don't forget to load the dependency require('jasmine-bail-fast');)
Also see:
Does jasmine-node offer any type of "fail fast" option?
The issue with the code above is that you are trying to compare a 'Promise' and a 'value'.
trueFalse.then(function(value)
{
if(value)
....
});
OR compare it via an expect statement. Something like expect(trueFalse).toBe(false);
Related
if(browser.getCurrentUrl().
toString.contain('local')){//if it is local,do something.if it is not local, i need to do another things
//do something
}
else{
//do another
}
I need to get url and check if it contains local. If it has local, i need to do operations for local. Else, i will do another operations.
I cant do this with expect because it will give failure if is was not matched.
So i need to use string operatipns.
But none of those worked:
browser.getCurrentUrl().toString.contain('local')
browser.getCurrentUrl().toString.contains('local')
browser.getCurrentUrl().contain('local')
browser.getCurrentUrl().contains('local')
error is
toString.contain is not a function
ANOTHER SOLUTION
While running protractor from console,
gulp protractor
i run with this.
SO if i can do like this:
gulp protractor local
or for another usages,
gulp protractor testmachine
it will be better. It can record that parameter to a variable so i will access that variable
if(paramter.equals="local"){//if it is local,do something.if it is not local, i need to do another things
//do something
}
else{
//do another
}
i can also do something like that instead of currenturl
if(logoutPageObject.baseUrl.toString.contain("local")){ because baseurl variable can say if i am on local or not. but also this doesnot work.
browser.getCurrentUrl() will return you a promise and not a string. First resolve the promise and use the exact URL for the validation.
browser.getCurrentUrl().then(function(url){
if(url.indexOf("local") >= 0 ){
console.log("url contains local")
}else{
console.log("do something else")
}
})
so basically i am e2e testing a web site and I am creating a language on the page as the page admin, so in case i something fails or similar my .then() function doesn't work in other words it only works if the code is run and doesn't fail so if it does it doesn't execute the else or the if, in this case if the language is not deleted it will just throw a F and wont execute "Error language not created", and take a screenshot. I am using this method like 20 more times in my script so any help would help on how to improve it if it is possible and to tell me if I am doing something wrong.
element.all(by.repeater('item in languages')).
get(0).isPresent().then(function (result){
console.log('Deleting language...');
if(result)
{
console.log('Error language not deleted...');
sShot = true; //Don't mind this, it is for whether to take a screenshot afterEach() or not.
console.log('-----------------------');
console.log("\n");
}
else{
console.log('Language deleted!');
console.log('-----------------------');
console.log("\n");
}
});
So if the language isn't deleted which i do above the code i posted when it fails there while deleting it it never executes the isPresent().then() it only executes it when It is successfu. It completely leaves the current test case and goes to the next. l hope I am making sense
I just started working with cucumberJs, gulp and protractor for an angular app and noticed, luckily as all my steps were passing, that if you don't pass in and use that 'callback' parameter in the step definition, cucumberJs might NOT know when this step is completed and will skip other steps and mark them all as 'passed'
Below is an example from the cucumberJs doc: https://github.com/cucumber/cucumber-js
Example 1:
this.Given(/^I am on the Cucumber.js GitHub repository$/, function (callback) {
// Express the regexp above with the code you wish you had.
// `this` is set to a World instance.
// i.e. you may use this.browser to execute the step:
this.visit('https://github.com/cucumber/cucumber-js', callback);
//
The callback is passed to visit() so that when the job's finished, the
next step can
// be executed by Cucumber
.
});
Example 2:
this.When(/^I go to the README file$/, function (callback) {
// Express the regexp above with the code you wish you had.
Call callback() at the end
// of the step, or callback(null, 'pending') if the step is not yet implemented:
callback(null, 'pending');
});
Example 3:
this.Then(/^I should see "(.*)" as the page title$/, function (title, callback) {
// matching groups are passed as parameters to the step definition
var pageTitle = this.browser.text('title');
if (title === pageTitle) {
callback();
} else {
callback(new Error("Expected to be on page with title " + title));
}
});
};
I understand you have 2 choices here:
a. Either you return a promise and don't pass the call back OR
b. You pass in the callback parameter and call it whenever the step definition is complete so cucumberJs knows to return and go to next step or next scenario.
However, I tried both above and still running into a weird situation where the top two scenarios will work NORMALLY as you would expect, but the third and fourth scenario within that same feature file will be skipped and all passed.
Is there anything special to consider about features with more than 2 scenarios?
As long as I have <= 2 scenarios per feature files, everything works fine, but the moment I had a third scenario to that feature file, that third scenario is ignored and skipped.
Any ideas?
Without seeing your actual steps I can't say for sure but it sounds like an asynchronous issue or dare I say it, a syntax error in the scenario. Have you tried changing the order of the scenarios to see if that has an impact.
Is there a way to have an expectation that an element is eventually on the page? e.g. a way for
browser.wait(protractor.ExpectedConditions.presenceOf(element(by.partialLinkText('Continue'))), 1000, 'Unable to find continue link');
to fail with an expectation error instead of a timeout? Essentially a way to have a isEventuallyPresent() instead of isPresent() in the line below
expect(element(by.partialLinkText('Continue')).isPresent()).toBe(true);
For reference, I'm using browser.ignoreSynchronization = true even though it's an Angular app, and using Jasmine (at least for now).
Using the facts that
browser.wait returns a promise that is resolved once the condition function returns truthy, or rejected if it times out.
If expect is passed a promise, it only runs the expectation when the promise is resolved
You can make a function that wraps a call to browser.wait
function eventual(expectedCondition) {
return browser.wait(expectedCondition, 2000).then(function() {
return true;
}, function() {
return false;
});
}
and then create an expectation
expect(eventual(protractor.ExpectedConditions.presenceOf(element(by.partialLinkText('Continue'))))).toBe(true);
Or, to make it work on any browser instance, you can monkey-patch the Protractor prototype
protractor.Protractor.prototype.eventual = function(expectedCondition) {
return this.wait(expectedCondition, 2000).then(function() {
return true;
}, function() {
return false;
});
}
and can be used as
expect(browser.eventual(protractor.ExpectedConditions.presenceOf(element(by.partialLinkText('Continue'))))).toBe(true);
To avoid timeouts, you must make sure that the timeout passed to browser.wait is less than the the Jasmine async test timeout, which is specified as jasmineNodeOpts: {defaultTimeoutInterval: timeout_in_millis} in the protractor configuration file
The presenceOf expected condition used with a browser.wait() would allow to have a single line in the test:
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(element(by.partialLinkText('Continue'))), 1000, 'Unable to find continue link');
where EC is protractor.ExpectedConditions - I usually make it global in onPrepare() through the global namespace.
Note that in case of a failure, you would have a Timeout Error, but with the Unable to find continue link error description.
As a side note, it is important to provide a meaningful custom error description, as you've already did. If you want to enforce it, there is a eslint-plugin-protractor plugin to ESLint static code analysis tool that would warn you if there is a browser.wait() used without an explicit error description text.
I have some code:
var Person = new Backbone.Model({name: 'Jeremy'});
Person.validate = function(attrs) {
if (!attrs.name) {
return 'I need your name';
}
};
Person.on("invalid", function(model, error) {
alert(model.get("title") + " " + error);
});
Person.set({name: 'Samuel'});
console.log(Person.get('name'));
// 'Samuel'
Person.unset('name', {validate: true});
console.log(Person.get('name'));//Why can i print name here if it unsetted?
When i type unset method i see an error alert. It's correct. But why can i print in console the name if it was unsetted?
The name is still there because the validation failure stopped the unset from doing anything.
The documentation isn't very explicit about how validation works with set and unset but it is quite explicit with save:
validate model.validate(attributes, options)
[...] If validate returns an error, save will not continue, and the model attributes will not be modified on the server.
So it is reasonable to think that validation errors will prevent the current operation (set, unset, save, ...) from changing anything.
You can see how it works by examining the Backbone source code. First, you need to know that unset is just a set call in disguise:
unset: function(attr, options) {
return this.set(attr, void 0, _.extend({}, options, {unset: true}));
}
So we look at set:
set: function(key, val, options) {
// A bunch of boring bookkeeping stuff...
// Run validation.
if (!this._validate(attrs, options)) return false;
// The stuff that changes attributes and triggers events.
}
The validations happen as soon as set knows what it is working with and set returns without changing anything if the validations fail.
The Backbone documentation leaves a lot of important things out so you need to be passingly familiar with the Backbone source if you're going to use Backbone. The source is fairly straight forward, don't be afraid to jump into it to see what's going on.
Do this: To not trigger events you can use the silent:true option. I believe there might be some issue upstream in your code. Anyways, do the following - it should work. ( in my tests, it did ).
Person.unset('name',{validate: true,silent:true})
p.s.: Mu ( below ) gives great information.