How to fail a Cypress test if text wraps at wrong point - testing

So I am trying to write a test that checks multiple viewports if an element wraps at certain words. I am using Next.JS with component testing. Here is an example:
The test should pass if it wraps like this:
If it wraps like this it should fail:
Here is the structure of the text:
<h1 class="text-[5rem] w-full leading-none text-left">
<span class=" inline-block font-extrabold">H</span>
<span class=" inline-block font-extrabold">e</span>
<span class=" inline-block font-extrabold">l</span>
<span class=" inline-block font-extrabold">l</span>
<span class=" inline-block font-extrabold">o</span>
<span class=" inline-block font-extrabold">,</span>
<br>
</h1>

You don't give a very precise requirement, just a couple of images. I'm going to assume you don't want to break mid-word, as that looks most likely.
cy.get('h1 span')
.should($spans => {
const result = offsets.reduce((acc,current) => {
if (acc.lastOffset && current[0].offsetTop > lastOffset) {
acc.breaks.push(current.text())
}
acc.lastOffset= current[0].offsetTop
return acc
}, {breaks:[], lastOffset:null})
// only breaks on spaces
expect(result.breaks.every(breakChar => breakChar === ' ').to.eq(true)
})

The way I would approach it is to measure the height of the element, HTMLElement.offsetHeight.
For example
cy.viewport(...) // ensure viewport size is known
...
cy.get('h1')
.should($h1 => {
const height = $h1[0].offsetHeight
expect(height).to.be.lt(300)
})

Related

Show as Html on vuejs

i have json file for translate ( en.json ) and this line :
{
"cancel order": "Hi, How can i <b> Cancel </b> ?",
}
<div class="d-flex align-items-center justify-content-center align-content-center mb-4">
<span class="description col-sm-11 col-md-7 col-lg-10">
{{ $t('cancel order') }}
</span>
</div>
now my result is " Hi, How can i Cancel "
The problem is that the html code does not apply like this code and the tags are displayed exactly without being applied.
You can use the v-html directive to rander raw html.
const htmlcontent = '<h1>Hello</h1>'
<span v-html="htmlcontent">
</span>
https://vuejs.org/guide/essentials/template-syntax.html#raw-html
use this :
<div v-html="$t('cancel order')"></div>
One observation : Using camelCase in property names consider as a best practice. Hence, use cancel order instead of cancel order.
To render your translation as an HTML message and not a static string. You can use v-html.
Template :
<span class="description col-sm-11 col-md-7 col-lg-10" v-html="$t('cancelOrder')"></span>

Set focus to first item in v-for using vue

I have a vue app and I'm trying to set the focus to the first item in my v-for list but struggling
HTML
<div class="input-group-append">
<button class="btn btn-light" type="submit" style="border: 1px solid lightgray" #click.prevent="findTest">
<i class="fas fa-search"></i>
</button>
</div>
<div v-if="this.Tests.length >= 2" class="list-group accList">
<a v-for="(test, i) in tests" :key="i" class="list-group-item list-group-item-action" :ref="i" :class="{ 'active': i === 0 }" #click.prevent="selectTest(test)">
{{ test.test1 }} ({{ test.test2 | capitalize }})
</a>
</div>
Note the word 'test' has replaced my actual values
I have tried using the following in my method which is called on button click but I keep getting get an error
methods: {
findTest() {
axios.get(END_POINT).then((response) => {
...SOMEOTHER CODE
//this.$refs.0.$el.focus()
//this.$refs.0.focus();
//this.$refs.a.$el.children[0].focus();
}
}
}
Error
I am relativly new to vue but I have been able to set my focus using:
this.$refs.[INPUT_NAME].$el.focus()
But it doesn't like me using a number
this.$refs.0.$el.focus() //0 being the index number
As WebStorm complains saying:
Expecting newline or semicolon
console.log(this.$refs)
When using v-for, ref maybe array of refs.
Template: use ref="tests" instead of :ref="i"
<a v-for="(test, i) in tests" :key="i" class="list-group-item list-group-item-action" ref="tests" :class="{ 'active': i === 0 }" #click.prevent="selectTest(test)">
{{ test.test1 }} ({{ test.test2 | capitalize }})
</a>
Script
this.$refs.tests[0]
I guess its undefined because you try to access the element while the v-for loop didnt finished its rendering
Try this:
methods: {
findTest() {
axios.get(END_POINT).then((response) => {
...SOMEOTHER CODE
this.$nextTick(()=> {
//put your code here
//this.$refs.0.$el.focus()
//this.$refs.0.focus();
//this.$refs.a.$el.children[0].focus();
})
}
}
}
Put your code into $nextTick() that should ensure that its get executed when the loop is done

Vue-test-utils cannot call text on empty wrapper

I have the following html template
<div>
<li class="posted-comment" v-for="commentDetail in commentDetail" :key="commentDetail.id"
#mouseover="hoverIn()" #mouseout="hoverOut()">
<div class="comment-user-avatar"><img :src="commentDetail.img_url"></div>
<div class="comment-user-details">
<span class="distinct-user-name">{{ commentDetail.name}}</span>
<span class="distinct-user-title">{{ commentDetail.user }}</span>
<span class="full-stop">.</span>
<span class="distinct-time-stamp">{{ commentDetail.time}}</span>
</div>
<div class="comment-info-block-wrapper">
<div id="distinct-user-comment">
{{ commentDetail.text}}
</div>
</div>
</li>
Calling wrapper.find('li.posted-comment .comment-info-block-wrapper #distinct-user-comment') says cannot call text on empty wrapper, looks like the "distinct-user-comment" id cant be found
describe('Comment.vue', () => {
it('renders distinct user comment class', () => {
const string = 'So what the German automaker is likely to focus on today is the bigger picture. This will be the first time we see the Taycan free from any prototype bodywork.';
const wrapper = shallowMount(Comment)
expect(wrapper.find("li.posted-comment .comment-info-block-wrapper #distinct-user-comment").text()).equal(string)
})
})

How can I find the exact value using xpath in selenium webdriver for text that contains ?

I'm having an issue selecting the exact text 'Section' from the code using xpath.
** To be clear I require the exact text selection to be made from the innerText or innerHTML of the element if that is possible, not the id. **
I'm able to use the contains text function, but that results in other partial matches that contain 'Section' being returned/highlighted as well:
//div[#aria-hidden='false']//ul/li[contains(text(),'Section')]
I've tried using the following methods, but I don't know if I've got the syntax correct, as nothing is returned/highlighted:
//div[#aria-hidden='false']//ul/li[text()='Section')]
//div[#aria-hidden='false']//ul/li[.='Section']
//div[#aria-hidden='false']//ul/li[normalize-space(.)='Section']
This is what is shown when inspecting the Section node:
<li id="GOS--/40" class="nodecollapsed item parent-node xh-highlight" style="" xpath="1">
Section <span class="child-count"></span>
</li>
This is what is shown in the element properties:
id: "GOS--/40"
innerHTML: "↵ Section <span class="child-count"></span>↵ "
innerText: " Section "
Here is the xml which shows the other partial matches that are returned:
<div class="selection-list-dialog modal-dialog Dialog">
<div class="modal-content">
<div class="modal-header SectionHeader">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<span class="modal-title" data-lang="StandardItems">Standard Items</span>
</div>
<div class="modal-body selection-list-container" style="margin-top: 30px" id="base">
<div>
<span data-lang="SelectItemInstructions">Select the items you are interested in from the list.</span>
</div>
<br/>
<div class="pull-left selection-tree-container">
<h4 class="selection-list-title">
<span data-lang="Available">Available</span>
</h4>
<ul class="selection-list selection-tree-list">
<li id="CS--/14" class="nodecollapsed item parent-node">
Country Section <span class="child-count"></span>
</li>
<li id="Sec1--/23" class="nodecollapsed item parent-node">
Section 1 <span class="child-count"></span>
</li>
<li id="Sec2--/24" class="nodecollapsed item parent-node">
Section 2 <span class="child-count"></span>
</li>
<li id="GOS--/40" class="nodecollapsed item parent-node">
Section <span class="child-count"></span>
</li>
<li id="RS--/43" class="nodecollapsed item parent-node">
Regional Section <span class="child-count"></span>
</li>
This was a tough one. The problem is that you have a number of similar options all containing "Section" in some flavor and it's hard to distinguish them apart. What adds to this is that each one contains a non-breaking space which means that normalize-space() won't work (directly) either.
But... I found that the below XPath will work.
//li[normalize-space()='Section\u00a0']
normalize-space() removes whitespace (but not &nbsp) so you have to add it in there with \u00a0. I've tested this locally and it's working.
Try following xpath see if it helps.
//li[starts-with(#id,'GOS')][#class='nodecollapsed item parent-node xh-highlight']
OR
//li[#class='nodecollapsed item parent-node xh-highlight'][#xpath='1']
you can try the below XPath to find a section node
Try if it helps
//li[#id='GOS--/40'][contains(text(),'Section')]
Let me throw my hat into the ring....
//li[(normalize-space(text()) = 'Section')]
Here is the method that will fetch the text from the parent only. (exclude the text in the child(ren))
In Python:
def get_pure_element_text(element):
return driver.execute_script(
"""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element).strip()
This method will iterate all the firstChild (direct children) and extract all text from all the text nodes.
In this context If you want to retrieve the text of li which have the id GOS--/40 then use the method as below.
element = driver.find_element_by_xpath("//li[#id='GOS--/40']")
print(get_pure_element_text(element))
Sharing this method, at least might help the others (if not the OP in this context).
C# implementation:(not tested)
string get_pure_text(IWebDriver driver, IWebElement element){
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
return (string)js.ExecuteScript(""""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element");
Usage:
string output = get_pure_text(driver,element)

BootstrapV4 - Can't push a span to the right

In the following code (react isn't important here), I'm using the bootstrapV4 class "text-sm-right". It works perfectly for my <button>, but it doesn't for my post.categories <span> which remain on the left. I can't make it work and I don't explain it. Is someone having an explanation ?
renderPosts() {
return this.props.posts.map((post) => {
return (
<li className="list-group-item" key={post.id}>
<span className="text-sm-right">{post.categories}</span>
<strong>{post.title}</strong>
</li>
);
});
}
render() {
return (
<div>
<div className="text-sm-right post-new-button">
<Link to="/posts/new" className="btn btn-primary">Add post</Link>
</div>
<h3>Posts</h3>
<ul className="list-group">
{this.renderPosts()}
</ul>
</div>
);
}
Here is a screenshot of the rendered site, button positioned as wanted but categories remaining on the left...
.list-group-item has display: flex by default. This means that all you have to do is to add justify-content-between class to your <li> and move your declaration one line bottom.
Your renderPosts method should look as follow:
renderPosts() {
return this.props.posts.map((post) => {
return (
<li className="list-group-item justify-content-between" key={post.id}>
<strong>{post.title}</strong>
<span>{post.categories}</span>
</li>
);
});
}
You can find an example of this approach on bootstrap documentation