How to maintain browser state between invocations under Selenium and Firefox? - c#

Context: Microsoft Azure VM; VS2015 Community; C#; Selenium.WebDriver.2.52.0; Firefox 44.0.2; Console (i.e. not running under IIS)
How is state maintained under Firefox using Selenium. Programmatically I go to one page, enter login details, and traverse to a second domain. Then I close the browser, re-open and try to go to a link on the second domain. I end up at the login page again being requested for login details.
When doing this interactively, the browser remembers that I logged in on the first page and automagically transports me the second domain's page.
I have set up a webserver profile in C:\Users\Bruce\AppData\Roaming\Mozilla\Firefox\profiles.ini as
[General]
StartWithLastProfile=1
[Profile0]
Name=default
IsRelative=1
Path=Profiles/eracklz4.default
[Profile1]
Name=webserver
IsRelative=1
Path=Profiles/webserver.default
Default=1
So one would think that even if I didn't explicitly state that I wanted to use the webserver profile, nevertheless, it would choose that profile and work with it. Just in case I go on to state it explicitly
var seleniumProxy = new Proxy();
seleniumProxy.HttpProxy = "localhost:" + port; // port provided by BrowserMob Proxy
...
FirefoxBinary fb = new FirefoxBinary(#" C:\Program Files (x86)\Mozilla Firefox\firefox.exe");
FirefoxProfileManager fpm = new FirefoxProfileManager();
FirefoxProfile fp = fpm.GetProfile("webserver");
fp.DeleteAfterUse = false;
fp.SetProxyPreferences(seleniumProxy);
IWebDriver wd = null;
try
{
wd = new FirefoxDriver(fb, fp);
}
catch (Exception exc)
{
System.Diagnostics.Debug.Print(exc.Message);
}
IJavaScriptExecutor js = wd as IJavaScriptExecutor;
ExistingProfiles in the FirefoxProfileManager lists webserver so the fpm var is not null.
At this point, I'm getting pretty confident that the session's data will be persisted, because when I look at fpm in the debugger, Non-Public members -> profiles -> [1] -> Value is given as "C:\\Users\\Bruce\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles/webserver.default".
Having transferred the profile data from fpm to fp, with the .GetProfile method, the ProfileDirectory property of fp reads as null, Non-Public members -> profileDir is also null and Non-Public members -> sourceProfileDir is "C:\\Users\\Bruce\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles/webserver.default"
By rights, therefore, one should expect passwords to be persisted to the webserver profile, especially when one explicitly saves data to the profile with regular calls to fp.WriteToDisk();.
However! The last time I ran the code, I got a anonymous.359f853715d5418c87c7393c629dcb1a.webdriver-profile in C:\Users\Bruce\AppData\Local\Temp
Granted, there did appear to be some activity in the Roaming profile. However, the password for the login page was not persisted.
What's happening here? Is session data persistable in Selenium + Firefox, or was there a design decision somewhere that no matter how you specified it, no state would be saved? Am I wanting to do something that is intrinsically forbidden?
NEXT DAY
Added the following code after reading a StackOverflow posting from 2014 discussing similar issues. However, I'm still seeing a temporary profile being created in AppData\Local\Temp. And no changes were made to the Roaming profile. Problem not solved.
A LITTLE LATER
Am currently experimenting with Google Chrome instead of Firefox, viz
ChromeOptions co = new ChromeOptions();
string tfn = #"C:\Temp";
co.AddArgument("user-data-dir=" + tfn);
co.Proxy = seleniumProxy;
IWebDriver wd = new ChromeDriver(co);
I'm not very confident that this will make much difference. Notably, I can't figure out how to set or get the name of the profile folder created in Temp. The above code creates a Default folder, but there's no mention of that in the properties view in VS2015C.
FINALLY
Surprise, surprise, that actually worked. Bye bye Firefox. Hello Google Chrome. Seems there's enough session data stored to make the traversal to the second site feasible. Will probably change the directory away from Temp and have it client-specific. Kudos to the folk at ActiveState Python.

Related

How to open a Chrome Profile through --user-data-dir argument of Selenium

I am attempting to load a chrome browser with selenium using my existing account and settings from my profile.
I can get this working using ChromeOptions to set the userdatadir and profile directory. This loads the browser with my profile like i want, but the browser then hangs for 60 seconds and times out without advancing through any more of the automation.
If I don't use the user data dir and profile settings, it works fine but doesn't use my profile.
The reading I've done points to not being able to have more than one browser open at a time with the same profile so I made sure nothing was open while I ran the program. It still hangs for 60 seconds even without another browser open.
m_Options = new ChromeOptions();
m_Options.AddArgument("--user-data-dir=C:/Users/Me/AppData/Local/Google/Chrome/User Data");
m_Options.AddArgument("--profile-directory=Default");
m_Options.AddArgument("--disable-extensions");
m_Driver = new ChromeDriver(#"pathtoexe", m_Options);
m_Driver.Navigate().GoToUrl("somesite");
It always hangs on the GoToUrl. I'm not sure what else to try.
As per your code trials you were trying to load the Default Chrome Profile which will be against all the best practices as the Default Chrome Profile may contain either of the following:
Extensions
Bookmarks
Browsing History
etc
So the Default Chrome Profile may not be in compliance with you Test Specification and may raise exception while loading. Hence you should always use a customized Chrome Profile as below.
To create and open a new Chrome Profile you need to follow the following steps :
Open Chrome browser, click on the Side Menu and click on Settings on which the url chrome://settings/ opens up.
In People section, click on Manage other people on which a popup comes up.
Click on ADD PERSON, provide the person name, select an icon, keep the item Create a desktop shortcut for this user checked and click on ADD button.
Your new profile gets created.
Snapshot of a new profile SeLeNiUm
Now a desktop icon will be created as SeLeNiUm - Chrome
From the properties of the desktop icon SeLeNiUm - Chrome get the name of the profile directory. e.g. --profile-directory="Profile 2"
Get the absolute path of the profile-directory in your system as follows :
C:\\Users\\Thranor\\AppData\\Local\\Google\\Chrome\\User Data\\Profile 2
Now pass the value of profile-directory through an instance of ChromeOptions with AddArgument method along with key user-data-dir as follows :
m_Options = new ChromeOptions();
m_Options.AddArgument("--user-data-dir=C:/Users/Me/AppData/Local/Google/Chrome/User Data/Profile 2");
m_Options.AddArgument("--disable-extensions");
m_Driver = new ChromeDriver(#"pathtoexe", m_Options);
m_Driver.Navigate().GoToUrl("somesite");
Execute your Test
Observe Chrome gets initialized with the Chrome Profile as SeLeNiUm
If you want to run Chrome using your default profile (cause you need a extension), you need to run your script using another browser, like Microsoft Edge or Microsoft IE and your code will lunch a Chrome instance.
My Code in PHP:
namespace Facebook\WebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Chrome\ChromeOptions;
require_once('vendor/autoload.php');
$host = 'http://localhost:4444/';
$options = new ChromeOptions();
$options->addArguments(array(
'--user-data-dir=C:\Users\paulo\AppData\Local\Google\Chrome\User Data',
'--profile-directory=Default',
'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
));
$caps = DesiredCapabilities::chrome();
$caps->setCapability(ChromeOptions::CAPABILITY, $options);
$caps->setPlatform("Windows");
$driver = RemoteWebDriver::create($host, $caps);
$driver ->manage()->window()->maximize();
$driver->get('https://www.google.com/');
// your code goes here.
$driver->quit();
i guys, in my enviroment with chrome 63 and selenum for control, i have find same problem (60 second on wait for open webpage).
To fix i have find a way by setting a default webpage in chrome ./[user-data-dir]/[Profile]/Preferences file, this is a json data need to insert in "Preferences" file for obtain result
...
"session":{
"restore_on_startup":4,
"startup_urls":[
"http://localhost/test1"
]
}
...
For set "Preferences" from selenium i have use this sample code
ChromeOptions chromeOptions = new ChromeOptions();
//set my user data dir
chromeOptions.addArguments("--user-data-dir=/usr/chromeDataDir/");
//start create data structure to for insert json in "Preferences" file
Map<String, Object> prefs = new HashMap<String, Object>();
prefs.put("session.restore_on_startup", 4);
List<String> urlList = new ArrayList<String>();
urlList.add("http://localhost/test1");
prefs.put("session.startup_urls", urlList);
//set in chromeOptions data structure
chromeOptions.setExperimentalOption("prefs", prefs);
//start chrome
ChromeDriver chromeDriver = new ChromeDriver(chromeOptions);
//this get command for open web page, response instant
chromeDriver.get("http://localhost/test2")
i have find information here https://chromedriver.chromium.org/capabilities

C# not able to get console Logs from PhantomJSDriver (Selenium)

I'm using Selenium in C# with the PhantomJS Driver.
I need to click specific coordinates on a website, that works with using Javascript (im using the ExecutePhantomJS(string script) function of the selenium phantomjs driver). I also need to capture the network traffic. I used browsermob earlier to do that, but for now i cant use it because i also need to use another proxy. So i solved it like that until now:
//Hide CMD of PhantomJS.exe
var driverService = PhantomJSDriverService.CreateDefaultService();
driverService.HideCommandPromptWindow = true;
//Initialize Driver and execute Network Script to capture traffic
driver = new PhantomJSDriver(driverService);
driver.ExecutePhantomJS(networkScript);
//Call URL
driver.Navigate().GoToUrl(url);
This is the networkScript:
string networkScript = "var page = this; page.onResourceRequested = function(req) { console.log('received: ' + JSON.stringify(res, undefined, 4)); }; page.onResourceReceived = function(res) { console.log('received: ' + JSON.stringify(res, undefined, 4)); };";
The good thing:
URL is called and all network traffic is logged into the console of the PhantomJS.exe.
But I dont know how I can get these console logs now in my C# code (I need to get specific things like URLs etc.. out of the network log).
I already read the whole afternoon but couldn't find a solution until now. Some of the things I already tried:
1) Tried to use PhantomJSOptions, there u can set LoggingPreferences and later i called driver.Manager().Logs.GetLog(LogType), but there were none of the console logs
2) Dont use console.log inside networkScript. I used require('system').stdout.write(...). It was also logged into console but I cant get the standard output stream of the phantomjs.exe from my C# code.
...
I really dont know how i could solve the problem.
One way would be to log into a .txt file instead of console, but it is very much text and later there will be many opened drivers, so I want to avoid that because then i will have very much and big .txt files

OpenQA.Selenium.NoSuchElementException

class Program
{
static void Main(string[] args)
{
IWebDriver driver = new ChromeDriver();
//Dev environment
driver.Url = /*URL*/;
var trialGroupName = driver.FindElement(By.Name("TrialGroupName"));
trialGroupName.SendKeys(/*trial group name */);
var userName = driver.FindElement(By.Name("UserName"));
userName.SendKeys(/*username*/);
var password = driver.FindElement(By.Name("UserPassword"));
password.SendKeys(/*password*/);
var loginButton = driver.FindElement(By.Id("Ok"));
loginButton.Click();
//Find and click on Browse tab
var browseTab = driver.FindElement(By.Id("17"));
browseTab.Click();
}
}
OpenQA.Selenium.NoSuchElementException: 'no such element: Unable to locate element: {"method":"id","selector":"17"}
(Session info: chrome=58.0.3029.110)
(Driver info: chromedriver=2.30.477700 (0057494ad8732195794a7b32078424f92a5fce41),platform=Windows NT 6.1.7601 SP1 x86_64)'
Here's the inspect information:
<td>
<a id="17" class="defaultMenu initMenu" href="javascript:onMenuHref(17)" notran="">Browse</a>
</td>
I've also tried running it with the XPath (both the short version from Chrome and the long version from FireBug) and I receive the same error. I've tried adding in an implicit wait and a Thread.Sleep() but still received the same error. Also tried starting on a different field and tabbing to it and then it gave me the same exception but on the new field. I also tried playing around with cssSelector this morning and couldn't get that to work either. I did try to do an explicit wait but I'll be honest, I'm still trying to digest and understand it as waits are a new concept and I don't fully understand it, so I don't think I'm doing it right.
I'm a beginner, and I'm currently just trying to write the script to get it to the actual page that needs testing. I've been teaching myself some coding and selenium as I'm the only QA person at my company right now and I really think we could benefit from automation. This portion of the page isn't actually programmed by us it's done by a third party who hosts the system we use so I'm limited to what I see in the inspect.
(I commented out the user login information and URL because it is for internal use only and the page can't be reached outside of our systems anyways. Also I'm pretty sure I'm not allowed to do so by my employer).
Any help on this would be greatly appreciated, or any additional resources I can use. I've been using google mostly so there may be other pages you are aware of that could help me that I haven't found yet.
The login button takes you to a new page, which you need to wait for it to load. Try using an explicit wait to wait for the tab to be clickable. The timeout is 10 seconds in the following example, so modify that as needed.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement browseTab = wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("17")));

Inconsistent behaviour of Click() in Selenium

I'm working on a Product automation(Web CMS), where element.Click() shows the inconsistent behaviour. Basically we are using,
Selenium + Nunit GUI(unit testing framework) - To run the test cases from local on a particular environment
Selenium + Asp.net web application - Multiple user's can run the test cases on different environment
Here environment I mean different levels(Dev, SIT, QA, Production).
My Concern
In one of my test cases, I want to Click a button. So for that, I have tried few code. But all are inconsistent behaviour. Here Inconsistent I mean, the code whatever I wrote for clicking a button are only working in my local or server and viceversa.
1st attempt:-
I tried all the element locator's
IWebElement element = driver.FindElement(By.Id("element id goes here"))
Working fine at my local, but not in server
Result - Failed
2nd attempt:-
driver.FindElement(By.XPath("Element XPath goes here")).SendKeys(Keys.Enter);
Working fine at server, but not in local
Result - Failed
3rd attempt:-
IWebElement element = driver.findElement(By.id("something"));
IJavaScriptExecutor executor = (IJavaScriptExecutor)driver;
executor.ExecuteScript("arguments[0].click()", element);
Not working in both(local and server)
Result - Failed
At last, I tried waiting for the element to be visible and performing action
4th attempt:-
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
return wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("element xpath goes here")));
After webdriver wait performing action on that element (element.click())
Working fine at local but not in server
Result - Failed
I'm looking for a solution, where Clicking the button should not be an inconsistent behaviour. Basically it should work fine in both (Local and Server). Your help would be greatly appreciated..Thanks in advance
FYI - I'm testing in Mozilla Firefox browser 38.5.2
I'm using Selenium in C# locally on Win7 and remotely on Win10 and MacOS with the Firefox browser and also noticed that Firefox sometimes requires special treatment for IWebElement.Click(). So I wrote myself an extension method, which works fine for me, no matter by what locator the element was found:
public static void Click(this IWebElement element, TestTarget target)
{
if (target.IsFirefox)
{
var actions = new Actions(target.Driver);
actions.MoveToElement(element);
// special workaround for the FirefoxDriver
// otherwise sometimes Exception: "Cannot press more then one button or an already pressed button"
target.Driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.Zero);
// temporarily disable implicit wait
actions.Release().Build().Perform();
target.Driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(MyDefaultTimeoutInSeconds));
Thread.Sleep(500);
actions.MoveToElement(element);
actions.Click().Build().Perform();
}
else
{
element.Click();
}
}
If you want more stable behavior for your test cases, I would recommend using ChromeDriver. It never needs any special treatment at all, and it's also much faster than the FirefoxDriver.

Rotativa ActionAsPdf() Very Slow

Using Rotativa 1.6.4 from NuGet and have noticed the following issue using the code below.
ActionAsPdf hangs randomly for indeterminate amount of time.
Code below that is hanging:
var pdfResult = new ActionAsPdf("Report", new {id = Request.Params["id"]})
{
Cookies = cookieCollection,
FormsAuthenticationCookieName = FormsAuthentication.FormsCookieName,
CustomSwitches = "--load-error-handling ignore"
};
Background info that may help:
The customSwitches is in use to ignore a documented issue calling wkhtmltopdf.exe using the ActionAsPdf, but it does not suppress errors in the code only in the wkhtmltopdf call.
Observations, usage and testing:
It works but when running the application (whether or not stepping through code), it can be anywhere from 10 seconds up to about 4 minutes between hitting the pdfResult = new ActionAsPdf and finally entering into the "Report" action being called. Can't discern anything actually happening in the output window of Visual Studio, no errors are being thrown that I have found. Just random slow transition into the Reports() action.
I can run the Reports() action directly via URL and it never slows like this and is quite fast for PDF generation. I am running it using the ActionAsPdf to obtain the binary to save to file system and send via email, which is the prescribed method of doing so for this library.
The behavior exists on both a local Windows 10 dev box and a remote Server 2008R2 Test box. .Net 4.5.1 on both boxes, default IIS on each.
Questions I have:
Any idea on what might cause this slow down and how to remedy it?
I ended up using UrlAsPdf() instead of ActionAsPdf() and it works. Seems there may be some issues with the ActionAsPdf() and I have filed a bug with Rotative project on GitHub. The ActionAsPdf() is still marked as beta, so hopefully it get's fixed in future versions or by the community.
In my case, I had to do few more tweaks along with using UrlAsPdf(). I have narrowed down the issue to the cookie collection that I was adding. So I tried just adding the cookie that I needed, and the issue was resolved. Following is the sample code that I have used.
var report = new UrlAsPdf(url);
Dictionary<string, string> cookieCollection = new Dictionary<string, string>();
foreach (var key in Request.Cookies.AllKeys)
{
if (Crypto.Hash("_user").Equals(key))
{
cookieCollection.Add(key, Request.Cookies.Get(key).Value);
break;
}
}
report.Cookies = cookieCollection;
report.FormsAuthenticationCookieName = FormsAuthentication.FormsCookieName;

Categories