I am sorry if this is a dumb question. But I am a C# noob. I am trying to make a program where the user can selected which browser is used to execute a Selenium script.
I can successfully select my desired browser, hit the START button, and launch the correct browser. The program then performs a simple test action by navigating to a page.
What I want also want to be able to do is hit a STOP button and have the browser close. I have tried messing with the get; set; feature. But I don't think I have it quite right. Please note that I had removed my attempt at a get; set; configuration for the IWebDriver because it simply was not working, and I didn't want to confuse anyone.
Thanks
Here is my Windows Form:`
namespace WindowsFormsApplication1
{
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
MyInitializeComponent();
}
private readonly Browser form;
public MainWindow(Browser form)
{
this.form = form;
}
//Initiate variables
public string selectedBrowser;
public string selBrowser
{
get { return comboBoxBrowser.Text; }
}
private void MyInitializeComponent()
{
//default values here
}
private void buttonStart_Click(object sender, EventArgs e)
{
//Launch Browser
Browser.ChooseDriver(selBrowser);
}
private void buttonStop_Click(object sender, EventArgs e)
{
//Perform the Quit operation on the Silenium driver
}
}
}
Here is my Program.cs:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenQA.Selenium;
using OpenQA.Selenium.Edge;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.UI;
namespace WindowsFormsApplication1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow());
}
}
public class Browser
{
private IWebDriver _driver_;
public IWebDriver driver
{
get { return _driver_; }
set { _driver_ = driver; }
}
public static void ChooseDriver(string selBrowser)
{
//Run this if IE was selected
if (selBrowser == "Internet Explorer")
{
RemoteWebDriver browserdriver = null;
string serverPath = "Microsoft Web Driver";
if (System.Environment.Is64BitOperatingSystem)
{
serverPath = Path.Combine(System.Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%"), serverPath);
}
else
{
serverPath = Path.Combine(System.Environment.ExpandEnvironmentVariables("%ProgramFiles%"), serverPath);
}
InternetExplorerOptions options = new InternetExplorerOptions();
options.PageLoadStrategy = InternetExplorerPageLoadStrategy.Eager;
browserdriver = new InternetExplorerDriver(serverPath, options);
Launch(browserdriver);
}
}
public static void Launch(RemoteWebDriver _driver)
{
//Set Page load timeout to 5 seconds
_driver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(5));
//Navigate to URL
_driver.Url = "http://www.outlook.com/";
}
}
}
In case you have to separate code of the Form and the test, you can use these 2 options:
Use process.Kill()
try
{
foreach (Process proc in Process.GetProcessesByName("chromedriver.exe"))
{
proc.Kill();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Launch cmd taskkill
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C taskkill /f /fi \"pid gt 0\" /im chromedriver.exe";
process.StartInfo = startInfo;
process.Start();
Thank you John for your help on this. I was able to get all of my code running successfully within the form class. it was still bugging me that I could not figure out how to solve my original goal. So I kept looking for more examples and finally found the part that I was missing.
I was not instantiating the Browser class from within the Form class.
private void buttonStart_Click(object sender, EventArgs e)
{
Browser _browser = new Browser();
_browser.GetBrowser(selBrowser);
}
I know it probably sounds like a simple mistake for someone to make, and easy to correct. But I've only been learning C# for a week or two, and the login behind doing that escaped me. Perhaps it still don't fully understand why or what i'm doing with this solution. But at least I can move forward.
And thanks to you as well Buaban. I will need that taskkill snippet to kill the console window that opens every time a selenium driver is initiated.
Related
I have a winforms project that whenever a button is clicked, it calls another class which uses selenium. I am trying to make it so I could run 1 - however many windows I want running. So, I made it so that whenever the button is clicked it makes a new thread and calls a method that calls the other class. The issue is whenever I do multiple windows, it appears that only one window is doing the action. So if I want two windows to try and select a country, only one will select a country. Both windows however, open the url. I am really confused how or why this is happening, I initialize a new webdriver in the constructor so I don't understand why it doesn't seem to do anything else.
using System;
using System.Threading;
using System.Windows.Forms;
namespace MRE
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(generate));
t.IsBackground = true;
t.Start();
// if (!InvokeRequired)
// {
// Invoke((Action)generate);
// }
}
private void generate()
{
Class1 generator = new Class1();
generator.start();
}
}
}
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using System;
using System.Threading;
namespace MRE
{
class Class1
{
public static IWebDriver driver;
public static WebDriverWait wait;
public Class1()
{
driver = new ChromeDriver();
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
}
public void start()
{
try
{
driver.Navigate().GoToUrl("your url");
//Input DOB
SelectElement oSelect = new SelectElement(driver.FindElement(By.Id("capture-country")));
Thread.Sleep(2000);
oSelect.SelectByValue("GBR");
//click
wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("dob-field-inactive"))).Click();
//enter Month
wait.Until(ExpectedConditions.ElementIsVisible(By.Name("dob-month"))).SendKeys("01");
Thread.Sleep(1000);
//enter Day
wait.Until(ExpectedConditions.ElementIsVisible(By.Name("dob-day"))).SendKeys("01");
Thread.Sleep(1000);
//enter Year
wait.Until(ExpectedConditions.ElementIsVisible(By.Name("dob-year"))).SendKeys("2000");
}
catch (WebDriverException e)
{
}
}
}
}
I actually found one way to solve this problem. Instead of initializing the Webdriver as a class variable, I made it so it was a local variable to the start() method. It is not shown in my MRE, but in my actual class I have different methods that use the driver, so I made it so the parameters for any methods I called included IWebDriver as a parameter. Therefore there wasn't one instance of the webdriver running in multiple windows. If there is another way around this please let me know.
I'm new to writing test scripts so I apologize for my lack of understanding here, I'm certainly willing to learn though!
I've recorded a number of scripts in the Selenium IDE, but have found it lacking in flexibility (a reliance on static UI elements for example) so I'm going to swap to writing scripts in Selenium WebDriver.
To avoid the complexity of recreating all of these test cases from the ground up I plan on exporting my existing test cases in C# with NUnit and modifying the scripts from there. But the scripts spat out by the IDE are structured in a way I'm not familiar with.
Here's a script that I wrote from scratch, that should help explain my linear understanding:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.UI;
using System;
namespace UnitTestProject
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
}
}
}
class GoogleSuggest
{
static void Main(string[] args)
{
IWebDriver driver = new FirefoxDriver();
Actions action = new Actions(driver);
driver.Navigate().GoToUrl("http://website.com/account/Login.aspx");
IWebElement query = driver.FindElement(By.Name("LoginForm$UserName"));
query.SendKeys("username");
query = driver.FindElement(By.Name("LoginForm$Password"));
query.SendKeys("password");
System.Threading.Thread.Sleep(500);
driver.FindElement(By.Name("LoginForm$Button1")).Click();
System.Threading.Thread.Sleep(1500);
action.ContextClick(driver.FindElement(By.Id("uielementid"))).Perform();
}
}
That's a script I wrote that signs in to a website. What I understand about that script is that it starts up a Firefox instance with the lines
static void Main(string[] args)
{
IWebDriver driver = new FirefoxDriver();
Actions action = new Actions(driver);
It has a Main where the application starts, then using referential commands it starts up Firefox. please correct me if I'm wrong here
However, when I export cases from the IDE into C# with the NUnit Framework and copy it into a test project in VS I can't find where to put my Main to make the program compilable. The test case reads:
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
namespace SeleniumTests
{
[TestFixture]
public class Login
{
private IWebDriver driver;
private StringBuilder verificationErrors;
private string baseURL;
private bool acceptNextAlert = true;
[SetUp]
public void SetupTest()
{
driver = new FirefoxDriver();
baseURL = "http://website.com/";
verificationErrors = new StringBuilder();
}
[TearDown]
public void TeardownTest()
{
try
{
driver.Quit();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
Assert.AreEqual("", verificationErrors.ToString());
}
[Test]
public void TheLoginTest()
{
driver.Navigate().GoToUrl(baseURL + "/account/Login.aspx");
driver.FindElement(By.Id("LoginForm_UserName")).Clear();
driver.FindElement(By.Id("LoginForm_UserName")).SendKeys("username");
driver.FindElement(By.Id("LoginForm_Password")).Clear();
driver.FindElement(By.Id("LoginForm_Password")).SendKeys("password");
driver.FindElement(By.Id("LoginForm_Button1")).Click();
}
private bool IsElementPresent(By by)
{
try
{
driver.FindElement(by);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
private bool IsAlertPresent()
{
try
{
driver.SwitchTo().Alert();
return true;
}
catch (NoAlertPresentException)
{
return false;
}
}
private string CloseAlertAndGetItsText() {
try {
IAlert alert = driver.SwitchTo().Alert();
string alertText = alert.Text;
if (acceptNextAlert) {
alert.Accept();
} else {
alert.Dismiss();
}
return alertText;
} finally {
acceptNextAlert = true;
}
}
}
}
I've not been able to find where to insert my Main in this test case, nor (perhaps more importantly) do I understand this structure.
Any help or feedback is appreciated, thank you!
Alright, so I'm creating a windows service that will start and stop my rendering executable based on whether or not a user is logged in. I have already determined that I want to run the exe from a service, and know it will run in a secure desktop with no gui. That is not a problem for me.
What is a problem is that my service, when I tell it to start, instantly starts. I think that means I'm missing some sort of loop or event handler or SOMETHING, but I have no clue what. This is the first service I've tried to program. As there seems to be no way to debug a service effectively, I was hoping to get some input from the brilliant minds here.
Any input would be very much appreciated! Here's the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Management;
namespace SessionService
{
public partial class renderServ : ServiceBase
{
private readonly ManagementClass _wmiComputerSystem = new ManagementClass("Win32_ComputerSystem");
private Process process;
Boolean isRunning;
public renderServ()
{
InitializeComponent();
process = new Process();
process.StartInfo = new ProcessStartInfo(#"C:\Windows\notepad.exe");
isRunning = false;
}
public void OnUserLogin()
{
/*if (isRunning == true)
{
process.Kill();
process.WaitForExit();
}*/
isRunning = false;
}
public void OnUserLogoff()
{
if (isRunning == false)
{
process.Start();
process.PriorityClass = ProcessPriorityClass.Idle;
}
isRunning = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
switch (changeDescription.Reason)
{
case SessionChangeReason.SessionLogon:
{
OnUserLogin();
} break;
case SessionChangeReason.SessionLogoff:
{
OnUserLogoff();
} break;
case SessionChangeReason.SessionLock:
{
OnUserLogoff();
} break;
case SessionChangeReason.SessionUnlock:
{
OnUserLogin();
} break;
}
}
protected override void OnStart(string[] args)
{
CanHandleSessionChangeEvent = true;
System.Windows.Forms.Application.Run();
}
protected override void OnStop()
{
}
}
}
I'd like to send a command from a c# app to open a web page in firefox and fill in a form and click a button.
I dont want to use Selenium, what can i do to build this on my own?
The reason frameworks like selenium work is because websites are tempermental and browsers like firefox already implement the requests and responses needed, and frameworks like selenium build on top of that.
As for the profile problem, look here to get some info on creating custom profiles for selenium to use and then instantiate the driver like this:
driver = new FirefoxDriver(new FirefoxProfile(#"...\AppData\Roaming\Mozilla\Firefox\Profiles\7923jt85.default"));
I personaly prefer Selenium's API. Basically I used the IDE extension in firefox to record and export a C# test case, and then used the output to figure out how Selenium parses the html, and then built a library wrapper to make it customizable to my needs.
(The exported test case has a lot of NUnit test framework attributes, I just delete all of those, and call the methods given.)
The example below will open firefox, search google for "Cute Fluffy Cats", and then click on the Images tab.
You can use the API to do more if necessary, its just a matter of seeing what is available in the documentation.
(You can copy this source, create a console project in visual studio, add the selenium references and see it execute right before you very eyes.)
Another alternative is WatiN, but it is similar to Selenium, a test framework for people who build and want to test the user experience of their websites.
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
namespace SeleniumTests
{
public class Googletest
{
private IWebDriver driver;
private WebDriverWait wait;
private StringBuilder verificationErrors;
private string baseURL;
private bool acceptNextAlert = true;
public static void Main(string[] args)
{
var gt = new Googletest();
gt.SetupTest();
gt.TheGoogleTest();
//gt.TeardownTest();
}
public void SetupTest()
{
driver = new FirefoxDriver();
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
baseURL = "https://www.google.com/";
verificationErrors = new StringBuilder();
}
public void TeardownTest()
{
try
{
driver.Quit();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
}
public void TheGoogleTest()
{
driver.Navigate().GoToUrl(baseURL + "/");
driver.FindElement(By.Id("gbqfq")).Clear();
driver.FindElement(By.Id("gbqfq")).SendKeys("Cute Fluffy Cats");
driver.FindElement(By.Id("gbqfb")).Click();
wait.Until(d => d.FindElement(By.LinkText("Images"))).Click();
}
private bool IsElementPresent(By by)
{
try
{
driver.FindElement(by);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
private bool IsAlertPresent()
{
try
{
driver.SwitchTo().Alert();
return true;
}
catch (NoAlertPresentException)
{
return false;
}
}
private string CloseAlertAndGetItsText()
{
try
{
IAlert alert = driver.SwitchTo().Alert();
string alertText = alert.Text;
if (acceptNextAlert)
{
alert.Accept();
}
else
{
alert.Dismiss();
}
return alertText;
}
finally
{
acceptNextAlert = true;
}
}
}
}
It is my first program for service.
If i run this code as Console, LOOP works, but if I convert it to service, it does the operation initially, but does not LOOP.
Could you help me correct it?
tnx
using System;
using System.Net;
using KICBservice;
using System.Data;
using ConsoleApplication1.Classes;
using System.IO;
using System.ServiceProcess;
using System.Configuration.Install;
using System.ComponentModel;
namespace KICBService
{
[RunInstaller(true)]
public class MyWindowsServiceInstaller : Installer
{
public MyWindowsServiceInstaller()
{
var processInstaller = new ServiceProcessInstaller();
var serviceInstaller = new ServiceInstaller();
//set the privileges
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.DisplayName = "KICB_Payment";
serviceInstaller.StartType = ServiceStartMode.Manual;
//must be the same as what was set in Program's constructor
serviceInstaller.ServiceName = "KICB_Payment";
this.Installers.Add(processInstaller);
this.Installers.Add(serviceInstaller);
}
}
class Program : ServiceBase
{
static void Main(string[] args)
{
ServiceBase.Run(new Program());
KICBservice.Service1SoapClient kicb = new KICBservice.Service1SoapClient();
kicb.ClientCredentials.Windows.ClientCredential = new NetworkCredential("register", "KICBregistr1");
kicb.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
while (true)
{
try
{
kicb.Open();
StreamWriter tw = File.AppendText("c:\\KICB.log");
NewPayment np = new NewPayment();
np = kicb.GetPayment("register", "KICBregistr1");
// Operation with Database
tw.WriteLine("----------------");
tw.WriteLine(DateTime.Now);
tw.Close();
kicb.Close();
System.Threading.Thread.Sleep(60000);
}
catch (Exception ex)
{
kicb.Abort();
}
}
}
public Program()
{
this.ServiceName = "KICB_Payment";
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
//TODO: place your start code here
}
protected override void OnStop()
{
base.OnStop();
//TODO: clean up any variables and stop any threads
}
}
}
I am pasting full code of my program.
Where is that first code located?
Without that context, my best guess is that your OnStart() method fires, and then the service quits as soon the method ends because there's nothing left to do.
Also, I'm not a fan of the while (true) { Sleep(60000); // do work } pattern for services. Instead, you want to look for a function that actually blocks execution to keep your code going. Examples include TcpListener.AcceptTcpClient() and Thread.Join(). If you can't find something like that for the meat of your service, you may want to do something like set up a scheduled task instead.
You've placed the code outside of a function. What you have shown in the question should not even compile, and it certainly won't loop.
Note the //TODO: comment in the OnStart function definition:
protected override void OnStart(string[] args)
{
base.OnStart(args);
//TODO: place your start code here
}