[小北De编程手记] : Lesson 07 - Selenium For C# 之 窗口处理
在实际的自动化测试过程中,我们会遇见许多需要对窗口进行处理的情况。比如,点击删除某条信息的时候系统会显示一个Alert框。或者点击某个超链接时会在浏览器中打开一个新的页面。这一篇,来和大家分享一下Selenium WebDriver窗口处理相关的API。那么,还是照例先看一下本文主要涉及到的话题:
- 窗口处理接口:ITargetLocator
- 浏览器弹出窗口的处理(新页面)
- JavaScript弹出框的处理:Alert, Confirm, Prompt
- 内嵌框架的处理:Frame , iFrame
(一)窗口处理接口:ITargetLocator
Selenium WebDriver处理窗口能力主要是由WebDriver对象的SwitchTo()方法返回的对象提供的。该对象实现了ITargetLocator接口,也基本涵盖了本文所有描述的所有情况(即对弹出窗口,JS模态窗口,内嵌框架的处理)。我们可以通过以下代码获取当前驱动的ITargetLocator对象:
1 /// <summary> 2 /// demo1 : 获取目标定位对象 3 /// </summary> 4 [Fact(DisplayName = "Cnblogs.WindowProcess.Demo1", Skip = "Just Demo")] 5 public void WindowProcess_Demo1() 6 { 7 // 1. 获取窗口定位对象 8 IWebDriver driver = new FirefoxDriver(); 9 //省略部分代码... ... 10 ITargetLocator locator = driver.SwitchTo(); 11 //后续操作... ... 12 driver.Close(); 13 }
ITargetLocator接口的定义如下所示,这里我先简要的介绍一下这些方法的作用(本文后面会逐个介绍):
- ActiveElement:获取当前焦点所在的元素,如果没有持有焦点的元素将返回Body元素(这个方法与窗口处理无关)。
- Alert:切换到JS弹出的模态窗口。
- DefaultContent:获取第一个页面上的Frame,当有iFrames的时候将获取主页面的Document。
- Frame:此方法有三个重载的实现,用来切换到到Frame。
- ParentFrame:选中获取当前页面的父辈Frame。
- Window:切换窗口。
1 // Summary: 2 // Defines the interface through which the user can locate a given frame or 3 // window. 4 public interface ITargetLocator 5 { 6 IWebElement ActiveElement(); 7 IAlert Alert(); 8 IWebDriver DefaultContent(); 9 IWebDriver Frame(int frameIndex); 10 IWebDriver Frame(IWebElement frameElement); 11 IWebDriver Frame(string frameName); 12 IWebDriver ParentFrame(); 13 IWebDriver Window(string windowName); 14 }
(二)浏览器弹出窗口的处理(新页面)
如上一小节所述,Selenium WebDriver对弹出窗口的处理主要是通过ITargetLocator.Window方法。下面我就来向大家介绍一下Selenium WebDriver中常用的窗口定位方式:
- 用窗口名称定位
- 结合标题和窗口句柄定位页面
@用窗口名称定位
参照ITargetLocator.Window方法的定义,该方法接受一个窗口的名称。因此我们可以通过窗口的名称切换到该窗口(前提是开发人员定义了这个窗口的名字):
1 // 1. 获取窗口定位对象 2 IWebDriver driver = new FirefoxDriver(); 3 //省略部分代码... ... 4 ITargetLocator locator = driver.SwitchTo(); 5 driver = locator.Window("windowName"); 6 //后续操作... ... 7 driver.Quit();
我们可以通过上面的代码切换窗口,但是问题来了,我们怎么获取到窗口的名字呢?所有的浏览器都有执行JS脚本的命令行工具,我们只需要输入“window.name”便可以看见当前窗口的名字了,下图是我在Firebug中的操作:
@结合标题和窗口句柄定位页面
很多情况下,开发人员是不会为每一个弹出的窗口定义名称的(实际上也没有这个必要)。那么,我们就需要用其他的方式来定位我们的目标窗口了,下面的代码使用了窗口句柄和标题定位需要访问的窗口,我们可以通过WebDriver对象的WindowHandles属性获取当前浏览器打开的所有句柄,在根据页面的特定条件(这里是用的标题)来判断哪一个句柄是需要操作的界面句柄。一般的情况下,我们需要保存当前的页面句柄,这样可以方便后操作完成之后能准确的返回当前页面。Demo的最后验证了操作页面的标题是否正确,代码如下:
1 /// <summary> 2 /// demo2 : 根据标题定位元素 3 /// </summary> 4 [Fact(DisplayName = "Cnblogs.WindowProcess.Demo2")] 5 public void WindowProcess_Demo2() 6 { 7 var articleName = "[小北De编程手记] : Lesson 02 - Selenium For C# 之 核心对象"; 8 9 _output.WriteLine("Step 01 : 启动浏览器并打开Lesson 01 - Selenium For C#"); 10 IWebDriver driver = new FirefoxDriver(); 11 driver.Url = "http://www.cnblogs.com/NorthAlan/p/5155915.html"; 12 13 _output.WriteLine("Step 02 : 点击链接打开新页面。"); 14 var lnkArticle02 = driver.FindElement(By.LinkText(articleName)); 15 lnkArticle02.Click(); 16 17 _output.WriteLine("Step 03 : 根据标题获取新页面的句柄。"); 18 var oldWinHandle = driver.CurrentWindowHandle; 19 foreach (var winHandle in driver.WindowHandles) 20 { 21 driver.SwitchTo().Window(winHandle); 22 if (driver.Title.Contains(articleName)) 23 { 24 break; 25 } 26 } 27 28 _output.WriteLine("Step 04 : 验证新页面标题是否正确。"); 29 var articleTitle = driver.FindElement(By.Id("cb_post_title_url")); 30 Assert.Equal<string>(articleName, articleTitle.Text); 31 32 _output.WriteLine("Step 05 : 关闭浏览器。"); 33 driver.Quit(); 34 }
值得说明的是,第22行代码使用了Title的内容做为判断是否是新开的页面的条件,这里你也可以根据实际的需要使用Url或是页面内容... ...等其他条件进行判断。
(三)JavaScript弹出框的处理
稍有Web编程经验的人都应该知道JavaScript可以弹出模态对话框。在介绍处理这些弹出的窗体之前我们先回顾一下浏览器内置的弹出框都有哪些类型:
- Alert:只有文字和一条提示信息以及一个确认按钮(用于提示用户)。
- Confirm:较Alert多了一个取消按钮(用于向用户确认信息)。
- Prompt:较Confirm多了一个文本输入框(向用户确认信息的同时可以获取用户输入)
- AuthenticationCredentials:用于输入用户名和密码的窗口(下图中没有给出)。
好了,现在我们开始介绍如何处理这些弹出框。上面我们提到过ITargetLocator.Alert方法可以用来处理模态窗口。该方法的返回对象实现了IAlert接口:
1 // Summary: 2 // Defines the interface through which the user can manipulate JavaScript alerts. 3 public interface IAlert 4 { 5 string Text { get; } 6 void Accept(); 7 void Dismiss(); 8 void SendKeys( string keysToSend); 9 void SetAuthenticationCredentials( string userName, string password); 10 }
在此,需要澄清一下,之前介绍的四种弹出窗口都是用实现了IAlert接口的对象描述的(也就是说Confirm,Prompt,AuthenticationCredentials都可以用实现了IAlert接口的对象进行处理):
- Text:获取弹出框文本信息(适用于所有模态窗口)
- Accept:点击确定按钮(适用于所有模态窗口)
- Dismiss:点击取消按钮(适用于Confirm,Prompt,AuthenticationCredentials)
- SendKeys:输入文本信息(适用于Prompt)
- SetAuthenticationCredentials:设置用户名和密码(适用于AuthenticationCredentials)
是不是 so... ... easy? 下面还是照例看一下具体的使用代码:
1 IAlert alert = driver.SwitchTo().Alert(); //转到弹出框 2 alert.Accept(); //确定:Alert , Confirm, Prompt 3 alert.Dismiss(); //取消:Confirm, Prompt 4 var text = alert.Text; //获取提示内容:Alert , Confirm, Prompt 5 alert.SendKeys("input text."); //输入提示文本:Prompt
(四)内嵌框架的处理
本文的最后,我来介绍一下关于网页内嵌框架的处理。早期的一些B/S系统会用iFrame和Frame进行布局和页面的嵌套。之前也有利用iFrame构建全局弹出框的设计方式。因此,如果你们的产品已经有多年的历史。那么,你可能会需要处理这部分的内容。其实Frame和iFrame的处理和窗口很类似,这里我简单的给出一个Demo:
1 ITargetLocator tagetLocator = driver.SwitchTo(); 2 tagetLocator.Frame(1); //frame index. 3 tagetLocator.Frame("frameName"); //frame frame name. 4 5 IWebElement frame = driver.FindElement(By .Id("frameId or iframeId" )); 6 tagetLocator.Frame(frame); 7 tagetLocator.DefaultContent();
从上面的代码中可以看到,可以使用index,frame name,或者frame对象把Driver切换到Frame上。
总结:本文主要介绍如何利用Selenium WebDriver核心的ITargetLocator接口处理各种窗口。
- 窗口处理接口:ITargetLocator
- 浏览器弹出窗口的处理(新页面)
- JavaScript弹出框的处理:Alert, Confirm, Prompt
- 内嵌框架的处理:Frame , iFrame
《Selenium For C#》的相关文章:Click here.
- [小北De编程手记] : Lesson 01 - Selenium For C# 之 环境搭建
- [小北De编程手记] : Lesson 02 - Selenium For C# 之 核心对象
- [小北De编程手记] : Lesson 03 - Selenium For C# 之 元素定位
- [小北De编程手记] : Lesson 04 - Selenium For C# 之 API 上
- [小北De编程手记] : Lesson 05 - Selenium For C# 之 API 下
- [小北De编程手记] : Lesson 06 - Selenium For C# 之 流程控制
- [小北De编程手记] : Lesson 07 - Selenium For C# 之 窗口处理
- [小北De编程手记] : Lesson 08 - Selenium For C# 之 PageFactory & 团队构建
说明:Demo地址:https://github.com/DemoCnblogs/Selenium