1、Selenium 1 原理
(1).测试用例(Testcase)通过Client Lib的接口向Selenium Server发送Http请求,要求和Selenium Server建立连接。
为什么要通过发送Http请求控制Selenium Server而不采用其他方式呢?从上文可以看出,Selenium Server是一个独立的中间服务器(确切地说是代理服务器),它可以架设在其他机器上!所以测试案例通过发送HTTP请求去控制Selenium Server是很正常的。
(2).Selenium Server的Launcher启动浏览器,把Selenium Core加载入浏览器页面当中,并把浏览器的代理设置为Selenium Server的Http Proxy。
(3).测试案例通过Client Lib的接口向Selenium Server发送Http请求,Selenium Server对请求进行解析,然后通过Http Proxy发送JS命令通知Selenium Core执行操作浏览器的动作。
(4).Selenium Core接收到指令后,执行操作。
(5).浏览器收到新的页面请求信息(因为在(4)中,Selenium Core的操作可能引发新的页面请求),于是发送Http请求,请求新的Web页面。
由于Selenium Server在启动浏览器时做了手脚,所以Selenium Server会接收到所有由它启动的浏览器发送的请求。
(6).Selenium Server接收到浏览器的发送的Http请求后,自己重组Http请求,获取对应的Web页面。
(7).Selenium Server的Http Proxy把接收的Web页面返回给浏览器。
2、WebDriver
WebDriver 提供了一堆用于查找和维护页面元素(DOM元素)的接口,以此方式来控制浏览器行为。目前已纳入W3C管理。
https://www.w3.org/TR/webdriver/
2.1 Webdriver 组件
在WebDriver协议里,包括local,remote,Intermidary,endpoint等概念:
·Local End:代表了WebDriver通信的客户端,通常情况下,是由一些特定语言基于通信协议组成的一套Client API。
·Remote End:remote是在通信协议的服务端。用于处理Client请求并作出响应。它包括两大类:
Intermidary node:intermidary 通常是代理,它实现了local,并代理了remote。
Endpoint :endpoint 才是实际上的remote 端的处理的地方。和Java Web开发中的action、Webservice中的endpoint是类似的概念。
Webdriver 的通信协议是基于HTTP的以命令(command)方式组织的各种请求。WebDriver在处理一个命令时,可能会使browser执行一系列的操作。上面图中,webdriver server就是remote end,WebDriver Client就是local end。
2.2 WebDriver 协议
2.2.1 Remote End 处理流程
在local end与remote end的连接建立后,Remote End会做如下处理:
1、根据HTTP协议读取一个完整的HTTP请求,并封装成request对象。
2、根据http request method, url对请求进行匹配,找到相应的endpoint。
3、如果匹配到了error ,就发送一个error给local end,然后step 1。
4、使用sessionid进行session匹配
5、如果匹配失败(session 列表里找不到与sessionid相关联的session),响应一个error,然后step 1。
6、如果是post请求,以json方式解析requet body。如果解析成功,但并不是一个对象,或者解析失败,响应一个error给Local。然后step 1。
7、等待浏览器导航完毕
8、响应结果
2.2.2 Commands & Endpoints & 请求路由
为了控制browser的行为,提供了一系列的command,大体可以分为几类:
1)Session管理(remote 与local之间的session)
2)浏览器URL导航
3)浏览器窗口管理
4)DOM元素管理
5)JS脚本执行
6)Cookie管理
7)Alert
8)截屏
9)一些操作例如(键盘,鼠标,批处理等)
Remote在接收到这些命令时,会进行Endpoint匹配。匹配时是根据URL、http method。
他们的对应关系是:
Method |
URI Template |
Command |
POST |
/session |
|
DELETE |
/session/{session id} |
|
GET |
/status |
|
GET |
/session/{session id}/timeouts |
|
POST |
/session/{session id}/timeouts |
|
POST |
/session/{session id}/url |
|
GET |
/session/{session id}/url |
|
POST |
/session/{session id}/back |
|
POST |
/session/{session id}/forward |
|
POST |
/session/{session id}/refresh |
|
GET |
/session/{session id}/title |
|
GET |
/session/{session id}/window |
|
DELETE |
/session/{session id}/window |
|
POST |
/session/{session id}/window |
|
GET |
/session/{session id}/window/handles |
|
POST |
/session/{session id}/frame |
|
POST |
/session/{session id}/frame/parent |
|
GET |
/session/{session id}/window/rect |
|
POST |
/session/{session id}/window/rect |
|
POST |
/session/{session id}/window/maximize |
|
POST |
/session/{session id}/window/minimize |
|
POST |
/session/{session id}/window/fullscreen |
|
GET |
/session/{session id}/element/active |
|
POST |
/session/{session id}/element |
|
POST |
/session/{session id}/elements |
|
POST |
/session/{session id}/element/{element id}/element |
|
POST |
/session/{session id}/element/{element id}/elements |
|
GET |
/session/{session id}/element/{element id}/selected |
|
GET |
/session/{session id}/element/{element id}/attribute/{name} |
|
GET |
/session/{session id}/element/{element id}/property/{name} |
|
GET |
/session/{session id}/element/{element id}/css/{property name} |
|
GET |
/session/{session id}/element/{element id}/text |
|
GET |
/session/{session id}/element/{element id}/name |
|
GET |
/session/{session id}/element/{element id}/rect |
|
GET |
/session/{session id}/element/{element id}/enabled |
|
POST |
/session/{session id}/element/{element id}/click |
|
POST |
/session/{session id}/element/{element id}/clear |
|
POST |
/session/{session id}/element/{element id}/value |
|
GET |
/session/{session id}/source |
|
POST |
/session/{session id}/execute/sync |
|
POST |
/session/{session id}/execute/async |
|
GET |
/session/{session id}/cookie |
|
GET |
/session/{session id}/cookie/{name} |
|
POST |
/session/{session id}/cookie |
|
DELETE |
/session/{session id}/cookie/{name} |
|
DELETE |
/session/{session id)/cookie |
|
POST |
/session/{session id}/actions |
|
DELETE |
/session/{session id}/actions |
|
POST |
/session/{session id}/alert/dismiss |
|
POST |
/session/{session id}/alert/accept |
|
GET |
/session/{session id}/alert/text |
|
POST |
/session/{session id}/alert/text |
|
GET |
/session/{session id}/screenshot |
|
GET |
/session/{session id}/element/{element id}/screenshot |
2.2.3 错误消息
从上面的流程里,有多次提到发现error时,回发一个error。而实际上返回的错误需要包括
{ Error: // 错误码 Message://错误信息 Stacktrace:// 发生错误时的stack } |
下面是各种错误的描述:
Error Code |
HTTP Status |
JSON Error Code |
Description |
element click intercepted |
400 |
element click intercepted |
The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested clicked. |
element not selectable |
400 |
element not selectable |
An attempt was made to select an element that cannot be selected. |
element not interactable |
400 |
element not interactable |
A command could not be completed because the element is notpointer- or keyboard interactable. |
insecure certificate |
400 |
insecure certificate |
Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate. |
invalid argument |
400 |
invalid argument |
The arguments passed to a command are either invalid or malformed. |
invalid cookie domain |
400 |
invalid cookie domain |
An illegal attempt was made to set a cookie under a different domain than the current page. |
invalid coordinates |
400 |
invalid coordinates |
The coordinates provided to an interactions operation are invalid. |
invalid element state |
400 |
invalid element state |
A command could not be completed because the element is in an invalid state, e.g. attempting to click an element that is no longer attached to the document. |
invalid selector |
400 |
invalid selector |
Argument was an invalid selector. |
invalid session id |
404 |
invalid session id |
Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it’s not active. |
javascript error |
500 |
javascript error |
An error occurred while executing JavaScript supplied by the user. |
move target out of bounds |
500 |
move target out of bounds |
The target for mouse interaction is not in the browser’s viewport and cannot be brought into that viewport. |
no such alert |
400 |
no such alert |
An attempt was made to operate on a modal dialog when one was not open. |
no such cookie |
404 |
no such cookie |
No cookie matching the given path name was found amongst the associated cookies of the current browsing context’sactive document. |
no such element |
404 |
no such element |
An element could not be located on the page using the given search parameters. |
no such frame |
400 |
no such frame |
A command to switch to a frame could not be satisfied because the frame could not be found. |
no such window |
400 |
no such window |
A command to switch to a window could not be satisfied because the window could not be found. |
script timeout |
408 |
script timeout |
A script did not complete before its timeout expired. |
session not created |
500 |
session not created |
A new session could not be created. |
stale element reference |
400 |
stale element reference |
A command failed because the referenced element is no longer attached to the DOM. |
timeout |
408 |
timeout |
An operation did not complete before its timeout expired. |
unable to set cookie |
500 |
unable to set cookie |
A command to set a cookie’s value could not be satisfied. |
unable to capture screen |
500 |
unable to capture screen |
A screen capture was made impossible. |
unexpected alert open |
500 |
unexpected alert open |
A modal dialog was open, blocking this operation. |
unknown command |
404 |
unknown command |
A command could not be executed because the remote end is not aware of it. |
unknown error |
500 |
unknown error |
An unknown error occurred in the remote end while processing the command. |
unknown method |
405 |
unknown method |
The requested command matched a known URL but did not match an method for that URL. |
unsupported operation |
500 |
unsupported operation |
Indicates that a command that should have executed properly cannot be supported for some reason. |
2.3 WebDriver 兼容性
为了支持各个浏览器,自然要由各个浏览器厂商来实现这一套协议。各个厂商的浏览器毕竟不同,各有各自的一些特性等。为了更好的支持各个浏览器,各个厂商可以在创建Session时,指定一些自定义的配置。
一些标准的配置有:
Capability |
Key |
Value Type |
Description |
Browser name |
"browserName" |
string |
Identifies the user agent. |
Browser version |
"browserVersion" |
string |
Identifies the version of the user agent. |
Platform name |
"platformName" |
string |
Identifies the operating system of the endpoint node. |
Accept insecure TLS certificates |
"acceptInsecureCerts" |
boolean |
Indicates whether untrusted and self-signed TLS certificates are implicitly trusted onnavigation for the duration of the session. |
Page load strategy |
"pageLoadStrategy" |
string |
Defines the current session’spage load strategy. |
Proxy configuration |
"proxy" |
JSONObject |
Defines the current session’sproxy configuration. |
Window dimensioning/positioning |
"setWindowRect" |
boolean |
Indicates whether the remote end supports all of thecommands in Resizing and Positioning Windows. |
"timeouts" |
JSONObject |
Describes the timeouts imposed on certain session operations. |
|
Unhandled prompt behavior |
"unhandledPromptBehavior" |
string |
Describes the current session’s user prompt handler. |
除此之外,各个厂商可以自定义自己的配置。
3、Selenium 2
Selenium 2 = WebDriver + Selenium1
只需要将Selenium 1 中的RC Server ,RC Client替换成 WebDriver ,就成了Selenium2的结构。