getByRole for text under li > a on test-library - javascript

I would like to use getByRole to write the test and I have html like following. when I use linkitem or 'link' as role. I cannt find element
// err
TestingLibraryElementError: Unable to find an accessible element with the role "listitem" and name "Click Me"
Here are the accessible roles:
--------------------------------------------------
list:
Name "":
<ul
class="bar-dropdownList"
/>
--------------------------------------------------
listitem:
Name "":
<li
class="bar-container"
/>
Name "":
<li
class="bar-actionContainer"
/>
--------------------------------------------------
// test.tsx
const name = screen.getByRole('listitem', {name: 'Click Me'});
// from screen.debug()
<ul class="bar-dropdownList">
<li class="bar-container">
<div>
<a class="bar-button">
<span class="bar-label">Click Me</span>
</a>
</div>
<div>
<a class="bar-button">
<span class="bar-label">Address</span>
</a>
</div>
</li>
</ul>

The problem is that React Testing Library will not recognize an anchor as a role="link" if it doesn't have an href. You can test this using RTL's Testing Playground -- if you try to query by the link role you'll get a node returned, but if you remove the href it returns nothing. You'll also note that if you remove the href and then attempt to navigate through the document by tabbing on the keyboard, the anchor element is now skipped and never receives focus. This is most likely the reason why RTL makes this distinction: browser treat an anchor without an href differently from an accessibility perspective. RTL tends to be pretty good about the rules it uses to match by accessible roles, so if it were me I'd err on the side of assuming that an anchor without an href represents an accessibility antipattern, and reassess how this is being built.

Related

Get an anchor text value among multiple anchor's with same href

My html is
<a id='_requestOne' href='#applynow'> apply one </a>
<a id='_requestTwo' href='#applynow'> apply two </a>
<a href='#applynow'> apply three </a>
I want to change the anchor text for the second one alone. so I implemented in script as
$("a[href='#applynow']").text("request call");
Its changing all the three tags, so I tried as
$("#_requestTwo a[href='#applynow']").text("request call");
But its not working.
Can anyone give me a solution that how could I declare both id & href in same call.
Thanks in advance.
What you can do is target the second Item of the jQuery Object:
$( $("a[href='#applynow']")[1] ).text('request call') //starts counting at 0
I do not advise on this, it makes the code less maintenable if the html markup changes. You have an ID, so use that instead.
$("#_requestTwo").text('request call')
PS:
The reason why your second try doesn't work is because you had an error in the selector:
$("#_requestTwo a[href='#applynow']")
//should be
$("a[href='#applynow']#_requestTwo")
First select anchors with href then specify with ID or select directly by ID because ID should be unique:
$("a[href='#applynow']#_requestTwo").text("request call");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a id='_requestOne' href='#applynow'> apply one </a>
<a id='_requestTwo' href='#applynow'> apply two </a>
<a href='#applynow'> apply three </a>
Always select elements from low to high specificity like:
$("tagname.class");

AureliaJS - replacing looped elements with a template (passing values?)

I have found https://sean-hunter.io/2016/10/23/inter-component-communication-with-aurelia/ where it is explained how simple communication of values can be made between a parent and a child template.
Now, I'm trying to apply that to the contact manager tutorial:
http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/contact-manager-tutorial/1
... also on https://github.com/aurelia/app-contacts/tree/master/src - in particular to the looped contact items, but I cannot get it to work.
I have made gists as an example, which can run on gist.run (note, gist.run seems to only work in Chrome, not in Firefox 50 yet - but you can replace gist.run/?id= with gist.github.com/ and look at the code):
Copy of original contacts manager app (works) - https://gist.run/?id=c73b047c8184c052b4c61c69febb33d8
My changes in the app (do not work) - https://gist.run/?id=47c4f1c053adbdf46f6a33413dd12d3d
This is what I'm trying to do: in the original contacts app, there is this in src/contact-list.html which works fine:
<template>
<div class="contact-list">
<ul class="list-group">
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
<h4 class="list-group-item-heading">${contact.firstName} ${contact.lastName}</h4>
<p class="list-group-item-text">${contact.email}</p>
</a>
</li>
</ul>
</div>
</template>
Now, I'd like to replace the inner elements of the "looped" li - that is, the a with the h4 and the p - with a new template.
So, I made src/contact-list-item.html:
<template>
<a route-href="route: contacts; params.bind: {id:theContact.id}" click.delegate="$parent.$parent.select(theContact)">
<h4 class="list-group-item-heading">${theContact.firstName} ${theContact.lastName}</h4>
<p class="list-group-item-text">${theContact.email}</p>
</a>
</template>
... and src/contact-list-item.js:
import {bindable} from 'aurelia-framework';
export class ContactListItem {
#bindable theContact;
}
... and changed src/contact-list.html as:
<template>
<require from="./contact-list-item"></require>
<div class="contact-list">
<ul class="list-group">
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<contact-list-item theContact.bind="contact"></contact-list-item>
</li>
</ul>
</div>
</template>
Basically, I've made a property in the contact-list-item class called theContact, and I'd like to bind it to the contact which is the looper variable in the repeat.for="contact of contacts" -- unfortunately, this doesn't work, as the data is not propagated (and so the contact names are empty). Also, the clicks on contact fiels do not propagate to show the details, even if I've changed click.delegate="$parent.select(contact)" to click.delegate="$parent.$parent.select(theContact)" in the new template.
What do I have to do, in order to have the data propagate form the li repeate.for loop, down to the new replacement template - and to have the app react on clicks on the new template?
Quick answer:
In contact-list.html, change:
<contact-list-item theContact.bind="contact"></contact-list-item>
to:
<contact-list-item the-contact.bind="contact"></contact-list-item>
Explanation:
HTML is not case-sensitive, but the convention is to use only lower-case letters. To respect that, Aurelia converts all camelCase variables to dash-case parameters and element names when interfacing with your HTML code.
More Information:
Dwayne Charrington wrote a good blog about this topic here:
http://ilikekillnerds.com/2016/06/dont-get-skewered-kebab-case-aurelia/

On click to menu-toggle change the Menu to Log In

I have a nav menu.
On click of the Menu button, I want to replace it with Login text
<div class = "navbar navbar-inverse navbar-fixed-top">
<div class = "container">
<!--Collapse menu with three lines-->
<button type = "button" class = "navbar-toggle" data-toggle = "collapse" data-target = ".navHeaderCollapse">
<span class = "icon-bar"></span>
<span class = "icon-bar"></span>
<span class = "icon-bar"></span>
</button>
<!--Actual menu-->
<div class ="collapse navbar-collapse navHeaderCollapse">
<ul class = "nav navbar-nav navbar-right">
<li class = "active">
<a data-toggle = "collapse" data-target = ".navHeaderCollapse" href = "#">Home</a>
</li>
<li>
<a data-toggle = "collapse" data-target = ".navHeaderCollapse" href = "#">Blog</a>
</li>
<li>
<a data-toggle = "collapse" data-target = ".navHeaderCollapse" href = "#">About</a>
</li>
<li>
<a data-toggle = "collapse" data-target = ".navHeaderCollapse" href = "#contact">Contact</a>
</li>
</ul>
</div>
</div>
</div>
I added a class like this
<div id="displaylogin" style="display:none;" >
LOG IN <i class="fa fa-bars"></i>
And trying to show hide like this using the JS.
$(function(){
$('.menu-toggle').click(function(){
$('.align-right').removeClass("visibleClass");
$('.displaylogin').addClass("visibleClass");
});
});
Here's the fiddle for the same.
It seems to me that you're trying to bind the click handler to the wrong element.
From what I can see, within the div#displaylogin you have an a element with the class menu-toggle however since the div#displaylogin is hidden you'll never click on it since it's not visible or clickable within a hidden element.
If you want your code to trigger in the first place you'd have to bind it to the button.navbar-toggle.
$('.navbar-toggle').on('click', function() {
// this line will not work provided the example code
// this is because this class is not in the example
// also this classname should not be used as a selector since you'll use it alot
// when you're using it all over the page jQuery will try to remove this class from every element with class 'align-right'
$('.align-right').removeClass('visibleClass')
// your element uses an ID, not a CLASS - therefore the '.' needs to be a '#'
$('.displaylogin').addClass('visibleClass')
});
The above example tries to point out what is going wrong however I have some additional recommendations so that your code won't turn into frog-soup later on in development.
When you want to bind something to a single element in JS, it's best to use an ID as they are (supposed to be) unique on the page.
This prevents screw-ups when it comes to you making changes later in your code.
also, using the class .align-right as a selector rings like a million alarm bells on my side since this class has such general naming I am assuming that you're going to re-use it on multiple elements.
In turn, every time you re-use that class on different elements it will try to remove the visibleClass from every element that has class="align-right". Can you see how that can become a problem?
This is all just advice so don't take it the wrong way, we're all trying to help each other here and that's what I'm trying to do right now :)
Fixing these issues and updating your question accordingly will allow us to help you until your problem is fixed.
It is also very important to understand that selectors are a very simple thing with very complex consequences when used improperly (as with this .align-right case).
I can't really say this is an answer but it's to large for a comment so I'm just going to keep updating this when more information is available.
Try to debug what you already have with my advice and come back to edit your question if you wish it to be solved, good luck in the process ;)

Link inside a button not working in Firefox

I have two links inside a button but the links don't seem to work on Firefox.
<button class="btn login">
<b>Log In</b>
|
<b>Sign Up</b>
</button>
I tried JavaScript onclick and redirecting - even that is not working.
This doesn't work because it is not allowed by HTML5:
Content model: Phrasing content, but there must be no interactive
content descendant.
Interactive content means any of the following elements:
a audio (if the controls attribute is present) button details embed
iframe img (if the usemap attribute is present) input (if the type
attribute is not in the hidden state) keygen label menu (if the type
attribute is in the toolbar state) object (if the usemap attribute is
present) select textarea video (if the controls attribute is present)
If it does work in some browsers it's just because they're trying to
play nice with malformed markup and provide some sort of meaningful result.
In other words: rewrite your HTML, it's a mess. If you want the links to look like they're in a button, put them in a div element and style that to look like one, instead of abusing semantically wrong elements for it.
<a> is not allowed inside <button>
Phrasing content, but there must be no interactive content descendant.
<a> is interactive content (regardless of whether it has an href apparently, but yours do). Thus you can't depend on having the links as children of the button and what Firefox is doing is correct. Use another element to contain the <a>s
I have two links inside a button but […]
“Yeah, but let me stop you right there …”
http://www.w3.org/TR/html5/forms.html#the-button-element:
4.10.8 The button element Content model: Phrasing content, but there must be no interactive content descendant.
--->
Interactive content is content that is specifically intended for user interaction.
⇒ a, audio […]
So, if you are writing invalid HTML, expect unexpected behavior ;-)
You can add this in the button element.
onclick="window.location.href='/link1'"
Example
<button onclick="window.location.href='/login'">Login</button>
That's invalid HTML,
Do something like this instead:
<ul>
<li>Log in</li>
<li>Sign up</li>
</ul>
Use javascript: window.location for the button.
<div class="product">
<button onClick="javascript: window.location='/checkout/outfield-
banner/1'">Add to Cart</button>
</div>
Or, you can put the button inside the anchor, it won't have the exact same look since it'll be two different buttons, but it will be a button that acts as a link. It's still not technically correct but it does work in FireFox.
<a href="/login">
<button class="btn login">
<b>Log In</b>
</button>
</a>
<a href="/signup">
<button class="btn login">
<b>Sign Up</b>
</button>
</a>

Jquery Toggle only works on one Post

I'm having an issue with using Jquery toggle on a feed. I have a hyperlink called Tags. When i click on this it toggles a div underneath it.
It works - But only for the top post in the feed - If I have any other posts in the feed it doesn't work.
Below Is Jquery:-
<script type="text/javascript">
$(function () {
$("#hypfeedTagBtn").click(function() {
$("#divPostBodyTags").toggle();
return false;
});
});
</script>
Below is HTML:-
<div id="divPostFoot_64" class="dPostMain dPostFoot">
<span id="Content_ucFeeds_repFeedThread_lblFeedViewCouont_0" class="spFootReplyCount"></span>
<span id="Content_ucFeeds_repFeedThread_lblFeedShareLink_0" class="spFootLinks"></span>
<span id="Content_ucFeeds_repFeedThread_lblFeedDeleteLink_0" class="spFootLinks"></span>
<a id="hypfeedTagBtn" class="spFootLinksShowTags">Tags</a>
<a id="Content_ucFeeds_repFeedThread_hypFeedMessageMe_0" class="spFootLinks" href="/Mail/NewMessage.aspx?FeedID=64">Message Me</a>
</div>
<div id="divPostBodyTags" class="dPostMain dPostTAGSDIV" style="display: block;">
<ul id="PostBodyTags">
<li class="TAGLiItem">
<a class="TAGaItem">Plumbers</a>
</li>
<li class="TAGLiItem">
<a class="TAGaItem">Plumbers</a>
</li>
</ul>
</div>
Thanks
Steve
MDN element.id
The ID must be unique in a document, and is often used to retrieve the
element using document.getElementById.
In some documents (in particular, HTML, XUL, and SVG), the id of an
element can be specified as an attribute on the element like so: .
However you can't use this attribute in a custom XML document without
correctly specifying the type of the id attribute in the DOCTYPE.
Other common usages of id include using the element's ID as a selector
when styling the document with CSS.
Note that IDs are case-sensitive, but you should not create IDs that
differ only in the capitalization (see Case Sensitivity in class and
id Names).
Use a class instead of an id if you want to toggle more than one section.

Categories