1313# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1414# See the License for the specific language governing permissions and
1515# limitations under the License.
16-
16+ import re
1717from collections import namedtuple
18- from inspect import isclass
18+ from inspect import getdoc , isclass
1919
2020from robot .api import logger
2121from robot .errors import DataError
@@ -59,19 +59,7 @@ class SeleniumLibrary(DynamicCore):
5959 [https://github.com/robotframework/SeleniumLibrary#browser-drivers|Browser drivers chapter]
6060 for more details about WebDriver binary installation.
6161
62- == Table of contents ==
63-
64- - `Locating elements`
65- - `Browser and Window`
66- - `Timeouts, waits and delays`
67- - `Run-on-failure functionality`
68- - `Boolean arguments`
69- - `Plugins`
70- - `EventFiringWebDriver`
71- - `Thread support`
72- - `Importing`
73- - `Shortcuts`
74- - `Keywords`
62+ %TOC%
7563
7664 = Locating elements =
7765
@@ -232,14 +220,14 @@ class SeleniumLibrary(DynamicCore):
232220 == Browser ==
233221
234222 When `Open Browser` or `Create WebDriver` keyword is called, it
235- will create a new Selenium WebDriver instance by using the
223+ will create a new Selenium WebDriver instance by using the
236224 [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
225+ API. In SeleniumLibrary terms, a new broser is created. It is
226+ possible to start multiple independent browsers (Selenium Webdriver
227+ instances) at the same time, by calling `Open Browser` or
228+ `Create WebDriver` multiple times. These browsers are usually
229+ independent to each other and do not share data like cookies,
230+ sessions or profiles. Typicall when browser starts, it
243231 creates a single window in the desktop.
244232
245233 == Window ==
@@ -259,8 +247,8 @@ class SeleniumLibrary(DynamicCore):
259247 | `Execute Javascript` window.open() # Opens a new window with location about:blank
260248
261249 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.
250+ to demonstrate how the different keywords can be used to interact
251+ with a browser and windows attached to the browser.
264252
265253 Structure:
266254 | BrowserA
@@ -286,13 +274,13 @@ class SeleniumLibrary(DynamicCore):
286274 | @{locations 1} | `Get Locations` | | | # By default lists locations under the currectly active browser. |
287275 | @{locations 2} | `Get Locations` | browser=ALL | | # By using browser=ALL argument keyword list all locations from all browsers. |
288276
289- The above example, @{locations 1} contains the following items:
290- https://robotframework.org/, https://robocon.io/ and
277+ The above example, @{locations 1} contains the following items:
278+ https://robotframework.org/, https://robocon.io/ and
291279 https://github.com/robotframework/'. The @{locations 2}
292- contains the following items: https://robotframework.org/,
280+ contains the following items: https://robotframework.org/,
293281 https://robocon.io/, https://github.com/robotframework/'
294282 and 'https://github.com/.
295-
283+
296284 = Timeouts, waits and delays =
297285
298286 This section discusses different ways how to wait for elements to
@@ -385,15 +373,6 @@ class SeleniumLibrary(DynamicCore):
385373 ``false``, ``no`` and ``none``, were considered true. Starting from
386374 SeleniumLibrary 4.0, strings ``0`` and ``off`` are considered as false.
387375
388- = Plugins =
389-
390- SeleniumLibrary offers plugins as a way to modify and add library keywords and modify some of the internal
391- functionality without creating new library or hacking the source code. See
392- [https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/extending.rst#Plugins|plugin API]
393- documentation for further details.
394-
395- Plugin API is new SeleniumLibrary 4.0
396-
397376 = EventFiringWebDriver =
398377
399378 The SeleniumLibrary offers support for
@@ -411,6 +390,15 @@ class SeleniumLibrary(DynamicCore):
411390 Selenium tool is not thread safe] within one browser/driver instance.
412391 Because of the limitation in the Selenium side, the keywords or the
413392 API provided by the SeleniumLibrary is not thread safe.
393+
394+ = Plugins =
395+
396+ SeleniumLibrary offers plugins as a way to modify and add library keywords and modify some of the internal
397+ functionality without creating new library or hacking the source code. See
398+ [https://github.com/robotframework/SeleniumLibrary/blob/master/docs/extending/extending.rst#Plugins|plugin API]
399+ documentation for further details.
400+
401+ Plugin API is new SeleniumLibrary 4.0
414402 """
415403 ROBOT_LIBRARY_SCOPE = 'GLOBAL'
416404 ROBOT_LIBRARY_VERSION = __version__
@@ -465,8 +453,10 @@ def __init__(self, timeout=5.0, implicit_wait=0.0,
465453 self .event_firing_webdriver = None
466454 if is_truthy (event_firing_webdriver ):
467455 self .event_firing_webdriver = self ._parse_listener (event_firing_webdriver )
456+ self ._plugins = []
468457 if is_truthy (plugins ):
469458 plugin_libs = self ._parse_plugins (plugins )
459+ self ._plugins = plugin_libs
470460 libraries = libraries + plugin_libs
471461 self ._drivers = WebDriverCache ()
472462 DynamicCore .__init__ (self , libraries )
@@ -487,6 +477,33 @@ def get_keyword_tags(self, name):
487477 tags .append ('plugin' )
488478 return tags
489479
480+ def get_keyword_documentation (self , name ):
481+ if name == '__intro__' :
482+ return self ._get_intro_documentation ()
483+ return DynamicCore .get_keyword_documentation (self , name )
484+
485+ def _parse_plugin_doc (self ):
486+ Doc = namedtuple ('Doc' , 'doc, name' )
487+ for plugin in self ._plugins :
488+ yield Doc (doc = getdoc (plugin ) or 'No plugin documentation found.' ,
489+ name = plugin .__class__ .__name__ )
490+
491+ def _get_intro_documentation (self ):
492+ intro = DynamicCore .get_keyword_documentation (self , '__intro__' )
493+ for plugin_doc in self ._parse_plugin_doc ():
494+ intro += '\n \n '
495+ intro = intro + '= Plugin: %s =' % plugin_doc .name + '\n \n '
496+ intro = intro + plugin_doc .doc
497+ return self ._create_toc (intro )
498+
499+ def _create_toc (self , intro ):
500+ toc = ['== Table of contents ==' , '' ]
501+ all_match = re .findall (r'(^\=\s)(.+)(\s\=$)' , intro , re .MULTILINE )
502+ for match in all_match :
503+ toc .append ('- `%s`' % match [1 ])
504+ toc .extend (['- `Importing`' , '- `Shortcuts`' , '- `Keywords`' ])
505+ return intro .replace ('%TOC%' , '\n ' .join (toc ))
506+
490507 def register_driver (self , driver , alias ):
491508 """Add's a `driver` to the library WebDriverCache.
492509
0 commit comments