I built an automation framewoek using maven, java, testng, selenium. As for now I am running my tests sequential and I would like to run them in parallel, however each time I try to run them in parallel there are several browsers that opens (like intended to) but I pay attention that only one window get the actions and other one opens (navigate to the url needed, but no action is being done beside it), I am using threads in order to initialize my webdriver and that they won't intefere each other in doing the actions.
This is my BaseTest class where I declare my webdriver and init it:
public class BaseUiTest extends BaseApiTest {
private static final Browser BROWSER = Browser.valueOf(EnvConf.getProperty("ui.browser.type"));
protected DriverWrapper driver;
protected LoginPage loginPage;
protected TopBar topBar;
protected CmsPage cmsPage;
@BeforeClass(alwaysRun = true)
public final void BaseUiSetup(ITestContext context) throws IOException {
driver = DriverWrapper.open(BROWSER, TEST_OUTPUT_FOLDER);
DriverFactory.getInstance().setDriver(driver);
driver = DriverFactory.getInstance().getDriver();
System.out.println("HEREREREREFSLKFSKJHFKJSHKJFSHKJFSHKJFSHKJFSHKJ");
loginPage = new LoginPage(driver);
cmsPage = new CmsPage(driver);
}
@AfterClass(alwaysRun = true)
public final void baseTeardown() {
Date testEndTime = new Date();
if (driver != null) {
printBrowserLog();
DriverFactory.getInstance().removeDriver();
}
Log.i("testEndTime=[%s]", testEndTime);
}
}
My DriverWrapper class only wrap the traditional WebDriver interface in this manner:
public class DriverWrapper implements WebDriver {
private final WebDriver driver;
private final static Logger Log = Logger.getLogger(DriverWrapper.class.getName());
private static final Duration WAIT_ELEMENT_TIMEOUT = new Duration(EnvConf.getAsInteger("ui.locator.timeout.sec"), TimeUnit.SECONDS);
private DriverWrapper(WebDriver driver){
this.driver = driver;
}
public static DriverWrapper open(Browser browser, File downloadsFolder) {
Log.info(String.format("Starting new %s browser driver", browser));
switch (browser) {
case FIREFOX:
return createFireFoxInst();
case CHROME:
return createChromeInst(downloadsFolder);
default:
throw new IllegalArgumentException("'" + browser + "'no such browser type");
}
}
private static DriverWrapper createChromeInst(File downloadsFolder){
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.setHeadless(EnvConf.getAsBoolean("selenium.headless"));
options.setAcceptInsecureCerts(true);
options.addArguments("--lang=" + EnvConf.getProperty("selenium.locale"));
LoggingPreferences logPrefs = new LoggingPreferences();
logPrefs.enable(LogType.BROWSER, Level.SEVERE);
options.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);
options.addArguments("--window-size=" + EnvConf.getProperty("selenium.window_size"));
ChromeDriverService service = ChromeDriverService.createDefaultService();
ChromeDriver driver = new ChromeDriver(service, options);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//enabling downloading resources when driver is headless
enableHeadlessDownload(service, driver, downloadsFolder);
return new DriverWrapper(driver);
}
private static void enableHeadlessDownload(ChromeDriverService service, ChromeDriver driver, File downloadsFolder){
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
Map<String, Object> commandParams = new HashMap<>();
commandParams.put("cmd", "Page.setDownloadBehavior");
Map<String, String> params = new HashMap<>();
params.put("behavior", "allow");
params.put("downloadPath", downloadsFolder.getAbsolutePath());
commandParams.put("params", params);
ObjectMapper objectMapper = new ObjectMapper();
String command = objectMapper.writeValueAsString(commandParams);
String u = service.getUrl().toString() + "/session/" + driver.getSessionId() + "/chromium/send_command";
HttpPost request = new HttpPost(u);
request.addHeader("content-type", "application/json");
request.setEntity(new StringEntity(command));
CloseableHttpResponse response = httpClient.execute(request);
Log.info(String.format("enable download, status code=[%d]", response.getCode()));
}catch (Exception e){
Log.error("failed to send command=[age.setDownloadBehavior] to chrome server");
Log.error(e.getMessage());
}
}
}
This is my DriverFactory class (where all the magic happens and where I defined my webdriver threads):
public class DriverFactory {
private DriverFactory() {}
private static DriverFactory instance = new DriverFactory();
public static DriverFactory getInstance() {
return instance;
}
ThreadLocal<DriverWrapper> driver = new ThreadLocal<>(); //thread local driver object for webdriver
public DriverWrapper getDriver() {
return driver.get();
}
public void setDriver(DriverWrapper driverParam){ //call this method to set the driver object
driver.set(driverParam);
}
public void removeDriver(){
driver.get().quit();
driver.remove();
}
}
And this is my testng.xml file:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Automation_Suite" parallel="tests" thread-count="4">
<test name="Critical tests to run after DEV deploy build">
<groups>
<run>
<include name="critical"/>
</run>
</groups>
<classes>
<class name="com.hackeruso.automation.ui.cms.categories.CategoriesTest"/>
</classes>
</test>
<test name="Critical tests to run after DEV deploy build2">
<groups>
<run>
<include name="critical"/>
</run>
</groups>
<classes>
<class name="com.hackeruso.automation.ui.cms.content_manager.ContentManagerPresentationTest"/>
</classes>
</test>
<test name="Critical tests to run after DEV deploy build3">
<groups>
<run>
<include name="critical"/>
</run>
</groups>
<classes>
<class name="com.hackeruso.automation.ui.cms.cyberpedia.TermsTest"/>
</classes>
</test>
<test name="Critical tests to run after DEV deploy build4">
<groups>
<run>
<include name="critical"/>
</run>
</groups>
<classes>
<class name="com.hackeruso.automation.ui.cms.institutions.ClassesTest"/>
</classes>
</test>
</suite>
And this is the profiles section in my pom.xml file that defines this profile(critical tests):
<profiles>
<profile>
<id>critical</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>critical_tests.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
This is a test class for example:
public class ContentManagerPresentationTest extends BaseUiTest {
private static final String PREVIEW_IMAGE_PATH = "/automation-tests/src/test/resources/images/lion.png";
private static final String PPT_FILE_PATH = "/automation-tests/src/test/resources/ppt/Google_Adword_Project.pptx";
private static final String NOT_EXIST_PRESENTATION_NAME = "Not Exist";
private ContentManagerPresentationsCMSPage contentManagerPresentationsCMSPage;
private VideosNPresentationsRow row;
@BeforeMethod(alwaysRun = true)
public void setUpMethod(){
adminSignIn();
topBar.clickItem(TopNavBarItem.CMS);
contentManagerPresentationsCMSPage = cmsPage.selectItemSidePanelDropDownMenu(SidePanelDropDownMenuOptions.CONTENT_MANAGER, "presentations");
Assert.assertTrue(contentManagerPresentationsCMSPage.verifyElement());
}
@AfterMethod(alwaysRun = true)
public void tearDownMethod(){
cmsPage.clickLogoutButtonAndVerify();
}
@Test(priority = 10, dataProvider = "cancelUploadPresentationsProvider", description = "Cancel upload a new presentation")
public void cancelUploadNewPresentation(String name, String desc, String previewImgPath, String pptFilePath, boolean toCreate) throws FileNotFoundException {
contentManagerPresentationsCMSPage
.uploadNewPresentationOrVideo(name, desc, previewImgPath, pptFilePath, toCreate);
Assert.assertTrue(contentManagerPresentationsCMSPage.verifyElement(), "Expected to be on presentation main page");
T_Logger.info("cancelling and returning to main presentation page is successful!");
}
@DataProvider(name = "cancelUploadPresentationsProvider")
public Object[][] cancelUploadPresentationsProvider(){
return new Object[][]{
{"Automation Test", "Automation Desc",
PREVIEW_IMAGE_PATH,
PPT_FILE_PATH,
false}
};
}
@Test(priority = 20, description = "Negative test for non exist presentation in the table")
public void verifyNonExistPresentationInTable(){
row = contentManagerPresentationsCMSPage.findRowByVideoName(NOT_EXIST_PRESENTATION_NAME);
Assert.assertNull(row);//, String.format("Row should be null, instead we got =[%s]", row.toString()));
T_Logger.info("Verification of not exist row in the table is successful");
}
@Test(priority = 25, dataProvider = "validationFieldsProvider", description = "Verify mandatory field requirements are fulfilled")
public void verifyMandatoryFieldsPresentation(String name, String desc, String imagePreviewPath,
String pptFilePath, boolean toCreate, int msgNumber, String expectedMsg) throws FileNotFoundException {
contentManagerPresentationsCMSPage
.uploadNewPresentationOrVideo(name, desc,
imagePreviewPath,
pptFilePath,
toCreate);
Assert.assertEquals(contentManagerPresentationsCMSPage.getActualErrorMsg(msgNumber), expectedMsg,
String.format("Expected error message=[%s] is not displayed as expected, instead actual message=[%s]",
expectedMsg, contentManagerPresentationsCMSPage.getActualErrorMsg(msgNumber)));
contentManagerPresentationsCMSPage.clickCreateOrCancel(false);
T_Logger.info("Verification of mandatory fields is successful");
}
@DataProvider(name = "validationFieldsProvider")
public Object[][] validationFieldsProvider(){
return new Object[][] {
{"", "Automation Desc", PREVIEW_IMAGE_PATH, PPT_FILE_PATH, true, 1, "Enter Presentation name"},
{"Automation Test", "Automation Desc", "", PPT_FILE_PATH, true, 2, "Preview Image is required"},
{"Automation Test", "Automation Desc", PREVIEW_IMAGE_PATH, "", true, 3, "Presentation file is required"}
};
}
@Test(priority = 30, dataProvider = "addNewPresentationsProvider", description = "Add new presentation",groups = {"critical"})
public void addNewPresentationAndVerify(String name, String desc, String previewImgPath, String pptFilePath, boolean toCreate) throws FileNotFoundException {
contentManagerPresentationsCMSPage
.uploadNewPresentationOrVideo(name, desc, previewImgPath, pptFilePath, toCreate);
row = contentManagerPresentationsCMSPage.findRowByVideoName(name);
Assert.assertEquals(row.getNameTxt(), name, String.format("Actual name is =[%s] not as expected", row.getNameTxt()));
}
@DataProvider(name = "addNewPresentationsProvider")
public Object[][] addNewPresentationsProvider(){
return new Object[][]{
{"Automation Test", "Automation Desc", PREVIEW_IMAGE_PATH, PPT_FILE_PATH, true}
};
}
@Test(priority = 35, dataProvider = "caseSensitiveProvider", description = "Validation existence of presentation - case sensitive")
public void searchTablePresentationsCaseSensitive(String pptName){
row = contentManagerPresentationsCMSPage.findRowByVideoName(pptName);
Assert.assertNotNull(row);
}
@DataProvider(name = "caseSensitiveProvider")
public Object[][] caseSensitiveProvider(){
return new Object[][] {
{"Automation Test"},
{"AUTOMATION TEST"}
};
}
}
The problem: when I run mvn test -Pcritical
there are 4 chrome browsers which opens but the actions occur only in one browser (although I defined and manage my webdrivers as threads to handle each one in his own thread), what am I missing?