How to select nth item inside select element in cypress - javascript

say I have the HTML:
<select name="subject" data-testid="contact-us-subject-field">
<option value="What is this regarding?">What is this regarding?</option>
<option value="Partnerships">Partnerships</option>
<option value="Careers">Careers</option>
<option value="Press">Press</option>
<option value="Other">Other</option>
</select>
Selecting an option with a known value, such as 'Careers' is as easy as:
cy.get('[data-testid="contact-us-subject-field"]').select('Careers');
How do I select the nth option in this field, regardless of its value?

Update
As pointed out by #dpstree in the comments, this doesn't answer the original question. Please see more recent answers for a complete solution.
Original
By using eq
cy.get('tbody>tr').eq(0) // Yield first 'tr' in 'tbody'
cy.get('ul>li').eq(4) // Yield fifth 'li' in 'ul'

In the particular context of selecting the nth option, this may be appropriate:
cy.get('select[name=subject] > option')
.eq(3)
.then(element => cy.get('select[name=subject]').select(element.val()))

Based on solution from Miguel Rueda, but using prevSubject option:
Cypress.Commands.add(
'selectNth',
{ prevSubject: 'element' },
(subject, pos) => {
cy.wrap(subject)
.children('option')
.eq(pos)
.then(e => {
cy.wrap(subject).select(e.val())
})
}
)
Usage:
cy.get('[name=assignedTo]').selectNth(2)
Explanation:
Using children('option') and .eq(pos) traverse children of select to specific element.
Call select method with value of selected element.

You can now select an option by index within the .select(index) command:
cy.get('select').select(0) // selects by index (yields first option) ie "What is this regarding?"
cy.get('select').select([0, 1]) // select an array of indexes
This should be easy now with the release of cypress v8.5.0. See documentation for more.

I had the same problem and solved it by creating a custom cypress command. No as pretty as I would like, but it did the job.
Cypress.Commands.add("selectNth", (select, pos) => {
cy.get(`${select} option +option`)
.eq(pos)
.then( e => {
cy.get(select)
.select(e.val())
})
})
then I used in the test as such
cy.viewport(375, 667)
.selectNth("customSelector", 3)
The option +option part was the only way I could find to get the full list of options inside a select and it's currently the bit of code i'm trying to work arround although it works fine.

since the working answers are using then anyways, eq or something fancier is redundant with array indexing...
// to click on the 1st button
cy.get('button').then($elements => {cy.wrap($elements[0]).click();});
// to click on the 4th tr
cy.get('tr').then($elements => {cy.wrap($elements[3]).click();});
// to click on the last div:
cy.get('div').then($elements => {cy.wrap($elements[$elements.length - 1]).click();});

Let's assume you wanna select 2nd option, you can do that simply by this
cy.get("select option").eq(2)
just keep in mind that cy.get() works like jquery's $().

Find dropdown using ID or Class -
cy.get('#ID').contains("dowpdown placeholder or name").click();
After Click dropdown result dropdown element will popup, find that result ID or Class using inspect element, Then -
cy.get('#result-ID').children().first().click();
This will click on the first element of the dropdown.

Capture all the elements in the drop-down using a selector. Get the length. Use math.random() to randomly get a number. Select the option at the index.
cy.get("ul > li").as("options")
cy
.get("#options")
.its('length')
.then(len => Math.floor(Math.random() * Math.floor(len)))
.then((index) => {
cy.get("#options").eq(index).click()
})

You can also rely on the :nth-child css pseudo-class:
cy.get("[data-testid="contact-us-subject-field"] option:nth-child(2)").click();
It's probably less flexible than using the cypress constructs but it is nice and clean. (And doesn't make me crawl through the cypress docs)

if you are looking a value to select then you cannot use .eq(), you need to use .contains()
.eq() is only for numbers(indexes)
Example: cy.get(dropdownOptions).contains(some_value).click()

Related

Nightwatch dropdowns handling by passing value

Below is the approach I have used in order to select values from a dropdown using nightwatch.As you can see this is not a good approach. We can't select the specific value from dropdown unless we click on the exact element.
this.useXpath();
this.click('(//td[#class="styles_selectDropdownContainer__2Vrns"])[1]')
this.useCss();
this.click('#react-select-6-option-1')
In selenium java there is a very good option like below
Select fruits = new Select(driver.findElement(By.id("fruits")));
fruits.selectByVisibleText("Banana");
I want to know of there is a similar approach can be used in nightwatch as well?
This is not built up using Select and Option tag so inbuilt selenium functions wouldn't work. Work around would be to click first on the parent span and then in list store every div (which is option), iterate the loop and for each web element if text matches with your desired text you can click on it.
Code :
this.useCss();
this.click("span[aria-live='polite']")
Now store options in a list :
var elements = document.querySelectorAll('.elements'); // use
//div[contains(#class,'option')] as element selector.
Now iterate the list :
// Iterate over them.
[].forEach.call(elements, function (element) {
// Manipulate each element.
element.click();
});
});

jQuery .not() doesn't remove element?

I am grabbing a copy of some info from a page, but I do not want to include certain <option> elements that appear inside <select> elements on the page.
Therefore, while I grab all the elements I want and am storing them in the variable fields, I check to see if each element is a <select> and if they have the specific <option> that I don't want.
var field = allFields[i].innerHTML; //allFields is the raw HTML I'm iterating through
if ($(field).find("select").length > 0) { //If the element we're looking at contains a select
console.log("Found a select. It is in " + field);
console.log($(field).find(".bad-option");
field = $(field).not(".bad-option").prop("outerHTML"); //Use .not() to remove the elements which have the .bad-option class
// (and .prop("outerHTML") is just there to convert it back to a String instead of a jQuery object)
}
console.log("Adding " + field);
fields[i] = field; //Add the HTML, free of any unwanted options, to the `fields` variable
Based on jQuery's documentation, I would expect the .not() function to remove any elements out of field which have the bad-option class. Yet that is not the case at all. When I log field before and after using .not(), it prints out the same thing. See the console output from the code above:
Found a select. It is in <label>Description: <select><option>thing1</option><option class="bad-option">thing2</option></select></label>
-----------------
[jQuery list object size 1, containing an object called option.bad-option]
-----------------
Adding <label>Description: <select><option>thing1</option><option class="bad-option">thing2</option></select></label>
So what's going on? How do I remove an option with a certain class from from within a jQuery object? Why isn't .not() working?
If I need to clarify anything, please let me know. I tried to make this question as specific as possible and would be happy to elaborate on any details further.
The documentation is perhaps a bit confusing: not removes elements from the selection, not the DOM. If you want to remove the elements, then just filter and remove:
const processed = $(field);
processed.filter(".bad-option").remove();
field = processed.prop("outerHTML");

jQuery find all attr rel

I have a this select dropdown:
<select id="category">
<option value="cat1">Category 1</option>
<option value="cat2">Category 2</option>
</select>
and I have this code that everytime I select something form the dropdown it takes the value and find the same class and show it on the last line
$('#category').change(function () {
var selected_category = $(this).val();
$('#sub-category').find('.option').hide();
$('#sub-category').find('.'+selected_category).show();
});
I just want to change instead of class so it will find the attribute rel
** edited **
You definitely don't need jQuery for this. Here's the code to find all option tags with a rel attribute of "sub-cat1":
document.querySelectorAll('option[rel="sub-cat1"]')
The above will work in IE8 and up, which should satisfy all browsers you need to support. The jQuery solution is similar, and uses the same selector string:
$('option[rel="sub-cat1"]')
Furthermore, you don't need to add a class of "option". Simply select using the option tag name.
There can be an alternate way to your answer.
Using jquery try ,
$ (".classname").each(function(){
//iterate over similar *classname* elements one by one
$(this).someFunc(); //it will help you to preform operation at current value while iteration
});
With rel if you want to iterate over rel tag values , try
$("[rel='sub-cat-1']").each(function(){
//Some operation
});

How to detect current input-text's index from an array of input-text with jquery

I have an array of input text boxes simplified as bellow:
<input type="text" name="quantity[3]" value="0">
<input type="text" name="quantity[6]" value="0">
<input type="text" name="quantity[7]" value="0">
<input type="text" name="quantity[11]" value="0">
Either of the two ways is acceptable for me, but I don't know how to do even one of them:
When the 3rd input box (with has index 7) is changed, either of the two alert()s is acceptable for me:
7 (because the real index of the 3rd text box is 7)
2 (because probably it will be counted from 0 and thus its index will be 2)
My code that doesn't work is:
$(document).ready(function(){
$('input[name^=quantity]').change(function(){
alert($(this).index());
});
})
Link: http://niamco.com/cp/problem.html
It is expected that when the user changes any of the Quantity text boxes, the text box's val() be alerted as well as their correct index(). We see that the val() is outputted correctly, but the index() is always returned 0.
As the val() is correct, we should be sure that jQuery is loaded well and working. So why shouldn't index() be true?
Strange is that as I've researched, both val() and index() are jQuery functionalities. If val() was javascript base, it could be accepted. But now, one jquery Base function works, and the other does not!
.index() gets the element's current position relative to it's siblings. You should use a regex to get the number between [ and ] in the input's name.
Use this instead:
$('input[name^=quantity]').change(function () {
var index = $(this).prop('name').match(/\[(.*?)\]/)[1];
console.log(index);
});
Here it is working: http://jsfiddle.net/u8HRq/1/
UPDATE: Based on your update here's a working fiddle: http://jsfiddle.net/qbmAU/2/
First off ids should be unique so I've changed them to classes and updated the selector for the change event.
I've also got .index() working:
$(this).index('.quantity')
index() usually works by returning the position relative to the matching siblings which is why mine and j08691's answers were working. However, if the elements aren't siblings then you can pass a selector as an argument. This returns the index of the current element relative to the matched elements.
This gets both:
$('input[name^=quantity]').change(function () {
console.log($(this).index(), +$(this).prop('name').match(/\d+/g));
});
jsFiddle example
$(this).index() is the true index
+$(this).prop('name').match(/\d+/g) is the index from the attribute
Update: After you updated your question to show the code you're really using, this should help you:
$('input[name^=quantity]').change(function () {
console.log($(this).closest('table').find('input[name^=quantity]').index($(this)), +$(this).prop('name').match(/\d+/g));
});
+$(this).prop('name').match(/\d+/g) still works to get the index from the attribute
$(this).closest('table').find('input[name^=quantity]').index($(this)) but you'll need this format using .index() to get the index of the input elements since they're not siblings of each other. You need to pass an argument for the collection of elements you want to compare them against, in this case $(this).closest('table').find('input[name^=quantity]').

Using .hide() and .show() in jQuery

In my program I have several very similar drop-down menus all with the same name (foo in the following example). On change they hide or show a nearby div tag depending on whether or not "ON" was selected.
$('.togClass').hide();
$('[name*="foo"]').change(function(){
if ($('[value="ON"]').is(':selected')) {
$('.togClass').show('blind', 1000);
} else {
$('.togClass').hide(1000);
}
});
As it is, all of the div tags with class "togClass" toggle when any of the drop down menus choose "ON", is there a way that I can choose to show/hide only the nearby div to the drop-down that chooses "ON"(they are nested in the same div)? I don't want to write a copy of this function for every div I want to hide.
Here is how it works in the HTML:
<select name="foo">
<option value="OFF">OFF</option>
<option value="ON">ON</option>
</select><br/>
<div class="togClass">
//Stuff
</div>
Ofcourse you can. Check out the jquery doc about traversing: http://api.jquery.com/category/traversing/ It has a lot of great examples.
For your problem the solution could be: .closest()
$('div.togClass').hide();
$('select[name*="foo"]').change(function(){
if ($(this).val() == "ON") {
$(this).siblings('div.togClass').show('blind', 1000);
} else {
$(this).siblings('div.togClass').hide(1000);
}
});
You have to tell us a bit more about what "nearby" means. But it appears that the fundamental piece you're missing is the use of $(this) within the change function. Instead of identifying any .togClass item, you want to identify a specific one relative to $(this) -- the element being changed.
Here's one way to do it with the assumption that the associated .togClass div is the next one to be found in the DOM.
$('[name*="foo"]').change(function(){
if( $(this).is(':selected') ) { // relative to the selected item
$(this).next('.togClass').show('blind',1000);
} else {
$(this).next('.togClass').hide(1000);
}
});
Where you see .next() you'll actually need the appropriate jQuery traversal methods -- unlikely to be the one I've randomly assumed in the example.
How about using .closest()?
Should do the trick.

Categories

Resources