I have a test ready to be executed but it takes a long time to finish. In this test I'm feeding in csv data, so basically the whole test will run 56 times. I was wondering if there's anyway I could use multiple browser instance and divide the workload to four instance. It will save me some time. I tried to use TestNG's ThreadPoolSize but it's not doing what I want it to. It's using the same data for four instances of firefox. I want each browser to have it's own unique data. Please check my code and let me know what I'm missing. I really appriciate every one's help.
public class StudentPageTest {
WebDriver driver;
DesiredCapabilities capability;
WebElement element;
WebDriverWait wait;
private String baseURL;
#BeforeTest
public void setUp() throws MalformedURLException{
//capability = DesiredCapabilities.firefox();
//driver = new FirefoxDriver();
//wait = new WebDriverWait(driver, 120);
//driver.manage().deleteAllCookies();
baseURL = "http://somewebsite.com";
}
#SuppressWarnings("resource")
#Test(threadPoolSize = 4)
public void StudentPortalTest() throws InterruptedException, IOException{
driver = new FirefoxDriver();
wait = new WebDriverWait(driver, 120);
driver.manage().deleteAllCookies();
String studentId = "studentID.csv";
BufferedReader br = null;
String line = "";
String cvsSplitBy = ",";
br = new BufferedReader(new FileReader(studentId));
while ((line = br.readLine()) != null) {
String[] student_id = line.split(cvsSplitBy);
//Logging in Student Portal---------------------------------------------------------------------------------------------------------------|
for (int i = 0; i < student_id.length; i++) {
driver.get(baseURL+student_id[i]);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.findElement(By.cssSelector(".logo>img")).isDisplayed();
driver.findElement(By.cssSelector("#UserName")).sendKeys("SecretUserName");
driver.findElement(By.cssSelector("#Password")).sendKeys("EvenMoreSecretPassword");
driver.findElement(By.cssSelector(".submitBtn")).click();
driver.manage().timeouts().implicitlyWait(120, TimeUnit.SECONDS);
Thread.sleep(4000);
...............and the test goes on below...................
}
#AfterTest
public void tearDown(){
driver.quit();
}
}
You can let the Selenium grid do the task of distribution. Use TestNG to run your cases in parallel using dataprovider. Use a dataprovider to read your csv and pass one data to one #Test.
Set dataprovider thread count in your suite xml and make sure you set #DataProvider(parallel=true)
Going to your code, replace your call of instantiating a firefoxdriver to remotewebdriver to use the grid. Make sure your driver is not at class level but is a threadlocal : threadlocal<driver>.
I was trying many different ways to achieve the same thing you are trying to do. After a lot of trial and error I finally came across a solution that worked for me.
You need Selenium Grid You can then set up a few nodes to run your different browsers from
You need TestNG like you have been using but instead of trying to use threads, you will use an .xml file to pass in parameters to your test which will run the one test over and over in parallel.
If you read this document carefully and follow the steps, you should be able to achieve the same result
#Test(threadPoolSize = 4, invocationCount = 4)
Related
I am beginner with selenium tests. I wrote this code and it works, but I need to loop this test with another csv line.
I spent almost 10 hours trying to do this.
Scenario of what I am trying to do:
The web browser is opening go to url
login with data from CSV file from first line
Driver is restarting and do the same but with data from second line from csv file.
I also tried to restart test with aftermethod/afterclass but it's not working.
public class CSVdataread {
private WebDriver driver;
String baseUrl = "URL";
String CSV_file = "C:\\Users\\xxxxxxxxxxx\\Desktop\\TestData.csv";
#BeforeClass
public void openBrowser() {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\xxxxxxxxxxxx\\Desktop\\webdriver\\chromedriver.exe");
driver = new ChromeDriver();
driver.navigate().to("URL");
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void verify_Search() throws InterruptedException, IOException {
CSVReader reader = new CSVReader(new FileReader(CSV_file));
String[] cell;
while((cell = reader.readNext()) != null)
for (int i = 0; i < 1; i++) {
String name = cell[i];
String email = cell[i + 1];
String baseUrl = "http://xxxxx.xxx/xxxx/";
driver.findElement(By.xpath("//input[#id='useridFormField-inputEl']")).sendKeys(name);
driver.findElement(By.xpath("//input[#id='userpasswordFormField-inputEl']")).sendKeys(email);
{
driver.quit();
}
}
}
}
JUnit 4 solution. This one is going to be huge...
First, let's start off with CSVReader and some good practices plus code readability. In your test, you read CSV data and use them in your tests. It's not the test's responsibility to read data. The test should already have all the data provided to it. It's called DataProvider. This term is actually used in TestNG testing framework, just like #user861594 suggested.
So, you should have something to provide data to your tests. But this already Step #2. Since you know you will read data row-by-row from CSV file, you should create a proper class to read the data from CSV.
Here's an example:
public class CSVReader {
private static final String DEFAULT_SEPARATOR = ",";
private BufferedReader reader;
private List<String> lines;
public CSVReader(File file) throws FileNotFoundException {
this.reader = new BufferedReader(new FileReader(file));
lines = this.reader.lines().collect(Collectors.toList());
}
public String[] getRow(int rowNumber) {
return lines.get(rowNumber).split(DEFAULT_SEPARATOR);
}
public int getRowCount() {
return lines.size();
}
}
The CSVReader constructor accepts a File as an argument and creates proper objects to read data in a specific manner (for example: read as String). Then, the data in the CSV file is read, just like in normal TXT file by saving the lines in the memory for later use.
Then we create 2 methods. First is getRowCount which gives us the total number of row/set of data.
Second is getRow which collect the specific row from the list and saves it to String[] array for later use.
String[] array has a presentation like 1 Excel row:
data index 0 | data index 1 | data index 2 | data index 3
We have a class which allows us to read the file in an easy matter. Let's create the DataProvider
To provide data to tests, we need to use #Parameters annotation and return Collection<Object[]> to our test. I will talk later about that.
So, let's implement it in our DataProvider
public class CSVDataProvider {
public Collection<Object[]> getData() throws FileNotFoundException {
CSVReader reader = new CSVReader(new File("C:\\Users\\xxxxxxxxxxx\\Desktop\\TestData.csv"));
int rowCount = reader.getRowCount();
Object[][] data = new Object[rowCount][2];
for (int i = 0; i < rowCount; i++) {
Object[] singleRow = reader.getRow(i);
data[i][0] = singleRow[0];
data[i][1] = singleRow[1];
}
return Arrays.asList(data);
}
}
I assume that you have only logins and passwords in the CSV file. That's why I created a 2-dimensional array new Object[rowCount][2]. We create the array by providing how many elements it has to store and we know how many rows we have from rowCount variable.
2 means we have only 2 data per row. Login and password. If you want to use additional element, for example - the role of the user, you can modify to [3]
In the for loop we are transforming the data from the CSV file to array and return it for later use.
Now, let's talk about our test class.
#RunWith(Parameterized.class)
public class OurTest {
private String login, password;
public OurTest(String login, String password) {
this.login = login;
this.password = password;
}
#Parameterized.Parameters(name = "{index}: Login: ({0}) Password: ({1})")
public static Collection<Object[]> data() throws FileNotFoundException {
return new CSVDataProvider().getData();
}
#Test
public void test() {
System.out.println(String.format("login : %s | Password: %s", login, password));
}
}
In order to pass the parameters from DataProvider to our test, we need to
1. Annotate the class with #RunWith(Parameterized.class)
2. Create a method returning Collection<Object[]> with annotation#Parameters`
3. Create a constructor reflecting what kind of data do we accept.
Regarding point 3, that's why I created a 2 argument constructor with String login and String password. We are passing those 2 parameters. JUnit will create a new instance of OurTest and pass different row for each test.
In the test method I just printed the data we've got from the DataProvider
I do not present a fully working solution because I want you to try to adjust your test to learn this specific approach. It's also called Data-driven Testing.
We have only 1 test method but each line in the CSV file will run as a separate test.
Hope it helps!
Your while loop looks broken. The for loop inside the while loop seems to mess up your login procedure.
while((cell = reader.readNext())!=null) { // iterate through csv file
String name = cell[0]; // cell is current row, you need first column for name
String email = cell[1]; // second column for email (as password?)
// what do you want to do with baseUrl here?
driver.findElement(By.xpath("//input[#id='useridFormField-inputEl']")).sendKeys(name);
driver.findElement(By.xpath("//input[#id='userpasswordFormField-inputEl']")).sendKeys(email);
// you need to check the successful login here
// then logout and open main page
// do not quit before you are finished
}
// quit after the loop is finished
driver.quit();
Without any knowledge of the website it is impossible to tell you how to check successful login and perform logout.
May I suggest you put some effort in learning the ropes with a less complex task? You seem to have a lot of trouble with basic Java elements. Never stop learning.
It looks you want to iterate your test with set of test data. In that case you should use TestNG data provider feature.
public class CSVdataread {
private WebDriver driver;
String baseUrl = "URL";
String CSV_file = "C:\\Users\\xxxxxxxxxxx\\Desktop\\TestData.csv";
#BeforeMethod
public void openBrowser() {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\xxxxxxxxxxxx\\Desktop\\webdriver\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test(dataProvider="users-data")
public void verify_Search(String name, String email) throws InterruptedException, IOException {
String baseUrl = "http://xxxxx.xxx/xxxx/";
driver.navigate().to(baseUrl);
driver.findElement(By.xpath("//input[#id='useridFormField-inputEl']")).sendKeys(name);
driver.findElement(By.xpath("//input[#id='userpasswordFormField-inputEl']")).sendKeys(email);
}
//This method will provide data to any test method that declares that its Data Provider
#DataProvider(name = "users-data")
public Iterator<Object[]> createDataFromCSV() {
CSVReader reader = new CSVReader(new FileReader(CSV_file));
List<Object[]> data = new ArrayList<Object[]>();
//read csv data to list
return data.iterator();
}
#AfterMethod
public void closeBrowser() {
driver.quit();
}
}
You can also utilize available data-provider-extension. For example, with qaf You don't need to write code for driver management or for data provider. Your test class will look like below:
public class CSVdataread extends WebDriverTestCase{
#QAFDataProvider(dataFile="resources/user-data.csv")
#Test()
public void verify_Search(String name, String email) throws InterruptedException, IOException {
String baseUrl = "http://xxxxx.xxx/xxxx/";
getDriver().navigate().to(baseUrl);
getDriver().findElement(By.xpath("//input[#id='useridFormField-inputEl']")).sendKeys(name);
//another way of finding element...
getDriver().findElement("xpath=//input[#id='userpasswordFormField-inputEl']").sendKeys(email);
}
}
i need to access a website multiple times a day and want to skip the Log-In page. This is why i want to use Cookies in Java Selenium Chromedriver, for skipping that Log-In after accessing it the first time on a day.
Selenium is saving the Cookies correctly, but does not use them and i dont get access on the following page. Can you help me?
This is my Code:
public static void main(String[] args) throws InterruptedException {
Set<Cookie> cookie = null;
Iterator<Cookie> itr = null;
while (true) {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\Maxi\\Desktop\\ChromeDriver.exe");
driver = new ChromeDriver();
driver.get("https://www.xxxxxx.xxx");
while (itr != null && itr.hasNext()) {
driver.manage().addCookie(itr.next());
}
driver.navigate().refresh();
WebDriverWait wait0 = new WebDriverWait(driver, 20);
if (itr == null) {
String UserID = "LoginFieldXpath";
wait0.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(UserID)));
driver.findElement(By.xpath(UserID)).sendKeys("Username");
String PW = "PasswordField Xpath";
driver.findElement(By.xpath(PW)).sendKeys("Password");
String LogIn = "LoginButtonXpath";
driver.findElement(By.xpath(LogIn)).click();
cookie = driver.manage().getCookies();
itr = cookie.iterator();
}
}
}
You can create user profile in Chrome like this
options:
addArguments("user-data-dir="+"path_to_empty_folder");
Then make sign up, so cookie will be stored in this profile. And than just copy this user data dir to another folder
FileUtils.copyDirectory(new File("path-to-dir-with-cookie"), new File("new-dir"));
options.addArguments("user-data-dir="+"new-dir");
Selenium starts a new temporary browser instance each time, so it doesn't come with any cookies stored, cache or anything like that.
I would suggest moving your open chrome driver to be outside of the while loop so you'll be able to reuse it each time you want to check a page. Maybe either move the login outside of the loop as well or check if you need to log in. Then just grab whatever page you're trying to check inside the loop each time you need to.
public static void main(String[] args) throws InterruptedException {
Set<Cookie> cookie = null;
Iterator<Cookie> itr = null;
// move this outside the loop
System.setProperty("webdriver.chrome.driver", "C:\\Users\\Maxi\\Desktop\\ChromeDriver.exe");
driver = new ChromeDriver();
while (true) {
driver.get("https://www.xxxxxx.xxx");
// not sure why you're adding a cookie?
// it should automatically accept page cookies that are set
while (itr != null && itr.hasNext()) {
driver.manage().addCookie(itr.next());
}
driver.navigate().refresh();
WebDriverWait wait0 = new WebDriverWait(driver, 20);
// check to make sure that you need to log in
if (itr == null) {
String UserID = "LoginFieldXpath";
wait0.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(UserID)));
driver.findElement(By.xpath(UserID)).sendKeys("Username");
String PW = "PasswordField Xpath";
driver.findElement(By.xpath(PW)).sendKeys("Password");
String LogIn = "LoginButtonXpath";
driver.findElement(By.xpath(LogIn)).click();
cookie = driver.manage().getCookies();
itr = cookie.iterator();
}
}
}
Webdriver launches multiple windows after performing click action. I have tried driver.close() but it close the webdriver and test fails.
WebDriver driver = new FirefoxDriver ();
driver.get("http://www.xyz.com/");
JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement page = driver.findElement(By.className("coupon-rows"));
List <WebElement> coupontrigger = page.findElements(By.className("code"));
System.out.println("number of couponsTriggers on carousel = "+ "coupontrigger.size());
for (int j=0; j<=coupontrigger.size(); j++) {
js.executeScript("$('.ccode.coupon-trigger').eq("+j+").click()");
System.out.println(driver.getTitle());
driver.switchTo().defaultContent();
driver.get("http://www.xyz.com/");
page = driver.findElement(By.className("coupon-rows"));
coupontrigger = page.findElements(By.className("code"));
}
}
If I understood your requirement you want to close the other popups rather than the main window. In that case you can do below. Though I am not 100% sure of your requirement.
String mwh=driver.getWindowHandle(); // Get current window handle
Set<String> s=driver.getWindowHandles();
Iterator<String> ite=s.iterator();
String popupHandle = "";
while(ite.hasNext())
{
popupHandle = ite.next().toString();
if(!popupHandle.contains(mwh)) // If not the current window then shift focus and close them
{
driver.switchTo().window(popupHandle);
driver.close();
}
}
driver.switchTo().window(mwh); // finally move control to main window.
You can introduce a helper method which will do that task for you. You just need to find out what your current view is (WebDriver#getWindowHandle will give the one you have focus on) and then just close the rest of the windows.
private String closeAllpreviouslyOpenedWindows() {
String firstWindow = webDriver.getWindowHandle();
Set<String> windows = webDriver.getWindowHandles();
windows.remove(firstWindow);
for (String i : windows) {
webDriver.switchTo().window(i);
webDriver.close();
}
webDriver.switchTo().window(firstWindow);
return firstWindow;
}
I'm using Selenium WebDriver to try to insert an external javascript file into the DOM, rather than type out the entire thing into executeScript.
It looks like it properly places the node into the DOM, but then it just disregards the source, i.e. the function on said source js file doesn't run.
Here is my code:
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Example {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://google.com");
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.getElementsByTagName('head')[0].innerHTML += '<script src=\"<PATH_TO_FILE>\" type=\"text/javascript\"></script>';");
}
}
The code of the javascript file I am linking to is
alert("hi Nate");
I've placed the js file on my localhost, I called it using file:///, and I tried it on an external server. No dice.
Also, in the Java portion, I tried appending 'scr'+'ipt' using that trick, but it still didn't work. When I inspect the DOM using Firefox's inspect element, I can see it loads the script node properly, so I'm quite confused.
I also tried this solution, which apparently was made for another version of Selenium (not webdriver) and thus didn't work in the least bit: Load an external js file containing useful test functions in selenium
According to this: http://docs.seleniumhq.org/docs/appendix_migrating_from_rc_to_webdriver.jsp
You might be using the browserbot to obtain a handle to the current
window or document of the test. Fortunately, WebDriver always
evaluates JS in the context of the current window, so you can use
“window” or “document” directly.
Alternatively, you might be using the browserbot to locate elements.
In WebDriver, the idiom for doing this is to first locate the element,
and then pass that as an argument to the Javascript. Thus:
So does the following work in webdriver?
WebDriver driver = new FirefoxDriver();
((JavascriptExecutor) driver)
.executeScript("var s=window.document.createElement('script');\
s.src='somescript.js';\
window.document.head.appendChild(s);");
Injecting our JS-File into DOM
Injecting our JS-File into browsers application from our local server, so that we can access our function using document object.
injectingToDOM.js
var getHeadTag = document.getElementsByTagName('head')[0];
var newScriptTag = document.createElement('script');
newScriptTag.type='text/javascript';
newScriptTag.src='http://localhost:8088/WebApplication/OurOwnJavaScriptFile.js';
// adding <script> to <head>
getHeadTag.appendChild(newScriptTag);
OurSeleniumCode.java
String baseURL = "http://-----/";
driver = new FirefoxDriver();
driver.navigate().to(baseURL);
JavascriptExecutor jse = (JavascriptExecutor) driver;
Scanner sc = new Scanner(new FileInputStream(new File("injectingToDOM.js")));
String inject = "";
while (sc.hasNext()) {
String[] s = sc.next().split("\r\n");
for (int i = 0; i < s.length; i++) {
inject += s[i];
inject += " ";
}
}
jse.executeScript(inject);
jse.executeScript("return ourFunction");
OurOwnJavaScriptFile.js
document.ourFunction = function(){ .....}
Note : If you are passing JS-File as String to executeScript() then don't use any comments in between JavaScript code, like injectingToDOM.js remove all comments data.
I am doing a Project in Java.
In this project I have to work with DOM.
For that I first load a dynamic page of any given URL, by using Selenium.
Then I parse them using Jsoup.
I want to get the dynamic page source code of given URL
Code snapshot:
public static void main(String[] args) throws IOException {
// Selenium
WebDriver driver = new FirefoxDriver();
driver.get("ANY URL HERE");
String html_content = driver.getPageSource();
driver.close();
// Jsoup makes DOM here by parsing HTML content
Document doc = Jsoup.parse(html_content);
// OPERATIONS USING DOM TREE
}
But the problem is, Selenium takes around 95% of the whole processing time, that is undesirable.
Selenium first opens Firefox, then loads the given page, then gets the dynamic page source code.
Can you tell me how I can reduce the time taken by Selenium, by replacing this tool with another efficient tool. Any other advice would also be welcome.
Edit NO. 1
There is some code given on this link.
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("general.useragent.override", "some UA string");
WebDriver driver = new FirefoxDriver(profile);
But what is second line here, I didn't understand. As Documentation is also very poor of selenium.
Edit No. 2
System.out.println("Fetching %s..." + url1);
System.out.println("Fetching %s..." + url2);
WebDriver driver = new FirefoxDriver(createFirefoxProfile());
driver.get("url1");
String hml1 = driver.getPageSource();
driver.get("url2");
String hml2 = driver.getPageSource();
driver.close();
Document doc1 = Jsoup.parse(hml1);
Document doc2 = Jsoup.parse(hml2);
Try this:
public static void main(String[] args) throws IOException {
// Selenium
WebDriver driver = new FirefoxDriver(createFirefoxProfile());
driver.get("ANY URL HERE");
String html_content = driver.getPageSource();
driver.close();
// Jsoup makes DOM here by parsing HTML content
// OPERATIONS USING DOM TREE
}
private static FirefoxProfile createFirefoxProfile() {
File profileDir = new File("/tmp/firefox-profile-dir");
if (profileDir.exists())
return new FirefoxProfile(profileDir);
FirefoxProfile firefoxProfile = new FirefoxProfile();
File dir = firefoxProfile.layoutOnDisk();
try {
profileDir.mkdirs();
FileUtils.copyDirectory(dir, profileDir);
} catch (IOException e) {
e.printStackTrace();
}
return firefoxProfile;
}
The createFireFoxProfile() method creates a profile if one doesn't exist. It uses if a profile already exists. So selenium doesn't need to create the profile-dir structure each and every time.
if you are sure, confident about your code, you can go with phantomjs. it is a headless browser and will get your results with quick hits. FF will take time to execute.