Cypress How do tick check boxes with no unique selectors - javascript

I am trying to select/tick checkboxes with no obvious selectors but a class name which is shared by all the checkboxes on the page.

Then You can directly use the text to find the locator and click it, something like:
cy.contains('Tool').click()
For the search button, you have the aria-label tag, you can use that directly:
cy.get('input[aria-label*="main-search-box"]').type('text')

I believe it goes against cypress' best practices to try and select any element other than using data-cy="add-unique-id-here" selector. The docs suggest that using CSS-style selectors is brittle, and may cause tests to fail in the future when you update your code. By using data-* selectors, you can gaurantee you're always selecting what you need.
Here's the link for the cypress docs: https://docs.cypress.io/guides/references/best-practices#Selecting-Elements
In your case, adding
<span class="ui-lib-checkbox__box" data-cy="descriptive-checkbox-name"> <svg>...</svg> </span> to your html
and cy.get('[data-cy=descriptive-checkbox-name]') to your cypress testing file, should do the trick.

Given the text for the checkboxes are unique, you can use cy.contains()
// 'Under 6 min' checkbox
cy.contains('span', 'Under 6 min')
// 'Tool' checkbox
cy.contains('span', 'Tool')
As for the search box, it will get a bit trickier. If it is the only search box that is visible on the page you can do the following.
cy.get('input[type=text][placeholder]')
.filter(':visible')

Related

How to search with querySelector for html-elements that have no id set in the source?

Is this possible with querySelector?
This doesn't work, but gives simply all elements
document.querySelectorAll('*:not([id=""])');
More info: The user can enter his selector into an input field, and it would be nice if such a search for missing id would be possible without using additional checkboxes or settings, but just with the query-selector.
Instead use
document.querySelectorAll(':not([id])');

How can I add a disable class to a single select, not all of that I have

I want to put a disabled class into my select, but when I do this:
$("input").attr("disabled",true);
//I tried to to this but it didn't work too:
$("#myId").attr("disabled",true);
It disable all of my selects and not one.
How can I disable only "myId"?
Without seeing your HTML (which at the time of writing has not been supplied) it's very difficult for us to tell you why it's not working.
However, if $("#myId").attr("disabled",true); isn't working, then it suggests to me that you do not have an element in your HTML with id='myId'.
Things to check in the rendered HTML (as seen by the browser, not your code)...
Is there an element with an id of myId
Is the id exactly myId, and not myID for instance (as the case is important)
Are you using something like ASP.Net where naming containers could be changing the id of the rendered control to something like ctl00_myId
Do you have 2 elements with an id of myId... in which case, this is invalid HTML, as each element must have a unique id, and would result in jQuery only setting the disabled on the first item
It disables them all because $("input").attr("disabled",true); adds the attribute disabled to all input elements. Without seeing your HTML it's hard to tell what the reason is for it not disabling when you try using #myId
Here are some mistakes I've made in the past for similar problems:
1) I did not actually have the id on the element that I thought I had. Whether it was a misspelling, or capitalization difference, or underscore vs dash...the point is the id I was trying to reference on the page simply did not match the one I was looking for with jQuery
2) I referenced it as an id but really it was a class or vice versa. . for classes, and # for id's is second nature, but sometimes if you're tired or exhausted you can very easily make that mistake
3) I had given an id that existed in multiple elements. id is supposed to be unique by convention. Duplicate id's will produce unexpected behavior
Hopefully one of these simple reasons is the cause for your issue and you can quickly resolve it. Maybe take a 30 minute break and come back to it.

Selecting the proper HTML Element

I use Nightwatch.js to test foreign website code. I used this command:
.waitForElementVisible('input[id="inputField"]', TIMEOUT)
This should wait until the specified element is visible. But I get this warning:
Warn: WaitForElement found 24 elements for selector "input[id="inputField"]". Only the first one will be checked.
I thought the id of a tag is unique. How is it possible to get a list of 24 elements when looking for this id?
What can I do now to select exactly the element I need?
How is it possible to get a list of 24 elements when looking for this id?
Because people constantly fail to understand the basic concept that ids must be unique. Apparently, the site you're testing against was written by one or more of those people.
What can I do now to select exactly the element I need?
According to the documentation, Nightwatch.js lets you use XPath as an alternative to CSS. With XPath, you can specify which of a set of elements to target, e.g.:
.useXpath()
.waitForElementVisible('//input[#id="inputField"][1]', TIMEOUT)
...would use the first, [2] would use the second, etc.
If you can't do it by the index of the element in the document, you'll need to find other things about it you can use to select it (with CSS or XPath).
The id of an element should be unique. However that doesn't take out the ability for a developer to create as many elements with the same id on the page as he wants.
Also, id selectors are usually specified like this input#inputField.
I could now solve the problem by selecting an unambiguous parent element and then selected the child of the child of it; something like this:
div[id="listItem_0"] > span > input[id="inputField"]

Why does the jquery selector ("id,id") selects all elements with duplicate IDs

I came across some year old code written by a good developer (yes, I knew him personally) to access all elements having the same id.
$("#choice,#choice")
It returns all elements having the id. But if we use the below
$("#choice")
It returns only the first match, as expected.
After searching for some time, I'm unable to figure out any official links pointing to his technique, as to how it selected all elements with duplicate id.
Can anyone please explain how is this working ?
UPDATE
Please see the question is not about what alternative to use. I'm aware of classSelectors and attributeSelectors and know having duplicate IDs is not recommended, but sometimes you just have to live with years old code the way it is (if you know what I mean).
http://jsbin.com/zodeyexigo/1/edit?html,js,output
If you look at the code of sizzle.js that jQuery uses for selecting elements based on selector you will understand why this happens. It uses following regex to match simple ID, TAG or class selector:
// Easily-parseable/retrievable ID or TAG or CLASS selectors
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
but as the selector in question is $("#ID,#ID") it does not match with the selector and uses querySelectorAll (line no 270 in ref link), which replaces selector to "[id='" + nid + "'] " (line no 297 in ref link) which selects all the elements with matching ID.
However, I agree with the other people in this thread, that it is not good idea to have same ID for multiple elements.
Having 2 elements with the same ID is not valid html according to the W3C specification.
When your CSS selector only has an ID selector (and is not used on a specific context), jQuery uses the native document.getElementById method, which returns only the first element with that ID.
However, in the other two instances, jQuery relies on the Sizzle selector engine (or querySelectorAll, if available), which apparently selects both elements. Results may vary on a per browser basis.
However, you should never have two elements on the same page with the same ID. If you need it for your CSS, use a class instead.
If you absolutely must select by duplicate ID, use an attribute selector:
$('[id="a"]');
Take a look at the fiddle: http://jsfiddle.net/P2j3f/2/
Note: if possible, you should qualify that selector with a tag selector, like this:
$('span[id="a"]');
Having duplicated id on the page making your html not valid . ID is unique identifier for one element on the page (spec). Using classes, that are classify similar elements that's your case and $('.choice') will return set of elements
So in JS Fiddle i have shown an example of what jQuery is doing.
https://jsfiddle.net/akp3a7La/
When you have a
$('#choice,#choice');
It is actually getting all the instances of the objects #choice twice, and then filtering out any duplicates.
in my example i show you how it does that also when you have something like this
$("#choice,li");
Where items are actually your #choice items.
In the Jquery Documentation
https://api.jquery.com/multiple-selector/
it talks about multiple Selectors, which is what i think is happening here, your developer friend is selecting the same ID twice, and it would be returning it twice. as you can only have one input with the same ID once on a page (good html syntax)

What is the easiest way to link radiobuttons to enable/disable other controls?

My webpage has a bunch of radiobuttons across a bunch of different radiobutton groups. Each radiobutton selection which is made will enable a directly corresponding element in the page and disable all other elements which correspond to the other radiobuttons in the group. What is the easiest way to make this link between the elements?
To use javascript-framework like jQuery by adding attribute 'disabled'.
For example:
$('#targetElement').attr('disabled', 'disabled');
Also you should keep in mind that it's easier to query for parent element and disable it's child elements.
Also, it's good to wait for the document being loaded and then add click-handlers on the radio controls
If you really want a slick way to do something like that, you should look into the eval(). It will allow you to dynamically execute a piece of code, based on a string. So, in your case, you can store this relation (maybe the ID of the corresponding element) as an attribute and then when any radio button is click. You extract this particular attribute and make an expression and eval() it to get it hide:
e.g. using jQuery:
eval( '$("#"' + some_attr + '").show()' );
However, this is generally not considered a good practise, but is pretty "automated".

Categories