Hi Community,
I hope I find some solution for this issue here, so far I have tried everything I know but still facing the same thing.I’m using appium java-client 7.6.0, testnt 7.6.1, Appium v1.22.3 with 1 ios simulator & 1 android emulator.
Issue:
What is happening is if I run only 2 tests same test file for android & ios everything seems to be working fine, but when I add more test & if one on the test finishes earlier it somehow intervene with other running test as well & closes it(when spinning up new driver session), I have used the thread-local in the Base-test class but still facing the issue.
I’m sharing my Basetest class file,TestNg.xml & one test class.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Mobile Test Automation Suite" parallel="tests" thread-count="2">
<listeners>
<listener class-name="com.qa.listeners.testListener"/>
</listeners>
<test name="iOS e2e Registration Test">
<parameter name="platformName" value="iOS"/>
<parameter name="deviceName" value="iphone12"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="15.5"></parameter>
<parameter name="udid" value="55896861-DB90-4F13-955A-F65D20F409B3"></parameter>
<parameter name="wdaLocalPort" value="8100"></parameter>
<classes>
<class name="com.qa.tests.E2ERegistrationTest"/>
</classes>
</test>
<test name="Android e2e Registration Test" >
<parameter name="platformName" value="Android"/>
<parameter name="deviceName" value="Pixel_3"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="12.0"></parameter>
<parameter name="udid" value="emulator-5554"></parameter>
<parameter name="systemPort" value="8200"></parameter>
<parameter name="mjpegServerPort" value="9000"></parameter>
<classes>
<class name="com.qa.tests.E2ERegistrationTest"/>
</classes>
</test>
<test name="iOS login Test">
<parameter name="platformName" value="iOS"/>
<parameter name="deviceName" value="iphone12"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="15.5"></parameter>
<parameter name="udid" value="55896861-DB90-4F13-955A-F65D20F409B3"></parameter>
<parameter name="wdaLocalPort" value="8101"></parameter>
<classes>
<class name="com.qa.tests.LoginTest"/>
</classes>
</test>
<test name="Android login Test">
<parameter name="platformName" value="Android"/>
<parameter name="deviceName" value="Pixel_3"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="12.0"></parameter>
<parameter name="udid" value="emulator-5554"></parameter>
<parameter name="systemPort" value="8201"></parameter>
<parameter name="mjpegServerPort" value="9001"></parameter>
<classes>
<class name="com.qa.tests.LoginTest"/>
</classes>
</test>
<test name="iOS Logout Test">
<parameter name="platformName" value="iOS"/>
<parameter name="deviceName" value="iphone12"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="15.5"></parameter>
<parameter name="udid" value="55896861-DB90-4F13-955A-F65D20F409B3"></parameter>
<parameter name="wdaLocalPort" value="8102"></parameter>
<classes>
<class name="com.qa.tests.LogoutTest"/>
</classes>
</test>
<test name="Android Logout Test">
<parameter name="platformName" value="Android"/>
<parameter name="deviceName" value="Pixel_3"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="12.0"></parameter>
<parameter name="udid" value="emulator-5554"></parameter>
<parameter name="systemPort" value="8202"></parameter>
<parameter name="mjpegServerPort" value="9002"></parameter>
<classes>
<class name="com.qa.tests.LogoutTest"/>
</classes>
</test>
<test name="iOS Today Screen Cards Test">
<parameter name="platformName" value="iOS"/>
<parameter name="deviceName" value="iphone12"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="15.5"></parameter>
<parameter name="udid" value="55896861-DB90-4F13-955A-F65D20F409B3"></parameter>
<parameter name="wdaLocalPort" value="8103"></parameter>
<classes>
<class name="com.qa.tests.TodayScreenCardsTest"/>
</classes>
</test>
<test name="Android Today Screen Cards Test">
<parameter name="platformName" value="Android"/>
<parameter name="deviceName" value="Pixel_3"/>
<parameter name="emulator" value="true"/>
<parameter name="platformVersion" value="12.0"></parameter>
<parameter name="udid" value="emulator-5554"></parameter>
<parameter name="systemPort" value="8203"></parameter>
<parameter name="mjpegServerPort" value="9003"></parameter>
<classes>
<class name="com.qa.tests.TodayScreenCardsTest"/>
</classes>
</test>
</suite>
public class BaseTest {
protected static ThreadLocal<AppiumDriver> driver = new ThreadLocal<AppiumDriver>();
protected static ThreadLocal<Properties> prop = new ThreadLocal<Properties>();
protected static ThreadLocal<HashMap<String, String>> strings = new ThreadLocal<HashMap<String, String>>();
protected static ThreadLocal<String> platform = new ThreadLocal<String>();
public Testutils utils;
public AppiumDriver getDriver() {
return driver.get();
}
public void setDriver(AppiumDriver driver2) {
driver.set(driver2);
}
public Properties getProperties() {
return prop.get();
}
public void setProperties(Properties prop2) {
prop.set(prop2);
}
public HashMap<String, String> getStrings() {
return strings.get();
}
public void setStrings(HashMap<String, String> strings2) {
strings.set(strings2);
}
public String getPlatform() {
return platform.get();
}
public void setPlatform(String Platform2) {
platform.set(Platform2);
}
public BaseTest() {
PageFactory.initElements(new AppiumFieldDecorator(getDriver(), Duration.ofSeconds(Testutils.WAIT)), this);
}
void setAllureEnvironment(String ios, String android) {
allureEnvironmentWriter(
ImmutableMap.<String, String>builder()
.put("iOS App Version:", ios)
.put("Android App Version:", android)
.put("Test Environment:", "")
.build());
}
@Parameters({"platformName", "deviceName", "emulator", "platformVersion", "udid","wdaLocalPort","systemPort","mjpegServerPort"})
@BeforeTest
public void driverInitialize(String platformName, String deviceName, String emulator, String platformVersion, String udid,@Optional("iOS Only") String wdaLocalPort,@Optional("Android Only") String systemPort,@Optional("Android Only")String mjpegServerPort) throws Exception {
setPlatform(platformName);
URL url;
InputStream inputStream = null;
InputStream stringsis = null;
Properties prop = new Properties();
AppiumDriver driver;
try {
String propFileName = "config.properties";
String xmlFilename = "Strings/Strings.xml";
inputStream = getClass().getClassLoader().getResourceAsStream(propFileName);
prop.load(inputStream);
setProperties(prop);
stringsis = getClass().getClassLoader().getResourceAsStream(xmlFilename);
utils = new Testutils();
setStrings(utils.parseStringXML(stringsis));
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability(MobileCapabilityType.PLATFORM_NAME, platformName);
caps.setCapability(MobileCapabilityType.DEVICE_NAME, deviceName);
url = new URL(prop.getProperty("AppiumURL"));
switch (platformName) {
case "Android":
caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, prop.getProperty("androidAutomationName"));
caps.setCapability("appPackage", prop.getProperty("androidAppPackage"));
caps.setCapability("appActivity", prop.getProperty("androidAppActivity"));
caps.setCapability("appWaitActivity","*");
String androidappURL = getClass().getResource(prop.getProperty("androidAppLocation")).getFile();
caps.setCapability(MobileCapabilityType.APP, androidappURL);
caps.setCapability("systemPort",systemPort);
caps.setCapability("mjpegServerPort",mjpegServerPort);
if (emulator.equalsIgnoreCase("true")) {
caps.setCapability("avd", deviceName);
caps.setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
} else {
caps.setCapability("udid", udid);
}
driver = new AndroidDriver(url, caps);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
break;
case "iOS":
caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, prop.getProperty("iOSAutomationName"));
String iOSappURL = getClass().getResource(prop.getProperty("iOSAppLocation")).getFile();
caps.setCapability("udid", udid);
caps.setCapability(MobileCapabilityType.APP, iOSappURL);
caps.setCapability("bundleId", prop.getProperty("iOSBundleId"));
caps.setCapability("autoAcceptAlerts", "true");
caps.setCapability("wdaLocalPort",wdaLocalPort);
caps.setCapability("derivedDataPath",prop.getProperty("iOSDerivedDataPath"));
driver = new IOSDriver(url, caps);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
break;
default:
throw new Exception("Invalid Platform" + platformName);
}
setDriver(driver);
setAllureEnvironment(prop.getProperty("iOSAppLocation"), prop.getProperty("androidAppLocation"));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
inputStream.close();
}
if (stringsis != null) {
stringsis.close();
}
}
}
public void waitForVisibility(MobileElement e) {
WebDriverWait wait = new WebDriverWait(getDriver(), Testutils.WAIT);
wait.until(ExpectedConditions.visibilityOf(e));
}
public void Click(MobileElement e) {
waitForVisibility(e);
e.click();
}
public void clear(MobileElement e) {
waitForVisibility(e);
e.clear();
}
public void sendKeys(MobileElement e, String txt) {
clear(e);
e.sendKeys(txt);
}
public String getAttribute(MobileElement e, String attribute) {
waitForVisibility(e);
return e.getAttribute(attribute);
}
public String getText(MobileElement e) {
waitForVisibility(e);
ElementDisplayed(e);
switch (getPlatform()) {
case "Android":
return getAttribute(e, "text");
case "iOS":
return getAttribute(e, "label");
}
return null;
}
public void ElementDisplayed(MobileElement e) {
waitForVisibility(e);
e.isDisplayed();
}
public void appReset() {
getDriver().resetApp();
}
@AfterTest(alwaysRun = true)
public void QuitDriverSession() {
if (getDriver() != null){
System.out.println("quit==="+getDriver().getSessionId());
getDriver().quit();
driver.remove();
}
}
package com.qa.tests;
import com.qa.BaseTest;
import com.qa.pages.LoginPage;
import com.qa.pages.SetReminderDayPage;
import com.qa.pages.WelcomeHomePage;
import io.qameta.allure.*;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.testng.Assert;
import org.testng.annotations.*;
import java.io.InputStream;
import java.lang.reflect.Method;
public class LoginTest extends BaseTest {
JSONObject loginUsers;
WelcomeHomePage welcomeHomePage;
LoginPage loginPage;
SetReminderDayPage setReminderDayPage;
@BeforeClass
public void LoadTestData() throws Exception {
InputStream data = null;
try {
String dataFileName = "data/Users.json";
data = getClass().getClassLoader().getResourceAsStream(dataFileName);
JSONTokener tokener = new JSONTokener(data);
loginUsers = new JSONObject(tokener);
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
if (data != null) {
data.close();
}
}
}
@BeforeMethod
public void initializePageObject(Method m) {
welcomeHomePage = new WelcomeHomePage();
}
@Feature("Login")
@Story("User enters Corrent Credentials")
@Severity(SeverityLevel.BLOCKER)
@Test(description = "Check Login with Valid Credentials")
public void validCredentials() {
appReset();
loginPage = welcomeHomePage.ClickloginLabel();
switch (getPlatform()) {
case "Android":
loginPage.enterUserName(loginUsers.getJSONObject("androidValidUser").getString("username"));
loginPage.enterPassword(loginUsers.getJSONObject("androidValidUser").getString("password"));
break;
case "iOS":
loginPage.enterUserName(loginUsers.getJSONObject("iOSValidUser").getString("username"));
loginPage.enterPassword(loginUsers.getJSONObject("iOSValidUser").getString("password"));
break;
}
setReminderDayPage = loginPage.clickLoginButton();
String actualTitle = setReminderDayPage.getTitle();
String expectedTitle = getStrings().get("reminder_day_Screen_title");
Assert.assertEquals(actualTitle, expectedTitle);
}
@Feature("Login")
@Story("User See all UI elemets visible")
@Test(description = "Check all Elements Displayed on Screen")
public void AllElementsDisplayed() {
loginPage = welcomeHomePage.ClickloginLabel();
loginPage.AllElementsDisplayed();
}
@Feature("Login")
@Story("User Enter Wrong Credentials")
@Test(description = "Check Login with Invalid Credentials")
public void invalidCredentials() {
appReset();
loginPage = welcomeHomePage.ClickloginLabel();
loginPage.enterUserName(loginUsers.getJSONObject("invalidUser").getString("username"));
loginPage.enterPassword(loginUsers.getJSONObject("invalidUser").getString("password"));
loginPage.clickLoginButton();
String actualErrText = loginPage.getErrText();
String expectedErrText = getStrings().get("login_fail_alert_text");
Assert.assertEquals(actualErrText, expectedErrText);
String actualErrTitle = loginPage.getErrTitle();
String expectedErrTitle = getStrings().get("login_fail_alert_title");
Assert.assertEquals(actualErrTitle, expectedErrTitle);
}
@Feature("Login")
@Story("User Enter Only password")
@Test(description = "Check Login with valid Password Only")
public void validPasswordOnly() {
appReset();
loginPage = welcomeHomePage.ClickloginLabel();
loginPage.enterPassword(loginUsers.getJSONObject("androidValidUser").getString("password"));
loginPage.clickLoginButton();
String actualEmailerrotext = loginPage.getWrongEmailErrorText();
String expectedEmailerrorText = getStrings().get("login_fail_pass_only");
Assert.assertEquals(actualEmailerrotext, expectedEmailerrorText);
}
}
Please any help on this will be greatly appreciated, I’m stuck on this for some time now
Regards,
Abdul