Check if element has class only with Jasmine test framework - webdriver

I am using webdriverJS and Jasmine to perform an end-to-end testing of a web page. I would like to test if an element has class under certain circumstances, but I would like to do it using methods from pure jasmine.
This is the part of the code where the issue is located:
describe('Header bar', function() {
it('should show/hide elements accoding to the window position', function() {
this.driver.executeScript('scroll(0, 1000)');
var elemSearch = this.driver.findElements(webdriver.By.id('animatedElement, animatedElement2, animatedElement3'));
expect(elemSearch).toContain('appear-2');
});
})
Do you know if there's a way to solve this issue, or a couple of examples I could look at, without using extensions like jasmine-jquery?
Thanks in advance for your replies!

If you don't want having jasmine-jquery or other third-party packages introducing custom jasmine matchers as a dependency, you can always extract the toHaveClass() matcher implementation and use it. Note that having your assertion logic encapsulated inside custom matchers helps to follow the DRY principle and make your tests cleaner.
FYI, here is toHaveClass implementation we are currently using:
beforeEach(function() {
jasmine.addMatchers({
toHaveClass: function() {
return {
compare: function(actual, expected) {
return {
pass: actual.getAttribute("class").then(function(classes) {
return classes.split(" ").indexOf(expected) !== -1;
})
};
}
};
},
});
});

Related

Polymerfire - Read document once

I was wondering if there is a way to retrieve a document just once, and avoid every kind of bidirectional sync with the database.
The Polymerfire documentation is poor, and I couldn't find it.
Thanks
No, the firebase-document element does not have a 'once' mode. However, you can easily drop down to the underlying JS SDK if you've already initialized the SDK with firebase-app:
Polymer({
is: 'my-element',
attached: function() {
firebase.database().ref('/path/to/doc')
.once('value').then(snap => this.data = snap.val());
}
});
I found another solution. You can check if the data are already loaded and then call the off() method on firebase reference, which disables all listeners.
Here are the important parts of code:
<firebase-document id="office_document" app-name="doctor-appointment-system" path="/offices/{{profileID}}" data="{{officeData}}">
</firebase-document>
dataNotLoaded: {
type: Boolean,
computed: 'computeDataAvailability(officeData)',
observer: 'disableReference'
}
computeDataAvailability: function (data) {
return Object.keys(data).length === 0;
}
disableReference: function (dataNotLoaded) {
if (!dataNotLoaded) {
this.$.office_document.ref.off();
}
},
I prefer this approach because it allows me to use Polymerfire and I needed to check if the data were loaded to disable paper-spinner so it didn't cause unnecessary complexity in my code.

Add test dependency in Protractor & Jasmine test framework

I looked up controlling the test flow but couldn't find a direct way to do it. Still wondering if someone found an alternate way to manage below situation.
How to write test case which are dependent on previous test case success? Consider below example:
describe('Test scenario started', function() {
BeforeEach(function() {
//Doing the login here and executing it once
});
it('TC001 (independent)', function() {
// Perform steps and validate
// Click a link for newpage and verify it's loaded
});
describe('Navigate to next page', function() {
it('TC002 (Dependent on success of TC001)', function() {
// Perform steps and validate
// Click a link for nav to page #3 and verify it's loaded
});
describe('Navigate to Page #3', function() {
it('TC003 (Dependent on success of TC002)', function() {
// Page #3 is available, let's perform the tasks now
});
})
});
});
I'd like to skip the test which are dependent if the parent test case fails thereby avoiding unnecessary delay of trying to execute them. I can add all the functionality to one test case but breaking up in smaller cases is something we prefer.
Anyone have an elegant way to handle this?
You can use any one of the below:
jasmine-bail-fast
jasmine-fail-fast
It will allow you to fail tests faster.

How to check if Accounts UI widget loaded on client?

The default Accounts-UI widget takes a while to load. I want to check on the client when it is ready, so that I can perform some DOM manipulations on it afterwards. I am currently using a timer like so:
Template.sign_in_modal.onRendered(function (){
Tracker.afterFlush(function () {
Meteor.setTimeout(function () {
$('a#login-sign-in-link').click();
$('a#login-name-link').click();
$('a.login-close-text').remove();
}, 100);
});
});
The above hack works locally (probably because it loads faster) but not when I push to saturnapi.com. I just want it to be expanded by default as shown below. Is there a way to ensure the UI widget is fully loaded via a template helper or otherwise make it expanded by default?
I would suggest checking when the <a id="login-sigin-in-link"></a> is added to the DOM. This could be verified by checking $('a#login-sign-in-link').length. If the element is on the DOM do your manipulation.
However if it is not just check again in a few milliseconds. I would suggest using setInterval().
See below for the complete solution:
Template.sign_in_modal.onRendered(function (){
var setIntervalId = Meteor.setInterval(function() {
if($('a#login-sign-in-link').length) {
$('a#login-sign-in-link').click();
$('a.login-close-text').remove();
Meteor.clearInterval(setIntervalId);
}
}, 100);
});
Template.sign_in_modal.onDestroyed(function() {
$('.modal-backdrop.fade.in').remove();
});
Some may think that using loginButtons.onRendered(function(){}); is a good way to verify if the element has been added to the DOM, but it is not. If you try to do the same DOM manipulation in onRendered, it will throw an afterFlush error. The onRendered function has been extremely misleading.

CodeMirror - AutoComplete "options" not setting right

I am using CodeMirror and attempting to do some CSS styling to the autocomplete pop up. This is a bit difficult, because I need it to not go away when I go to inspect styles and stuff.
So I hunted for a way to do this. I found this code in show-hint.js
if (options.closeOnUnfocus !== false) {
var closingOnBlur;
cm.on("blur", this.onBlur = function () { closingOnBlur = setTimeout(function () { completion.close(); }, 100); });
cm.on("focus", this.onFocus = function () { clearTimeout(closingOnBlur); });
}
If I comment this out, then the autocomplete pop up does not go away when I click on other things; That's what I wanted. But I thought I would explore this more and try to determine what to do to toggle this on and off at will.
So I wanted to be able to set this closeOnUnfocus option on my own. That seemed simple enough.
I cannot find a way to do this, though. Exploring further I found an example on code mirror's website that demonstrates a way to setup the autocomplete system using the following code;
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword);
}
Exploring further, show-hint.js starts out with a function called showHint that has this signature;
CodeMirror.showHint = function (cm, getHints, options) {
// We want a single cursor position.
if (cm.somethingSelected()) return;
if (getHints == null) {
if (options && options.async) return;
else getHints = CodeMirror.hint.auto;
}
if (cm.state.completionActive) cm.state.completionActive.close();
var completion = cm.state.completionActive = new Completion(cm, getHints, options || {});
CodeMirror.signal(cm, "startCompletion", cm);
if (completion.options.async)
getHints(cm, function (hints) { completion.showHints(hints); }, completion.options);
else
return completion.showHints(getHints(cm, completion.options));
};
Okay, so it stands to reason that I could accomplish what I want by passing my option through here; like this...
CodeMirror.commands.autocomplete = function (cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword, {
closeOnUnfocus: false
});
}
But this doesn't work - in fact, it seems that the options just don't get passed at all. If I do a console.log in the show-hint.js, the options are outright ignored. They never get through.
So how can I pass options through? I am very confused.
If you want to change the styles of of the hint menu, just use the provided CSS hooks. There is no need to mess around with the autocomplete handlers. e.g.:
.CodeMirror-hints {
background-color: red;
}
.CodeMirror-hint {
background-color: green;
}
.CodeMirror-hint-active {
background-color: blue;
color: yellow;
}
And here's a live Demo.
I've just started to use Codemirror (v4.1) and I've found the same problem. After checking show-hint.js contents it seems that documentation is not updated.
Try to write this when you want to get the suggestions:
CodeMirror.showHint({hint: CodeMirror.hint.deluge, completeSingle: false, closeOnUnfocus: true});
If you need to use the async mode of getting suggestions (it was my case), now you have to do this before previous snippet:
CodeMirror.hint.deluge.async = true;
Hope this helps!
You can pass the options like this :
CodeMirror.showHint(cm,CodeMirror.hint.anyword,{completeSingle: false,closeOnUnfocus:false});
You can write the code as follows:
editor.on("keyup",function(cm){
CodeMirror.showHint(cm,CodeMirror.hint.deluge,{completeSingle: false});
});
It's working for me.

Durandal: How to route away from current view within that view's activate() function?

I have the following:
function activate(routeData) {
// make dataservice call, evaluate results here. If condition is met, reroute:
if (true){
router.navigateTo("#/someRoute");
}
alert ("should not be shown");
}
The alert is getting hit however, and then the view changes.
How do I fully navigate away from the current item and prevent any further code in that vm from being hit?
Update:
I tried using guardroute but I have to activate the viewModel to call the dataservice that returns the data that determines whether or not I should re-route. Using guardroute totally prevents the dataservice from getting called (since nothing in the activate function will get hit).
I also tried returning from the if block but this still loads the view / viewAttached / etc so the UX is glitchy.
The following worked for me in Durandal 2.0:
canActivate: function() {
if(condition)
return {redirect: 'otherRoute'};
return true;
}
activate: // Do your stuff
It's mentioned in the documentation: http://durandaljs.com/documentation/Using-The-Router.html
Here's #EisenbergEffect answer to a quite similar discussion in google groups.
Implement canActivate on your view model. Return a promise of false,
then chain with a redirect.
You might want to give #JosepfGabriel's example (discussion) a try in Durandal 1.2. Check the correct router syntax for your Durandal version, you might have to substitute it with something like router.navigateTo("#/YourHash", 'replace').
canActivate: function () {
return system.defer(function (dfd) {
//if step 2 has a problem
dfd.resolve(false);
})
.promise()
.then(function () { router.navigate("wizard/step1", { trigger: true, replace: true }); });
}
However this is NOT working in Durandal 2.0 and there's a feature request https://github.com/BlueSpire/Durandal/issues/203 for it.
You can't call redirect into the active method.
You can override the guardRoute method from router, to implement redirections.
You can do somehting like that:
router.guardRoute= function(routeInfo, params, instance){
if(someConditios){
return '#/someRoute'
}
}
You can return a promise, true, false, the route to redirect... You can find more information about that in the next link: http://durandaljs.com/documentation/Router/
Rainer's answer was pretty good and works for me adding this small fix.
Inside the then() block simply call the navigation like this
setTimeout(function() { router.navigateTo('#/YOUR DESTINATION'); }, 200);
that should fix your problem. The setTimeout does the trick. Without it the newly navigated page catches the old NavigationCancel from the previous one.
Adding a return in your if (true) block should fix this.
function activate(routeData) {
if (true){
router.navigateTo("#/someRoute");
return;
}
alert ("should not be shown");
}

Resources