Skip to content

Commit 3d049d5

Browse files
Snooz82aaltat
authored andcommitted
Modified Window Handling to be able to work over all active Browsers. (#1412)
* Added Keywords "Get Browser Ids" and "Get Browser aliases" to get a lists of all browsers. * Added "Switch Window" as replacement for select window. Added "browser" Option to all wondow Getters to get windows information of all browsers. * Added Option "browser" to "Switch Window" (only CURRENT or <id or alias> are possible). Switches Browser before. * Added example for Browser and window handling in Doc * Select Window deprecation warning to silent. * Moved window related keywords back to BrowserManagementKeywords to oversee the relevant changes better. * Added acceptance tests for edited Window- and Browser-Information handling. Modified dynamic_content.html to be able to manipulate the Window title freely.
1 parent 9411cbc commit 3d049d5

File tree

10 files changed

+405
-43
lines changed

10 files changed

+405
-43
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
*** Setting ***
2+
Documentation These tests must open own browser because windows opened by
3+
... earlier tests would otherwise be visible to Get Window XXX keywords
4+
... even if those windows were closed.
5+
Suite Setup Open 3 Browsers with Windows
6+
Suite Teardown Close All Browsers
7+
Resource resource.robot
8+
9+
*** Variables ***
10+
@{BrowserA_EXP_TITLES}= WindowA1 WindowA2 WindowA3
11+
@{BrowserB_EXP_TITLES}= WindowB1 WindowB2
12+
@{BrowserC_EXP_TITLES}= WindowC1
13+
@{ALL_BROWSERS_EXP_TITLES}= @{BrowserA_EXP_TITLES} @{BrowserB_EXP_TITLES} @{BrowserC_EXP_TITLES}
14+
@{EXP_ALIASES}= BrowserA BrowserB BrowserC
15+
@{EXP_IDS}= ${1} ${2} ${3}
16+
17+
18+
*** Test Cases ***
19+
Check Titles of Multiple Browser-Windows
20+
@{BrowserA_Titles}= Get Window Titles browser=BrowserA
21+
Should Be Equal ${BrowserA_Titles} ${BrowserA_EXP_TITLES}
22+
@{BrowserB_Titles}= Get Window Titles browser=BrowserB
23+
Should Be Equal ${BrowserB_Titles} ${BrowserB_EXP_TITLES}
24+
@{BrowserC_Titles}= Get Window Titles browser=BrowserC
25+
Should Be Equal ${BrowserC_Titles} ${BrowserC_EXP_TITLES}
26+
@{All_Browsers_Titles}= Get Window Titles browser=ALL
27+
Should Be Equal ${All_Browsers_Titles} ${ALL_BROWSERS_EXP_TITLES}
28+
29+
Check Count of Handle
30+
Check Handle Count 3 BrowserA
31+
Check Handle Count 2 BrowserB
32+
Check Handle Count 1 BrowserC
33+
Check Handle Count 6 ALL
34+
35+
Check Count of Names
36+
Check Name Count 3 BrowserA
37+
Check Name Count 2 BrowserB
38+
Check Name Count 1 BrowserC
39+
Check Name Count 6 ALL
40+
41+
Check Count of Identifiers
42+
Check Identifiers Count 3 BrowserA
43+
Check Identifiers Count 2 BrowserB
44+
Check Identifiers Count 1 BrowserC
45+
Check Identifiers Count 6 ALL
46+
47+
Check Locations
48+
@{Locations}= Get Locations browser=ALL
49+
Should Be Equal As Strings @{Locations}[0] ${FRONT_PAGE}javascript/dynamic_content.html?1
50+
Should Be Equal As Strings @{Locations}[1] ${FRONT_PAGE}javascript/dynamic_content.html?2
51+
Should Be Equal As Strings @{Locations}[2] ${FRONT_PAGE}javascript/dynamic_content.html?3
52+
Should Be Equal As Strings @{Locations}[3] ${FRONT_PAGE}javascript/dynamic_content.html?4
53+
Should Be Equal As Strings @{Locations}[4] ${FRONT_PAGE}javascript/dynamic_content.html?5
54+
Should Be Equal As Strings @{Locations}[5] ${FRONT_PAGE}javascript/dynamic_content.html?6
55+
${count} Get Length ${Locations}
56+
Should Be Equal As Integers 6 ${count}
57+
58+
Get Browser Ids and Alias
59+
@{Aliases}= Get Browser Aliases
60+
Should Be Equal ${Aliases} ${EXP_ALIASES}
61+
&{Aliases}= Get Browser Aliases
62+
Should Be Equal ${Aliases.BrowserA} ${1}
63+
Should Be Equal ${Aliases.BrowserB} ${2}
64+
Should Be Equal ${Aliases.BrowserC} ${3}
65+
@{IDs}= Get Browser Ids
66+
Should Be Equal ${IDs} ${EXP_IDS}
67+
68+
Select Window by Location
69+
Switch Browser BrowserA
70+
Switch Window WindowA1
71+
Switch Window By Location ${FRONT_PAGE}javascript/dynamic_content.html?5
72+
${location} Get Location
73+
Should Be Equal ${FRONT_PAGE}javascript/dynamic_content.html?5 ${location}
74+
Title Should Be WindowB2
75+
76+
Switch Window to Different Browser
77+
Switch Browser BrowserC
78+
Switch Window WindowC1
79+
Location Should Be ${FRONT_PAGE}javascript/dynamic_content.html?6
80+
Switch Window title:WindowA1 browser=BrowserA
81+
Location Should Be ${FRONT_PAGE}javascript/dynamic_content.html?1
82+
Switch Window url:${FRONT_PAGE}javascript/dynamic_content.html?4 browser=BrowserB
83+
Title Should Be WindowB1
84+
85+
Get Specific Locations and Title
86+
Switch Browser BrowserA
87+
Switch Window title:WindowA1
88+
Location Should Be ${FRONT_PAGE}javascript/dynamic_content.html?1
89+
@{Locations}= Get Locations browser=BrowserB
90+
Should Be Equal @{Locations}[0] ${FRONT_PAGE}javascript/dynamic_content.html?4
91+
Should Be Equal @{Locations}[1] ${FRONT_PAGE}javascript/dynamic_content.html?5
92+
${count}= Get Length ${Locations}
93+
Should Be Equal As Integers ${count} 2
94+
@{Titles}= Get Window Titles browser=BrowserC
95+
Should Be Equal @{Titles}[0] WindowC1
96+
${count}= Get Length ${Titles}
97+
Should Be Equal As Integers ${count} 1
98+
99+
100+
Fail Switching Window and Locations From Different Browser
101+
Switch Browser BrowserA
102+
Switch Window WindowA1
103+
${Error_Msg}= Run Keyword And Expect Error * Switch Window WindowB1
104+
Should Be Equal As Strings ${Error_Msg} No window matching handle, name, title or URL 'WindowB1' found.
105+
${Error_Msg}= Run Keyword And Expect Error * Get Locations browser=UnknownBrowser
106+
Should Be Equal As Strings ${Error_Msg} Non-existing index or alias 'UnknownBrowser'.
107+
${Error_Msg}= Run Keyword And Expect Error * Get Window Handles browser=${4}
108+
Should Be Equal As Strings ${Error_Msg} Non-existing index or alias '4'.
109+
110+
111+
112+
*** Keywords ***
113+
Open 3 Browsers with Windows
114+
Close All Browsers
115+
Open Browser With Alias And Title BrowserA WindowA1 1
116+
Open New Window and set Title WindowA2 2
117+
Open New Window And Set Title WindowA3 3
118+
Open Browser With Alias And Title BrowserB WindowB1 4
119+
Open New Window And Set Title WindowB2 5
120+
Open Browser With Alias And Title BrowserC WindowC1 6
121+
122+
Open New Window And Set Title
123+
[Arguments] ${title} ${id}
124+
Execute Javascript window.open("dynamic_content.html?${id}")
125+
Switch Window locator=NEW
126+
Set Window Title ${title}
127+
128+
Open Browser With Alias And Title
129+
[Arguments] ${alias} ${title} ${id}
130+
Open Browser ${FRONT_PAGE}javascript/dynamic_content.html?${id} ${BROWSER} alias=${alias}
131+
Set Window Title ${title}
132+
133+
Set Window Title
134+
[Arguments] ${title}
135+
Input Text id:titleChangeTxt ${title}
136+
Click Button id:titleChangeBtn
137+
Title Should Be ${title}
138+
139+
Check Handle Count
140+
[Arguments] ${length} ${browser_alias}=${None}
141+
@{WinCountBrowser}= Get Window Handles ${browser_alias}
142+
${len}= Get Length ${WinCountBrowser}
143+
Should Be Equal As Integers ${len} ${length}
144+
145+
Check Name Count
146+
[Arguments] ${length} ${browser_alias}=${None}
147+
@{WinCountBrowser}= Get Window Names ${browser_alias}
148+
${len}= Get Length ${WinCountBrowser}
149+
Should Be Equal As Integers ${len} ${length}
150+
151+
Check Identifiers Count
152+
[Arguments] ${length} ${browser_alias}=${None}
153+
@{WinCountBrowser}= Get Window Identifiers ${browser_alias}
154+
${len}= Get Length ${WinCountBrowser}
155+
Should Be Equal As Integers ${len} ${length}
156+
157+
Switch Window By Location
158+
[Arguments] ${selected_location}
159+
@{IDs}= Get Browser Ids
160+
:FOR ${id} IN @{IDs}
161+
\ @{locations}= Get Locations browser=${id}
162+
\ Run Keyword If '${selected_location}' in $locations
163+
... Switch Window url:${selected_location} browser=${id}

atest/resources/html/javascript/dynamic_content.html

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
<a href="javascript:return false;" onclick="add_content('target', 'added content'); return false;">add content</a><br/>
1818
<a id="unicode" href="javascript:return false;" onclick="document.title='äää'; return false;">title to ääää</a><br/>
1919
<p>
20-
<input type="radio" name="group" value="title"
21-
onclick="document.title='Changed by Button';" />Change Title<br/>
22-
<input type="radio" name="group" value="content"
23-
onclick="add_content('button_target', 'added by button');"/>Add Content<br/>
20+
<input type="radio" name="group" value="title"
21+
onclick="document.title='Changed by Button';" />Change Title<br/>
22+
<input type="radio" name="group" value="content"
23+
onclick="add_content('button_target', 'added by button');"/>Add Content<br/>
2424
</p>
2525
<div id="target">
2626
</div>
@@ -30,8 +30,18 @@
3030
<input type=button value="Change the title"
3131
onClick="if(confirm('Really change the title?'))
3232
document.title += ' Changed!';" >
33-
</form>
34-
33+
</form>
34+
<p>
35+
<form name=titleChanger>
36+
<td>
37+
<input type=text id=titleChangeTxt value="Enter Title here">
38+
</td>
39+
<td>
40+
<input type=button id=titleChangeBtn value="Set Title"
41+
onClick="document.title = document.getElementById('titleChangeTxt').value;" >
42+
</td>
43+
</form>
44+
</p>
3545
</body>
3646
</html>
3747

src/SeleniumLibrary/__init__.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class SeleniumLibrary(DynamicCore):
6262
== Table of contents ==
6363
6464
- `Locating elements`
65+
- `Browser and Window`
6566
- `Timeouts, waits and delays`
6667
- `Run-on-failure functionality`
6768
- `Boolean arguments`
@@ -223,6 +224,75 @@ class SeleniumLibrary(DynamicCore):
223224
224225
See the `Add Location Strategy` keyword for more details.
225226
227+
= Browser and Window =
228+
229+
There is different conseptual meaning when SeleniumLibrary talks
230+
windows and browsers. This chapter explains those differences.
231+
232+
== Browser ==
233+
234+
When `Open Browser` or `Create WebDriver` keyword is called, it
235+
will create a new Selenium WebDriver instance by using the
236+
[https://www.seleniumhq.org/docs/03_webdriver.jsp|Selenium WebDriver]
237+
API. In SeleniumLibrary terms, a new broser is created. It is
238+
possible to start multiple independent browsers (Selenium Webdriver
239+
instances) at the same time, by calling `Open Browser` or
240+
`Create WebDriver` multiple times. These browsers are usually
241+
independent to each other and do not share data like cookies,
242+
sessions or profiles. Typicall when browser starts, it
243+
creates a single window in the desktop.
244+
245+
== Window ==
246+
247+
Windows are the part of a browser that loads the web site and presents
248+
it to the user. All content of the site is content of the window.
249+
Windows are children of a WebDriver instance, in SeleniumLibrary
250+
WebDriver is referred as browser. One browser may have multiple
251+
windows. Windows can appear as tabs or as separate windows with
252+
different position and size. Windows belonning to the same browser
253+
typically share the sessions detail, like cookies. If there is a
254+
need to separate sessions detail, example login with two different
255+
users, two browser (Selenium WebDriver instances) must be created.
256+
New windows can be opened example by the application under test or
257+
by example `Execute Javascript` keyword:
258+
259+
| `Execute Javascript` window.open() # Opens a new window with location about:blank
260+
261+
In the example in below opens multiple browser and windows,
262+
to demonstrate how the different keywords can be used to interact
263+
with a browser and windows atteched to the browser.
264+
265+
Structure:
266+
| BrowserA
267+
| Window 1 (location=https://robotframework.org/)
268+
| Window 2 (location=https://robocon.io/)
269+
| Window 3 (location=https://github.com/robotframework/)
270+
|
271+
| BrowserB
272+
| Window 1 (location=https://github.com/)
273+
274+
Example:
275+
| `Open Browser` | https://robotframework.org | ${BROWSER} | alias=BrowserA | # BrowserA with first window is opened. |
276+
| `Execute Javascript` | window.open() | | | # In BrowserA second window is opened. |
277+
| `Switch Window` | locator=NEW | | | # Switched to second window in BrowserA |
278+
| `Go To` | https://robocon.io | | | # Second window navigates to to robocon site. |
279+
| `Execute Javascript` | window.open() | | | # In BrowserA third window is opened. |
280+
| ${handle} | `Switch Window` | locator=NEW | | # Switched to third window in BrowserA |
281+
| `Go To` | https://github.com/robotframework/ | | | # Third windows goes to robot framework github site. |
282+
| `Open Browser` | https://github.com | ${BROWSER} | alias=BrowserB | # BrowserB with first windows is opened. |
283+
| ${location} | `Get Location` | | | # ${location} is: https://www.github.com |
284+
| `Switch Window` | ${handle} | browser=BrowserA | | # BrowserA second windows is selected. |
285+
| ${location} | `Get Location` | | | # ${location} = https://robocon.io/ |
286+
| @{locations 1} | `Get Locations` | | | # By default lists locations under the currectly active browser. |
287+
| @{locations 2} | `Get Locations` | browser=ALL | | # By using browser=ALL argument keyword list all locations from all browsers. |
288+
289+
The above example, @{locations 1} contains the following items:
290+
https://robotframework.org/, https://robocon.io/ and
291+
https://github.com/robotframework/'. The @{locations 2}
292+
contains the following items: https://robotframework.org/,
293+
https://robocon.io/, https://github.com/robotframework/'
294+
and 'https://github.com/.
295+
226296
= Timeouts, waits and delays =
227297
228298
This section discusses different ways how to wait for elements to

src/SeleniumLibrary/keywords/browsermanagement.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def open_browser(self, url, browser='firefox', alias=None,
180180
| options = webdriver.ChromeOptions()
181181
| options.add_argument('--disable-dev-shm-usage')
182182
| return options
183-
183+
184184
Then the `${options}` variable can be used as argument to
185185
``options``.
186186
@@ -350,6 +350,44 @@ def switch_browser(self, index_or_alias):
350350
self.debug('Switched to browser with Selenium session id %s.'
351351
% self.driver.session_id)
352352

353+
@keyword
354+
def get_browser_ids(self):
355+
"""Returns index of all active browser as list.
356+
357+
Example:
358+
| @{browser_ids}= | Get Browser Ids | | |
359+
| FOR | ${id} | IN | @{browser_ids} |
360+
| | @{window_titles}= | Get Window Titles | browser=${id} |
361+
| | Log | Browser ${id} has these windows: ${window_titles} | |
362+
| END | | | |
363+
364+
See `Switch Browser` for more information and examples.
365+
366+
New in SeleniumLibrary 4.0
367+
"""
368+
return self.drivers.active_driver_ids
369+
370+
@keyword
371+
def get_browser_aliases(self):
372+
"""Returns aliases of all active browser that has an alias as NormalizedDict.
373+
The dictionary contains the aliases as keys and the index as value.
374+
This can be accessed as dictionary ``${aliases.key}`` or as list ``@{aliases}[0]``.
375+
376+
Example:
377+
| `Open Browser` | https://example.com | alias=BrowserA | |
378+
| `Open Browser` | https://example.com | alias=BrowserB | |
379+
| &{aliases} | `Get Browser Aliases` | | # &{aliases} = { BrowserA=1|BrowserB=2 } |
380+
| `Log` | ${aliases.BrowserA} | | # logs ``1`` |
381+
| FOR | ${alias} | IN | @{aliases} |
382+
| | `Log` | ${alias} | # logs ``BrowserA`` and ``BrowserB`` |
383+
| END | | | |
384+
385+
See `Switch Browser` for more information and examples.
386+
387+
New in SeleniumLibrary 4.0
388+
"""
389+
return self.drivers.active_aliases
390+
353391
@keyword
354392
def get_session_id(self):
355393
"""Returns the currently active browser session id.
@@ -370,7 +408,7 @@ def get_title(self):
370408

371409
@keyword
372410
def get_location(self):
373-
"""Returns the current browser URL."""
411+
"""Returns the current browser window URL."""
374412
return self.driver.current_url
375413

376414
@keyword
@@ -413,7 +451,7 @@ def location_should_contain(self, expected, message=None):
413451

414452
@keyword
415453
def log_location(self):
416-
"""Logs and returns the current URL."""
454+
"""Logs and returns the current browser window URL."""
417455
url = self.get_location()
418456
self.info(url)
419457
return url
@@ -460,7 +498,7 @@ def go_back(self):
460498

461499
@keyword
462500
def go_to(self, url):
463-
"""Navigates the active browser instance to the provided ``url``."""
501+
"""Navigates the current browser window to the provided ``url``."""
464502
self.info("Opening url '%s'" % url)
465503
self.driver.get(url)
466504

src/SeleniumLibrary/keywords/cookie.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def get_cookies(self, as_dict=False):
5252
sending HTTP requests. The dictionary format is helpful when
5353
the result can be passed to requests library's Create Session
5454
keyword's optional cookies parameter.
55-
55+
5656
The `` as_dict`` argument is new in SeleniumLibrary 3.3
5757
"""
5858
if is_falsy(as_dict):

src/SeleniumLibrary/keywords/element.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,12 +435,12 @@ def get_element_size(self, locator):
435435
@keyword
436436
def cover_element(self, locator):
437437
"""Will cover elements identified by ``locator`` with a blue div without breaking page layout.
438-
438+
439439
See the `Locating elements` section for details about the locator
440440
syntax.
441-
441+
442442
New in SeleniumLibrary 3.3.0
443-
443+
444444
Example:
445445
|`Cover Element` | css:div#container |
446446
"""

0 commit comments

Comments
 (0)