page.click use value attribute as selector? - node.js

Problem:
The selector might randomly change due to various reasons, therefore, using the selector doesn't guarantee success all the time. Here is my code with the selector.
await page.click('body > div.api-container > div > div.clearAll > form > input[type="submit"]:nth-child(3)');
Is it possible to instead use page.click to click an element based on the "value" attribute? Here is the HTML:
<input name="submit" type="submit" value="Accept">
As you can see the value will always equal "Accept" and it would be easier to search the page and click the matching element.
Based on my research it looks like page.$x(expression) would work but I'm unsure how to write the expression.
Any help is greatly appreciated!

Is it possible to instead use page.click to click an element based on the "value" attribute?
It is, and you already have a variety of that in your initial selector, I'm talking about input[type=submit]. Instead of type there can be any other property of an element, including value:
await page.click('input[value="Accept"]');
await page.click('input[name="submit"]');
You could even omit type of element and search by its property only: '[value="Accept"]', but keep in mind that this approach can potentially find several results, and only the first of them will be clicked (quite possibly, not the one you had in mind), so do test selector in a real browser's console first.

Related

How to highlight p:tab's with inputfields that contain validation errors

A large form has several input fields so that they are grouped inside primefaces tabview tabs. Some of these fields are mandatory. When the user tries to submit, it gets the required message, but the user has to scroll through all the tabes to locate the fields missing fields. Is there any way to highlight tabs with missing values?
I would personally do this client-side.
I'd start with checking IF a validation failed in general or not like in the PrimeFaces solution in here:
How to find indication of a Validation error (required="true") while doing ajax command
In the javascript function that you can call, I'd find the surrounding form via jquery.
jQuery find parent form
And from that form down I'd find via jquery all inputs with a css class that indicate an error.
jquery find element by specific class when element has multiple classes
From each error I'd find the ancestor element that is the tab of the div (this might be where you need to be most creative, but it IS all plain jquery with wich many can help you if you make it a plain jquery question) and add a css class to this so you can style it 'in error'.
I'd find, again with jquery, the first tab that has errors and 'fake' a click on it.
find first occurrence of class in div
Simulate a click on 'a' element using javascript/jquery
You can do server-side validation. So if a validation error occurred you know the tab that the error is locate.
Then you can use the activetabindex of TabView and activate the tab that you want.
Then you can use Spotlite as #fuggerjak61 said to locate the missing/not valid fields.

How to select an option from a dropdown list using chromeless API?

I am using chromeless API (https://github.com/graphcool/chromeless)
How can I select an option from a dropdown list?
Specifically I want to select last option having value="other".
My HTML is:
You could achieve this with the evaluate() method which lets you evaluate any Javascript within the browser-context of any page you load:
await chromeless
.goto('http://yourwebsite.com/yourpage')
.evaluate(() => {
select = document.querySelector('select.decline-form-select')
select.value = 'other'
})
Or, specifically select whatever the last item is in the select list:
await chromeless
.goto('http://yourwebsite.com/yourpage')
.evaluate(() => {
document.querySelector('select.decline-form-select option:last-child').selected = true
})
It can be done without the evaluate() method, too, albeit in a somewhat convoluted way. Avoiding evaluate() is useful when it is unknown exactly which events have to be triggered upon change, for the web application to work.
await chromeless
.click('#the-select-element')
.type('First characters of description text of desired option', '#the-select-element')
.click('#the-select-element option[value="the-matching-value"]')
Or using the example posted in the question:
await chromeless
.click('select.decline-form-select')
.type('Oth', 'select.decline-form-select')
.click('select.decline-form-select option[value="other"]')
Selecting an option using native Chromeless commands involves first clicking the select element, then typing text to select the desired option, based on the visible text content of the option (the first few characters that unambiguously identify the option should be enough), and then clicking the desired option element. Since it is not possible to find the option element by text content using css selectors, the element must be selected by some other means – e.g. value or ordinal number.
Sending arrow key presses instead of typing characters to select the option might work, but I found in my testing that using the press() method was buggy. (A tab with Chrome settings would open randomly while executing tests that used press() to send either the return or the space key.)
All this said, I was unable to make tests run reliably with Chromeless. There seemed to be problems related to scrolling elements into view or not. While the webdriver-based systems http://webdriver.io, http://nightwatchjs.org and https://www.npmjs.com/package/selenium-webdriver are a bit more complicated to set up and code for, it might be worth the effort in order to get better reliability.

IE11 full screen on element

IE 11 has been out just one day as of this posting.
I cannot get an element to go full screen (div or document)
http://msdn.microsoft.com/en-us/library/ie/dn265028
msRequestFullscreen will error 'object does not support this...)
However, the above msdn example will work on passing a target - makeFullScreen(evt.target).
Can I get an div to go fullscreen as in following jquery code?:
var xxx = $('#container');
xxx.msRequestFullscreen();
Or better still: click a button then have a div or the entire document to go fullscreen?
As it stands now, when a click a button, it's the button that goes full screen.
I think this is actually a small misconception of JQuery. JQuery-ing an ID doesn't actually return the element found - it returns a "JQuery object" which allows many actions on that element (or, on a series of elements if you used a class selector)
I don't have IE11 available so I can't test for you, but try this. The [0] should retrieve the element itself.
var xxx = $('#container')[0]; xxx.msRequestFullscreen();
Your code:
var xxx = $('#container');
xxx.msRequestFullscreen();
This is wrong, because you're trying to call a DOM method on a jQuery object.
jQuery calls like $('#container') return jQuery objects. You can do lots of things with these objects, but one thing you can't do is call standard DOM methods. For that, you need an actual DOM object.
jQuery objects contain an array of matching DOM objects, which you can access via [0] for the first one, and [1], etc if there was more than one matching element. So you can do your call by changing your second line as follows:
xxx[0].msRequestFullscreen();
This will call the msRequestFullscreen() on the DOM element rather than the jQuery element, and that should work for you.
In this case, you don't even need jQuery at all, since you're not using any of the jQuery functionality. You could simply use document.getElementById('container') to get the DOM object in the first place rather than the jQuery method. Then you don't need the [0] syntax on the second line because you've already got the DOM object.
Finally, you might want to be careful of course, because this is an IE-specific method; the ms at the front of the name tells you that, which means that your code won't work in other browsers, even if they support the same feature. You need to do it in a cross-browser way. There are some tips on how to do this here: How to make the window full screen with Javascript (stretching all over the screen)

How can we use ONLY client side script for "hide/whens"?

I am working on a large, worldwide application, which includes access from areas of low bandwidth. As such, I want to use a minimum of SSJS or partial refreshes for all the complex hide/when calculations. Here is what I have so far for a simple "hide/when":
A Yes/No radio button, with CSJS to show a panel ("Yes") or hide the
panel ("No").
The panel has a formTable inside it, and the values are shown or hidden, as per #1.
In the XPage's onClientLoad, the following code is run:
// "getRadioValue" is a simple script to return the value of a radio button
var v_value = getRadioValue("#{id:radioButton}");
v_div = '#{javascript:getClientId("radioButtonPanel")}';
// show or hide div simply use dojo to change the display of the panel
if (v_value == 'Yes') {
showDiv(v_div);
} else {
hideDiv(v_div);
};
For a new document, the onClientLoad script will hide the "radioButtonPanel" successfully. Changing the radio button to "Yes" will show the radioButtonPanel, just as clicking "No" will hide it. It works great! :-)
Once the document is saved and reopened in read mode, though, the onClientLoad CSJS event should read the saved value in the document, and decide to show the panel or not. When the document is opened in edit mode, the onClientLoad fires, reads the radioButton value and successfully shows or hides the panel.
This is what I've tried so far, to get it to work in read mode:
In CSJS, using "#{javascript:currentDocument.getItemValueString('radioButton'}" to get the value,
Doing some calculations in the "rendered" or "visible" properties, but that's SSJS and, if hidden, prevents any of the "show/hideDiv" CSJS visibility style changes.
Adding an old fashioned "div" to compute the style (which is what I used to do before XPages), but since I can't do pass-thru html any more, I can't seem to get a CSJS calculation for the style. Ideally, I can do something like this:
<div id="radioButtonPanel" style="<ComputedValue>">
Where the ComputedValue would read the back end value of the document, and decide to add nothing or "display:none".
Note that I don't want to use viewScopes, since this long form would need many of them for all the other hide/when's.
Is there any way to make this 100% CSJS? I feel like I'm very close, but I wonder if there's something I'm just missing in this whole process.
First, rather than computing style, I'd recommend computing the CSS class instead -- just define a class called hidden that applies the display:none; rule. Then toggling visibility becomes as simple as a call to dojo.addClass or dojo.removeClass.
Second, I see that you're using the #{id:component} syntax to get the client ID of the radio button but using SSJS to get the client ID of the panel. Use the id: syntax for both; this is still just a server-side optimization, but if there are many instances of these calculations, it adds up. Similarly, replace #{javascript:currentDocument.getItemValueString('radioButton'} with #{currentDocument.radioButton}. Both will return the same value, but the latter will be faster.
Finally, any attribute of a pass-thru tag (any component with no namespace, like xp: or xc:) can still be computed, but you'll need to populate the expression by hand, since the editor doesn't know which attributes for valid for these tags, and therefore doesn't provide a graphical expression editor. So if the ideal way to evaluate the initial display is by wrapping the content in a div, the result might look something like this:
<div class="#{javascript:return (currentDocument.getValue('radioButton') == 'Yes' ? 'visible' : 'hidden');}">
<xp:panel>
...
</xp:panel>
</div>

XPages disableOutput tag issue

Has anyone experienced an issue with disableOutputTag property where if you disable output tag for a computed field control inside a repeat control and have ssjs computed content inside that tag, it won't compute the content? Is disableOutputtag property only meant to work with static content inside a repeat control or is it a bug?
I don't know whether its a bug or not, but you can emulate the behavior of disableOutputTag by removing the ID attribute from and setting the disableTheme attribute to true. Maybe this helps you in short term.
EDIT: You can refer here for more information.
Not only does this happen when placing the xp:Text control inside a repeat but in also when you create a new XPage, add a xp:text onto it and define its value like:
<xp:text value="This is a test" disableOutputTag="true"/>
In the above example the xp:text will disappear. This is not what you would have expected. I would expect that only the value would be visible on the rendered page. But I think I can explain why this happens. Since there are no tags defined (disableoutputtag) somewhere in the rendered of this component it states that it should not generate anything. Because it can not bind its id to 'nothing' and so on.
Anyway, I could not think of a scenario where I would like to render plain text without any surrounding tags. It should at least be surrounded by a span or paragraph (<p>) tag so you can style it. And an ID would be nice so I can change the contents with a partial refresh.

Resources