Testing CI4 response with selected dropdown - codeigniter

I have been playing today (with CI 4.1.9) automated testing. The response includes an HTML selected option such as this:
<option value="hello" selected="selected">world</option>
I have the following code which is testing this:
$result = $this->withSession($this->mysession)->get('my/url');
print'<pre>';print_r($result->getBody());print'</pre>';exit;
print'<pre>';print_r($result);print'</pre>';exit;
$result->assertSee('"selected">');
$result->assertDontSee('selected>');
It may be that my version is out of date, but I am seeing something very strange. Although the output of the 2nd print_r clearly shows the content as expected, the results of getBody() show <option value="hello" selected>world</option>. As a result, when I assertSee() for the correct text, it fails, but calling the incorrect format finds the result.
Maybe this is a bug but wanted to see if I'm missing anything.

Related

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

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.

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?

ember-changeset-validations not working as expected with a boolean

I have an Ember object that has as attribute a boolean field that I want to validate with ember-changeset-validations.
It is the typical "Agree to terms" checkbox.
Here is the hbs code:
{{one-way-checkbox changeset.agree_terms
class="form-control"
update=(action (mut changeset.agree_terms))}}
{{#each changeset.error.agree_terms.validation as |error|}}
<span class="text-danger help-block m-l-3">{{t (concat 'bookings.error.' error)}}</span>
{{/each}}
I have a validations file, where the particular validation for this member of changeset is:
agree_terms: validateFormat({
regex: /^(true)$/,
message: 'You need to agree on Terms!'
})
Thing is, for some reason this never validates to TRUE correctly, I always get the error message...any ideas what I'm doing wrong here?
This is a bit tricky; but I figured that out. ember-change-set-validations do make use of ember-validators underneath. Since; you are using validateFormat; the following code is being run at the end. If you look at the link I have provided; there is a check !canInvoke(value, 'match') causes you the problem. Since the checked value of a checkbox is a boolean and you cannot invoke match on booleans you always end up having an invalid validation.
What can you do? Well; I am not an expert at ember-change-set-validations and ember-validators but it is pretty easy to write a custom validator. This is what I did in the following twiddle. It seems to be working pretty fine.
What I understood is; it is not a good idea to use boolean values with format type validator (it clearly does not work); I only wished it was documented. I hope this helps you.

object is disabled {:element=>#<Selenium::WebDriver::Element:

We are using a drop-down to select 'Yes' 'No' values from the list. This method is being used across multiple pages. When I run my script it fails saying "Object is disabled" even though it is running fine for first drop down of the page.
Below is the code we are using
def select_value(value, field)
get_screen_element(field).options.map(&:text).include? value }
Watir::Wait.until{get_screen_element(field).select value}
end
Sometimes the script runs fine without errors sometimes it dosen't, its not consistent.

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()
});

Resources