Conditional testing in Cypress - check if cy.xpath-element has class value - class

What I want to do: I want to click a button. Then some element expands, and the button class name is changing. I only want to expand the element if not done yet.
I have to use cy.xpath, which makes it more complicate.
if (cy.xpath('//div[1]/button').should('have.class', 'it-is-focused'))
{
// do something
}
This code is not working, because the class is not available. An error is thrown.
With .then() implemented
cy.xpath('//div[1]/button').then(($btn) => {
if($btn.hasClass('abc-focused')) {
// do something
}
else {
// do something else
}
})
Problem, if-bracket is never executed. $btn.hasClass('abc-focused') seem not to work. But the class is available in the DOM of this button.

Related

Polymer 2 - Perform action every time element is shown via iron-pages/iron-selector

I'm attempting to create a logout page that will work even after that element has been attached once to the DOM. This occurs when you get a login, then logout, then login again, and attempt to log back out.
For instance, the shell has
<iron-selector selected="[[page]]" attr-for-selected="name">
<a name="logout" href="[[rootPath]]logout">
<paper-icon-button icon="my-icons:sign-out" title="Logout" hidden$="[[!loggedIn]]"></paper-icon-button>
</a>
<a name="login" href="[[rootPath]]login">
<paper-icon-button icon="my-icons:sign-in" title="Login" hidden$="[[loggedIn]]"></paper-icon-button>
</a>
</iron-selector>
<<SNIP>>
<iron-pages selected="[[page]]" attr-for-selected="name" fallback-selection="view404" role="main">
<my-search name="search"></my-search>
<my-login name="login"></my-login>
<my-logout name="logout"></my-logout>
<my-view404 name="view404"></my-view404>
</iron-pages>
I also have an observer for page changes in the shell:
static get observers() {
return [
'_routePageChanged(routeData.page)',
];
}
_routePageChanged(page) {
this.loggedIn = MyApp._computeLogin();
if (this.loggedIn) {
this.page = page || 'search';
} else {
window.history.pushState({}, 'Login', '/login');
window.dispatchEvent(new CustomEvent('location-changed'));
sessionStorage.clear();
this.page = 'login';
}
}
This works well as when I click on the icon to logout, it attaches the my-logout element just fine and performs what in ready() or connectedCallback() just fine.
my-logout has
ready() {
super.ready();
this._performLogout();
}
The issue comes when, without refreshing the browser and causing a DOM refresh, you log back in and attempt to log out a second time. Since the DOM never cleared, my-logout is still attached, so neither ready() nor connectedCallback() fire.
I've figured out a way of working around this, but it feels very kludgy. Basically, I can add an event listener to the element that will perform this._performLogout(); when the icon is selected:
ready() {
super.ready();
this._performLogout();
document.addEventListener('iron-select', (event) => {
if (event.detail.item === this) {
this._performLogout();
}
});
}
Like I said, it works, but I dislike having a global event listener, plus I have to call the logout function the first time the element attaches and I have to listen as the listener isn't active till after the first time the element is attached.
There does not appear to be a "one size fits all" solution to this. The central question is, "Do you want the parent to tell the child, or for the child to listen on the parent?". The "answer" I came up with in the question works if you want to listen to the parent, but because I don't like the idea of a global event listener, the below is how to use <iron-pages> to tell a child element that it has been selected for viewing.
We add the selected-attribute property to <iron-pages>:
<iron-pages selected="[[page]]" attr-for-selected="name" selected-attribute="selected" fallback-selection="view404" role="main">
<my-search name="search"></my-search>
<my-login name="login"></my-login>
<my-logout name="logout"></my-logout>
<my-view404 name="view404"></my-view404>
</iron-pages>
Yes, this looks a little confusing considering the attr-for-selected property. attr-for-selected says, "What attribute should I match on these child elements with the value of my selected property?" So when I click on
<iron-selector selected="[[page]]" attr-for-selected="name">
<a name="logout" href="[[rootPath]]logout"><paper-icon-button icon="my-icons:sign-out" title="Logout" hidden$="[[!loggedIn]]"></paper-icon-button></a>
</iron-selector>
it will set the <my-logout> internally as the selected element and display it. What selected-attribute="selected" does is to set an attribute on the child element. If you look in the browser JS console, you will see that the element now looks like
<my-login name="login"></my-logout>
<my-logout name="login" class="iron-selected" selected></my-logout>
We can define an observer in that in the <my-logout> element that checks for changes
static get properties() {
return {
// Other properties
selected: {
type: Boolean,
value: false,
observer: '_selectedChanged',
},
};
}
_selectedChanged(selected) {
if (selected) {
this._performLogout();
}
}
The if statement is so that we only fire the logic when we are displayed, not when we leave. One advantage of this is that we don't care if the element has already been attached to the DOM or not. When <iron-selector>/<iron-pages> selects the <my-logout> the first time, the attribute is set, the element attaches, the observer fires, the observer sees that selected is now true (as opposed to the defined false) and runs the logic.

bootstrap-validator check form

I am using 1000hz BootstrapValidator and after click on button (not submit because I need to stay on page without refresh) I want to check if form is correct.
I just can call $("#form2").validator('validate'); but I am not able to get return value.
I know about isDefaultPrevented but it is called after submit and I do not want submit.
$('#form').validator().on('submit', function (e) {
if (e.isDefaultPrevented()) {
// handle the invalid form...
} else {
// everything looks good!
}
})
Yeah one way is to change the from submit button type from submit to buttonand handle the validation via click function and count the length if any input field has error ($('#form2').validator('validate').has('.has-error').length) and handle it with if/else condition.
$(document).ready(function(){
$("#myButton").click(function() {
if ($('#form2').validator('validate').has('.has-error').length) {
alert('SOMETHING WRONG');
} else {
//$("#form2").submit();
alert('EVERYTHING IS GOOD');
}
});
});
Fiddle Example

scala : double "selection changed" event raised for ListView component

here is the part of code:
val lsv_syns = new ListView[String]()
val scp_syns = new ScrollPane() {
listenTo(lsv_syns.mouse.moves,lsv_syns.selection)
reactions += {
case me: MouseExited => {
txf_mot.requestFocus()
}
case SelectionChanged(`lsv_syns`)=> {
println("sélection:"+lsv_syns.selection.items(0))
}
}
}
As you can see, the listView is in a scrollPane; don't pay attention to the mouseExited event, the interesting thing is the selectionChanged, which seems to be called twice when I only click on time on an other line, because the println is called two times.
thanks.
Well i also recently worked with a ListView and now that you mentioned it, it also does my calculation twice.
The answer seems to be related to mouse events. Following the stack trace SelectionChanged is called twice. One coming from the Java event MousePressed and one from MouseReleased.
When you change the selection with KeyEvents it is only called once.
My first (and I guess not nice) idea to avoid the problem would be to ignore one of the events:
reactions += {
case SelectionChanged(`lsv_syns`) if !lsv_syns.selection.adjusting => {
println("sélection:"+lsv_syns.selection.items(0))
}
}
Both ListSelection events share the same data except getValueIsAdjusting. So if you check for it you can avoid doing your stuff twice.
Warning: !lsv_syns.selection.adjusting will result in printing on key release and not on press!
If you put lsv_syns.selection.adjusting it will correspond to key press but it will also filter key events. As I said. Not nice at all...

Clicking keyboard 'Next' key using UIAutomation

I have a search field in my app and I have set the return key type of the keyboard for this field to UIReturnKeyNext. I am attempting to write a UIAutomation test that clicks the Next button on the keyboard using the following line:
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().keys().firstWithName("next");
This call is failing because the key with name 'next' is not being found. I have done a dump of all of the elements in my app using:
UIATarget.localTarget().frontMostApp().logElementTree();
This reveals that there is indeed a key in the keyboard with name 'next', but somehow my attempt to retrieve it as show above still fails. I can however retrieve other keys (like the key for the letter 'u') using this method. Is there a known issue here or am I doing something wrong?
I've tried other variations with no luck:
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().elements()["next"];
Here is a screen capture of the elements in my UIAKeyboard:
If you just want to click it, and you know the keyboard has "next" as "Return key" (defined in your nib), then you can use this:
app.keyboard().typeString("\n");
Jelle's approach worked for me. But I also found an alternative way if anybody needed it.
XCUIApplication().keyboards.buttons["return"].tap()
Where you can create XCUIApplication() as a singleton on each UI Test session. The thing about this approach is you can now distinguish between return and done and other variants and even check for their existence.
You can go extra and do something like following:
extension UIReturnKeyType {
public var title: String {
switch self {
case .next:
return "Next"
case .default:
return "return"
case .continue:
return "Continue"
case .done:
return "Done"
case .emergencyCall:
return "Emergency call"
case .go:
return "Go"
case .join:
return "Join"
case .route:
return "Route"
case .yahoo, .google, .search:
return "Search"
case .send:
return "Send"
}
}
}
extension XCUIElement {
func tap(button: UIReturnKeyType) {
XCUIApplication().keyboards.buttons[button.title].tap()
}
}
And you can use it like:
let usernameTextField = XCUIApplication().textFields["username"]
usernameTextField.typeText("username")
usernameTextField.tap(button: .next)
I dont't have an example to test, but as the "Next" button is an UIAButton, and not an UIAKey you could try :
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().buttons()["next"];
If it doesn't work, you can also try
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().buttons()[4];
The following works for me:
UIATarget.localTarget().frontMostApp().mainWindow().keyboard().buttons().firstWi‌​thPredicate("name contains[c] 'next'");
For me, keyboard does not fall under mainWindow() in the View Hierarchy. It is at the same level as mainWindow() when you logElementTree() from top level. So, what you want to do is:
UIATarget.localTarget().frontMostApp().keyboard().buttons()["next"];
This worked for me when I was trying to press the "Search" button on keyboard.

jquery selection with .not()

I have some troubles with jQuery.
I have a set of Divs with .square classes. Only one of them is supposed to have an .active class. This .active class may be activated/de-activated onClick.
Here is my code :
jQuery().ready(function() {
$(".square").not(".active").click(function() {
//initialize
$('.square').removeClass('active');
//activation
$(this).addClass('active');
// some action here...
});
$('.square.active').click(function() {
$(this).removeClass('active');
});
});
My problem is that the first function si called, even if I click on an active .square, as if the selector was not working. In fact, this seems to be due to the addClass('active') line...
Would you have an idea how to fix this ?
Thanks
Just to give something different from the other answers. Lonesomeday is correct in saying the function is bound to whatever they are at the start. This doesn't change.
The following code uses the live method of jQuery to keep on top of things. Live will always handle whatever the selector is referencing so it continually updates if you change your class. You can also dynamically add new divs with the square class and they will automatically have the handler too.
$(".square:not(.active)").live('click', function() {
$('.square').removeClass('active');
$(this).addClass('active');
});
$('.square.active').live('click', function() {
$(this).removeClass('active');
});
Example working: http://jsfiddle.net/jonathon/mxY3Y/
Note: I'm not saying this is how I would do it (depends exactly on your requirement) but it is just another way to look at things.
This is because the function is bound to elements that don't have the active class when you create them. You should bind to all .square elements and take differing actions depending on whether the element has the class active:
$(document).ready(function(){
$('.square').click(function(){
var clicked = $(this);
if (clicked.hasClass('active')) {
clicked.removeClass('active');
} else {
$('.square').removeClass('active');
clicked.addClass('active');
}
});
});