Suppose I have the following page:
<div>
<div class="item">
<p data-testid=title>Item One Title</p>
<p data-testid=subtitle>Item One Subtitle</p>
</div>
<div class="item">
<p data-testid=title>Item Two Title</p>
<p data-testid=subtitle>Item Two Subtitle</p>
</div>
</div>
I would like to test that Item One Title and Item One Subtitle are present within the same parent div.item. What would be the best way to do this in Cypress?
What I tried so far:
Test #1:
cy.get('[data-testid=title]').should('contain.text', 'Item One Title');
cy.get('[data-testid=subtitle]').should('contain.text', 'Item One Subtitle');
These tests will pass, but does not check that Item One Title and Item One Subtitle are within the same parent div.
Test #2:
cy.get('[data-testid=title]').should('contain.text', 'Item One Title').then(($foo) => {
cy.wrap($foo).next().should('contain.text', 'Item One Subtitle');
});
Seems to be the same as Test #1, does not check that Item One Title and Item One Subtitle are within the same parent div.
The .parent() selector looks suitable
cy.contains('[data-testid=title]', 'Item One Title')
.parent()
.should('contain', 'Item One Subtitle');
or use the parent directly
cy.contains('div.item', 'Item One Title')
.should('contain', 'Item One Subtitle');
You can use siblings
cy.contains('[data-testid=title]', 'Item One Title')
.siblings()
.should('have.attr', 'data-testid', 'subtitle')
.and('contain.text', 'Item One Subtitle')
You could add a data-testid attr to the item div element are looking to verify or do the following.
// swap div with [data-testid=item] if you add it to item div
cy.contains('div', 'Item One Title')
.within( () => {
// all queries will only be subject to the item div with 'Item One Title' text
cy.get('[data-testid=title]').should('contain.text', 'Item One Title');
cy.get('[data-testid=subtitle]').should('contain.text', 'Item One Subtitle');
})
Related
Faced with a problem, I want to find the card I need in the list of cards guided by the text, and click in this card on the button.
The idea is that would not go into details of nesting.
Enclosing a screenshot of how it looks like:
html structure:
<div class="card">
<span>name 1</span>
<button data-test="more-menu"><svg /></button>
</div>
<div class="card">
<span>name 2</span>
<button data-test="more-menu"><svg /></button>
</div>
<span>name 3</span>
<button data-test="more-menu"><svg /></button>
</div>
Would like something like this:
cy.get('data-test=badge').then(($) => {
cy.wrap($).contains(`${name} ${lastname}`).then(() => {
cy.wrap($).find('[data-test=moreMenu]')
})
})
You can use the .contains for this. It gets the DOM element containing the text. And then use next() which gets the immediate sibling of the current element, something like this:
cy.contains('span', 'Name 1').next().click()
In case you have a nested structure inside your card class, you can use first parent() which will go to the card parent element and then use within to scope the next commands inside the same card class, something like this:
cy.contains('span', 'Name 1').parent('.card').within(() => {
cy.get('[data-test="more-menu"]').click()
})
Now We have used parent() once since the .card is available one level up from span. In case you have more levels you have to add more parent().
Continuing from the comment:
cy.get('#card').contains(your_name).within(($el) => {
cy.wrap($el).find('#menu').click()
})
Adding Timur Zakirov's answer suited for their case:
cy.contains('Name 1')
.parents('[data-test=badge]')
.within(() => {
cy.get('[data-test=badgeMoreMenu]').click()
})
I want to add an item in cart with a matching text like 'cashews'. I tried below code but .click() function is giving error as "bind and event handler to the click javascript event"
cy.get('.products').find('.product').each(($e1, index, $list) => {
const textveg = $e1.find('h4.product-name').text() {
if (textveg.includes('Cashews')) {
$e1.find('.button').click();
}
}
})
can someone suggest what can be the possible reason that .click() method is not identified by cypress. I am using cypress version 7
How you do this depends on the structure of the HTML.
It looks like you may have this sort of hierarchy
<div class="products">
<div class="product">
<h4 class="product-name">Almonds</h4>
<button>Add to cart</button>
</div>
<div class="product">
<h4 class="product-name">Cashews</h4>
<button>Add to cart</button>
</div>
</div>
Take the product section containing the text you want, and within that find the products <button>.
Your test might be
cy.contains('.product', 'Cashews') // pick the <div class="product"> with required text
.find('button') // inside the product, find it's button
.click()
You can use .filter() to find your element and click it:
cy.get('h4.product-name').filter(':contains("Cashews")').click()
How do I select one item of a list and apply the conditions to only that item?
I have this html:
<ion-list v-if="mangelzuordnungs.length > 0">
<ion-item>
<h2>Item A</h2>
<button
data-cy="photo-add-button"
shape="round"
>
<span data-cy="photo-add-button-text"> Hinzufügen </span>
</button>
</ion-item>
<ion-item>
<h2>Item B</h2>
</ion-item>
</ion-list>
And this test:
it('Ensures when Mangelzustand does contains photos, the "Hinzufügen" Button Text does not exist', () => {
cy.get("ion-item")
.eq(1)
.get("[data-cy=photo-add-button")
.get("[data-cy=photo-add-button-text")
.should("not.contain", "Hinzufügen");
});
I would expect that the test succeeds because it fails arguing that photo-add-button-text exists and highlights the element of the first list item.
What am I missing?
If you use .get() after .eq(1) you are searching from cy.root(), which is the the whole DOM.
Try .find() instead.
cy.get("ion-item")
.eq(1)
.find("[data-cy=photo-add-button")
.find("[data-cy=photo-add-button-text")
.should("not.contain", "Hinzufügen");
Your second item in the list doesn't contain [data-cy="photo-add-button-text] and [data-cy=photo-add-button-text], hence when you are trying to use get(), the test is failing. Instead you can directly assert:
cy.get("ion-item").eq(1).should("not.contain", "Hinzufügen")
<ul class="ItemList">
<li class="Item" data-id="2"><label><input type="checkbox" value="on"><span>bb</span><button type="button">X</button></label></li>
<li class="Item" data-id="3"><label><input type="checkbox" value="on"><span>aaa</span><button type="button">X</button></label></li>
</ul>
from the above list I need to select second item and select the check box.
You can do this:
cy.contains('aaa')
.parent()
.find('input')
.check()
This will search for the text of the second checkbox, then gets the parent and searches for an 'input' within that parent. And check it after all.
If you want to click the 'X' per element it's just as easy:
cy.contains('aaa')
.parent()
.find('button')
.click()
In an acceptance test I'm trying to click the .fa-trash-o icon for a given address. To simplify things, I've been trying to select the 2nd element on the page with the given class name.
I've tried several variations of the following with no luck.
$I->click(\Codeception\Util\Locator::find('a', ['class' => 'fa fa-trash-o']).'[2]');
$I->click('//a[contains(#class,"fa-trash-o")][2]');
Here's my template:
<div class="grid simple address-card">
<div class="grid-title no-border">
<h4>{{ $address->name }}</h4>
<div class="tools">
{!! Form::open(['url' => '/account/address/'.$address->id, 'method' => 'delete']) !!}
<a onclick="$(this).closest('form').submit();" class="fa fa-trash-o"></a>
{!! Form::close() !!}
</div>
</div>
<div class="grid-body no-border">
#include('partials.address')
</div>
</div>
How can I click that delete button?
You're tripping up on a common mistake related to the way the // operator is defined. The XPath expression
//a[contains(#class,"fa-trash-o")][2]
actually means
/descendant-or-self::node()/child::a[contains(#class,"fa-trash-o")][2]
The [2] applies to the child:: step rather than the descendant search, so it will select every a element that is the second fa-trash-o link under its respective parent. This finds nothing since there is only ever one such a within any given div. If you add parentheses:
(//a[contains(#class,"fa-trash-o")])[2]
then it will select the second fa-trash-o in the whole document - the [2] now applies to the whole result of the (...) expression rather than just the final step.