Simulator hangs con execute browserComponent.executeAndReturnString("navigator.userAgent" - codenameone

On simulator App hangs on execute browserComponent.executeAndReturnString("navigator.userAgent")
BrowserComponent browserComponent = new BrowserComponent();
String userAgent = (String) browserComponent.executeAndReturnString("navigator.userAgent");
String userAgent = "";
if (userAgent == null) {
userAgent = "";
}
On console logs:
Using:
JCEF Version = 83.4.0.260
CEF Version = 83.4.0
Chromium Version = 83.0.4103.106
initialize on Thread[AWT-EventQueue-0,6,main] with library path C:\Users\Kandy\.codenameone\cef\lib\win64
Added scheme search://
Added scheme client://
Added scheme cn1stream://
DevTools listening on ws://127.0.0.1:53523/devtools/browser/2da17f15-4c86-45d2-98d2-c853b71d3d7a
AppHandler.stateHasChanged: NEW
AppHandler.stateHasChanged: INITIALIZING

Although this API wasn't deprecated its usage is strongly discouraged in the JavaDocs in favor of this.
Try:
bc.execute("navigator.userAgent", userAgent -> {
// ...
});
Notice that user-agent is something you submit/set in the browser component so you can determine it.

Related

How to handle Authentication pop up in Safari using Selenium?

I have been having issues with Safari 11 using WebDriver. I was able to bypass that authentication popup by using the following:
String URL = "http://" + username + ":" + password + "#" + Settings.AUT;
Driver.Navigate().GoToUrl(URL + "/");
This somehow worked with Safari 10, though I upgraded my Safari to 11 due to the maximize window is not working with Safari 10.
I am currently using webdriver 2.48 for safari.
I have no idea anymore on what to do with Safari tests. Is this a known issue? I know there is AutoIT but is there any other way to do this?
It is possible that your current web driver doesn't work with that version of browser.
SafariDriver - DEPRECATED - use Apple's SafariDriver with Safari 10+
SafariDriver now requires manual installation of the extension prior
to automation
From:
http://www.seleniumhq.org/download/
According to the RFC 3986 this format of passing the user name and password in the URL is deprecated and while it still works in Chrome and FF, Safari does not support this anymore.
You can use AppleScript and Java to handle the browser pop-up. Here is the Java code to execute AppleScript, just call this function and pass the AppleScript as String:
public static void execute(String appleScript)
{
Process process = null;
try
{
String[] args = { "osascript", "-e", appleScript };
process = Runtime.getRuntime().exec(args);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String logs = null;
while ((logs = bufferedReader.readLine()) != null)
{
System.out.println(logs);
}
}
catch (Exception e)
{
}
finally
{
if (process != null)
process.destroy();
}
}
If you don't know how to write AppleScript go to their tutorials.
Also, to check you have given access permission to System Events; go to 'System Preferences > Security & Privacy > Privacy > Accessibility' and make sure you have 'Eclipse' and 'System Events' checked.

Configuring Webpack build for file:// use in CEF

I have to develop a webapp for a CEF-Browser environment. There is no HTTP server available, everything will be served over file:// protocol.
When developing a Webapp nowadays one doesn't get round working with a framework like react/vue for frontend. The standard webpack build scripts of those build a bundle which only works served over HTTP.
Is it possible to configure webpacks build bundle to work on file:// or is there another way to use react or vue via file://?
I'm suggest read CEF wiki more carefully. You are especially interested in https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-request-handling
In short:
You can register custom scheme handler to serve resources over http+custom fake domain.
You can pack resources in zip for example if you like, or leave them at file system as is (but in that case you can expect that some funny users can edit your files, and then report back unexisting errors back to you).
Important helpers already done (but you can write own when need.)
You can... many other things.
Main thing that "file" scheme are more restricted, and for example you can't do XHR requests. But for custom handler you can. Even if dynamic loader for some reason use XHR instead DOM-based loading it will work again same as on http without touching network.
cefclient itself also has usage of custom schemes. Check URL of Tests->Other... in menu. :)
PS: Sorry that my answer doesnt have direct answer for your question. But, custom resource handling in CEF is so common, that i'm just should say about.
fddima is right - you don't need to configure your webpack (although it would be theoretically possible). Instead you can use custom scheme handler in CEF. I made it work with angular at work.
I wrote blog post on how to serve web application via 'file' protocol in CEF.
What you want to add is your scheme handler and its factory:
using System;
using System.IO;
using CefSharp;
namespace MyProject.CustomProtocol
{
public class CustomProtocolSchemeHandler : ResourceHandler
{
// Specifies where you bundled app resides.
// Basically path to your index.html
private string frontendFolderPath;
public CustomProtocolSchemeHandler()
{
frontendFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "./bundle/");
}
// Process request and craft response.
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
var requestedFilePath = frontendFolderPath + fileName;
if (File.Exists(requestedFilePath))
{
byte[] bytes = File.ReadAllBytes(requestedFilePath);
Stream = new MemoryStream(bytes);
var fileExtension = Path.GetExtension(fileName);
MimeType = GetMimeType(fileExtension);
callback.Continue();
return true;
}
callback.Dispose();
return false;
}
}
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "customFileProtocol";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new CustomProtocolSchemeHandler();
}
}
}
And then register it before calling Cef.Initialize:
var settings = new CefSettings
{
BrowserSubprocessPath = GetCefExecutablePath()
};
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});

Handling multiple windows in IE and Chrome browsers

In the below code,
//Element clicked in parent window
driver.findElement(By.id("ID")).click();
//Once after clicking the ID, system takes the user to a different tab in chrome and launches an external link
//In IE the same external link will launch in a new browser which is different from chrome behavior
Iterator<String> browsers = driver.getWindowHandles().iterator();
while(browsers.hasNext()){
driver.switchTo().window(browsers.next());
//Element to be clickable in the child window or external site
driver.findElement(By.xpath(".//button")).click();
Can anyone help me out how can we handle the scenario,i want something which works both in IE and chrome. Currently the above code works in chrome but not in IE as the external link opens in a new browser. I am not able to handle the scenario
Try the below method for IE:
Java:
DesiredCapabilities cap = DesiredCapabilities.internetExplorer();
cap.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,true);
cap.setCapability(InternetExplorerDriver.IGNORE_ZOOM_SETTING,true);
cap.setCapability(InternetExplorerDriver.UNEXPECTED_ALERT_BEHAVIOR,"accept");
cap.setCapability(InternetExplorerDriver.REQUIRE_WINDOW_FOCUS,true);
cap.setCapability(InternetExplorerDriver.INITIAL_BROWSER_URL,"");
WebDriver dr = new InternetExplorerDriver(cap);
C#:
var options = new InternetExplorerOptions();
options.IntroduceInstabilityByIgnoringProtectedModeSettings = true;
options.EnsureCleanSession = true;
options.IgnoreZoomLevel = true;
options.UnhandledPromptBehavior = UnhandledPromptBehavior.Accept;
options.RequireWindowFocus = true;
options.InitialBrowserUrl = "";
string iedriver = TestContext.DataRow["IEDRIVER"].ToString();
dr = new InternetExplorerDriver(iedriver,options);

Why do I get ClassCastException using HttpURLConnection in AppEngine?

I try to call an external web service (not mine) from my GWT application working with App Engine.
I know it's impossible to do it from the client due to the SOP (Same Origin Policy) and RequestBuilder is not a solution on the server. I followed the tutorial on the web site and using java.net as well
Here is the client
AsyncCallback<CustomObject> callback = new AsyncCallback<CustomObjectCustomObject>() {
#Override
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
#Override
public void onSuccess(CustomObject result) {
// code omitted
}
};
service.callMethod(aString, callback);
And this is the server
try {
String xmlRequest = "xmlToSend";
URL url = new URL("https://www.externalWebService.com");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setAllowUserInteraction(false);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type","application/soap+xml");
conn.setRequestProperty( "Content-length", Integer.toString(xmlRequest.length()));
conn.setRequestProperty("charset", "utf-8");
conn.setConnectTimeout(10000);
OutputStream rawOutStream = conn.getOutputStream();
PrintWriter pw = new PrintWriter(rawOutStream);
pw.print(xmlRequest);
pw.flush();
pw.close();
if(conn.getResponseCode() != 200){
// Something...
}
I keep having the same error at conn.getResponseCode() :
java.lang.ClassCastException: com.google.appengine.repackaged.org.apache.http.message.BasicHttpRequest cannot be cast to com.google.appengine.repackaged.org.apache.http.client.methods.HttpUriRequest
Without making a real request, the remote service works well : it's able to serialize and return objects to the client. The issue is not linked to the communication between the client and the server, it's more like AppEngine doesn't support HttpURLConnection. But it should on the server (isn't it?)
Any thoughts would be hightly appreciated! Thanks in advance
Your problem has nothing to do with GWT: as long as you are running on the server, you can use any 'normal' Java and it will work unless AppEngine has restrictions.
It seems you have imported the repackaged version of Apache HttpClient in your class. You should not do that: download your own HttpClient .jar, add it to the dependencies and use that one.
AppEngine also has some issues with HttpClient. There's an adapter available here that fixes most of the issues.
Thanks #Marcelo, you were right!
Here is the solution I found.
I added httpcore.jar and httpclient.jar to my build path and wrote the code below for the server (the client is the same) :
String xmlRequest = "xmlToSend";
CloseableHttpClient httpclient = HttpClients.custom().build();
//RequestConfig requestConfig = RequestConfig.custom()
// .setConnectionRequestTimeout(10000)
// .build();
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(out);
writer.write(xmlToSend);
writer.flush();
writer.close();
HttpPost request = new HttpPost("https://www.externalWebService.com/path");
request.setEntity(new ByteArrayEntity(out.toByteArray()));
//request.setConfig(requestConfig);
CloseableHttpResponse response = httpclient.execute(request);
if(response.getStatusLine().getStatusCode() == 200){
// retrieve content with a BufferReader
// from response.getEntity().getContent()
...
}
The code works and is up to date.
Edit
Here is the rest of the solution when using a proxy. Mine only deals with NTCredentials but otherwise UsernamePasswordCredentials can be used instead.
HttpHost proxy = new HttpHost("addresse.proxy.com", port);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(proxy),
new NTCredentials(System.getProperty("user.name") + ":" + password));
RequestConfig requestConfig = RequestConfig.custom()
.setProxy(proxy)
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultRequestConfig(requestConfig)
.build();
Thanks again for your help, I really appreciated!

How to test Android toast messages in Appium ( selenium Java)

I am using Selenium with Java to run scripts on android (thru Appium server).
I see that it is not possible to locate a toast by using selenium's
driver.findElement(By.LinkText("User not logged in")
in Appium
But can be used in Selendroid to capture toast messages.
I there a way I can use both Selendroid and Appium in the same script?
Finally, we are able to read the toast message without the need of taking screenshots and performing OCR.
I have tested this on Appium 1.15.1.
Toast messages comes under com.package.system.
Normally, Xpath for this will be "/hierarchy/android.widget.Toast".
And, Class Name will be "android.widget.settings"
You can confirm this by refreshing element inspector screen when toast message is displayed.
WebDriverWait waitForToast = new WebDriverWait(driver.25);
waitForToast.until(ExpectedConditions.presenceOfElementLoacted(By.xpath("/hierarchy/android.widget.Toast")));
String toastMessage = driver.findElement((By.xpath("/hierarchy/android.widget.Toast")).getText();
System.out.println(toastMessage);
Method 1: from Appium version 1.6.4 supports toast messages, for that you need to use automationName:'uiautomator2'.
toast = driver.find_element(:xpath, "//android.widget.Toast[1]")
if toast.text == "Hello"
But i don't recommend this because uiautomator2 is not stable yet.
Method 2:
Trigger text message on the screen
Capture screenshots
Convert image to text file
def assettoast(string)
sname = (0...8).map { (65 + rand(26)).chr }.join
$driver.driver.save_screenshot("#{sname}")
# Make sure tesseract is installed in the system. If not you can install using "brew install tesseract" in mac
system ("tesseract #{sname} #{sname}")
text_file="#{sname}.txt"
var= get_string_from_file(string, text_file)
raise if var != true
end
Check whether toast message is there in text file
def get_string_from_file(word, filename)
File.readlines(filename).each do |line|
return true if line.include?(word)
end
end
Looks like you can't switch driver type within same session.
If you trying to switch to Selendroid only for toast verification - you could use OSR image recognition engine.
Check this answer w/ Ruby bindings
Idea is quite simple:
make toast message to appear
take few screenshots
iterate over taken screenshots and look for required text
Here is nice and simple example of OCR usage in Java: tess4j example (make sure that Tesseract engine installed)
Step 1:
File scrFile=null;
String path1 = null;
BufferedImage originalImage=null;
BufferedImage resizedImage=null;
System.out.println("Starting\n\n\n\n");
scrFile = ((TakesScreenshot) appiumDriver).getScreenshotAs(OutputType.FILE);
System.out.println("after scrfile\n\n\n\n");
originalImage = ImageIO.read(scrFile);
System.out.println("after originalFile\n\n\n");
BufferedImage.TYPE_INT_ARGB : originalImage.getType();
resizedImage = CommonUtilities.resizeImage(originalImage, IMG_HEIGHT, IMG_WIDTH);
ImageIO.write(resizedImage, "jpg", new File(path + "/"+ testCaseId + "/img/" + index + ".jpg"));
Image jpeg = Image.getInstance(path + "/" + testCaseId + "/img/"+ index + ".jpg");
Step 2:
BufferedImage pathforToast= original image;
Step 3:
System.setProperty("jna.library.path","C:/Users/Dell/workspace/MOBILEFRAMEWORK/dlls/x64/");
Tesseract instance = Tesseract.getInstance();
`enter code here`ImageIO.scanForPlugins();
String result=null;
result = instance.doOCR(pathforToast);`enter code here`
System.out.println(result);`enter code here`
Appium 1.6.4#beta latest version supports toast messages
Take screen shot of Toast Message page and try to convert the image file in to Text and verify the text using the below code.
public void imageconversion(String filePath) throws IOException,
{
ITesseract instance = new Tesseract();
//file path is the image which you need to convert to text
File imageFile = new File(filePath);
BufferedImage img = null;
img = ImageIO.read(imageFile);
BufferedImage blackNWhite = new BufferedImage(img.getWidth(),img.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics2D graphics = blackNWhite.createGraphics();
graphics.drawImage(img, 0, 0, null);
//path where your downloaded tessdata exists
instance.setDatapath("E://ocr//data");
//What language you required to convert,( e.g. English)
instance.setLanguage("eng");
String result = instance.doOCR(blackNWhite);
System.out.println(result);
}
Appium Directly does not give any API to read toast message we need to do it using tess4j jar. First we need to take screen shot and then we need to read the text from screen shot using tess4j API.
static String scrShotDir = "screenshots";
File scrFile;
static File scrShotDirPath = new java.io.File("./"+ scrShotDir+ "//");
String destFile;
static AndroidDriver driver = null;
public String readToastMessage() throws TesseractException {
String imgName = takeScreenShot();
String result = null;
File imageFile = new File(scrShotDirPath, imgName);
System.out.println("Image name is :" + imageFile.toString());
ITesseract instance = new Tesseract();
File tessDataFolder = LoadLibs.extractTessResources("tessdata"); // Extracts
// Tessdata
// folder
// from
// referenced
// tess4j
// jar
// for
// language
// support
instance.setDatapath(tessDataFolder.getAbsolutePath()); // sets tessData
// path
result = instance.doOCR(imageFile);
System.out.println(result);
return result;
}
/**
* Takes screenshot of active screen
*
* #return ImageFileName
*/
public String takeScreenShot() {
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy__hh_mm_ssaa");
new File(scrShotDir).mkdirs(); // Create folder under project with name
// "screenshots" if doesn't exist
destFile = dateFormat.format(new Date()) + ".png"; // Set file name
// using current
// date time.
try {
FileUtils.copyFile(scrFile, new File(scrShotDir + "/" + destFile)); // Copy
// paste
// file
// at
// destination
// folder
// location
} catch (IOException e) {
System.out.println("Image not transfered to screenshot folder");
e.printStackTrace();
}
return destFile;
}
For more details Refer this video - https://www.youtube.com/watch?v=lM6-ZFXiSls
I found three ways to capture a Toast message and verify them.
To get the page source and verify the toast message from it.
public void verifyToastMessageUsingPageSource(String toastmsg) throws InterruptedException {
boolean found = false;
for(int i =0 ; i <8; i++){
if(getDriver().getPageSource().contains("class=\"android.widget.Toast\" text=\""+toastmsg+"\"")){
found = true;
break;
}
Thread.sleep(300);
}
Assert.assertTrue(found,"toast message "+toastmsg+" is present");
}
Similar can be found using Xpath: //android.widget.Toast[1]
Using the grep command, wait for a toast message in uiautomator events.
run the command before clicking and toast message will be varified.
adb shell uiautomator events | grep "ToastMessgae"
This is tricky and needs more code to run.
start capturing screenshots thread.
perform click action
stop screen capturing thread.
extract text from the captured images using OCR and verify the toast message is present in the captured images.
I prefer the 1st and 2nd option, it provides validation in less time with less code.
comment if you need code for 2nd and 3rd point.
Appium with version number>=1.6.4 supports toast notification with UiAutomator2.
In Javascript with webdriver you can do like this
let toast=await driver1.elements("xpath","/hierarchy/android.widget.Toast");
let data=await toast[0].text();
console.log(data)

Resources