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

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)

Related

How to trigger screenshot on every validator/Assert pass and fail using testng listener

I want to take screenshot for every validator/assert pass and fail steps. Let me know if we have testng listeners can help me to implement this scenario as I am new to selenium webdriver and testng automation testing
You can take screen-shot by following :
File screen = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
BufferedImage img = ImageIO.read(screen);
File filetest = Paths.get(".").toAbsolutePath().normalize().toFile();
ImageIO.write(img, "png", new File(filetest + "\\Screenshots\\"+ "ScreenshotName" + ".png"));
Here, Screenshot will save in "Screenshots" folder(Which you need to create) under project workspace by using Absolute path. If you want to save on other location, You can locate path for same.
If you want TestNG validator on every #Test whether its pass or fail, you can implement it in AfterMethod.
#AfterMethod
public void testStatus(ITestResult result) throws IOException
{
if (result.getStatus() == ITestResult.FAILURE) {
testResult = "Test Fail :" + result.getName();
testResult = "Details of Fail Testcase:" + result.getThrowable();
}
}
You can define above Screenshot utility in testStatus method, which will take screen shot if #Test got fail.

Codename One: dealing with server/connection unavailability when loading images

It seems that if at the time when URLImage.createCachedImage is called to load and the image is not available (no connection, etc.), it won't be called again to reload when the connection comes back.
Description:
When the connection is unavailable, it shows a blank image. And it still shows the same blank image when the Display.getInstance().callSerially(...) is called again. It does not seem like it is invoking the connection to try to load the image but the blank image has apparently become the cache.
I'm not sure if I'm describing my problem properly, but here's the simplified question: how to deal with loading of image and handle events when the connection/server is unavailable? (I thought URLImage.createCachedImage knows if the image is not loaded and will try again.)
I have this piece of code to load Image:
protected static final Image loadImage(String imageAccessLocation) {
int filenameIndex = imageAccessLocation.lastIndexOf("/");
String filename = imageAccessLocation.substring(filenameIndex + 1);
String imageAccessBaseLocation = Application.getInstance().getImagesAccessBaseLocation();
String imageAccessURL = imageAccessBaseLocation + imageAccessLocation;
int displayWidth = Display.getInstance().getDisplayWidth();
EncodedImage imagePlaceholder = EncodedImage.createFromImage(Image.createImage(displayWidth, displayWidth / 5, 0xffff0000), true);
Image image = URLImage.createCachedImage(filename, imageAccessURL, imagePlaceholder, FLAG_RESIZE_SCALE);
return image;
}
protected static final Container prepareImageContainer(Item item) {
Image image = item.getImage();
if(image == null) {
return null;
}
Image scaledImage = image.scaled(50, 50);
Container imageContainer = new Container();
imageContainer.add(scaledImage);
return imageContainer;
}
private final void prepare() {
Container imageContainer = prepareImageContainer(lookslike);
Container textContainer = prepareTextDescription(lookslike);
add(imageContainer);
add(textContainer);
}
You're right. If there is a network problem, URLImage will just silently fail.
If the URLImage hasn't finished downloading the image for whatever reason, its isAnimation() method will return true. This is a way to detect if it hasn't finished downloading. It doesn't tell you whether the download failed or just hasn't completed, but you could combine that with some sort of timeout to check if the image is downloaded, and, if not, replace it with a new URLImage for the same URL.
Not ideal, I know. You can file an RFE in the issue tracker and we'll evaluate the request.

Image always missing in the received message while sharing an image in Codename One

I am generating an image that is saved in FileSytemStorage.getAppHomePath() dir. I now need to share it via Email, SMS ... That's why I am using the following code (based on Codename One documentation) in my action method :
long time = new Date().getTime();
String fullOutputPath = FileSystemStorage.getInstance().getAppHomePath()
+ "Montage_" + Long.toString(time) + ".png";
// Save the image with the ImageIO class
try (OutputStream os = FileSystemStorage.getInstance().openOutputStream(fullOutputPath)){
ImageIO.getImageIO().save(montage.getMontageImage(), os, ImageIO.FORMAT_PNG, 1.0f);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Enable image sharing (outside the try/catch so that the outputstream in closed for sure)
if (FileSystemStorage.getInstance().exists(fullOutputPath)) {
Dialog.show("Saved", "Photo collage saved to " + fullOutputPath
+ " (file size = " + FileSystemStorage.getInstance().getLength(fullOutputPath) +" B)", "OK", null);
//Photo collage saved to file://home/Montage_14669... .png (file size = 50387B)
findValidateMontageShareButton3().setImageToShare(fullOutputPath, "image/png");
// Null pointer exception
So in that way I get a NPE and if I don't test if the file does exist there is no NPE but the image is still missing (both in the simulator and on the device).
The stack trace is as follows :
java.lang.NullPointerException
at userclasses.StateMachine.onPage3_ValidateMontageShareButton3Action(StateMachine.java:852)
at generated.StateMachineBase.handleComponentAction(StateMachineBase.java:757)
at com.codename1.ui.util.UIBuilder$FormListener.actionPerformed(UIBuilder.java:2835)
at com.codename1.ui.util.EventDispatcher.fireActionSync(EventDispatcher.java:459)
at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:362)
at com.codename1.ui.Button.fireActionEvent(Button.java:411)
at com.codename1.ui.Button.released(Button.java:442)
at com.codename1.ui.Button.pointerReleased(Button.java:530)
at com.codename1.ui.Form.pointerReleased(Form.java:2627)
at com.codename1.ui.Form.pointerReleased(Form.java:2563)
at com.codename1.ui.Component.pointerReleased(Component.java:3158)
at com.codename1.ui.Display.handleEvent(Display.java:2025)
at com.codename1.ui.Display.edtLoopImpl(Display.java:1067)
at com.codename1.ui.Display.mainEDTLoop(Display.java:996)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
It looks that the file my app is generating is not accesible to the sharing app. Do I have to add any extra permission as advised here for Android ?
Please note : I don't know if it is related to this problem but I cannot access to Codename One Settings menu from Eclipse anymore (maybe since upgrade to CN1 lib v 115)
Any help appreciated,
Cheers
So here is part of the answer which works in the simulator (ie the image appears in the fake email client => see image below).
So it appears that the share button cannot be set up in the action method (ie the method that is triggered when the user click on the share button). It has to be set up previously.
Consequently, in the beforeShow method my code reads as follows :`
FontImage.setMaterialIcon(findValidateMontageShareButton3(), FontImage.MATERIAL_CHECK_CIRCLE);
final long time = new Date().getTime();
// We generate the montage filename JPG otherwise it cannot be sent
montage.setMontageFullPath(FileSystemStorage.getInstance().getAppHomePath()
+ "Montage_" + Long.toString(time) + ".jpg");
// We assign the montage filename to the share button BEFORE we can click the button (otherwise the
// filename cannot be taken into account)
findValidateMontageShareButton3(f).setImageToShare(
montage.getMontageFullPath(), "image/jpeg");
Then in the onAction method related to the share button the code reads :
// Save the image with the ImageIO class
// We wait until the file is completely written to continue
Display.getInstance().invokeAndBlock(new Runnable() {
#Override
public void run() {
try (OutputStream os = FileSystemStorage.getInstance().openOutputStream(montage.getMontageFullPath())){
ImageIO.getImageIO().save(montage.getMontageImage(), os, ImageIO.FORMAT_JPEG, 1);
} catch (IOException e) {
Dialog.show("Erreur", "Impossible de sauvegarder le montage! Merci de vérifier l'espace disque disponible.", null, "OK" );
}
}
});
I tested it and it worked on the simulator but not on the device. Either with a png or a jpeg file, the file cannot be attached to the SMS or email (Android error message "abnormal file, can't attached file").
However if I do it a second time, then the file can be attached. So now the image is not missing but it cannot be attached (the first time) which is still embarrassing.

Taking Screen shots on specific error page in selenium web driver

My scenario is, I'm getting same error page on many of my button clicks on the site.
I want to take screenshots, of this same error page, with reference on which link of the site this error page occured.
So I want screenshot whenever this error page occurs on any click.
Can you suggest me how to write the function for this and how to call that function in some other function in selenium Webdriver.
Please share some code sample for that.
As of currently, I'm writing it only as :
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(scrFile, new File("D:\\Home\\Ruchi\\failure.png"));
But in this I need to write these lines of code after every failure occurrence.
use try and catch block
try{
// Put your script here
}
catch(Exception ex)
{
File scrn=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
// extracting date for folder name.
SimpleDateFormat sdfDate1 = new SimpleDateFormat("yyyy-MM-dd");//dd/MM/yyyy
Date now1 = new Date();
String strDate1 = sdfDate1.format(now1);
// extracting date and time for snapshot file
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");//dd/MM/yyyy
Date now = new Date();
String strDate = sdfDate.format(now);
String filefolder="./Snap/"+strDate1+"/"; // create a folder as snap in your project directory
// Creating folders and files
File f = new File(filefolder+strDate+".jpeg");
FileUtils.copyFile(scrn, new File(f.getPath()));
}
If your script fails then the program jumps to catch block and then code will take screen shot for you
Hope it will help you :)

How to automate upload multiple files using sikuli and selenium webdriver in java

I am new with sikuli, Unable to generate Sikuli script for upload functionality for web application.
Please note that typically, you can automate file upload scenario using Selenium only, no need for Sikuli.
For uploading a file you just need to callsendKeys() method (with file path as argument) on the WebElement that is displayed for file uploading. Code goes like this:
//Put this for textbox near to upload button
driver.findElement(By.id("id_or_other_locator_goes_here")).sendKeys("file_path_goes_here");
And then click the upload button:
driver.findElement(By.xpath("locator_for_upload_button")).click(); // Click Upload button
Sikuli :
I have used Sikuli to automate file download scenario in IE and below are the steps for this:
First capture image of Save button in File download dialog box and save it
Put Sikuli jar in your Java project
Use following code snippet
// Code:
//Save the file in Downloads directory by using on Sikuli
ScreenRegion s = new DesktopScreenRegion();
Target target = new ImageTarget(new File("SavedImagePath.png"));
ScreenRegion r = s.find(target);
Mouse mouse = new DesktopMouse();
if (r != null) {
mouse.click(r.getCenter());
Thread.sleep(5000);
} else {
System.out.println("Unable to click using Sikuli")
}
Thanks sandeep!
tried below script using Screen and Pattern class of Sikuli to capture desktop based file from open folder windows at run time and it works!!
String FileToUpload = "/location of file to upload/"
String fileNameLoc = "/fileName_input sikuli image location"
String openButtonLoc = "/Open button sikuli image location/"
//Code to perform action using action using sikuli script
Screen src = new Screen();
src.setAutoWaitTimeout(80);
Pattern fileName = new Pattern(fileNameLoc).similar((float) 0.5);
if (src.exists(fileName, 10) != null)
{
System.out.println("File Name Pattern exist..");
Match match = src.getLastMatch();
match.find(fileName);
match.click(fileName);
match.type(fileName, FileToUpload);
match.setAutoWaitTimeout(50);
}
else
{
System.out.println("File Name pattern not found on screen..");
}
Pattern open = new Pattern(openButtonLoc).similar((float) 0.5);
if (src.exists(open, 5) != null)
{
System.out.println("Open Button pattern exist..");
Match match = src.getLastMatch();
match.find(open);
match.click(open);
match.setAutoWaitTimeout(30);
}
else
{
System.out.println("Open buton pattern not found on screen..");
}

Resources