I used SeleniumHQ to record my actions and then exported them to Java Unity WebDrive. Then I edited exported code and added many small extra things like looping over array, time-stamps, etc.
My code does following:
Log into my site.
Goto my profile.
Delete my previous announcement.
Post new announcement.
Log out.
I have tried using FirefoxDriver and HtmlUnitDriver, but every single of them gives me this weird problem. My code start doing its work and randomly stops in random spot and hangs there forever.
For example it could log in -> goto profile -> delete previous and then stop, or it could hang right in the login. I loop over those steps over and over again, and more I loop more likely it is to get stuck.
First loops success rate is 90% second loop is around 40% etc. Also which Driver I use also affects this. It is most likely to hang with HtmlUnitDriver and I would really want to use HtmlUnitDrive because I want to run my code headless on Ubuntu Server.
Has anyone else had similar problems?
EDIT : Now after many hours of testing, I noticed that its only HtmlUnitDriver that hangs and not Firefox. When using Firefox I can see what it is doing and it is doing everything as it should. Problem occurs with HtmlUnitDriver.
And here is the code itself:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import org.openqa.selenium.*;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
public class WebUpdater {
private WebDriver driver;
private String baseUrl;
private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();
#Before
public void setUp() throws Exception {
driver = new HtmlUnitDriver(true); // JavaScript enabled.
baseUrl = "http://exampleurl.com";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void testUnity() throws Exception {
openAndLogin();
gotoProfile();
deletePreviousPost();
uploadPost();
logOut();
System.out.println("Done!");
}
private void openAndLogin() {
driver.get(baseUrl);
driver.findElement(By.linkText("Login")).click();
driver.findElement(By.id("jsid-login-id")).clear();
driver.findElement(By.id("jsid-login-id")).sendKeys("bilgeis.babayan#gmail.com");
driver.findElement(By.id("jsid-login-password")).clear();
driver.findElement(By.id("jsid-login-password")).sendKeys("volume1991");
driver.findElement(By.cssSelector("input.right")).click();
}
private void gotoProfile() {
driver.findElement(By.cssSelector("img[alt=\"Profile\"]")).click();
}
private void deletePreviousPost() {
try {
driver.findElement(By.cssSelector("img[alt=\"ExampleName\"]")).click();
driver.findElement(By.linkText("Delete")).click();
assertTrue(closeAlertAndGetItsText().matches("^Confirm to delete this post[\\s\\S]$"));
} catch (Exception e) {
System.out.println(e);
}
}
private void uploadPost() {
driver.findElement(By.linkText("ExampleAction")).click();
driver.findElement(By.id("example_url")).clear();
driver.findElement(By.id("example_url")).sendKeys("Example text that gets typed in textfield.");
driver.findElement(By.cssSelector("input[name=\"example\"]")).clear();
driver.findElement(By.cssSelector("input[name=\"example\"]")).sendKeys("ExampleName");
driver.findElement(By.linkText("ExampleAction2")).click();
System.out.println("Done");
}
private void logOut() {
driver.get("http://exampleurl.com/logout");
System.out.println("Logged out.");
}
#After
public void tearDown() throws Exception {
driver.quit();
String verificationErrorString = verificationErrors.toString();
if (!"".equals(verificationErrorString)) {
fail(verificationErrorString);
}
}
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
private String closeAlertAndGetItsText() {
try {
Alert alert = driver.switchTo().alert();
if (acceptNextAlert) {
alert.accept();
} else {
alert.dismiss();
}
return alert.getText();
} finally {
acceptNextAlert = true;
}
}
}
in my main class I call WebUpdater class like this:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
public static void main(String[] args) {
Logger logger = Logger.getLogger("");
logger.setLevel(Level.OFF);
scan();
}
private static void scan() {
while (true) {
try {
// Test if connection is available and target url is up.
URL url = new URL("http://exampleurl.com");
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.connect();
// Start tests.
WebUpdater updater = new WebUpdater();
updater.setUp();
updater.testUnity();
updater.tearDown();
} catch (Exception ex) {
System.out.println(ex);
}
try {
Thread.sleep(12000);
} catch (InterruptedException e) {
}
}
}
}
I had a bad experience with HtmlUnitDriver. Some time ago I wrote testing framework which were supposed to be fired at Hudson, and finally I decided to use Firefox driver which was more predictable and easier to debug. The point is that in my case it was a page full of javascripts - dynamically loaded fields, etc., and working with HtmlUnitDriver was really a can of worms.
If you really need to use HtmlUnitDriver try do debug 'pagesource' which is accessible for Selenium in 'current' (hanging) moment.
HtmlUnit 2.11 is flawed (see here and here), and since HtmlUnit 2.12 went live march 6th, the current version of HtmlUnitDriver is probably still based on HtmlUnit 2.11.
If you post your "http://exampleurl.com/" source code (or just give me a working url to the page if it's public) I could run the page with scripts through HtmlUnit 2.12.
Related
I have some methods that are used to wait for an element to display, and in the try/catch for these methods, the catch is:
throw new ElementNotVisibleException()
I'm upgrading from Selenium 2.53 to Selenium 4, and ElementNotVisibleException() seems to not be available in Selenium 4. What should I replace it with? Is ElementNotInteractableException a suitable replacement?
Since release 4.1.3, the method ElementNotVisibleException() has been removed from selenium/java/src/org/openqa/selenium
See v4.1.2, where the classes ElementNotVisibleException & ElementNotSelectableException exist.
See v4.1.3, where the aforementioned classes have been removed.
This is due to the following:
Selenium 4 is more strict regarding W3C WebDriver, and W3C WebDriver has nothing to say about visibility at this point. If an element is not visible, the driver in W3C mode should return a ElementNotInteractableException
So methods using the ElementNotVisibleException.java class will have to be updated to use ElementNotInteractableException.java
Confirmation here: [🐛 Bug]: ElementNotVisibleException class is not found in selenium 4.1.3. Getting compilation issues saying ElementNotVisibleException not found
#10538
Example:
import org.openqa.selenium.ElementNotVisibleException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;
public void selectUpload(String uploadType) throws Exception {
WebElement dropdown = driver.findElement(By.xpath("//select[contains(#name,'uploadFileResultsInput')]"));
int timeout = 0;
Exception finalException = null;
while (timeout < 5000) {
try {
new Select(dropdown).selectByVisibleText(uploadType);
return;
} catch (ElementNotVisibleException e) {
finalException = e;
}
Thread.sleep(500);
timeout += 500;
}
throw finalException;
}
to
import org.openqa.selenium.ElementNotInteractableException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;
public void selectUpload(String uploadType) throws Exception {
WebElement dropdown = driver.findElement(By.xpath("//select[contains(#name,'uploadFileResultsInput')]"));
int timeout = 0;
Exception finalException = null;
while (timeout < 5000) {
try {
new Select(dropdown).selectByVisibleText(uploadType);
return;
} catch (ElementNotInteractableException e) {
finalException = e;
}
Thread.sleep(500);
timeout += 500;
}
throw finalException;
}
I would like to take a screenshot every single time test fails or if multiple tests then multiple screenshots of course.
So far I understand that I can just wrap my single test with a try catch block and proceed taking a screenshot, however I would not want to wrap it in every test I have. I want it to apply to all of them without wrapping each one, do I have to do that in my setup?
public class WebDriverSettings
{
protected WebDriver driver;
protected String TARGET_URL;
#BeforeEach
public void setUp()
{
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver(new ChromeOptions().addArguments("window-size=1920x1480"));
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
loginToEnvironment();
}
}
public class LoginServiceTest extends WebDriverSettings
{
private LoginModal loginModal;
private AccountApi accountApi;
private Credentials credentials;
#BeforeEach
public void setUp()
{
super.setUp();
credentials = new SignUp();
accountApi = new AccountApi(credentials);
accountApi.createAccount();
loginModal = new HomePage(driver).acceptCookies().clickOnMyAccountTab().switchToLoginTab();
}
#Test
public void shouldSuccessfullyLogin()
{
try
{
accountApi.createAccount();
assertFalse(loginModal.login(credentials).getMyAccountName().getText().isEmpty());
} catch (Exception e)
{
try
{
File screenshotFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshotFile, new File("path"));
} catch (IOException ioException)
{
ioException.printStackTrace();
}
accountApi.closeAccount();
}
}
}
Solution advised by Jeff
So creating Util package and adding a class that would be responsible for creating a screenshot also it would generate random name but needs to be refactored i just made it quickly to make it work
public class ScreenShotCreator {
public static void takeScreenShot(WebDriver driver) {
try {
File screenshotFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshotFile, new File(fileNameGenerator()));
} catch (IOException e) {
throw new RuntimeException("Could not make a screenshot");
}
}
// creating this for test purposes , need to use string builder instead to append it instead of adding it
private static String fileNameGenerator() {
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy-HH:mm");
String path = ".....";
return path + "screenshot" + formatter.format(new Date()) + " " + RandomStringUtils.randomAlphanumeric(10) + ".png";
}
Then before closing it down just call the created method
#AfterEach
public void tearDown() {
ScreenShotCreator.takeScreenShot(driver);
driver.manage().deleteAllCookies();
driver.close();
driver.quit();
}
The solution that worked for me was to create this extension:
package some.thing;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
public class Screenshotter implements AfterTestExecutionCallback {
private static final Logger LOG = LogManager.getLogger();
private static WebDriver driver;
public static void setDriver(WebDriver driver) {
Screenshotter.driver = driver;
}
#Override
public void afterTestExecution(ExtensionContext context) throws Exception {
if (context.getExecutionException().isPresent()) { // if the test execution has failed
String baseFileName = context.getRequiredTestClass().getSimpleName() + "-"
+ context.getRequiredTestMethod().getName()
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("-yyMMdd-HHmmss"));
File targetFile = new File("somewhere/" + baseFileName + ".png");
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
Files.copy(scrFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
targetFile.setReadable(true, false);
LOG.info("Screenshot saved to " + targetFile.toPath());
}
}
}
Then apply it to the relevant test class like so:
#ExtendWith(Screenshotter.class)
public class SomeTest {
...
#BeforeAll
public void initialize() {
...
Screenshotter.setDriver(driver);
...
}
...
}
What I would suggest is
Create a method to take a screenshot and put that in a Utils class and call it when you want to take a screenshot. This will make taking a screenshot a lot easier because all the code lives in one place and can be easily called from anywhere.
Create a tearDown() method, if you don't have one already. Looks like it would go in the WebDriverSettings class from your currently posted code. Mark it with an #AfterEach annotation and then detect a failed test case and if it failed, take a screenshot.
If you aren't sure how to do that, there's a class in JUnit 4.9 and later called TestWatcher that you can use. There are lots of examples on the web on how to use it.
I have added code snippet for further clarity.
I am using java-selenium-testNG and trying to login to a website zoho.com with 3 accounts and verifying if success. I have looked through somewhat similar issues but haven't found a solution that works in my case.
I instantiate the ChromeDriver in #BeforeMethod. Then I login to the website with first account and close the browser in my #AfterMethod.
I have to re-instantiate the browser with Driver = new ChromeDriver to login back with a new account as the instance is closed or atleast that's the feeling it gives error that the session id doesn't exists.
My issue is only the last instance of the driver is getting closed as I have driver.quit in the #AfterTest method. The other two instances remain in memory.
I have also tried using the same instance without closing the browser but in such cases the login option is not available on that particular website and my subsequent tests fail.
here is the code below for further clarification
package uk.dev.test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.*;
import io.github.bonigarcia.wdm.WebDriverManager;
import java.util.concurrent.TimeUnit;
public class zohoLogin {
WebDriver driver=null;
String winHandleBefore;
#DataProvider(name ="testData")
public Object[][] loginPasswordData()
{
return new Object[][]{
{"xxx#gmail.com",new String ("somepassword")} ,
{"yyy#gmail.com",new String ("somepassword")},
{"zzz#gmail.com",new String ("somepassword")},
};
}
#Test ( dataProvider = "testData")
public void enterUserDetails(String userEmail, String userPassword) throws InterruptedException {
driver.findElement(By.xpath("//input[#id='login_id']")).sendKeys(userEmail);
System.out.println(("Running for Test data " + userEmail));
Thread.sleep(2000);
driver.findElement(By.xpath("//button[#id='nextbtn']")).click();
Thread.sleep(2000);
System.out.println("clicked on Next");
driver.findElement(By.xpath("//input[#id='password']")).sendKeys(userPassword);
System.out.println("Entered the password");
driver.findElement(By.xpath("//button[#id='nextbtn']//span[contains(text(),'Sign in')]")).click();
System.out.println("Clicked on Signin");
Thread.sleep(2000);
}
#BeforeMethod
public void loginZoho() throws InterruptedException
{
driver = new ChromeDriver();
driver.get("https://www.zoho.com");
System.out.println("Open the browser");
driver.findElement(By.xpath("//a[#class='zh-login']")).click();
//driver.manage().timeouts().implicitlyWait(5000, TimeUnit.MILLISECONDS);
Thread.sleep(5000);
}
#AfterMethod
public void closeBrosers() throws InterruptedException {
Thread.sleep(2000);
driver.close();
System.out.println("Close the browser");
}
#BeforeTest
public void setupBrowser()
{ WebDriverManager.chromedriver().setup();
}
#AfterTest
public void tearDown()
{
driver.quit();
}
}
Attached the run results where 2 chrome driver instance can be seen.Also note the AfterMethod is not getting executed.
enter image description here
I am using driver.quit() method in selenium but facing the same issue. I think issue is related to the latest version of chromedriver.
public static void CloseDriver()
{
if (Driver != null)
{
Driver.Quit();
Driver = null;
}
}
I even tried Driver.Kill() but it resulted in closing all the browsers.
I am trying to automate an android application using Appium and Cucumber with Java.I have written the code for a functionality and it is working fine. But some times while running the script, it throws an error
org.openqa.selenium.WebDriverException: An unknown server-side error occurred while processing the command. Original err
or: Could not proxy command to remote server. Original error: Error: read ECONNRESET (WARNING: The server did not provid
e any stacktrace information)
Source code:
import com.google.common.base.Function;
import com.intel.truevr.appautomation.core.Capabilities;
import org.openqa.selenium.By;
import io.appium.java_client.MobileDriver;
import io.appium.java_client.MobileElement;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.openqa.selenium.support.ui.Wait;
import java.util.List;
import io.appium.java_client.TouchAction;
public class C754L2D {
Capabilities c = new Capabilities();
MobileDriver driver = c.getDefaultCapabilities();
Wait wait = new Wait() {
#Override
public Object until(Function isTrue) {
return null;
}
};
#Given("^User taps the toggle button in the live 2D video playing screen$")
public void user_taps_toggle_button() throws Exception {
MobileElement allow = (MobileElement) driver.findElement(By.id("com.android.packageinstaller:id/permission_allow_button"));
allow.click();
List<MobileElement> list = driver.findElements(By.id("android:id/text1"));
for(MobileElement ele :list) {
String text = ele.getText();
if(text.equals("Live")){
ele.click();
break;
}
}
MobileElement panoramicButton = (MobileElement) driver.findElement(By.id("com.jackalopelite.simplecontainer:id/rl_select_2d"));
panoramicButton.click();
MobileElement Screen= (MobileElement) driver.findElement(By.className("android.view.View"));
TouchAction ta = new TouchAction(driver);
ta.tap(Screen, 531, 357).perform();
MobileElement toggleButton = (MobileElement) driver.findElement(By.id("com.jackalopelite.simplecontainer:id/fab_player_switch_mode"));
toggleButton.click();
}
#When("^Taps back button in the transition screen$")
public void taps_back_button() throws InterruptedException {
Thread.sleep(1000);
MobileElement backButton = (MobileElement) driver.findElement(By.id("com.jackalopelite.simplecontainer:id/iv_cardboard_back"));
backButton.click();
}
#Then("^The transition screen should dismiss and user should be navigated back to 2d live video playing screen$")
public void dismiss_transition_screen() {
try{
MobileElement cameraAngleSelectionButton = (MobileElement) driver.findElement(By.id("com.jackalopelite.simplecontainer:id/rl_player_switch_camera_parent"));
if(cameraAngleSelectionButton != null) {
System.out.println("The transition screen is dismissed and user is navigated back to 2d live video playing screen");
}
}catch(Exception e){
System.out.println("The transition screen is not dismissed and user is not navigated back to 2d live video playing screen");
}
//driver.quit();
}
}
This error gets cleared and the script works fine when I close the emulator and open it again. Can anybody help me in this?
Hey please then kill all simulator programmatically after executing testcase. Below code might help you.
/**
* Stop Simulator
*/
public void stopSimulator() {
try {
Runtime.getRuntime().exec("killall \"iOS Simulator\"");
} catch (IOException e) {
//e.printStackTrace();
}
try {
Runtime.getRuntime().exec("killall Simulator");
} catch (IOException e) {
//e.printStackTrace();
}
}
If you are openning a specific simulator you can specify this in above code.
For android simulator please use
Runtime.getRuntime().exec("adb emu kill");
There's a massive amount of postings on this topic, but for some reason, I've found little relating to Chrome (it seems the support was recently added for headless). The tests work running locally with a browser.
Is it possible to trigger an Xvfb display from Java so I can manage everything in one place? I'd rather not have to do:
Xvfb :1 -screen 0 1024x768x24 &
Via the command line. It'd be useful to run a display, then shut it down.
SetEnvironmentProperty to ChromeDriver programatically is what I found to be the solution.
The problem? I can't get it to work on an Ubuntu machine.
The error I receive is:
/home/ubuntu/myproject/conf/chromedriver: 1: Syntax error: Unterminated quoted string
The test class I'm using:
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import play.Logger;
import utils.LocalInfo;
import com.google.common.collect.ImmutableMap;
public class TestCI {
private WebDriver driver;
#SuppressWarnings("deprecation")
public TestCI(String url) {
if (!LocalInfo.isEC2()) {
Logger.info("Running tests by opening a browser...");
System.setProperty("webdriver.chrome.driver", "conf/chromedriver");
setWebDriver(new ChromeDriver());
} else {
Logger.info("Running tests headlessly...");
String xPort = System.getProperty("Importal.xvfb.id", ":1");
ChromeDriverService service = new ChromeDriverService.Builder()
.usingChromeDriverExecutable(new File("conf/chromedriver"))
.usingAnyFreePort()
.withEnvironment(ImmutableMap.of("DISPLAY", xPort)).build();
setWebDriver(new ChromeDriver(service));
}
getWebDriver().get("http://www.google.com");
try {
someUITest();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
getWebDriver().close();
}
public WebDriver getWebDriver() {
return driver;
}
public void setWebDriver(ChromeDriver driver) {
this.driver = driver;
}
public void someUITest() throws Exception {
getWebDriver().findElement(By.name("q"));
}
}
I switched to the chromedriver for linux and it got rid of the unterminated quoted string error http://code.google.com/p/chromedriver/downloads/list