I am writing e-2-e tests for our frontend using Cypress.
When I try to target an element, I am using .button-module_btnLabel__30kQb, but as I understand this makes my test brittle as the classname hash may change.
However, when I try to add a selector, Cypress can't find it. An example below:
import { Button } from '...ui'
<Button.Primary
data-cy="submit"
onClick={startLogin}
>
Log In
</Button.Primary>
cy.get('data-cy="submit"')
.should('be.visible')
.should('contain.text','Log In')
.click()
AssertionError: Timed out retrying after 4000ms: Expected to find element: `[data-cy=submit]`, but never found it.
If you are selecting on an attribute, you need enclosing square brackets.
cy.get('[data-cy="submit"]')
Note React does not pass on all attributes, but data prefix should be ok.
Related
I created some end-2-end with cypress. Locally tests work fine, but when these tests run on CircleCI it shows errors from cypress
CypressError: Timed out retrying: You attempted to make a chai-jQuery assertion on an object that is neither a DOM object or a jQuery object.
The chai-jQuery assertion you used was:
> css
The invalid subject you asserted on was:
> 250px
To use chai-jQuery assertions your subject must be valid.
This can sometimes happen if a previous assertion changed the subject.
And this is the code responsible for this error.
cy.get('.vce-single-image')
.should('have.css', 'width')
.and('have.css', 'height')
The same error for this one.
cy.window()
.then((win) => {
cy.get('.vce-row')
.should('have.css', 'width')
.and('have.css', 'height')
})
I tried to add first() after get() but it didn't help. I tried it locally on different devices and there're no problems with that.
For CircleCi docker image I use own image, which is based on circleci/php:7.3.2-apache. Here is the link https://github.com/wpbakery/ci-wordpress/blob/master/circleci/Dockerfile.
Normally, cy.should() yields the value that it was chained off of. However, some assertions, including have.css, change the subject yielded by cy.should(). (here is the relevant chai-jquery documentation)
So, this should work:
cy.get('.vce-single-image').should('have.css', 'width', '250px')
cy.get('.vce-single-image').should('have.css', 'height', '250px')
Relevant reading: How do I know which assertions change the subject and which keep it the same?
I have a fillInput() function that takes a selector and a value as parameters, then:
clear the the input via cy.get(selector).clear()
then fills the input value via cy.get(selector).type(value)
As far as I know, this is really some sort of anti-pattern and a cypress command should be the way to go.
So, reading about child commands, I came out with this command that should do the same as my fillInput() utility function:
Cypress.Commands.add('fillInput', {prevSubject: 'element'}, (subject, value) => {
subject.clear();
subject.type(value);
});
However, when I try this in a spec via:
cy.get('#my-selector').fillInput('my-value');
I get this error in the cypress browser console:
TypeError: subject.clear is not a function
In the docs, cy.get() is said to yield a DOM Element, and the {prevSubject: 'element'} should make subject to be the same type (as far as I understand this).
However, subject seems to be a different type and methods that work on elements like type() or ' clear()or ' should() does not work on child command subjects.
How can I get the subject of my child command to act as a Dom Element?
While investigating to post the question, I came up with a simple solution to this problem. The subject is an object which has a selector, so you can use that selector with cy.get(subject.selector) to get the Dom Element:
Cypress.Commands.add('fillInput', {prevSubject: 'element'}, (subject, value) => {
cy.get(subject.selector).clear().type(value);
});
I think this is not a lot of clear and more people may have this issue, so I leave my solution here.
Try to use
cy.wrap(subject)
For me that was the trick.
I have a window-box with two buttons 'add' and 'close'. I need to test below scenario:
When clicked on 'add' button it throws error and the window remains open. I need to click on 'close' button to proceed.
I used below code:
if(element(by.xpath("xpath_of_error_box")).isEnabled())
{
element(by.xpath("xpath_of_close_button")).click();
}
But it throws below error:
No element found using locator: By(xpath, xpath_of_error_box)
Is there any way to handle this?
According to the error, it seems that your xpath locator didn't match any element. And according to the additional clarification in the question you could try:
element(by.xpath("xpath_of_error_box")).isDisplayed().then(isDisplayed => {
if (isDisplayed) {
// do what you need when it is visible
} else {
// if not then proceed
}
});
As it was pointed out, isEnabled might not be the proper method you should use in this case. If it seems that the element you try to find is always present in the dom, you might better try to check for its visibility using isDisplay instead.
An advice. It's not a good idea to use xpath locators in your tests, because this ties them to the html DOM structire of the web page you are observing. As we know, the UI happens to change often, which would make your tests to brake often as well. Although this is of cource a personal preference, it is such until you end up with tons of brocken tests after a single small change in the html.
If you need to check if an element is present you can use the following code:
if (element(by.xpath("yourXpath")).isPresent())
But your problem is not on your if code, your problem is that the xpath your are searching doesn't exist.
isEnabled() and isPresent() returns promise (not boolean) and have to be resolved.
isEnabled() could be only used for <button>.
You can use XPath all the time, don't listen to anyone.
PS. Of course it would be glad to see your HTML to check the correctness of your XPath.
I have a module which contains a switch statement producing content, and a variety of on events waiting dependent on what content is inserted into the DOM and then whichever trigger is activated.
I'm finding that on event handlers using dom.byId('foo'):
on(dom.byId('foo'), touch.press, function(e){
produce the error:
Uncaught TypeError: cannot read property 'on' of null.
I can kind of understand this - if the node foo doesn't yet exist because a different switch condition has been satisfied, but i've managed to skirt this by using a css class instead:
on(query('.foo'), touch.press, function(e){
But this has the same chance of existence as the id!
I'm relatively new to Dojo, and have had "fun" getting to grips with it, and i'm interested to know why this is happening, but also if it's a Big Red Flag that i'm doing something wrong!
It's hard to say without the full code but if you want to use query you need to use this way :
require(["dojo/query"], function(query){
query(".foo").on("click", clickHandler);
});
I don't know the context of your project but if it's for mobile you maybe look at "dojo/gesture/tap" like in this exemple in the doc :
define(["dojo/on", "dojo/gesture/tap", function(listen, tap){
on(button, tap, tapHandler);
...
I'm using WebdriverIO and selenium-standalone to write automated tests that will verify that various parts of our user interface are working.
I need to verify that an element is not present on the page. For example, our system allows staff to track various types of resources that we are referring clients to. If a staff member accidentally adds the wrong resource, they can delete it, and I want to verify that the resource was actually deleted and is not present on the page.
WebdriverIO has an .isExisting() property, but no way to check if something is not existing (or not visible/present). I could also use Chai assertions to figure this out, but haven't delved into that world yet.
Here's a snippet of my code:
it('I can delete a resource from a need', function() {
return driver
.moveToObject('span.ccx-tasklist-task') // Hover mouse over resource
.click('div.referral-controls a.btn.dropdown-standalone') // Click Resource drop-down
.click('div.referral-controls.ccx-dropdown-menu-selected li > a') // Delete Resource
.pause(2000);
// Need to Verify that resource was deleted here
Any advice? Let me know if you need more information.
You can waitForExist with the reverse option set to true.
.waitForExist( '[id$=OpenNeedsPanel] div.commodities', 500, true )
I was able to verify that an element didn't exist on the page like this:
.isExisting('[id$=OpenNeedsPanel] div.commodities').should.eventually.equal(false);
you can simply use the below mentioned line of code
int temp=driver.findElements(By.xpath("your x-path expression")).size();
you can even replace your xpath locator with your other locators as well like id,class,link etc.
Now, if the value of temp>0, it means , your element exists
You can refer https://webdriver.io/docs/api/element/waitForExist.html
Wait for an element for the provided amount of milliseconds to be present within the DOM. Returns true if the selector matches at least one element that exists in the DOM, otherwise throws an error. If the reverse flag is true, the command will instead return true if the selector does not match any elements.
resource.waitForExist(1000, true);
where 1000 is the timeout in ms.