Cypress-Xpath: Correct Xpath syntax for id? It can't find it - xpath

Tried cy.get(#Username) , doesn't work- cypress says it can't find it. could it be related to uppercase letter?
Installed Xpath plugin and used this
cy.xpath('//input[#id="Username"]') but it didn't work.
<input type="email" class="form-control" autocomplete="off" data-gd="identity-login-local-form-username" autofocus="" data-val="true" data-val-required="The Username field is required." id="Username" name="Username" value="">
Please before giving -1 , please explain what I need to improve. Thanks!

After downloading xpath plugin, did you add require('cypress-xpath') in your project's cypress/support/index.js file?
According to your example, code below should find the Username
cy.xpath('//input[#id="Username"]')
cy.get('#Username')

The capital letter may be causing the problem. Usually ids have a small letter.
Try using the data-gd attribute instead.
cy.get('[data-gy="identity-login-local-form-username"]')
If that does not work, you may have some shadow DOM before the <input> that blocks the search, in which case you can search inside the shadow like this
it('tests the input', {includeShadowDom:true}, () => {
cy.get('[data-gy="identity-login-local-form-username"]')
})
I tested with a capital letter cy.get('#Username') and cy.xpath('//input[#id="Username"]') - both worked for me, so likely there is shadow DOM or an <iframe> on your page.

Is it possible that the page has a default namespace? If the page is served as XHTML, it may have a default XML namespace, in which case the input's name is not simply input.
If that is the problem, then you could declare the http://www.w3.org/1999/xhtml namespace and associate it with a prefix, e.g. xhtml (I don't know cypress so not sure how you'd do that), and then query for //xhtml:input[#id="Username"]. An alternative is to query for an element whose local name is input in any namespace at all, e.g. //*[local-name()='input'][#id="Username"]

In case your username field is under a shadow DOM which means other fields will also be under the shadow Dom, it would be advisable to write includeShadowDom: true in your cypress config file to avoid repetition(cypress.json if cypress version < 10; cypress.config.js if cypress version > 10), then directly use the command:
cy.get('#Username').type('username-text')
In case your username field is under an iframe, you can get the cypress iframe plugin
To install npm install -D cypress-iframe
Go to cypress/support/commands.js file, add the following:
import 'cypress-iframe';
// or
require('cypress-iframe');
In your test write:
cy.iframe('#my-frame')
.find('#Username')
.should('be.visible')
.type('username-text')

I can also confirm the way you are selecting the Username input element is correct.
If you suspect shadow DOM is interfering with your test, the best way to debug IMO is to
inspect your DOM around the <input>
look for a parent element that has #shadow-root below it (in bold)
change the test to include this parent
add the .shadow() command after the parent to break through the barrier
cy.get('parent-with-shadow-root')
.shadow()
.find('#Username')
This debugs and confirms your issue. Everything else, e.g setting global config etc can be done after you know what you have to deal with.

After I tried suggestions and people's confirmation that my xpath was correct, I shifted my focus on the error I got while Cypress was trying to find the element. The error I got was uncaught exception.https://stackoverflow.com/questions/53845493/cypress-uncaught-assertion-error-despite-cy-onuncaughtexception

This error occurs when a module fails to load due to some exception. The error message above should provide additional context. A common reason why the module fails to load is that you've forgotten to include the file with the defined module or that the file couldn't be loaded.
Using ngRoute In AngularJS 1.2.0 and later, ngRoute has been moved to its own module. If you are getting this error after upgrading to 1.2.x or later, be sure that you've installed ngRoute.

Related

Problem getting Cypress to play nice with StencilJS components

I am experiencing some flaky behavior with Cypress tests against my Angular application: they work fine when targeting my local box but when setting CYPRESS_BASE_URL to a remote machine running the same code, then some of the tests fail.
I think I have narrowed this down to the interaction of StencilJS components. Consider: I have one form that asks for username, password, etc., using regular <input> elements, to wit:
<input formControlName="username" type="text">
...and so forth. The tests work reliably with those, meaning these statements correctly fill in the fields:
cy.get('[formControlName=fullname]').type(name)
cy.get('[formControlName=username]').type(username)
cy.get('[formControlName=password]').type(passwrod)
I have another form that uses a StencilJS component which has an embedded <input>, so the elements look like this:
<my-input ngDefaultControl formControlName="newPassword" type="password"></my-input>
<my-input ngDefaultControl formControlName="confirmPassword" type="password"></my-input>
My code then attempts to fill in the two fields:
cy.get('[formControlName=newPassword]').find('input').type(updated_password).blur()
cy.get('[formControlName=confirmPassword]').find('input').type(updated_password).blur()
But here the test fails: what it actually does is fill in the first password, advance to the second field and fill in the second--but then the first field mysteriously becomes blank!
The Stencil component is a simple wrapper around an <input>:
return (
<input type={ this.type }
value={ this.value }
placeholder={ this.placeholder }
onChange={ this.handleChange.bind(this) }></input>
);
I have tried with and without .blur().
I have tried with and without chaining with .then().
But the above test always fails with a remote target and always succeeds with a local target machine.
Any other suggestions on how to make this work reliably?

How do I extract a value from page element, to use in a later step in ruby

I'm using ruby, selenium webdriver within cucumber to run my tests.
I have the following code;
<input class="input" value="qa-regression-test-1" id="furl" name="furl" type="text" aria-invalid="false">
And I need to extract the 'value' part of this code, and then use this value (qa-regression-test-1 in this particular case) to navigate the webdriver to a new URL.
i.e. http://www.xxxxx.co.uk/qa-regression-test-1
However, this 'value' will be different for each test, so this is why I need to get this 'value', and then use it for the final part of the subsequent URL rather than just use this current value.
Hope this is clear, but can provide more info if required.
Any help on this would be greatly appreciated.
Many thanks.
You are almost there - just puts friendlyurl instead of puts friendlyurl.text
:)
Basically you're good to go - just slam that String together with the host part of your url

Loading non valid xml in Calabash / xproc

I am trying to create a routine for validating xhtml documents. I use xproc which I run in Calabash. In is an xhtml document. This document may not be valid.
For testing I edit an xhtml document. I simply delete a and introduce an error. This is the error I hope to detect when I validate the document.
In order to validate I use , I supply a schema, and I output the result of the validation in a new file.
But if the input file is not valid in the first place xproc/Calabash stops. The error message is basically an error message from Saxon pointing out that the is missing. But I wanted the validation output in my output file. How do I do that?
<p:input port="source" primary="true"/>
<p:load name="xml-doc" href="'input.xhtml'"/>
<p:validate-with-xml-schema name="validate">
<p:input port="source">
<p:pipe port="result" step="xml-doc"/>
</p:input>
<p:with-option name="assert-valid" select="'false'"/>
<p:with-option name="mode" select="'lax'"/>
<p:input port="schema">
<p:document href="xhtml-schema.xsd"/>
</p:input>
</p:validate-with-xml-schema>
<p:store name="valid-store">
<p:input port="source">
<p:pipe port="result" step="validate"/>
</p:input>
<p:with-option name="href" select="'output.xml'"/>
</p:store>
From your question it's not clear what exactly is Saxon complaining about, but I assume that it cannot find the input XHTML file. You wrap the file name in single quotes in p:load/#href, which is not correct. When you use the attribute-based shortcut form for options, the value of the attribute is taken as-is and is not interpreted as an XPath expression (which is the case when you use the long p:with-option form).

Inserting a translation into a placeholder with Emblem.js

I'm trying to write a login form with ember.js/emblem.js. Everything works, unless I try I18ning the placeholders like so:
Em.TextField valueBinding="view.username" placeholder="#{t 'users.attributes.username}"
Em.TextField valueBinding="view.password" placeholder="#{t 'users.attributes.password'}" type="password"
I get the same response if I try:
= input value=view.username placeholder="#{t 'users.attributes.username}"
= input value=view.password placeholder="#{t 'users.attributes.password'}" type="password"
In both cases, I get this error message:
Pre compilation failed for: form
. . . .
Compiler said: Error: Emblem syntax error, line 2: Expected BeginStatement or DEDENT but "\uEFEF" found. Em.TextField valueBinding="view.username" placeholder="#{t 'users.attributes.username}"
I assume this is happening because I'm trying to compile something from within a statement that's already being compiled. In evidence of this, I don't get the runtime error if I change the code to:
input value=view.username placeholder="#{t 'users.attributes.username}"
input value=view.password placeholder="#{t 'users.attributes.password'}" type="password"
But the downside is that the value bindings no longer work, which still leaves the form nonoperational. Is there another way of approaching this problem that I haven't considered?
As Alexander pointed out, this is a limitation of Ember and Handlebars. The workaround that I've been using is to make the placeholder refer to a controller property which then returns the translated string. For example:
{{input
type="text"
value=controller.filterText
placeholder=controller.filterPlaceholder }}
And then in the controller:
filterPlaceholder: function () {
return i18n.t('players.filter');
}.property('model.name'),
This is beyond the scope of what Emblem can do because it's an inherent limitation of Ember+Handlebars. What you're trying to do is use the input helper and, inside the helper invocation, use another helper t to get the value for the placeholder option. You can't (presently) do this in Ember, so Emblem's not going to be able to do that for you.
edit: you should try the Ember i18n library. I haven't used it yet, but it seems like what you'll want to do is to mix in the TranslateableAttributes mixin into Ember.View, like:
Ember.View.reopen(Em.I18n.TranslateableAttributes)
and then in your emblem template you can do something like
= input placeholderTranslation="button.add_user.title"
I noticed a typo in the first placeholder="#{t 'users.attributes.username}". It's missing the closing single quote.
The Emblem syntax error, line 2: Expected BeginStatement or DEDENT but "\uEFEF" found. can be misleading. I've found that the error is somewhere else entirely to what was being reported. For instance, linkTo without a | for plain text reports a similar error.
You should use the views to format things and drop them into the template. Controllers are not meant to know what happens at the template.
You would also want that to be a property, so i18n will work just once and then you can use the cache version.
Templete:
{{input value=view.username placeholder=view.usernamePlaceholder}}
{{input value=view.password placeholder=view.passwordPlaceholder type="password"}}
View:
export default Ember.View.extend({
usernamePlaceholder: function() {
return Ember.I18n.t('users.attributes.username');
}.property(),
passwordPlaceholder: function() {
return Ember.I18n.t('users.attributes.password');
}.property()
});

Selenium WebDriver issue with By.cssSelector

I have an element whose html is like :
<div class="gwt-Label textNoStyle textNoWrap titlePanelGrayDiagonal-Text">Announcements</div>
I want to check the presence of this element. So I am doing something like :
WebDriver driver = new FirefoxDriver(profile);
driver.findElement(By.cssSelector(".titlePanelGrayDiagonal-Text"));
But its not able to evaluate the CSSSelector.
Even I tried like :
By.cssSelector("gwt-Label.textNoStyle.textNoWrap.titlePanelGrayDiagonal-Text")
tried with this as well :
By.cssSelector("div.textNoWrap.titlePanelGrayDiagonal-Text")
Note : titlePanelGrayDiagonal-Text class is used by only this element in the whole page. So its unique.
Contains pseudo selector I can not use.
I want to identify only with css class.
Versions: Selenium 2.9 WebDriver
Firefox 5.0
When using Webdriver you want to use W3C standard css selectors not sizzle selectors like you may be used to using in jquery. In your example you would want to use:
driver.findElement(By.cssSelector("div[class='titlePanelGrayDiagonal-Text']"));
From reading over your post what you should do since that class is unique is just do a FindElement(By.ClassName("titlePanelGrayDiagonal-Text"));
Also the CssSelector doesn't handle the contains keyword it was something that the w3 talked about but never added.
I haven't used css selectors, but this is the xpath selector I would use:
"xpath=//div[#class='gwt-Label textNoStyle textNoWrap titlePanelGrayDiagonal-Text']"
The css selector should then probably be something like
"css=div[class='gwt-Label textNoStyle textNoWrap titlePanelGrayDiagonal-Text']"
Source: http://release.seleniumhq.org/selenium-remote-control/0.9.2/doc/dotnet/Selenium.html
Did you ever tried following code,
By.cssSelector("div#gwt-Label.textNoStyle.textNoWrap.titlePanelGrayDiagonal-Text");
I believe using a wildcard in CSS would be more helpful. Something as follows
driver.findElement(By.cssSelector("div[class$='titlePanelGrayDiagonal-Text']");
This will look into the class attribute and see what that attribute is ending with. Since your class attribute is ending with "titlePanelGrayDiagonal-Text" string, the added '$' in the css statement will find the element and then you can perform whatever action you're trying to perform.

Resources