How to verify if an element is disabled using protrator - angularjs

I tried with below methods
1) using isEnabled api
expect(locator.isEnabled()).toEqual('false');
but it fails, as the API always returns true.
2) using disabled attribute
expect(locator.getAttribute('disabled')).toEqual('disabled');
but it fails, as the API returns null

The disabled attribute is of type boolean so will return true or false.
isEnabled schedules a command to query whether the DOM element represented by this instance is enabled, as dicted by the disabled attribute.
Therefore in your situation the following assertion should be used when using isEnabled:
expect(locator.isEnabled()).toBe(false);
getAttribute schedules a command to query for the value of the given attribute of the element. It will return the current value. getAttribute returns a string and as the disabled attribute is considered a boolean, it will return 'true' of type string or null.
When using getAttribute you should use the following assertion:
expect(locator.getAttribute('disabled')).toEqual('true');

As I learned, there are two ways to archive element disable in web development.
1) use disabled attribute, only work on Form Control element
Note: If a Form Control element defined disabled attribute, no matter the attribute value is 'disabled', 'true', 'false', '1234' or anything else. Selenium isEnabled() will always return true.
In such case you can use: expect(locator.isEnabled()).toEqual()
2) use CSS & JavaScript, work on any HTML element
Note: In most time, using CSS & JavaScript way to archive disable goal, developer will add class name like: 'invalid', 'disable', 'ng-invalid' in element attribute class.
In such case, you can use: expect(locator.getAttribute('class')).toContain('xxx')
You need to find out which way developer used on the element before you can decide how to write script to check it.

Related

Display [object HTMLDivElement] of google tag manager

I'm trying to setup event tracking of my website using GTM.
However, when trying to debug a tag which fires on a CSS selector, I cannot properly determine which value my clicks are tacking since I can only see:
[object HTMLDivElement]
in the preview mode, like this:
So clearly, the second condition is not met, but I'm not sure why since I can only see the name of the object.
Is there a way to display this? perhaps using another custom tag, or sending the value to the data layer?
Supposedly the element that is target of the click event do is not the one with id #navbar-brand. It seems to be a div inside your #navbar-brand element. If it's the case I'd suggest you to extend your firing condition to include all descendants of a #navbar-brand with selector #navbar-brand *

How to clear the md-autocomplete cache?

I'm using md-autocomplete to show results of an api query. Attribute md-items is iterating over a promise: item in getItems(searchText).
This is working well, and using the cache subsequent uses of the same search text return immediately with the same results.
But I need to be able to clear the cache at some points, when other search parameters change. How can I do this? By accessing the md-autocomplete controller perhaps? Although that seems non-standard and I'm not sure how.
As of version 1.0.5 of angular-material this isn't possible. I didn't find any acceptable workarounds, so I'm just disabling the cache with md-no-cache="true".
I've logged an issue for this on the angular-material project including a suggestion on how it could work.
It is definitely possible to reset the md-no-cache attribute programmatically anytime on your md-autocomplete directive.
If you have a boolean variable on your controller, let's say:
$scope.noCacheResults = false;
Then on your directive you can bind this variable to the md-no-cache attribute:
<md-autocomplete ...
md-no-cache="noCacheResults">
</md-autocomplete>
Like this, whenever your search parameters change you can set the $scope.noCacheResults to true or false depending whether you want to keep caching the query results or not.
Something that worked for me. Put an ng-if on your autocomplete. Then, in the code that changes the value of the other fields affecting this field, set that value to false, and then within a timeout, set it to true again. This will effectively remove the item from the DOM and put it back all nice and new with no cache.

Custom validator directive combined with other directive fires multiple times

I have a custom validation directive iban which checks if the value is a valid (Dutch) IBAN. That validator needs the value to be uppercased. I also have an uppercase directive which changes a value to uppercase. I want to combine both on one input element:
<input type="text" ng-model="iban" name="iban" capitalize="" iban="" />
I've created a jsfiddle demonstrating the situation.
I am struggling with the correct order of execution. If the user types in a value, I want capitalize to fire first, so the iban validator receives an uppercased value. If the model value is set from code, I also want to uppercase it first.
When the user types in a lowercase character, the uppercase directive calls ctrl.$setViewValue to set the view value. This triggers another run through the parsers. So both the uppercase directive and the iban directive are executed twice. The console log shows:
parsers.capitalize: nL12HHBA0429672071
uppercasing: nL12HHBA0429672071 => NL12HHBA0429672071, setting view value
parsers.capitalize: NL12HHBA0429672071
uppercasing: NL12HHBA0429672071 already uppercased
parsers.iban: NL12HHBA0429672071
setting validity to: true
returning NL12HHBA0429672071
parsers.iban: NL12HHBA0429672071
setting validity to: true
returning NL12HHBA0429672071
I would think it is not the intention to loop through your parsers multiple times.
Another problem is when I set the value from code to an invalid IBAN that's already uppercased (last link in my fiddle). In that case, the uppercase directive won't have to do anything. The iban directives formatter will set validity to false, and just return the value. If it's an lowercase invalid IBAN, the uppercase directive will call setViewValue, causing the IBAN directives parser code to execute which will return undefined. so that situation will change the model's value to undefined.
Am I making things too complicated? Should I try to create just an iban directive which will make sure that an uppercased value gets stored in the model when the user enters a valid lowercased iban value? Should I just keep the lowercased value in the model if it set from code? And maybe just use style="text-transform: uppercase" on the element to always show the value as if it is uppercased? A disadvantage would be that if the model is set to a valid but lowercased value, the form will show the uppercased value, which would be valid, while the model value is actually invalid.
There is definitely some complexity here. And in playing around with, there is some Angular weirdness as well (at least in my eyes - I'll get to that).
One complexity introduced here is that your capitalize $formatter actually changes the model value. I think this goes against the intent of the formatter function (transforming the value in model -> view direction). The View (and the formatter via its directive lives in the View) should only change the model when the change originates from the View. This keeps the model as the source of truth, and if it is set to an invalid value, then so be it - the validity should be reflected in the View, but it should not try to "fix" the model.
With this in mind, let's also use $validators for validation (rather than $parsers/$formatters pipeline):
.directive("iban", function(){
return {
require: "?ngModel",
link: function(scope, element, attrs, ngModel){
if (!ngModel) return;
ngModel.$validators.iban = function(modelValue, viewValue){
// after parser ran, validate the resulting modelValue
return validate(modelValue);
};
function validate(val){
return modelValue === "VALID IBAN"; // for the sake of example
}
}
};
});
$parsers (changing the model value) and $formatters (changing the view value) are called before $validators run.
Another complexity though (and what seems like an Angular's weirdness) is that your capitalize formatter can make the $viewValue to become valid for an invalid $modelValue. This on its own behaves correctly - it formats the $viewValue and keeps the validity as false (since the model is false). However, if you now change the model to the currently-set (and valid) $viewValue, then Angular decides to skip (src) the validators (since it finds no difference between new and old $viewValues), and so the validity never becomes valid despite both the model and view values being valid. Same, for valid-to-invalid case (the invalid low case value never invalidates the model).
This is, however, a rare case, and if coded properly should be avoided altogether. Why? Because the model should rarely (if ever) assume invalid values and should operate within the valid range.
ng-model ensures this (by default, unless you allowInvalid) by setting the model to undefined for invalid values.
So, for your question, decide whether low case IBAN is considered invalid in the ViewModel that you defined:
If low case is invalid, then never assign a low case value to your ViewModel iban property - plunker
If low case is valid, then do case-insensitive iban validator - plunker

Drupal 7 pass value from javascript to webform hidden field

I have a webform with some normal fields, but also some hidden fields which are set to Secure value (allows use of all tokens), so I am able to use tokens.
How do I pass values from JavaScript into those hidden fields so they are submitted with the form?
I tried using the %post[f1], %post[f2], and %post[f3] tokens, but I still don't know how to add those values with JavaScript.
You can use some basic jQuery for this.
$('input[name=INPUT_NAME]').val('NEW_VALUE');
To fully comply with Drupal theming, you probably want to wrap this up in a Drupal behavior:
(function ($) {
Drupal.behaviors.CUSTOMNAME = {
attach: function(context) {
$('input[name=INPUT_NAME]').val('NEW_VALUE');
}
}
})(jQuery);
...and of course change INPUT_NAME with the name attribute of the hidden input field and CUSTOMNAME with a descriptive camelcase name (e.g ChangeHiddenValuesForm).
As a final note: be sure to include this javascript file on the page of your form.
EDIT:
Sorry, I overlooked the Secure value reference.
Anyway, if you want the value to be secure then you shouldn't be altering it by Javascript as anyone can change it to whatever he or she likes through the DOM... That's why Webform implements the Secure value feature: the value does get submitted along with the form but simply won't be sent to the end user's browser and hereby disabling possible abuse. (For the record: Secure value uses the 'value' type from Drupal's Form API)
If you do want to change such a hidden value, you should opt for Hidden element (less secure, changeable via JavaScript) which already mentions its ability to be changed through Javascript and then use the Drupal behavior described above. Only if you do it like this it gets printed as a hidden input.
If you just want to add some JavaScript then use drupal_add_js(), for example in hook_preprocess_page() in a theme.
function mytheme_preprocess_page(&$vars, $hook) {
drupal_add_js(drupal_get_path('theme', 'mytheme') . '/mytheme.js');
$vars['scripts'] = drupal_get_js();
}

ng-show binding to string expression in angular

Is there a way to bind a ng-show expression to a string which contains the bind expression itself?
For Instance:
field={};
field.a=true;
field.showExpression='a == true';
<input ng-show="field.showExpression">
I´ve tried <input ng-show="{{field.showExpression}}"> as well, but none of them seems to work.
I want the bind to stay active, so that when the field.a object changes from true to false the expression gets evaluated again, hiding the input.
Just as background, i´m trying to implement dependant dropdowns, so my showExpressions should be of form field.showExpression='maindropdownValue!=null', and whenever the maindropdown which will be bound to the maindropdownValue gets selected the second one gets displayed.
I´m using angular 1.0.8
showExpression is evalued as a String not as a JS code. You have to use a function instead.
$scope.isTrue = function() {
return $scope.field.a; // or a more complex check
}
//
ng-show="isTrue()"
if you only have to check for a boolean, you can check var directly in the view:
ng-show="field.a"
If you really want to use eval, this is what you want:
ng-show="$parent.$eval(field.showExpression)"
link: http://docs.angularjs.org/guide/expression

Resources