CSS selector that excludes some child elements - javascript

I have this HTML:
<div class="item-cost">
<a data-passage="Shop" class="link-internal macro-link" tabindex="0" id="Link1">$10 <sup>1</sup></a>
</div>
I am writing this testcafe code to get the cost:
.expect(Selector('.item-cost').nth(0).innerText)
.eql('$1')
This fails because the inner text is $11, not $1. The reason it's failing is because the contents of the sup element are included in the inner text. Is there any way I can modify the selector above so that it gives me the inner text without including the sup element? I cannot modify the HTML.

How about using <sup> in your test too?
.expect(Selector('.item-cost').nth(0).innerText)
.eql('$1 ' + Selector('.item-cost sup').nth(0).innerText)

Instead of using innerText, use innerHTML and then use a regexp to remove the trailing <sup>...</sup> (including the space before <sup>):
.expect(Selector('.item-cost').nth(0).innerHTML.replace(/ <sup>.*<\/sup>$/, ''))
.eql('$1')
That will give you just the $10.

I hesitate to add my 2 cents to this discussion as I just happened to stumble into it and am not really familiar with testcafe. But those 2 cents are too long for a comment, so I figure I'll post it as a possible answer and you make of it what you will.
It seems to me that what you are trying to do is select the text of the <a> node while at the same time excluding that of its <sup> child node. An operation like that is easily achieved by using an xpath expression like:
//div/a/text()
Unfortunately, testcafe doesn't seem to support xpath and there is no intention to do it in the future. The main reason seems to be the existence of utilities that can convert xpath to css selectors for use with testcafe.
Unfortunately again, xpath and css selctors aren't equivalent and there are things you can do with xpath that cannot (currently) be done with css selectors. And this case is probably one of them.
To the rescue may comes this utility for adding xpath support to testcafe. So I would try using that with the xpath expression above and see if it works for you. If not, no harm done, I guess.

Related

Is there a way to apply css to part of the element?

I am looking for a way to apply new CSS to only part of the element.
For example. The original HTML looks like
<p>123456</p>
I want to make only 456 into bold.
Of course, I can do it by adding another tag into 456 like
<p>123<b>456</b></p>
But in my application, I do want not to change the original DOM structure. By adding a new tag, I changed the DOM structure.
To do that, I am thinking of adding new custom attribute to the existing tag like
<p data-wms="e-3">123456</p>
Here data-wms means that there are special part and e-3 means that from index 3 character (it is 4 here) to the end will have a special attribute (like bold in this example)
Now I have all the information about where to change inside the element.
But still, how can I do that with javascript without adding a tag, without changing dom.
Thanks
You can use the span element to do so, it's made specifically to handle inline styling while mantaining the overall structure.
An example would be:
<p>123<span class="bold-highlight">456</span></p>
Thanks to everyone's advice, I researched more, especially about nth-letter.
Though nth-letter is exactly what I want, I found that it is still just proposal, not implemented in any browser.
Thus, there is no way to applying different css letter by letter in one text element without embracing each letter with span tag at this moment (2021-March). I hope that there will be nth-letter in the near future.
I think that I have to re-design my project...
if it's a static page and you want to change a style for specific text in a specific tag like the following case
<p>11111</p>
<p>22222</p>
<p>33333</p>
<p>44444</p>
let's say you want just style the third element, you can change it by the following code using jQuery for sure you can use JavaScript but jQuery will help you to make your code shorter
$( "p:nth-child(3)" ).css("color","#f00");

Using CSS selectors instead of XPath locators when searching through siblings

Currently, I have the following page object fields:
this.filterTeamDropdown = $("filter-item-edit .dropdown button");
this.teams = this.filterTeamDropdown.all(by.xpath("following-sibling::ul//li[contains(#class, 'dropdown-list-item')]"));
Is there a way to replace the XPath locator for the teams field and have a CSS selector instead?
The motivation for it is coming from the Style Guide and the recommendation not to use XPaths.
From what I understand, it is impossible to have a CSS selector to go to the next sibling starting from current element in the context. But, are there any alternatives?
Saying NEVER to anything is silly. I strongly favor CSS selectors because locating element by id, CSS selector, just about anything... is faster than XPath. But... at the same time we're talking a few ms of difference.
There are some things that XPath can do that no other locator method can. One example that comes to mind is finding an element (other than A) by contained element text. Other than that I generally stick to CSS selectors when ID doesn't work.
I strongly dislike a lot of people's locator strategies on SO because XPath seems to be the goto way to find elements to the point where it's silly. I've seen people looking for nothing but an id and using XPath. I think part of it is the ease of which you can obtain an XPath, right click on element in inspector and copy XPath and paste in code. The problem with that, as I'm sure you know, is that sometimes (many times?) that results in a very brittle XPath but some/many people don't know any better.
All that said, I'll point you to the W3C CSS Selector reference and maybe you can find what you are looking for. There are some sibling combinators in there but I don't have your HTML so I don't know which, if any, of them would work.
https://www.w3.org/TR/selectors/#selectors
https://www.w3.org/TR/selectors/#adjacent-sibling-combinators
I just read some of the comments below your question and see that you already knew about the + combinator. Is there some reason you can't reuse your initial locator CSS with the XPath converted string? I don't know if this is even valid/usable but I've combined the two locators you provided in your code after converting the XPath to a CSS selector.
filter-item-edit .dropdown button + ul li.dropdown-list-item
There is an another, Protractor-specific way to solve it - use the locator() of the parent element and concatenate to make a child element selector:
this.filterTeamDropdown = $("filter-item-edit .dropdown button");
this.teams = this.filterTeamDropdown.$$(this.filterTeamDropdown.locator().value + " + ul li.dropdown-list-item")

How to convert from mixed HTML-string/DOM-elements to DOM-elements in Javascript?

I wish to implement the following Javascript function:
function AllToDom(partsArray)
{
// Magic!
}
// Called like:
var rowObject = AllToDom(['<tr>', tdElem1, tdElem2, '<td>XXX</td>', '<td>',
divContents,'</td></tr>']);
// Where tdElem1, tdElem2, divContents are DOM node objects.
The thing is I want it to work on any kinds of combinations of DOM nodes and HTML fragments. As long as it produces a valid HTML of course. Unclosed HTML tags and disallowed element combinations (like <table><div></div>) are allowed to have undefined behavior.
My first idea was to concatenate it all in a HTML string, except in place of DOM elements add a placeholder comment <!--SNOOPY-->. So the above would result in the following string:
<tr><!--SNOOPY--><!--SNOOPY--><td>XXX</td><td><!--SNOOPY--></td></tr>
This is already a valid piece of HTML, so next I create a <div>, assign this to innerHTML, gather the produced DOM nodes, and iterate through them and replace all <!--SNOOPY--> with the respective DOM element.
There are two flaws with this approach however:
Adding a <tr> as a child element to a <div> is invalid. I don't know if it might not break on some condition.
Internet Explorer 8 (the least version that I need to support) strips all comments when assigning to innerHTML.
Are there any workarounds? Is this possible at all?
Finally found an answer: jQuery has already done all the dirty work in their parseHTML() method. And I just happen to be using jQuery anyway, so good for me! :)
I checked what the magic was behind the scenes, and it's really pretty gruesome. First, they inspect the HTML (with regexs...) to see what parent tag they need to use, and then they have a workaround for IE8, which apparently it DOES preserve comment nodes - but only if they come after a text node. All comments before the first text node are lost. And some tags are affected this way too, which I had no idea about. And then there's half a dozen other workarounds for IE & Webkit problems that I've never even heard of.
So, I'm just going to leave it to them to do the right thing, because trying to reproduce that stuff would be madness.

id.text() of jquery ignoring more than 1 white space in ie8

I have a span with id SOMEID.When I am accessing its text value using folloing code it is breaking in IE8 and IE7 only.How to fix it.
$("#DocumentPath").text(). If DocumentPath contain name like My doc.txt it is not working. Note here there is 3 white space between My and doc.
You very vague problem description "code it is breaking" can make us only guess, but note the following: IE treats whitespaces in the markup differently than other browsers.
From the docs:
(Due to variations in the HTML parsers in different browsers, the text returned may vary in newlines and other white space.)
The result of the .text() method is a string containing the combined text of all matched elements.
As of jQuery 1.4, the .text() method returns the value of text and CDATA nodes as well as element nodes.
Thus said, it may be more appropriate for you, to use the html() method.
Should be
$("#DocumentPath").html()
That said you say your span has an id SOMEID?! If it's id is SOMEID it should be:
$("#SOMEID").html()
Maybe you should try another approach, on jQuery's docs they recommend call .eval() function to retrieve a value instead of .text() check their doc:http://api.jquery.com/text/
So the code snippet could be:
$("#DocumentPath").eval()
Regards
:)

Alternative for execCommand('underline');

Okay, some Guys will know what i mean and edit my Question but they did it wrong.
A better explanation:
You have a contenteditable div with the text This is a Test String..
If you use now the execCommand('underline') on Test String you get This is a <u>Test String</u>
if you use now the execCommand('strikethrough') on is a Test you get This <s>is a <u>Test</u></s><u>String</u>, THIS is correct.
So, in HTML5 <u> and <s> are obsolete.
For the first execCommand you can use the surroundContents() with a <span style="text-decoration:underline;">. If you now use the surroundContets() for the second execCommand you receive the BAD_BOUNDARYPOINTS_ERR.
The Thing i want is a Function which works like the execCommand in this case but with functions where i can define with witch HTML-Tag the String will wrapped… (It should be intelligent in the case if there is any overlapping…)
The surroundContents() will have problems: if the selection encompasses multiple block elements, such as <div>s or <p>s, the surrounded contents will be placed in a new block, breaking it out of its original position. To overcome this, you could easily adapt my answer here: apply style to range of text with javascript in uiwebview
You'll need to do the following:
Create a CSS class with the rule "text-decoration: underline;"
Add an intersectsNode method of Range for browsers that don't have it, such as Firefox (see MDC for an example: https://developer.mozilla.org/en/DOM/range.intersectsNode)
If you care about IE, you'll need to write a completely different solution.
CSS text-decoration: underline.

Categories

Resources