I work at a place that blocks social media sites and pops up a proxy log-in for those (few) folks who have legitimate business reasons for going to them. Since most sites have a Facebook, Twitter or similar link, the proxy prompt comes up quite a bit. When browsing in a normal, human-driven fashion, I just hit the ESC key to get rid of the proxy log-in dialogue. How can I do this via Selenium? I've seen alot of posts and solutions for either closing ALERT messages or modal dialogues but I haven't seen anything for closing the proxy log-in; just bypassing it by supplying credentials.
Any help/tips would be appreciated. Thanks!
Specs:
I'm using Selenium 2.44 with the Firefox driver in C#
(Edit #2: A little more info on this dialogue)
This log-in prompt is coming from our own internal proxy server. Our proxy server is basically asking the user if they even have permission to go to the site requested before any communication is made to the remote site. It pops up any time an element is on the remote site. So for instance, if a site has a button for Facebook and Twitter which pulls the button from Facebook or Twitter itself, the user will see two proxy log-in prompts. While the other elements of the page will load as it waits, the page-load process ultimately waits for an answer for any elements that are otherwise automatically blocked.
One way I have gotten around this is to use the Firefox driver in combination with NoScript and remove all social networking links from the white-list. It's a crude workaround and forces the use of one browser. What I'm seeking is a way for Selenium to simply close the proxy log-in prompt via code (if that even be done).
(Edit: Added screenshot example)
(Edit: Added screenshot from Inspect)
Not sure about selenium but you could use the System.Windows.Automation namespace instead.
Subscribe to top level window opens
Use the AutomationElement received to check if it matches your Firefox window information (you can use a took like Inspect to find out what they are)
Use the AutomationElement above to subscribe to child window opened events
On event, check if it is the proxy popup
Use the close method on it or SendKeys to send an ESC
Here's a sample code, you will have to gather the classnames, automation ids and names of the windows (feel free to commend and I'll edit the answer):
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Automation;
namespace FirefoxAutomation
{
class FirefoxAutomation
{
private const string FF_CLASSNAME = "MozillaWindowClass"; //"Firefox ClassName taken from Inspect";
private const string FF_AUTOMATIONID = null;//"Firefox AutomationId taken from Inspect";
private static readonly Regex FF_NAME = new Regex("( - Mozilla Firefox)$"); //new Regex("Firefox Name regex based on name taken from Inspect");
private const string PROXY_CLASSNAME = "MozillaDialogClass";//"Proxy window ClassName taken from Inspect";
private const string PROXY_AUTOMATIONID = null;//"Proxy window AutomationId taken from Inspect";
private static readonly Regex PROXY_NAME = new Regex("^(Authentication Required)$");//new Regex("Proxy window Name regex based on name taken from Inspect");
public FirefoxAutomation()
{
SubscribeTopLevelWindowOpened();
}
private void SubscribeTopLevelWindowOpened()
{
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement, TreeScope.Children, TopLevelWindowOpened);
}
private void TopLevelWindowOpened(object sender, AutomationEventArgs e)
{
var element = sender as AutomationElement;
if (element == null) return;
// Filter for FireFox window element
if (!MatchWindow(element, FF_CLASSNAME, FF_AUTOMATIONID, FF_NAME)) return;
// Subscribe for child window opened even
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
element, TreeScope.Children, FireFoxChildWindowOpened);
}
private void FireFoxChildWindowOpened(object sender, AutomationEventArgs e)
{
var element = sender as AutomationElement;
if (element == null) return;
// Filter for a proxy message
if (!MatchWindow(element, PROXY_CLASSNAME, PROXY_AUTOMATIONID, PROXY_NAME)) return;
// Find the cancel button
var controls = element.FindAll(TreeScope.Children, Condition.TrueCondition).Cast<AutomationElement>().ToList();
var cancelButton = controls.FirstOrDefault(c => c.Current.ControlType == ControlType.Button && c.Current.Name == "Cancel");
if (cancelButton == null) return;
// Get the click pattern
object clickPatternObj;
if (!cancelButton.TryGetCurrentPattern(InvokePattern.Pattern, out clickPatternObj)) return;
((InvokePattern)clickPatternObj).Invoke(); // click the cancel button
}
private bool MatchWindow(AutomationElement element, string className, string automationId, Regex name)
{
var current = element.Current;
if (current.ControlType != ControlType.Window) return false;
if (className != null && current.ClassName != className) return false;
if (automationId != null && current.AutomationId != automationId) return false;
if (name != null && name.IsMatch(current.Name)) return false;
return true;
}
}
}
Navigate to the website like this:
WebDriver.Navigate().GoToUrl("http://username:password#website.com");
The website.com would be the usual website.
If you do not want to log in you can just use an Action to send an Escape key to the driver:
var action = new Actions(WebDriver);
action.SendKeys(Keys.ESCAPE).Build().Perform();
Related
I'm trying to programmatically login to a site like espn.com. The way the site is setup is once I click on the Log In button located on the homepage, a Log In popup window is displayed in the middle of the screen with the background slightly tinted. My goal is to programmatically obtain that popup box, supply the username and password, and submit it -- hoping that a cookie is returned to me to use as authentication. However, because Javascript is used to display the form, I don't necessarily have easy access to the form's input tags via the main page's HTML.
I've tried researching various solutions such as HttpClient and HttpWebRequest, however it appears that a Webbrowser is best since the login form is displayed using Javascript. Since I don't necessarily have easy access to the form's input tags, a Webbrowser seems the best alternative to capturing the popup's input elements.
class ESPNLoginViewModel
{
private string Url;
private WebBrowser webBrowser1 = new WebBrowser();
private SHDocVw.WebBrowser_V1 Web_V1;
public ESPNLoginViewModel()
{
Initialize();
}
private void Initialize()
{
Url = "http://www.espn.com/";
Login();
}
private void Login()
{
webBrowser1.Navigate(Url);
webBrowser1.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(webpage_DocumentCompleted);
Web_V1 = (SHDocVw.WebBrowser_V1)this.webBrowser1.ActiveXInstance;
Web_V1.NewWindow += new SHDocVw.DWebBrowserEvents_NewWindowEventHandler(Web_V1_NewWindow);
}
//This never gets executed
private void Web_V1_NewWindow(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Processed)
{
//I'll start determing how to code this once I'm able to get this invoked
}
private void webpage_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement loginButton = webBrowser1.Document.GetElementsByTagName("button")[5];
loginButton.InvokeMember("click");
//I've also tried the below InvokeScript method to see if executing the javascript that
//is called when the Log In button is clicked, however Web_V1_NewWindow still wasn't called.
//webBrowser1.Document.InvokeScript("buildOverlay");
}
}
I'm expecting the Web_V1_NewWindow handler to be invoked when the InvokeMember("click") method is called. However, code execution only runs through the webpage_DocumentCompleted handler without any calls to Web_V1_NewWindow. It might be that I need to use a different method than InvokeMember("click") to invoke the Log In button's click event handler. Or I might need to try something completely different altogether. I'm not 100% sure the Web_V1.NewWindow is the correct approach for my needs, but I've seen NewWindow used often when dealing with popups so I figured I should give it a try.
Any help would be greatly appreciated as I've spent a significant amount of time on this.
I know it is the late answer. But it will help someone else.
You can extract the value from FRAME element by following
// Get frame using frame ID
HtmlWindow frameWindow = (from HtmlWindow win
in WbBrowser.Document.Window.Frames select win)
.Where(x => string.Compare(x.WindowFrameElement.Id, "frm1") == 0)
.FirstOrDefault();
// Get first frame textbox with ID
HtmlElement txtElement = (from HtmlElement element
in frameWindow.Document.GetElementsByTagName("input")
select element)
.Where(x => string.Compare(x.Id, "txt") == 0).FirstOrDefault();
// Check txtElement is nul or not
if(txtElement != null)
{
Label1.Text = txtElement.GetAttribute("value");
}
For more details check
this article
Prelude
At first, sorry for my bad english. :)
I read a tone of similar questions on SO, but none of them provide a solution for my problem, or I'm just stupid. :)
Question
How would I open a new chat form to talk with User1 and retain the possibility to open chat forms with other users from "users list", but block opening a chat form with a user which is already open?
I tried to find something for this, but whatever I tried, it always is same (I can open same form again and again).
So, for example, I can open a chat form with User1, I can talk with him, and I can also open a new chat form with User2 and I can talk with him. But I can also open multiple forms with User1, and with User2 to, etc.
Also, I need to pass some data from MainForm form to TalkForm, so as prototype I created this code and I tried to list, but I'm not sure how to check if a form does exist in the list:
List<TalkForm> b = new List<TalkForm>();
private void TextBoxConnectedClients_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (TextBoxConnectedClients.SelectedIndex == -1)
{
return;
}
int index = this.TextBoxConnectedClients.IndexFromPoint(e.Location);
if (index != System.Windows.Forms.ListBox.NoMatches)
{
string username = TextBoxConnectedClients.SelectedItem.ToString();
TalkForm a = new TalkForm(im, username, displayname);
b.Add(a);
a.Show();
}
}
Can someone please give me some examples or tell me what I'm doing wrong? Thank you.
List<TalkForm> b = new List<TalkForm>();
You are using this list to track the forms opened for each unique user. I would update your code to check if form object is already added. You need to add using System.Linq
if (index != System.Windows.Forms.ListBox.NoMatches)
{
string username = TextBoxConnectedClients.SelectedItem.ToString();
// Check if form is already opened. Username will be unique.
var form = b.firstOrDefault(f => f.Username == username);
if (form == null) // Show new form
{
TalkForm a = new TalkForm(im, username, displayname);
b.Add(a);
a.Show();
}
else // Activate already opened form
{
form.BringToFront();
}
}
You need to expose TalkForm.Username property, if it's not in place already. And initialize that property in the constructor with username parameter.
Note: Make sure you Remove the form instance from list b when close a form for specific user.
Edit: Updated code to show already opened form as per #Draken's suggestion.
I have used this method i found online, which will take a Uri then check if the uri is opened in an IE browser if it is opened it will prevent the opening of new tab or instance of the same site, if not a new IE tab will open which is great for what i was looking for the method is bellow:
public static void LaunchSite(Uri sitUrl)
{
SHDocVw.ShellWindows w = new SHDocVw.ShellWindows();
bool found = false;
foreach (SHDocVw.ShellBrowserWindow item in w)
{
var doc = item.LocationURL;
if (!string.IsNullOrEmpty(doc))
if (doc == sitUrl.AbsoluteUri)
{
found = true;
break;
}
}
if (!found)
Process.Start(sitUrl.AbsoluteUri);
}
Then used the method in a button_click event handler as follow:
private void btnSubs_Click(object sender, RoutedEventArgs e)
{
Uri oxfArt = new Uri(#"http://www.somesite.com/subscriber/");
StartProcess.LaunchSite(oxfArt);
}
my questions are :
within the method how can i check if there is already an instance of IE open, if it is i need to open the site within that IE window not as a new tab or new IE instance, basically i need to be able to have one instance and one windows of all my sites to be opened in current window?.
within the button event handler i need to use switch statement that uses different URI to save me creating different button event handler for each URI, How would I be able to achieve that
The answer to my 2nd question has 2 option for solution:
Button btnSub = e.Source as Button;
if (btnSub != null)
{
Uri uri = new Uri((string)btnSub.Tag);
StartProcess.LaunchSite(uri);
}
within the butonn click event handler.
then in the button triggered the event we need to set the tag to the desired Uri as follow:
<Button x:Name="theorytst" Cursor="Hand" Tag="http://theorytestpro.co.uk/">
the 2nd solution is to use the switch statement using the button x:Name and the button tag property as before then cast button tag as Uri to pass to the calling method StartProcess.LaunchSite(uri);
switch (btnSub.Name)
{
case "oxfArt":
Uri uri = new Uri((string)btnSub.Tag);
StartProcess.LaunchSite(uri);
break;
case "theorytst":
Uri uri1 = new Uri((string)btnSub.Tag);
StartProcess.LaunchSite(uri1);
break;
default:
break;
}
I need to be able to have one instance and one windows of all my sites to be opened in current window?
Process[] pname = Process.GetProcessesByName("iexplore");
if (pname.Length == 0)
{
Process.Start("IEXPLORE.EXE", "http://www.somesite.com/subscriber/");
}
else
{
try
{
foreach (Process proc in Process.GetProcessesByName("iexplore"))
{
proc.Kill();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Within the button event handler i need to use switch statement that uses different URI to save me creating different button event handler for each URI, How would I be able to achieve that
As I understand correctly you want to call various button handlers. You can do it using switch statement. For example:
string input="http://getyourURI.com"; //you should set your own http address.
//It is just an example
Uri uri = new Uri(input);
string address = uri.OriginalString;
switch(address)
{
case "hey.com":
btnExcel_Click(null, null);
break;
case "another.com":
callAnotherBtn_Click(null, null);
break;
}
So I'm working with selenium firefox webdrivers in c# winform and I have this code below to get the handle of the popup that shows when you click on the "webtraffic_popup_start_button" and it should get the handle of the popup but the popup handle is same as current one.
string current = driver.CurrentWindowHandle;
driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']")).Click();
Thread.Sleep(Sleep_Seconds);
popup = driver.CurrentWindowHandle;
Thread.Sleep(3000);
driver.SwitchTo().Window(current);
Thread.Sleep(1000);
Any help with this would be much appreciated thank you
This is what pop up looks like.
WebDriver does absolutely no tracking whatsoever to detect which window is actually in the foreground in the OS, and does no automatic switching when new browser windows are opened. That means the proper way to get the handle of a newly-opened popup window is a multi-step process. To do so, you would:
Save the currently-focused window handle into a variable so that you
can switch back to it later.
Get the list of currently opened window handles.
Perform the action that would cause the new window to appear.
Wait for the number of window handles to increase by 1.
Get the new list of window handles.
Find the new handle in the list of handles.
Switch to that new window.
In code using the .NET language bindings, that would look something like this:
string currentHandle = driver.CurrentWindowHandle;
ReadOnlyCollection<string> originalHandles = driver.WindowHandles;
// Cause the popup to appear
driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']")).Click();
// WebDriverWait.Until<T> waits until the delegate returns
// a non-null value for object types. We can leverage this
// behavior to return the popup window handle.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
string popupWindowHandle = wait.Until<string>((d) =>
{
string foundHandle = null;
// Subtract out the list of known handles. In the case of a single
// popup, the newHandles list will only have one value.
List<string> newHandles = driver.WindowHandles.Except(originalHandles).ToList();
if (newHandles.Count > 0)
{
foundHandle = newHandles[0];
}
return foundHandle;
});
driver.SwitchTo().Window(popupWindowHandle);
// Do whatever you need to on the popup browser, then...
driver.Close();
driver.SwitchTo().Window(currentHandle);
Alternatively, if you're using the .NET bindings, there's a PopupWindowFinder class in the WebDriver.Support assembly that is specifically designed to do these operations for you. Using that class is much simpler.
// Get the current window handle so you can switch back later.
string currentHandle = driver.CurrentWindowHandle;
// Find the element that triggers the popup when clicked on.
IWebElement element = driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']"));
// The Click method of the PopupWindowFinder class will click
// the desired element, wait for the popup to appear, and return
// the window handle to the popped-up browser window. Note that
// you still need to switch to the window to manipulate the page
// displayed by the popup window.
PopupWindowFinder finder = new PopupWindowFinder(driver);
string popupWindowHandle = finder.Click(element);
driver.SwitchTo().Window(popupWindowHandle);
// Do whatever you need to on the popup browser, then...
driver.Close();
// Switch back to parent window
driver.SwitchTo().Window(currentHandle);
If the lastly opened window is your target then simply do the following after the click
driver.SwitchTo().Window(driver.WindowHandles.ToList().Last());
EDIT
//You may need to go back to parent window to perform additional actions;
// to the new window
driver.SwitchTo().Window(driver.WindowHandles.ToList().Last());
// to the new window
driver.SwitchTo().Window(driver.WindowHandles.ToList().First());
//or
driver.SwitchTo().DefaultContent();
I've got some code you might like. The quickest solution is to use Popup Finder, but I've made my own method as well. I would never rely on the order the Window Handles are in to select the appropriate window. Popup Window Finder:
PopupWindowFinder finder = new PopupWindowFinder(driver);
driver.SwitchTo().Window(newWin);
My Custom method. Basically you pass it the element you want to click, your webdriver, and optionally the time to wait before searching after you click the element.
It takes all of your current handles and makes a list. It uses that list to eliminate the previously existing windows from accidentally getting switched to. Then it clicks the element that launches the new window. There should always be some sort of a delay after the click, as nothing happens instantly. And then it makes a new list and compares that against the old one until it finds a new window or the loop expires. If it fails to find a new window it returns null, so if you have an iffy webelement that doesn't always work, you can do a null check to see if the switch worked.
public static string ClickAndSwitchWindow(IWebElement elementToBeClicked,
IWebDriver driver, int timer = 2000)
{
System.Collections.Generic.List<string> previousHandles = new
System.Collections.Generic.List<string>();
System.Collections.Generic.List<string> currentHandles = new
System.Collections.Generic.List<string>();
previousHandles.AddRange(driver.WindowHandles);
elementToBeClicked.Click();
Thread.Sleep(timer);
for (int i = 0; i < 20; i++)
{
currentHandles.Clear();
currentHandles.AddRange(driver.WindowHandles);
foreach (string s in previousHandles)
{
currentHandles.RemoveAll(p => p == s);
}
if (currentHandles.Count == 1)
{
driver.SwitchTo().Window(currentHandles[0]);
Thread.Sleep(100);
return currentHandles[0];
}
else
{
Thread.Sleep(500);
}
}
return null;
}
I am stuck when trying to switch windows using the latest version of webdriver in C#.
I have a base window, when i click a button, it opens a new window.
The target code for this button is as below.
window.open(uri, "DisplayPage", " width=1200, scrollbars=yes , resizable = yes , toolbar = no , menubar = no");
I am using the below mentioned code to target the new window
string BaseWindow = _driver.CurrentWindowHandle;
ReadOnlyCollection<string> handles = _driver.WindowHandles;
foreach (string handle in handles)
{
if (handle != BaseWindow)
{
_driver.SwitchTo().Window(handle).Title.Equals("DisplayPage");
}
}
}
As you can see from above, I am switching to the window using the Target Title from the base window. This does not seem to work.
I then noticed that the Title of the opened window was different, it was "Display - Transaction Page"
I then modified the code to this
string BaseWindow = _driver.CurrentWindowHandle;
ReadOnlyCollection<string> handles = _driver.WindowHandles;
foreach (string handle in handles)
{
if (handle != BaseWindow)
{
_driver.SwitchTo().Window(handle).Title.Equals("Display - Transaction Page");
}
}
}
Still no luck.
Interestingly, I do not get any errors saying "Window not found".
The problem is that When i try to click on elements on the newly opened page, i get a NoSuchElementException which means that the newly opened window has not been targeted.
Any ideas?
Regards,
Hasan
You should break the loop once window changed to your window, otherwise it will always switch to last opened window:
foreach (string handle in handles) {
if (handle != BaseWindow) {
if(_driver.SwitchTo().Window(handle).Title.Equals("Display - Transaction Page"))
break;
}
}
You can try with Contains instead of equal, it will simplify the window search:
_driver.SwitchTo().Window(handle).Title.Contains("Display");
Although you cracked the answer yourself, there is another way to handle switching between the windows in C#.
// initiate webdriver
IWebDriver driver = new FirefoxDriver();
//perform some action to open a new window. Like clicking a link.
driver.FindElement(By.Id("btnId")).Click();
//switch to new window.
driver.SwitchTo().Window(driver.WindowHandles.Last());
//if you want to switch back to your first window
driver.SwitchTo().Window(driver.WindowHandles.First());