是否可以将Selenium与包含WebBrowser对象的C#窗体表单一起使用?

时间:2022-04-06 21:33:20

I'm wondering if it's possible to use Selenium with a C# Windows Form that contains a WebBrowser object.

我想知道是否可以将Selenium与包含WebBrowser对象的C#Windows窗体一起使用。

I'm using selenium and I'm able to create test cases with the Selenium script record; I'm just trying to pinpoint whether or not I can export the C# code and have it all run within a C# environment. I appreciate any thoughts or explanations.

我正在使用selenium,我可以使用Selenium脚本记录创建测试用例;我只想确定是否可以导出C#代码并让它们都在C#环境中运行。我感谢任何想法或解释。

update I got to the point to have Selenium open the WinForm which contains the WebBrowser Component. However from there my test won't execute. Looks like it doesn't understand selenium command. I don't see any error messages being thrown though. hmmm

更新我得到了Selenium打开包含WebBrowser组件的WinForm的观点。但是从那里我的测试将不会执行。看起来它不懂selenium命令。我没有看到任何错误消息被抛出。嗯

The thing is winformWithWebBrowserTest.exe which opens winForm with webbrowser is opened. But nothing happens. Below code is the one that fires up the .exe

东西是winformWithWebBrowserTest.exe打开winForm打开webbrowser。但没有任何反应。下面的代码是启动.exe的代码

test code (Selenium command)

测试代码(Selenium命令)

namespace ClassLibrary1
{
    class Class2
    {
        private ISelenium selenium;
        private StringBuilder verificationErrors;

        [SetUp]
        public void SetupTest()
        {

            selenium = new DefaultSelenium
                ("localhost", 4444, "*custom C:\\Users\\m-tak\\Documents\\Visual Studio 2010\\Projects\\winformWithWebBrowserTest\\winformWithWebBrowserTest\\bin\\Release\\winformWithWebBrowserTest.exe", "http://www.livemocha.com");

            selenium.Start();
            verificationErrors = new StringBuilder();
        }

        [TearDown]
        public void TeardownTest()
        {
            selenium.Stop();
        }

        [Test]
        public void TheUntitledTest()
        {
            //nothing here gets executed :(
            Console.WriteLine("foobar front");
            selenium.Open("/");
            Console.WriteLine("foobar");
            selenium.WaitForPageToLoad("30000");
            selenium.Open("/users/logout");
            selenium.Open("/users/login");


        }

    }
}

.exe

。可执行程序

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
           //this gets executed always......
            HtmlElement head = webBrowser1.Document.GetElementsByTagName("body")[0]; 
            HtmlElement scriptOne = webBrowser1.Document.CreateElement("script");
            IHTMLScriptElement element = (IHTMLScriptElement)scriptOne.DomElement;
            element.text = "function sayHello() { " + 
                "alert('hello');" +
                " }" ;
            head.AppendChild(scriptOne);
            webBrowser1.Document.InvokeScript("sayHello");


        }
        //getter setter..... 
        public WebBrowser getWebBrowser() 
        {
            return this.webBrowser1;

        }
        public void setWebBrowser(WebBrowser wb) 
        {
            this.webBrowser1 = wb;
        }

        //just address bar
        private void button1_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(textBox1.Text))
            {
                webBrowser1.Navigate(textBox1.Text);
            }
        }

        //just address bar
        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if (textBox1.Text != e.Url.ToString())
            {
                textBox1.Text = e.Url.ToString();
            }
        }

    }
}

UPDATE

UPDATE

I made my test simple so now I don't use NUnit. I've created C# console app just to run the c# .exe file. But in my console it would output "--1--" and "--2--" only..

我让我的测试变得简单,所以现在我不使用NUnit。我创建了C#console app只是为了运行c#.exe文件。但是在我的控制台中它只会输出“--1--”和“--2--”。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Selenium;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("-- 1---");
            ISelenium selenium;


            selenium = new DefaultSelenium
                ("localhost", 4444, "*custom C:\\Users\\m-takayashiki\\Documents\\Visual Studio 2010\\Projects\\winformWithWebBrowserTest\\winformWithWebBrowserTest\\bin\\Release\\winformWithWebBrowserTest.exe", "http://www.livemocha.com");

            Console.WriteLine("-- 2---");

            selenium.Start();

            Console.WriteLine("-- 3---");


            selenium.Open("/");
            selenium.WaitForPageToLoad("30000");
            selenium.Open("/users/logout");
            selenium.Open("/users/login");


            Console.WriteLine("test test test");

            //tear down
            selenium.Stop();

        }
    }
}

UPDATE

UPDATE

I checked RC log:

我检查了RC日志:

15:40:35.379 DEBUG [13] org.openqa.jetty.http.HttpContext - Handler org.openqa.selenium.server.SeleniumDriverResourceHandler in HttpContext[/selenium-server,/selenium-server]
15:40:35.380 DEBUG [13] org.openqa.selenium.server.SeleniumDriverResourceHandler - req: POST /selenium-server/driver/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Host: localhost:4444
Content-Length: 247
Expect: 100-continue
Connection: keep-alive

15:40:45.408 DEBUG [13] org.openqa.selenium.server.FrameGroupCommandQueueSet - waiting for window 'null' local frame 'null' for 1790 more secs
15:40:45.408 DEBUG [13] org.openqa.selenium.server.FrameGroupCommandQueueSet - waiting for condition for 1000 more ms
15:40:45.945 DEBUG [12] org.openqa.selenium.server.FrameGroupCommandQueueSet - got condition? : false

4 个解决方案

#1


3  

I haven't done this with selenium, but I did the same thing with WatiN when I wanted to automate InfoPath. The approach that I took was as follows:

我没有用selenium做过这个,但是当我想自动化InfoPath时,我对WatiN做了同样的事情。我采取的方法如下:

  1. Kill off all the processes that have that name in my case it was "infopath"

    在我的案例中取消所有具有该名称的流程它是“infopath”

    foreach (Process proc in Process.GetProcessesByName("infopath"))
    {    
      proc.Kill();
    }
    
  2. Launch your test application call Process.GetProcessesByName to get all the process id's then get the window handle of the first as there should only be one process running.

    启动测试应用程序调用Process.GetProcessesByName以获取所有进程ID然后获取第一个窗口句柄,因为应该只有一个进程在运行。

    Process[] updatedInfopathProcessList = Process.GetProcessesByName("infopath");
    if (updatedInfopathProcessList[0].Id == 0)
    {
        throw new ApplicationException("No Infopath processes exist");
    }
    infopathProcessId = updatedInfopathProcessList[0].Id;
    infopathHwnd = updatedInfopathProcessList[0].MainWindowHandle;
    
  3. Now that I had the window handle, I get the IHTMLDocument2 to automate against with WatiN.

    现在我有了窗口句柄,我得到了IHTMLDocument2来自动化WatiN。

    InternalHTMLDOMDocument = IEDom.IEDOMFromhWnd(this.hWnd);
    

The real rubber hits the road in the IEDom class ... code is below ...

真正的橡胶在IEDom类中崭露头角......代码如下......

    namespace ItiN
    {
        public class IEDom
        {

            internal static IHTMLDocument2 IEDOMFromhWnd(IntPtr hWnd)
            {
                Guid IID_IHTMLDocument2 = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");

                Int32 lRes = 0;
                Int32 lMsg;
                Int32 hr;

                //if (IsIETridentDlgFrame(hWnd))
                //{
                    if (!IsIEServerWindow(hWnd))
                    {
                        // Get 1st child IE server window
                        hWnd = NativeMethods.GetChildWindowHwnd(hWnd, "Internet Explorer_Server");
                    }

                    if (IsIEServerWindow(hWnd))
                    {
                        // Register the message
                        lMsg = NativeMethods.RegisterWindowMessage("WM_HTML_GETOBJECT");
                        // Get the object
                        NativeMethods.SendMessageTimeout(hWnd, lMsg, 0, 0, NativeMethods.SMTO_ABORTIFHUNG, 1000, ref lRes);
                        if (lRes != 0)
                        {
                            // Get the object from lRes
                            IHTMLDocument2 ieDOMFromhWnd = null;
                            hr = NativeMethods.ObjectFromLresult(lRes, ref IID_IHTMLDocument2, 0, ref ieDOMFromhWnd);
                            if (hr != 0)
                            {
                                throw new COMException("ObjectFromLresult has thrown an exception", hr);
                            }
                            return ieDOMFromhWnd;
                        }
                    }
               // }
                return null;
            }

            internal static bool IsIETridentDlgFrame(IntPtr hWnd)
            {
                return UtilityClass.CompareClassNames(hWnd, "Internet Explorer_TridentDlgFrame");
            }

            private static bool IsIEServerWindow(IntPtr hWnd)
            {
                return UtilityClass.CompareClassNames(hWnd, "Internet Explorer_Server");
            }
        }
    }

Sorry this is not for selenium, but it is how I solved the problem for WatiN so I hope it can help. The code is here http://itin.codeplex.com/, and I also think that this has been added to WatiN as well.

对不起,这不是selenium,但它是我如何解决WatiN的问题,所以我希望它可以帮助。代码在http://itin.codeplex.com/,我也认为这也被添加到WatiN中了。

#2


1  

In theory it would work as long Selenium can inject JS into the browser component. You would need to use the *custom command and pass in the executable that you want Selenium to start up and then it will try do what you want.

从理论上讲,只要Selenium可以将JS注入浏览器组件,它就能工作。您需要使用* custom命令并传入您希望Selenium启动的可执行文件,然后它将尝试执行您想要的操作。

#3


1  

I think you can, but you might have to use Selenium RC. It has a .Net version of the Selenium API.

我想你可以,但你可能不得不使用Selenium RC。它有一个.Net版本的Selenium API。

#4


0  

We hacked the selenium webdriver code slightly to attach to an embedded IE instance inside a windows app. http://bradbax.blogspot.ca/2013/07/driving-embedded-wpf-browser-with.html

我们稍微破解了selenium webdriver代码,以附加到Windows应用程序内的嵌入式IE实例。 http://bradbax.blogspot.ca/2013/07/driving-embedded-wpf-browser-with.html

#1


3  

I haven't done this with selenium, but I did the same thing with WatiN when I wanted to automate InfoPath. The approach that I took was as follows:

我没有用selenium做过这个,但是当我想自动化InfoPath时,我对WatiN做了同样的事情。我采取的方法如下:

  1. Kill off all the processes that have that name in my case it was "infopath"

    在我的案例中取消所有具有该名称的流程它是“infopath”

    foreach (Process proc in Process.GetProcessesByName("infopath"))
    {    
      proc.Kill();
    }
    
  2. Launch your test application call Process.GetProcessesByName to get all the process id's then get the window handle of the first as there should only be one process running.

    启动测试应用程序调用Process.GetProcessesByName以获取所有进程ID然后获取第一个窗口句柄,因为应该只有一个进程在运行。

    Process[] updatedInfopathProcessList = Process.GetProcessesByName("infopath");
    if (updatedInfopathProcessList[0].Id == 0)
    {
        throw new ApplicationException("No Infopath processes exist");
    }
    infopathProcessId = updatedInfopathProcessList[0].Id;
    infopathHwnd = updatedInfopathProcessList[0].MainWindowHandle;
    
  3. Now that I had the window handle, I get the IHTMLDocument2 to automate against with WatiN.

    现在我有了窗口句柄,我得到了IHTMLDocument2来自动化WatiN。

    InternalHTMLDOMDocument = IEDom.IEDOMFromhWnd(this.hWnd);
    

The real rubber hits the road in the IEDom class ... code is below ...

真正的橡胶在IEDom类中崭露头角......代码如下......

    namespace ItiN
    {
        public class IEDom
        {

            internal static IHTMLDocument2 IEDOMFromhWnd(IntPtr hWnd)
            {
                Guid IID_IHTMLDocument2 = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");

                Int32 lRes = 0;
                Int32 lMsg;
                Int32 hr;

                //if (IsIETridentDlgFrame(hWnd))
                //{
                    if (!IsIEServerWindow(hWnd))
                    {
                        // Get 1st child IE server window
                        hWnd = NativeMethods.GetChildWindowHwnd(hWnd, "Internet Explorer_Server");
                    }

                    if (IsIEServerWindow(hWnd))
                    {
                        // Register the message
                        lMsg = NativeMethods.RegisterWindowMessage("WM_HTML_GETOBJECT");
                        // Get the object
                        NativeMethods.SendMessageTimeout(hWnd, lMsg, 0, 0, NativeMethods.SMTO_ABORTIFHUNG, 1000, ref lRes);
                        if (lRes != 0)
                        {
                            // Get the object from lRes
                            IHTMLDocument2 ieDOMFromhWnd = null;
                            hr = NativeMethods.ObjectFromLresult(lRes, ref IID_IHTMLDocument2, 0, ref ieDOMFromhWnd);
                            if (hr != 0)
                            {
                                throw new COMException("ObjectFromLresult has thrown an exception", hr);
                            }
                            return ieDOMFromhWnd;
                        }
                    }
               // }
                return null;
            }

            internal static bool IsIETridentDlgFrame(IntPtr hWnd)
            {
                return UtilityClass.CompareClassNames(hWnd, "Internet Explorer_TridentDlgFrame");
            }

            private static bool IsIEServerWindow(IntPtr hWnd)
            {
                return UtilityClass.CompareClassNames(hWnd, "Internet Explorer_Server");
            }
        }
    }

Sorry this is not for selenium, but it is how I solved the problem for WatiN so I hope it can help. The code is here http://itin.codeplex.com/, and I also think that this has been added to WatiN as well.

对不起,这不是selenium,但它是我如何解决WatiN的问题,所以我希望它可以帮助。代码在http://itin.codeplex.com/,我也认为这也被添加到WatiN中了。

#2


1  

In theory it would work as long Selenium can inject JS into the browser component. You would need to use the *custom command and pass in the executable that you want Selenium to start up and then it will try do what you want.

从理论上讲,只要Selenium可以将JS注入浏览器组件,它就能工作。您需要使用* custom命令并传入您希望Selenium启动的可执行文件,然后它将尝试执行您想要的操作。

#3


1  

I think you can, but you might have to use Selenium RC. It has a .Net version of the Selenium API.

我想你可以,但你可能不得不使用Selenium RC。它有一个.Net版本的Selenium API。

#4


0  

We hacked the selenium webdriver code slightly to attach to an embedded IE instance inside a windows app. http://bradbax.blogspot.ca/2013/07/driving-embedded-wpf-browser-with.html

我们稍微破解了selenium webdriver代码,以附加到Windows应用程序内的嵌入式IE实例。 http://bradbax.blogspot.ca/2013/07/driving-embedded-wpf-browser-with.html