How to restart browser after test when using data providers - java

Im currently using a Data Provider to enter numerous different users, but when the tests ends then the previous user is still logged in, how do make the bowser reset after each run? Heres my code:
public class login_from_login_page extends ConditionsWebDriverFactory {
public static final int TEST_CASE_PASSED_STATUS = 1;
public static final int TEST_CASE_FAILED_STATUS = 5;
#Test(dataProviderClass = Data.DataProviders.class, dataProvider = "customer")
public void LoginActionTest (String pass, String email, String user) throws Exception{
Header header = new Header();
header.guest_select_login();
Pages.Login login = new Pages.Login();
login.LoginAction(pass, email, user);
//TestRail.addResultForTestCase("16870",TEST_CASE_PASSED_STATUS," ");
//TestRail.addResultForTestCase("16874",TEST_CASE_PASSED_STATUS," ");
//TestRail.addResultForTestCase("17199",TEST_CASE_PASSED_STATUS," ");
}
}
I have a Webdriverfactory class that is extended from my test class here but its doesn't seem to be creating a new instance, im always still logged in when it restarts using the new DataProvider information.
#Listeners({ScreenShotOnFailListener.class})
public class ConditionsWebDriverFactory {
#BeforeClass
public void beforeTest() {
Drivers.startBrowser(true);
Drivers.getDriver().manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
}
#AfterClass (alwaysRun = true)
public void afterTest() {
Drivers.finishBrowser();
}
}

Start your test with initialization before test execution:
#BeforeMethod
void setupTest() {
WebDriver driver = new ChromDriver();
// method code here
}
Alternatively initialize your page object with new driver instance:
Pages.Login login = new Pages.Login(new ChromDriver());
Another alternative:
#Test
void seleniumTest() {
// Test code here
login.getDriver().manage().deleteAllCookies();
login.getDriver().navigate.refresh();
}

You can add after method, if you use testng:
#AfterMethod
void deleteCoockies() {
Drivers.getDriver().manage().deleteAllCookies();
Drivers.getDriver().get ("homePageUrl");
}

Related

Parallel run of Selenium tests (uses ThreadLocal) results in orphaned browsers being opened

I use ThreadLocal for thread safety and run the tests in parallel using Maven failsafe and JUnit. I am running two tests from two feature files to test parallel running.
But I always have the first browser blank. Then the subsequent ones are fine and the tests pass. If I run sequentially, there isn’t any issue.
HookStep class:
public class HookStep {
#Before()
public void beginTest() {
WebDriverFactory.setDriver(Props.getValue("browser.name"));
}
#After()
public void stopTest(Scenario scenario) {
switch (environment) {
case "local":
case "aws": {
if (scenario.isFailed()) {
Screenshots.Shot shot = new Screenshots(Screenshots.CONTEXT_TEST_FAIL)
.takeShot(scenario.getName() + formCounter.getAndIncrement() + "");
scenario.embed(shot.getContent(), "image/png", "Error - ");
}
WebDriverFactory.closeBrowser();
}
}
}
WebDriverFactory class:
public class WebDriverFactory {
private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
public static synchronized void setDriver(String browser) {
switch (browser) {
case "chrome":
driver = ThreadLocal.withInitial(() -> {
WebDriverManager.chromedriver().setup();
return new ChromeDriver(BrowserOptions.getChromeOptions());
});
prepareBrowser();
break;
case "fireFox":
driver = ThreadLocal.withInitial(() -> {
WebDriverManager.firefoxdriver().setup();
return new FirefoxDriver(BrowserOptions.getFirefoxOptions());
});
break;
default:
throw new IllegalStateException("Unexpected value: " + browser);
}
}
private static void prepareBrowser() {
getDriver().manage().window().maximize();
getDriver().manage().deleteAllCookies();
getDriver().manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
getDriver().manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
}
public static synchronized WebDriver getDriver() {
return driver.get();
}
public static void closeBrowser() {
getDriver().quit();
}
}
The StepDef class:
public class SampleStepDef {
private final WorldHelper helper;
public SampleStepDef(WorldHelper helper) {
this.helper = helper;
}
#Given("I click on the URL")
public void iClickOnTheURL() {
helper.getSamplePage().navigateToSite();
}
}
public class WorldHelper {
WebDriverFactory webDriverFactory = new WebDriverFactory();
protected WebDriver webDriver = webDriverFactory.getDriver();
private BasePage basePage;
private SamplePage samplePage;
public SamplePage getSamplePage() {
if(samplePage != null)
return samplePage;
samplePage = PageFactory.initElements(webDriver, SamplePage.class);
return samplePage;
}
}
public class SamplePage extends BasePage {
public SamplePage(WebDriver webDriver) {
super(webDriver);
}
public void navigateToSite() {
webDriver.get("https://www.bbc.co.uk");
webDriver.findElement(By.xpath("//a[contains(text(),\'News\')]")).click();
}
}
public class BasePage extends WorldHelper {
public BasePage(WebDriver driver) {
this.webDriver = driver;
}
}
How can I fix this problem?
I noticed multiple problems associated with your code.
You are making use of ThreadLocal.withInitial(). Ideally speaking this should have been defined when you are instantiating the driver thread local static variable.
So instead of
private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
it should have been
private static final ThreadLocal<WebDriver> driver = ThreadLocal.withInitial(() -> {
return null; //Your supplier goes here.
});
There's a clear mess up in your inheritance hierarchy (there's a very good chance that you were trying to create a simple example and perhaps have omitted out the details behind the layers of inheritance), but it wasn't clear as to why does all your page object classes extend WorldHelper
You are having multiple statements at the class level such as this. The problem with these field level initialisations is that they get invoked when the object is constructed. So if the object is being constructed in a different thread, then you run into the problem of the WebDriver initialisation being triggered for that thread. End result: You have a lot of ghost browser instances that keep getting opened up, but no selenium actions are directed to them.
private final WebDriver driver = WebDriverFactory.getDriver();
When working with ThreadLocal variants of WebDriver management, you need to make sure that your calls are always from within your step definitions and never from the constructor or from class level field initialisations such as above.
Here are the list of fixes that you need to do.
Remove all occurrences of private final WebDriver driver = WebDriverFactory.getDriver(); in your code. They are not needed.
Refactor your WebDriverFactory class to look like below (For brevity I have removed off all the commented out code)
public class WebDriverFactory {
private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
public static void setDriver(String browser) {
RemoteWebDriver rwd;
switch (browser) {
case "chrome":
WebDriverManager.chromedriver().setup();
rwd = new ChromeDriver(BrowserOptions.getChromeOptions());
break;
case "fireFox":
WebDriverManager.firefoxdriver().setup();
rwd = new FirefoxDriver(BrowserOptions.getFirefoxOptions());
break;
default:
throw new IllegalStateException("Unexpected value: " + browser);
}
driver.set(Objects.requireNonNull(rwd));
prepareBrowser();
}
private static void prepareBrowser(){
getDriver().manage().window().maximize();
getDriver().manage().deleteAllCookies();
getDriver().manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
getDriver().manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
}
public static WebDriver getDriver(){
return Objects.requireNonNull(driver.get());
}
public static void closeBrowser() {
getDriver().manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
getDriver().close();
getDriver().quit();
}
}
Since all your page classes seem to be extending from WorldHelper, add a getter method such as below in it (or) ensure that no where in any of your page classes you have a WebDriver field. Whenever you need to get hold of the WebDriver instance, you should do it directly via WebDriverFactory.getDriver() (or) via the getter method such as below in your WorldHelper or whatever base class you are creating.
protected WebDriver getDriver() {
return WebDriverFactory.getDriver();
}
Once you have fixed the afore-mentioned problems, you should be good and shouldn't see any blank browser windows open up.
Note: Please clean up your project on GitHub. I noticed some cloud service provider credentials in it (it could be real credentials or could be fake. I wouldn't know.)
I haven't used webDriverFactory, but I'd try calling driver.set() in the factory class, as in this tutorial:
http://makeseleniumeasy.com/2020/05/27/threadlocal-static-webdriver-for-parallel-execution/

How to separate page objects from code logic in Selenium- java

I am learning and trying to separate locators from actual code in selenium. I have already separated them but I need guidance on more optimization, how can I optimize the code more? Is the Page Object design model used to store only locators? Or can we store their methods too. Can someone please explain with reference to below code?
Link: https://www.goibibo.com/
Actual code with Logic(TC_01Test.java) and Base.java class initializes driver
public class TC_01Test extends Base {
WebDriver driver;
#BeforeTest
public void initialize() throws IOException {
driver = initializeDriver();
}
// Sign In functionality
#Test
public void SignIn() throws InterruptedException {
TC_01 tc02 = new TC_01(driver);
tc02.siginLink().click();
System.out.println(driver.getWindowHandle());
driver.switchTo().frame("authiframe");
System.out.println(driver.getWindowHandle());
tc02.mobileNumber().sendKeys(prop.getProperty("phoneNumber"));
System.out.println("number entered");
tc02.submitButton().click();
System.out.println("button clicked");
driver.switchTo().defaultContent();
System.out.println(driver.getWindowHandle());
tc02.closePopup().click();
}
// SignUp functionality
#Test
public void SignOut() {
TC_01 tc01 = new TC_01(driver);
tc01.sigupLink().click();
driver.switchTo().frame("authiframe");
tc01.mobileNumber().sendKeys(prop.getProperty("phoneNumber"));
tc01.submitButton().click();
driver.switchTo().defaultContent();
tc01.closePopup().click();
}
#AfterTest
public void closeBrowser() {
driver = tearDown();
}
}
Below is the code for Page Object(TC_01.java) created for above test case.
public class TC_01 {
WebDriver driver;
public TC_01(WebDriver driver) {
this.driver = driver;
}
// driver.findElement(By.xpath("//a[#id='get_sign_in']"))
// mobileNumber= driver.findElement(By.xpath("//input[#id='authMobile']")
// driver.findElement(By.id("mobileSubmitBtn"))
// driver.findElement(By.xpath("//div[#class='popContent']/a"))
By signinLink = By.xpath("//a[#id='get_sign_in']");
By signupLink = By.xpath("//a[#id='get_sign_up']");
By mobileNumber = By.xpath("//input[#id='authMobile']");
By submitButton = By.id("mobileSubmitBtn");
By closePopup = By.xpath("//div[#class='popContent']/a");
public WebElement siginLink() {
return driver.findElement(signinLink);
}
public WebElement sigupLink() {
return driver.findElement(signupLink);
}
public WebElement mobileNumber() {
return driver.findElement(mobileNumber);
}
public WebElement submitButton() {
return driver.findElement(submitButton);
}
public WebElement closePopup() {
return driver.findElement(closePopup);
}
}
Answering on your question - yes, you can store methods in PO classes as well. Furthermore, it's a good practice.
Regarding your code optimization - it's better to express business behavior instead of granular technical actions. Also, instead of returning WebElement methods and then perform actions (click, sendKeys etc) in the Test class you can simply perform such actions in PO class.
Check the code below.
public void enterFirstName() {
driver.findElement(firstName).sendKeys("abc");
}
public void enterLastName() {
driver.findElement(lastName).sendKeys("qwerty");
}
public void pressSubmitButton() {
driver.findElement(submitButton).click();
}
// instead of invocation all of these methods above in test class you can simply do this:
public void loginWithValidCredentials(String firstNameValue, String lastNameValue) {
driver.findElement(firstName).sendKeys(firstNameValue);
driver.findElement(lastName).sendKeys(lastNameValue);
driver.findElement(submitButton).click();
}
// Thus your test will look like:
#Test
public void loginTest() {
POclass po = new POclass();
po.loginWithValidCredentials("yourName", "yourNameABC");
// some assert() methods...
}
This is much simplier.
BTW, it's useful to know and use PageFactory concept - https://www.guru99.com/page-object-model-pom-page-factory-in-selenium-ultimate-guide.html
P.S. - read about "Chain of responsibilities" pattern, but in case you are strong in Java, because this is a quite advanced topic.

How do I write this test case?

I am currently doing a small project on spring-mvc in my backend and I am trying to create tests for my converters and engines. Below is my BookmarkEngine.java file
#Service
public class BookmarkEngine implements IBookmarkEngine{
private static final String URL_PREFIX = "http://";
#Override
public String getFullUrl(String url) {
if(!url.startsWith(URL_PREFIX))
{
return URL_PREFIX + url;
}
return url;
}
}
How would I go about writing a test for this?
Here is my BookmarkEngineTest:
public class BookmarkEngineTest {
IBookmarkEngine bookmarkEngine = new BookmarkEngine();
private ViewBookmark defaultBookmark;
#Before
public void setUp() throws Exception {
defaultBookmark = new ViewBookmark();
defaultBookmark.setBookmarkId(1L);
defaultBookmark.setTitle("A sample bookmark");
defaultBookmark.setUrl("This is a sample bookmark.");
defaultBookmark.setAuthor(".");
defaultBookmark.setLastUpdated(1497812309081L);
}
#Test
public void getFullUrl() {
String result = bookmarkEngine.getFullUrl(defaultBookmark.getUrl());
assertThat(result.length(), is(defaultBookmark.getUrl().length()));
}
}
That certain test in getFullUrl() does not run, but how can I can make it work?
You can make a test to see if the strings will match such as
#Test
public void getFullUrl() {
String testurl = "facebook.com";
String testurl2 = "http://facebook.com";
assertEquals(bookmarkEngine.getFullUrl(testurl),"http://facebook.com");
assertEquals(bookmarkEngine.getFullUrl(testurl2),"http://facebook.com");
}

How to call test method by creating object in testNG

I'm using POM framework and managed the code in following way :
This is My InviteFriendPage
public class InviteFriends
{
#FindBy(xpath ="//li/a[normalize-space()='Invite Friends']")
public WebElement inviteFriendsLink;
#FindBy(id = "divLoader")
public WebElement loader;
#FindBy(xpath = "//input[#name='lstInviteFriendsModel[1].FriendName']")
public List<WebElement> friendName;
#FindBy(xpath = "//input[#name='lstInviteFriendsModel[1].FriendMobile']")
public WebElement friendNumber;
WebDriver driver;
public InviteFriends(WebDriver driver)
{
PageFactory.initElements(driver, this);
this.driver=driver;
}
public void inviteFriend(String friendName, String friendMobile)
{
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("arguments[0].click();", inviteFriendsLink);
for(int i=1;i<=3;i++)
{
driver.findElement(By.xpath("//input[#name='lstInviteFriendsModel["+i+"].FriendName']")).sendKeys(friendName);
driver.findElement(By.xpath("//input[#name='lstInviteFriendsModel["+i+"].FriendMobile']")).sendKeys(friendMobile);
}
}
}
This is my Executor Class from where I'm calling all the pages by creating object
public class MainSuitExecuter extends DriverSetup
{
#Test()
public void submitFeedback() throws InterruptedException
{
ContactUsPage conpage = new ContactUsPage(driver);
conpage.submitContactUsForm(TestDataComman.fName, TestDataComman.fEmail, TestDataComman.fMobile, TestDataComman.fType, TestDataComman.fMessage);
}
#Test()
public void login() throws IOException, InterruptedException
{
UserLogin login = new UserLogin(driver);
ReadExcel read = new ReadExcel();
String uname = read.getCellData(1, 0);
String passwd = read.getCellData(1, 1);
login.doLogin(uname, passwd);
}
#Test()
public void inviteFriend()
{
InviteFriends invitefriend = new InviteFriends(driver);
invitefriend.inviteFriend();
}
}
and Executing the MainSuitExecuter class from testing.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="MyKart">
<test name="Functional_Test">
<parameter name="browser" value="chrome" />
<classes>
<class name="com.commonutils.DriverSetup"/>
<class name="com.testexecuter.MainSuitExecuter"/>
</classes>
</test>
</suite>
The Problem is, For friend Invitation minimum 3 friends details(friendname and number) mandatory. So i'm using DataProvider of TestNG for that. But not getting the clear idea where i need to use in My code as i have structure as mentioned above.
I have tried it in InviteFriend.java class Like :
#Test(getData)
public void inviteFriend(String friendName, String friendMobile)
{
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("arguments[0].click();", inviteFriendsLink);
for(int i=1;i<=3;i++)
{
driver.findElement(By.xpath("//input[#name='lstInviteFriendsModel["+i+"].FriendName']")).sendKeys(friendName);
driver.findElement(By.xpath("//input[#name='lstInviteFriendsModel["+i+"].FriendMobile']")).sendKeys(friendMobile);
}
}
#DataProvider
public Object[][] getData()
{
Object[][] data = new Object[3][2];
// 1st row
data[0][0] ="A";
data[0][1] = "9442307801";
// 2nd row
data[1][0] ="B";
data[1][1] = "9887252210";
// 3rd row
data[2][0] ="C";
data[2][1] = "9925497562";
return data;
}
but no success as i have to call inviteFriend() method from MainSuitExecuter class so there i need to pass parameter.
Can anybody help me to get out from this glitch and suggest me better idea to accomplish my motive
This how you can probably do.
Create a separate Friend Class. with attribute you required, i.e. Name and mobile number
Create the object or list of object of this friends. I think list of object would be better.
Rather than using data provider, in your test create this friend object and pass it some of the method in inviteFriend class.
I think this would be cleaner approach and better to understand.
Sample code
Friend.java
public class Friend {
String name;
String mobile;
public Friend(String name, String mobile){
this.name = name;
this.mobile = mobile;
}
}
InviteFriends.java
public class InviteFriends {
public InviteFriends(WebDriver driver){
PageFactory.initElements(driver, this);
}
public void createFriendInvitation(List<Friend> friendList){
for (Friend friend: friendList) {
System.out.println(friend.mobile);
System.out.println(friend.name);
}
}
}
Your Test Class
public class TestClass {
#Test
public void testFriendInvitation(){
WebDriver driver = new FirefoxDriver();
List<Friend> friends = new ArrayList<Friend>();
friends.add(new Friend("bestfriend", "11111"));
friends.add(new Friend("newfriend", "222"));
friends.add(new Friend("oldfriend", "33333"));
InviteFriends inviteFriends = PageFactory.initElements(driver, InviteFriends.class);
inviteFriends.createFriendInvitation(friends);
driver.quit();
}
}
The code is pretty much good except one. We need a give a name to the data provider annotation and refer it as a source of input for the respectective #test method. The code below will ideally work for you,
public class MainSuitExecuter extends DriverSetup
{
#Test()
public void submitFeedback() throws InterruptedException
{
ContactUsPage conpage = new ContactUsPage(driver);
conpage.submitContactUsForm(TestDataComman.fName, TestDataComman.fEmail, TestDataComman.fMobile, TestDataComman.fType, TestDataComman.fMessage);
}
#Test()
public void login() throws IOException, InterruptedException
{
UserLogin login = new UserLogin(driver);
ReadExcel read = new ReadExcel();
String uname = read.getCellData(1, 0);
String passwd = read.getCellData(1, 1);
login.doLogin(uname, passwd);
}
#Test(dataProvider="users") //use dataprovider with name "users" as input source
public void inviteFriend(String name, String number)
{
InviteFriends invitefriend = new InviteFriends(driver);
invitefriend.inviteFriend(name, number);
}
#DataProvider(name = "users") //naming as users
public Object[][] getData()
{
Object[][] data = new Object[3][2];
// 1st row
data[0][0] ="A";
data[0][1] = "9442307801";
// 2nd row
data[1][0] ="B";
data[1][1] = "9887252210";
// 3rd row
data[2][0] ="C";
data[2][1] = "9925497562";
return data;
}
}
DataProvider becomes handy when we need to pass the data from excel sheet becomes handy. More details are available in the testng documentation.
http://testng.org/doc/documentation-main.html#parameters-dataproviders
Some tutorials for data provider implementation
http://learn-automation.com/data-driven-framework-in-selenium-webdriver/
I hope this helps you.
Thanks.

Error during converting Selenium Java project to Page Object Design Pattern

I created 4 classes also after I decided to convert my project into this design pattern. I moved my codes inside the related classes into the methods. While compiling I'm facing failures and I don't know why.
The main class
GidiyorTest.java
public class GidiyorTest {
protected WebDriver driver;
protected String baseUrl;
private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();
static GidiyorTest gittiGidiyor = new GidiyorTest();
static String generatedMail = gittiGidiyor.generateString();
static String generatedUsername = gittiGidiyor.generateString();
static RegisterPage registerPage = new RegisterPage();
static LoginPage loginPage = new LoginPage();
static SearchPage searchPage = new SearchPage();
static DiscountsPage discountsPage = new DiscountsPage();
public String generateString(){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 7; i++) {
char c = chars[random.nextInt(chars.length)];
sb.append(c);
}
String output = sb.toString();
return output;
}
#Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseUrl = "https://www.gittigidiyor.com/";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void testGidiyor() throws Exception {
registerPage.Register();
loginPage.Login();
searchPage.Search();
discountsPage.Discount();
}
#After
....
RegisterPage.java (One of the four new classes for instance sharing just one)
public class RegisterPage extends GidiyorTest {
public void Register() throws InterruptedException {
driver.get(baseUrl + "/kayit-ol");
driver.findElement(By.name("name")).clear();
driver.findElement(By.name("name")).sendKeys("murat");
driver.findElement(By.name("surname")).clear();
driver.findElement(By.name("surname")).sendKeys("yilmaz");
Thread.sleep(300);
driver.findElement(By.id("suggestion_email_input_verifier")).clear();
driver.findElement(By.id("suggestion_email_input_verifier")).sendKeys(
generatedMail + "#gmail.com");
driver.findElement(By.id("nickname")).clear();
driver.findElement(By.id("nickname")).sendKeys(generatedUsername);
Thread.sleep(300);
driver.findElement(By.name("passwd")).clear();
driver.findElement(By.name("passwd")).sendKeys("123456abc");
driver.findElement(By.name("passwd2")).clear();
driver.findElement(By.name("passwd2")).sendKeys("123456abc");
Thread.sleep(300);
driver.findElement(By.id("cepgsm")).clear();
driver.findElement(By.id("cepgsm")).sendKeys("531");
driver.findElement(By.id("cep")).clear();
driver.findElement(By.id("cep")).sendKeys("600 29 79");
Thread.sleep(1000);
driver.findElement(By.id("SubmitForm")).click();
}
}
And the error is beginning at registerPage.Register(); line. One another is java.lang.NullPointerException.
Hope you can help.
The way you're creating your PageObject is not correct. You should not extend the test, one of the main points is that the PageObject should not know anything about the test, rather just expose the services offered by the page.
On the other hand your test should hold the assertions and other test related logic.
The second wrong thing is that you should use PageFactory to instantiate your page object, so that you can take advantage of the lazy binding mechanism. So change to something like this
public class RegisterPage {
private WebDriver driver;
public RegisterPage(WebDriver driver) {
this.driver = driver;
}
// The rest of your class
}
and instantiate inside the test using PageFactory
PageFactory.initElements(driver, RegisterPage.class);
also to ease up maintainence and benefit from lazy element binding you can think about adding your elements as fields, and mark them via annotation, so they get populated by PageFactory as well e.g.
public class RegisterPage {
private WebDriver driver;
public RegisterPage(WebDriver driver) {
this.driver = driver;
}
#FindBy(name = "name")
private WebElement name;
...
}
}

Categories

Resources