Selenium Webdriver: Highligh an Element at some Coordinates - javascript

I am automating an application which is built with HTML5 using Selenium Webdriver. Now I want to highlight the point I have clicked. Highlighting the element is not a big deal but to know at what coordinates it has been clicked is what I need. For ex. I am clicking an Canvas element at coordinates 200,500.
If I implement java script to highlight element then it will highlight whole Canvas element where as I want to highlight the point(200,500) clicked. Please provide your answers. Thanks in advance.
I am using specflow with C#.
Code for clicking the Canvas at coordinates:
public void ClickCanvasElement(IWebDriver driver, By locator, int offsetX, int offsetY)
{
try
{
IWebElement element = FindElement(driver, locator);
Actions actions = new Actions(driver);
for (int i = 0; i < 10; i++)
{
if ((element.Displayed == true && element.Enabled == true) || element == null)
{
actions.MoveToElement(element, offsetX, offsetY).Click().Perform();
break;
}
System.Threading.Thread.Sleep(500);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

You can try below code:- You need to use javascript to highlight particular element.
public void ClickCanvasElement(IWebDriver driver, By locator, int offsetX, int offsetY)
{
try
{
IWebElement element = FindElement(driver, locator);
Actions actions = new Actions(driver);
for (int i = 0; i < 10; i++)
{
if ((element.Displayed == true && element.Enabled == true) || element == null)
{
actions.MoveToElement(element, offsetX, offsetY).Click().Perform();
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("arguments[0].setAttribute('style', arguments[1]);"element","color: red; border: 3px solid red;");
break;
}
System.Threading.Thread.Sleep(500);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

The only solution what comes to my mind is to edit canvas itself, for example drawing a square/circle with x,y parameters(200,500) as first two arguments in context.fillRect. You could try this approach:
IWebElement element = FindElement(driver, locator);
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("var example = arguments[0]
var context = example.getContext('2d')
context.fillRect(200,500,10,10)",element);
However It will only works If provided by You coordinates are canvas coordinate. If not You will need to take more complicated path (Hope will help: http://javascript.info/coordinates)
Find canvas element
Extract absolute coords of founded element
Calculate relative coordinations
Use javascript for creating new shape on Canvas from point 1

Related

How to hover mouse on goJS canvas diagram in selenium

I am writing an IT test in selenium to click on a button that appears only when we hover over another button. Attached recording
I have the below function, but for some reason, it is not hovering. The function is wrapped in a java method.
function moveNodeCenter(canvasParent, nodeIndex){
var canvas = go.Diagram.fromDiv(canvasParent);
var nodeDataArray = getAllNodes(canvasParent);
var targetNodeKey = nodeDataArray[nodeIndex].key;
var targetNodeObj = canvas.findNodeForKey(targetNodeKey);
var robot = new Robot(canvas);
robotMove(robot,targetNodeObj.x,targetNodeObj.y);
}
public void moveNodeCenter(int nodeIndex) throws IOException, InterruptedException {
WebElement canvasParent = this.getCanvasParent();
String script = ResourceUtilities.getResource(DESIGNER_SCRIPT_PATH);
script += "\n moveNodeCenter(arguments[0], arguments[1])";
js.executeScript(script, canvasParent, nodeIndex);
}
can someone help? or is there any away i could do this.
i do see mouseMove event here: https://gojs.net/latest/extensions/Robot.js

Javascript performance issue in IE

PFB Function of javascript.It is performing good in Chrome.But the performance is very poor in IE.If the function is taking 4ms in chrome,It is taking 170ms in IE.Someone please help me on this.
Identified the issue is not because of Javascript.It is because of the ExecuteScript from webdriver
Is there any way to improve the performance in IE in this case?
public string OnMouseMoveListner()
{
string onMouseMove = #"
function OnMouseMove (event)
{
window.onEscape=null;
window.isRefresh='set';
var posX = event.clientX, posY = event.clientY;
// displays the coordinates used for the elementFromPoint method
// get the element that is located under the mouse y
var overElem = document.elementFromPoint (posX, posY);
if (overElem && overElem.tagName === undefined)
{ // in case of text nodes (Opera)
overElem = overElem.parentNode; // the parent node will be selected
window.control= overElem ;
}
// the body and the html tag won't be selected
if (overElem && overElem.tagName.toLowerCase () !='body' && overElem.tagName.toLowerCase () != 'html')
{
window.control= overElem ;
}
window.outerHeight=window.outerHeight;
window.innerHeight=window.innerHeight;
}
window.isRefresh='set';
";
return onMouseMove;
}
((IJavaScriptExecutor)webDriver).ExecuteScript(js.OnMouseMoveListner());

Cordova Ionic Keyboard plugin disable completely on “Init”

I have the following problem, I need to disable the native Keyboard completely. The keyboard should only show when I call the show() and hide when I call the close() function (this will be on a Button for the user to toggle the Keyboard).
The Keyboard showing on clicking the Field and on Focus needs to be completely disabled.
On Stackoverflow I found this:
InputMethodManager im = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
im.hideSoftInputFromWindow(editText.getWindowToken(), 0);
So my thought was In the "Init"(Line 52 in the IonicKeyboard.java) I need to change it.
if ("init".equals(action)) {
cordova.getThreadPool().execute(new Runnable() {
public void run() {
//new Logic on init
View v = cordova.getActivity().getCurrentFocus();
((InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
DisplayMetrics dm = new DisplayMetrics();
cordova.getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
final float density = dm.density;
//http://stackoverflow.com/a/4737265/1091751 detect if keyboard is showing
final View rootView = cordova.getActivity().getWindow().getDecorView().findViewById(android.R.id.content).getRootView();
OnGlobalLayoutListener list = new OnGlobalLayoutListener() {
int previousHeightDiff = 0;
#Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
rootView.getWindowVisibleDisplayFrame(r);
PluginResult result;
int heightDiff = rootView.getRootView().getHeight() - r.bottom;
int pixelHeightDiff = (int)(heightDiff / density);
if (pixelHeightDiff > 100 && pixelHeightDiff != previousHeightDiff) { // if more than 100 pixels, its probably a keyboard...
String msg = "S" + Integer.toString(pixelHeightDiff);
result = new PluginResult(PluginResult.Status.OK, msg);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
else if ( pixelHeightDiff != previousHeightDiff && ( previousHeightDiff - pixelHeightDiff ) > 100 ){
String msg = "H";
result = new PluginResult(PluginResult.Status.OK, msg);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
previousHeightDiff = pixelHeightDiff;
}
};
rootView.getViewTreeObserver().addOnGlobalLayoutListener(list);
PluginResult dataResult = new PluginResult(PluginResult.Status.OK);
dataResult.setKeepCallback(true);
callbackContext.sendPluginResult(dataResult);
}
});
return true;
}
return false; // Returning false results in a "MethodNotFound" error.
}
Sadly this does not work at all...
I think I have to change the close / show function too but I am not really sure what the correct code is, and I dont know if this change would affect other Keyboard behaviour. (But I basically need Focus without Keyboard)
I also found this Cordova Plugin
which looks very promising, but I decided to change this in the Ionic Keyboard Plugin, because I need the same behaviour in Windows too.
Very glad if someone could help me out here.
Regards Christopher
This can be accomplished by disabling all inputs with ng-disabled and later showing the keyboard with the Ionic Keyboard Plugin.
If you do not want the inputs to appear differently when disabled, you can override this style with CSS using the :disabled selector.
Hide on load:
<input ng-disabled="hideKeyboard">
hideKeyboard = true;
Show on function:
<input ng-disabled="hideKeyboard">
function showKeyboard(){
hideKeyboard = false;
cordova.plugins.Keyboard.show();
}

Using and HTMLHelper to display an image in .backstretch

I am using backstretch to provide a full height/width image background. I am doing a little themeing and need to be able to call an image from the HTML Helper into the backstretch javascript. It won't pull the image in for some reason. It seems to be adding my MVC View root, which is Account onto it. Here is my code:
$.backstretch('#Html.ThemeImage("login-background.jpg")');
The backstretch javascript is here:
https://raw.githubusercontent.com/srobbin/jquery-backstretch/master/jquery.backstretch.min.js
the link its producing is this
http://localhost/xxx.xxx.xxx/Account/%3Cimg%20src=%22/xxx.xxx.xxxx
/Content/Client/Images/login-background.jpg%22%20/%3E
The actual url should be
http://localhost/xxx.xxxxxxx.xxx/Content/Client/Images/login-background.jpg
This is the extension control
ublic static class HtmlExtensions
{
public static MvcHtmlString ThemeImage(this HtmlHelper helper, string fileName, string alt = "", int width = 0, int height = 0, string cssClass = "", string id = "")
{
var clientFolder = string.Format("{0}/Content/{1}/Images", HttpRuntime.AppDomainAppVirtualPath, AppSettings.ClientName);
var fullFileName = string.Format("{0}/{1}", clientFolder, fileName);
var builder = new TagBuilder("img");
builder.MergeAttribute("src", fullFileName);
if (alt != "")
{
builder.MergeAttribute("alt", alt);
}
if (width != 0)
{
builder.MergeAttribute("width", width.ToString());
}
if (height != 0)
{
builder.MergeAttribute("height", height.ToString());
}
if (cssClass != "")
{
builder.MergeAttribute("class", cssClass);
}
if (id != "")
{
builder.MergeAttribute("id", id);
}
//var imgString = String.Format("<img src='{0}' alt='{1}' width='{2}' height='{3}' class='{4}' id='{5}'/>", fullFileName, alt, width, height, cssClass, id);
return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
}
}
I believe my extension control needs to be changed, but I can't figure out where.

HTML book-like pagination

How can I split the content of a HTML file in screen-sized chunks to "paginate" it in a WebKit browser?
Each "page" should show a complete amount of text. This means that a line of text must not be cut in half in the top or bottom border of the screen.
Edit
This question was originally tagged "Android" as my intent is to build an Android ePub reader. However, it appears that the solution can be implemented just with JavaScript and CSS so I broadened the scope of the question to make it platform-independent.
Building on Dan's answer here is my solution for this problem, with which I was struggling myself until just now. (this JS works on iOS Webkit, no guarantees for android, but please let me know the results)
var desiredHeight;
var desiredWidth;
var bodyID = document.getElementsByTagName('body')[0];
totalHeight = bodyID.offsetHeight;
pageCount = Math.floor(totalHeight/desiredHeight) + 1;
bodyID.style.padding = 10; //(optional) prevents clipped letters around the edges
bodyID.style.width = desiredWidth * pageCount;
bodyID.style.height = desiredHeight;
bodyID.style.WebkitColumnCount = pageCount;
Hope this helps...
Speaking from experience, expect to put a lot of time into this, even for a barebones viewer. An ePub reader was actually first big project I took on when I started learning C#, but the ePub standard is definitely pretty complex.
You can find the latest version of the spec for ePub here:
http://www.idpf.org/specs.htm
which includes the OPS (Open Publication Structure), OPF (Open Packaging Format), and OCF (OEBPS Container Format).
Also, if it helps you at all, here is a link to the C# source code of the project I started on:
https://www.dropbox.com/sh/50kxcr29831t854/MDITIklW3I/ePub%20Test.zip
It's not fleshed out at all; I haven't played with this for months, but if I remember correctly, just stick an ePub in the debug directory, and when you run the program just type some part of the name (e.g. Under the Dome, just type "dome") and it will display the details of the book.
I had it working correctly for a few books, but any eBooks from Google Books broke it completely. They have a completely bizarre implementation of ePub (to me, at least) compared to books from other sources.
Anyway, hopefully some of the structural code in there might help you out!
I've had to code something like this too, and my (working) solution is this:
You have to apply these lines to the webview...
webView_.getSettings().setUseWideViewPort(true);
webView_.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
Also, you have to inject some javascript. I've had tons of problems with the differents scales of my activity and the content rendered in the webview, so my solution doesn't take any kind of value from "outside".
webView_.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String url) {
injectJavascript();
}
});
[...]
public void injectJavascript() {
String js = "javascript:function initialize() { " +
"var d = document.getElementsByTagName('body')[0];" +
"var ourH = window.innerHeight; " +
"var ourW = window.innerWidth; " +
"var fullH = d.offsetHeight; " +
"var pageCount = Math.floor(fullH/ourH)+1;" +
"var currentPage = 0; " +
"var newW = pageCount*ourW; " +
"d.style.height = ourH+'px';" +
"d.style.width = newW+'px';" +
"d.style.webkitColumnGap = '2px'; " +
"d.style.margin = 0; " +
"d.style.webkitColumnCount = pageCount;" +
"}";
webView_.loadUrl(js);
webView_.loadUrl("javascript:initialize()");
}
Enjoy :)
I recently attempted something similar to this and added some CSS styling to change the layout to horizontal instead of vertical. This gave me the desired effect without having to modify the content of the Epub in any way.
This code should work.
mWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// Column Count is just the number of 'screens' of text. Add one for partial 'screens'
int columnCount = Math.floor(view.getHeight() / view.getWidth())+1;
// Must be expressed as a percentage. If not set then the WebView will not stretch to give the desired effect.
int columnWidth = columnCount * 100;
String js = "var d = document.getElementsByTagName('body')[0];" +
"d.style.WebkitColumnCount=" + columnCount + ";" +
"d.style.WebkitColumnWidth='" + columnWidth + "%';";
mWebView.loadUrl("javascript:(function(){" + js + "})()");
}
});
mWebView.loadUrl("file:///android_asset/chapter.xml");
So, basically you're injecting JavaScript to change the styling of the body element after the chapter has been loaded (very important). The only downfall to this approach is when you have images in the content the calculated column count goes askew. It shouldn't be too hard to fix though. My attempt was going to be injecting some JavaScript to add width and height attributes to all images in the DOM that don't have any.
Hope it helps.
-Dan
I was able to improve Nacho's solution to get horizontal swipe paging effect with WebView. You can find solution here and example code.
Edit:
Solution code.
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
wv = (HorizontalWebView) findViewById(R.id.web_view);
wv.getSettings().setJavaScriptEnabled(true);
wv.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
injectJavascript();
}
});
wv.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
int pageCount = Integer.parseInt(message);
wv.setPageCount(pageCount);
result.confirm();
return true;
}
});
wv.loadUrl("file:///android_asset/ch03.html"); // now it will not fail here
}
private void injectJavascript() {
String js = "function initialize(){\n" +
" var d = document.getElementsByTagName('body')[0];\n" +
" var ourH = window.innerHeight;\n" +
" var ourW = window.innerWidth;\n" +
" var fullH = d.offsetHeight;\n" +
" var pageCount = Math.floor(fullH/ourH)+1;\n" +
" var currentPage = 0;\n" +
" var newW = pageCount*ourW;\n" +
" d.style.height = ourH+'px';\n" +
" d.style.width = newW+'px';\n" +
" d.style.margin = 0;\n" +
" d.style.webkitColumnCount = pageCount;\n" +
" return pageCount;\n" +
"}";
wv.loadUrl("javascript:" + js);
wv.loadUrl("javascript:alert(initialize())");
}
In my WebChromeClient's onJsAlert get the number of horizontal pages which i pass to the custom HorizontalWebView to implement paging effect
HorizontalWebView.java
public class HorizontalWebView extends WebView {
private float x1 = -1;
private int pageCount = 0;
public HorizontalWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x1 = event.getX();
break;
case MotionEvent.ACTION_UP:
float x2 = event.getX();
float deltaX = x2 - x1;
if (Math.abs(deltaX) > 100) {
// Left to Right swipe action
if (x2 > x1) {
turnPageLeft();
return true;
}
// Right to left swipe action
else {
turnPageRight();
return true;
}
}
break;
}
return true;
}
private int current_x = 0;
private void turnPageLeft() {
if (getCurrentPage() > 0) {
int scrollX = getPrevPagePosition();
loadAnimation(scrollX);
current_x = scrollX;
scrollTo(scrollX, 0);
}
}
private int getPrevPagePosition() {
int prevPage = getCurrentPage() - 1;
return (int) Math.ceil(prevPage * this.getMeasuredWidth());
}
private void turnPageRight() {
if (getCurrentPage() < pageCount - 1) {
int scrollX = getNextPagePosition();
loadAnimation(scrollX);
current_x = scrollX;
scrollTo(scrollX, 0);
}
}
private void loadAnimation(int scrollX) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, "scrollX",
current_x, scrollX);
anim.setDuration(500);
anim.setInterpolator(new LinearInterpolator());
anim.start();
}
private int getNextPagePosition() {
int nextPage = getCurrentPage() + 1;
return (int) Math.ceil(nextPage * this.getMeasuredWidth());
}
public int getCurrentPage() {
return (int) (Math.ceil((double) getScrollX() / this.getMeasuredWidth()));
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
}
Maybe it would work to use XSL-FO. This seems heavy for a mobile device, and maybe it's overkill, but it should work, and you wouldn't have to implement the complexities of good pagination (e.g. how do you make sure that each screen doesn't cut text in half) yourself.
The basic idea would be:
transform the XHTML (and other EPUB stuff) to XSL-FO using XSLT.
use an XSL-FO processor to render the XSL-FO into a paged format that you can display on the mobile device, such as PDF (can you display that?)
I don't know whether there is an XSL-FO processor available for Android. You could try Apache FOP. RenderX (XSL-FO processor) has the advantage of having a paged-HTML output option, but again I don't know if it could run on Android.
There is several ways this could be done. If every line is in its own element all you have to do is to check if one of it's edges goes outside of the view (either the browsers, or the "book page").
If you want to know how many "pages" there is going to be in advance, just temporary move them into the view and get what line a page ends. This could potentially be slow because of that page reflow is needed for the browser to know where anything is.
Otherwise I think that you could use the HTML5 canvas element to measure text and / or draw text.
Some info on that here:
https://developer.mozilla.org/en/Drawing_text_using_a_canvas
http://uupaa-js-spinoff.googlecode.com/svn/trunk/uupaa-excanvas.js/demo/8_2_canvas_measureText.html
Had this same problem recently and inspired by the answers found a plain CSS solution using CSS3's column-* attributes:
/* CSS */
.chapter {
width: 600px;
padding: 60px 10px;
-webkit-column-gap: 40px;
-webkit-column-width: 150px;
-webkit-column-count: 2;
height:400px;
}
/* HTML */
<div class="chapter">
your long lorem ipsum arbitrary HTML
</div>
The example above gives great results on a retina iPhone. Playing around with the different attributes yields in different spacing between the pages and such.
If you need to support multiple chapters for instance which need to start on new pages, there's an XCode 5 example on github: https://github.com/dmrschmidt/ios_uiwebview_pagination
You could split the pages in separate XHTML files and store them in a folder. Eg: page01, page02. You can then render those pages one by one underneath each other.
You can look at http://www.litres.ru/static/OR/or.html?data=/static/trials/00/42/47/00424722.gur.html&art=424722&user=0&trial=1 but the code may be heavily obfuscated, so just use Firebug to inspect DOM.
If the link isn't working, comment - would give you fixed.

Categories