Repository: robotframework/SeleniumLibrary
Pull request #919 (2017-09-26 00:25:37)

Improves documentation for `Select Frame` and `Unselect Frame`.
For #892.

~~REVIEW required - I can't get the example correct.~~

Added note on having to Unselect Frame to start searching from main frame.

Expanded examples.

HelioGuilherme66: This is how the help looks now.
![imagem](https://user-images.githubusercontent.com/2866630/30992874-d592a340-a4a3-11e7-9855-13a03eaea5a8.png)


Patch:
diff --git a/.travis.yml b/.travis.yml
index a6d96d2d..7e1299ec 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,13 +35,13 @@ matrix:
         - BROWSER=chrome
         - SELENIUM=3.5.0
         - ROBOTFRAMEWORK=3.0.2
-        - ROBOT_OPTIONS=
+        - ROBOT_OPTIONS=--dotted
     - python: "2.7"
       env:
         - BROWSER=chrome
         - SELENIUM=2.53.6
         - ROBOTFRAMEWORK=2.9.2
-        - ROBOT_OPTIONS=
+        - ROBOT_OPTIONS=--dotted
     - python: "2.7"
       env:
         - BROWSER=chrome
@@ -53,13 +53,13 @@ matrix:
         - BROWSER=chrome
         - SELENIUM=2.53.6
         - ROBOTFRAMEWORK=3.0.2
-        - ROBOT_OPTIONS=
+        - ROBOT_OPTIONS=--dotted
     - python: "3.3"
       env:
         - BROWSER=firefox
         - SELENIUM=3.5.0
         - ROBOTFRAMEWORK=3.0.2
-        - ROBOT_OPTIONS="--exclude Known_Issue_Firefox"
+        - ROBOT_OPTIONS="--exclude Known_Issue_Firefox --dotted"
 before_script:
   - "export DISPLAY=:99.0"
   - "sh -e /etc/init.d/xvfb start"
diff --git a/BUILD.rst b/BUILD.rst
index b0792e81..ec8458ff 100644
--- a/BUILD.rst
+++ b/BUILD.rst
@@ -149,19 +149,22 @@ Set version
       git commit -m "Updated version to $VERSION" src/SeleniumLibrary/__init__.py
       git push
 
-Keyword documentation
----------------------
+Documentation
+-------------
 
 1. Generate keyword documentation::
 
-      invoke keyword-documentation
+      invoke kw-docs
+      git commit -m "Generated docs for version $VERSION" docs/SeleniumLibrary.html
+      git push
 
    Note that this *must* be done after`setting version <Set version>`_ above
    or docs will have wrong version number.
 
-2. Commit and push changes::
+2. If README.rst has changed, generate project documentation based on it::
 
-      git commit -m "Generated docs for version $VERSION" docs/SeleniumLibrary.html
+      invoke project-docs
+      git commit -m "Regenerated project docs" docs/index.html
       git push
 
 Tagging
diff --git a/CHANGES.rst b/CHANGES.rst
index ad8b5772..755ec822 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -6,6 +6,8 @@ Release Notes
 - Added 'Get Locations' keyword [thaffenden]
 - Fix getting window information and switching windows on browsers that do not
   support javascript
+- Added 'Get Cookie' keyword [wappowers]
+- Added 'expiry' as value that can be set with 'Add Cookie' keyword [wappowers]
 
 1.8.0
 -----
diff --git a/README.rst b/README.rst
index 9d4bae98..dfed1e7c 100644
--- a/README.rst
+++ b/README.rst
@@ -2,21 +2,19 @@ SeleniumLibrary
 ===============
 
 .. contents::
-   :local:
 
 Introduction
 ------------
 
 SeleniumLibrary_ is a web testing library for `Robot Framework`_ that
 utilizes the Selenium_ tool internally. The project is hosted on GitHub_
-and downloads can be found from PyPI_. See `keyword documentation`_
-for available keywords and more information about the library in general.
+and downloads can be found from PyPI_.
 
 SeleniumLibrary works with Selenium 2.53.6 or newer, including Selenium 3.
 It supports Python 2.7 as well as Python 3.3 or newer. In addition to the
 normal Python_ interpreter, it works also with PyPy_ and Jython_. Unfortunately
-Selenium_ isn't currently supported by IronPython_ and thus this library
-doesn't work with IronPython_ either.
+Selenium_ is not currently supported by IronPython_ and thus this library
+does not work with IronPython either.
 
 SeleniumLibrary is based on the `old SeleniumLibrary`_ that was forked to
 Selenium2Library_ and then later renamed back to SeleniumLibrary.
@@ -24,7 +22,7 @@ See the Versions_ and History_ sections below for more information about
 different versions and the overall project history.
 
 The new SeleniumLibrary is currently in pre-release phase. The final
-SeleniumLibrary 3.0 release is planned for early September.
+SeleniumLibrary 3.0 release is planned for October.
 
 .. image:: https://img.shields.io/pypi/v/robotframework-seleniumlibrary.svg?label=version
    :target: https://pypi.python.org/pypi/robotframework-seleniumlibrary
@@ -35,6 +33,11 @@ SeleniumLibrary 3.0 release is planned for early September.
 .. image:: https://api.travis-ci.org/robotframework/SeleniumLibrary.png
    :target: http://travis-ci.org/robotframework/SeleniumLibrary
 
+Keyword documentation
+---------------------
+See `keyword documentation`_ for available keywords and more information
+about the library in general.
+
 Installation
 ------------
 
@@ -156,7 +159,7 @@ The above example is a slightly modified version of an example in a
 `demo project`_ that illustrates using Robot Framework and SeleniumLibrary.
 See the demo for more examples that you can also execute on your own
 machine. For more information about Robot Framework test data syntax in
-general see `Robot Framework User Guide`_.
+general see the `Robot Framework User Guide`_.
 
 Support
 -------
@@ -221,7 +224,7 @@ SeleniumLibrary. This decision basically meant following changes:
 
 - Create separate repository for the `old SeleniumLibrary`_ to preserve
   its history since Selenium2Library was forked.
-- Rename Selenium2Library project and the library itself to SeleniumLibrary.
+- Rename Selenium2Library project and the library itself to SeleniumLibrary_.
 - Add new Selenium2Library_ project to ease transitioning from Selenium2Library
   to SeleniumLibrary.
 
diff --git a/docs/extra.css b/docs/extra.css
new file mode 100644
index 00000000..16b741e0
--- /dev/null
+++ b/docs/extra.css
@@ -0,0 +1,15 @@
+/* Additional styles to use with style.css. */
+
+.contents li p, table p {
+    margin: 0;
+}
+th, td {
+    padding: 0.2em 0.4em;
+    border-width: 1px;
+    border-style: solid;
+    vertical-align: top;
+}
+th {
+    white-space: nowrap;
+    vertical-align: middle;
+}
diff --git a/docs/index.html b/docs/index.html
index 76564f4a..76400f17 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,16 +1,249 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Robot Framework SeleniumLibrary</title>
-    <meta charset="utf-8">
-  </head>
-  <body>
-    <h1>Robot Framework SeleniumLibrary</h1>
-    <ul>
-      <li><a href="SeleniumLibrary.html">Keyword documentation</a></li>
-      <li><a href="https://github.com/robotframework/SeleniumLibrary">Project pages</a></li>
-      <li><a href="https://bitbucket.org/robotframework/webdemo">SeleniumLibrary demo project</a></li>
-      <li><a href="http://robotframework.org">Robot Framework</a></li>
-    </ul>
-  </body>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta charset="utf-8"/>
+<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
+<title>SeleniumLibrary</title>
+<link rel="stylesheet" href="style.css" type="text/css" />
+<link rel="stylesheet" href="extra.css" type="text/css" />
+</head>
+<body>
+<div class="document" id="seleniumlibrary">
+<h1 class="title">SeleniumLibrary</h1>
+
+<div class="contents topic" id="contents">
+<p class="topic-title first">Contents</p>
+<ul class="simple">
+<li><p><a class="reference internal" href="#introduction" id="id5">Introduction</a></p></li>
+<li><p><a class="reference internal" href="#keyword-documentation" id="id6">Keyword documentation</a></p></li>
+<li><p><a class="reference internal" href="#installation" id="id7">Installation</a></p></li>
+<li><p><a class="reference internal" href="#browser-drivers" id="id8">Browser drivers</a></p></li>
+<li><p><a class="reference internal" href="#usage" id="id9">Usage</a></p></li>
+<li><p><a class="reference internal" href="#support" id="id10">Support</a></p></li>
+<li><p><a class="reference internal" href="#versions" id="id11">Versions</a></p></li>
+<li><p><a class="reference internal" href="#history" id="id12">History</a></p></li>
+</ul>
+</div>
+<div class="section" id="introduction">
+<h1><a class="toc-backref" href="#id5">Introduction</a></h1>
+<p><a class="reference external" href="https://github.com/robotframework/SeleniumLibrary">SeleniumLibrary</a> is a web testing library for <a class="reference external" href="http://robotframework.org">Robot Framework</a> that
+utilizes the <a class="reference external" href="http://seleniumhq.org">Selenium</a> tool internally. The project is hosted on <a class="reference external" href="https://github.com/robotframework/SeleniumLibrary">GitHub</a>
+and downloads can be found from <a class="reference external" href="https://pypi.python.org/pypi/robotframework-seleniumlibrary">PyPI</a>.</p>
+<p>SeleniumLibrary works with Selenium 2.53.6 or newer, including Selenium 3.
+It supports Python 2.7 as well as Python 3.3 or newer. In addition to the
+normal <a class="reference external" href="http://python.org">Python</a> interpreter, it works also with <a class="reference external" href="http://pypy.org">PyPy</a> and <a class="reference external" href="http://jython.org">Jython</a>. Unfortunately
+<a class="reference external" href="http://seleniumhq.org">Selenium</a> is not currently supported by <a class="reference external" href="http://ironpython.net">IronPython</a> and thus this library
+does not work with IronPython either.</p>
+<p>SeleniumLibrary is based on the <a class="reference external" href="https://github.com/robotframework/OldSeleniumLibrary">old SeleniumLibrary</a> that was forked to
+<a class="reference external" href="https://github.com/robotframework/Selenium2Library">Selenium2Library</a> and then later renamed back to SeleniumLibrary.
+See the <a class="reference internal" href="#versions">Versions</a> and <a class="reference internal" href="#history">History</a> sections below for more information about
+different versions and the overall project history.</p>
+<p>The new SeleniumLibrary is currently in pre-release phase. The final
+SeleniumLibrary 3.0 release is planned for October.</p>
+<a class="reference external image-reference" href="https://pypi.python.org/pypi/robotframework-seleniumlibrary"><img alt="https://img.shields.io/pypi/v/robotframework-seleniumlibrary.svg?label=version" src="https://img.shields.io/pypi/v/robotframework-seleniumlibrary.svg?label=version" /></a>
+<a class="reference external image-reference" href="http://www.apache.org/licenses/LICENSE-2.0"><img alt="https://img.shields.io/pypi/l/robotframework-seleniumlibrary.svg" src="https://img.shields.io/pypi/l/robotframework-seleniumlibrary.svg" /></a>
+<a class="reference external image-reference" href="http://travis-ci.org/robotframework/SeleniumLibrary"><img alt="https://api.travis-ci.org/robotframework/SeleniumLibrary.png" src="https://api.travis-ci.org/robotframework/SeleniumLibrary.png" /></a>
+</div>
+<div class="section" id="keyword-documentation">
+<h1><a class="toc-backref" href="#id6">Keyword documentation</a></h1>
+<p>See <a class="reference external" href="http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html">keyword documentation</a> for available keywords and more information
+about the library in general.</p>
+</div>
+<div class="section" id="installation">
+<h1><a class="toc-backref" href="#id7">Installation</a></h1>
+<p>The recommended installation method is using <a class="reference external" href="http://pip-installer.org">pip</a>:</p>
+<pre class="literal-block">pip install --pre --upgrade robotframework-seleniumlibrary</pre>
+<p>Running this command installs also the latest Selenium and Robot Framework
+versions, but you still need to install <a class="reference internal" href="#browser-drivers">browser drivers</a> separately.
+Notice that the <span class="docutils literal"><span class="pre">--pre</span></span> option is needed to get the current SeleniumLibrary,
+not the <a class="reference external" href="https://github.com/robotframework/OldSeleniumLibrary">old SeleniumLibrary</a>, until the final SeleniumLibrary 3.0 is
+released. The <span class="docutils literal"><span class="pre">--upgrade</span></span> option can be omitted when installing the
+library for the first time.</p>
+<p>Those migrating from <a class="reference external" href="https://github.com/robotframework/Selenium2Library">Selenium2Library</a> can install SeleniumLibrary so that
+it is exposed also as Selenium2Library:</p>
+<pre class="literal-block">pip install --pre --upgrade robotframework-selenium2library</pre>
+<p>The above command installs the normal SeleniumLibrary as well as a new
+Selenium2Library version that is just a thin wrapper to SeleniumLibrary.
+That allows importing Selenium2Library in tests while migrating to
+SeleniumLibrary.</p>
+<p>To install the last legacy <a class="reference external" href="https://github.com/robotframework/Selenium2Library">Selenium2Library</a> version, use this command instead:</p>
+<pre class="literal-block">pip install robotframework-selenium2library==1.8.0</pre>
+<p>An alternative to using <span class="docutils literal">pip</span> is getting the project source code either
+from a source distribution at <a class="reference external" href="https://pypi.python.org/pypi/robotframework-seleniumlibrary">PyPI</a> or by cloning the <a class="reference external" href="https://github.com/robotframework/SeleniumLibrary">GitHub</a> repository,
+and installing the code using <span class="docutils literal">python setup.py install</span>. This approach
+does not install Selenium or other dependencies, so they need to be installed
+separately.</p>
+<p>See <a class="reference external" href="https://github.com/robotframework/robotframework/blob/master/INSTALL.rst">Robot Framework installation instructions</a> for detailed information
+about installing Python and Robot Framework itself. For more details about
+using <span class="docutils literal">pip</span> see <a class="reference external" href="http://pip-installer.org">its own documentation</a>.</p>
+</div>
+<div class="section" id="browser-drivers">
+<h1><a class="toc-backref" href="#id8">Browser drivers</a></h1>
+<p>After installing the library, you still need to install browser and
+operating system specific browser drivers for all those browsers you
+want to use in tests. These are the exact same drivers you need to use with
+Selenium also when not using SeleniumLibrary. More information about
+drivers can be found from <a class="reference external" href="https://seleniumhq.github.io/selenium/docs/api/py/index.html#drivers">Selenium documentation</a>.</p>
+<p>The general approach to install a browser driver is downloading a right
+driver, such as <span class="docutils literal">chromedriver</span> for Chrome, and placing it into
+a directory that is in <a class="reference external" href="https://en.wikipedia.org/wiki/PATH_(variable)">PATH</a>. Drivers for different browsers
+can be found via Selenium documentation or by using your favorite
+search engine with a search term like <span class="docutils literal">selenium chrome browser driver</span>.
+New browser driver versions are released to support features in
+new browsers, fix bug, or otherwise, and you need to keep an eye on them
+to know when to update drivers you use.</p>
+</div>
+<div class="section" id="usage">
+<h1><a class="toc-backref" href="#id9">Usage</a></h1>
+<p>To use SeleniumLibrary in Robot Framework tests, the library needs to
+first be imported using the <span class="docutils literal">Library</span> setting as any other library.
+The library accepts some import time arguments, which are documented
+in the <a class="reference external" href="http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html">keyword documentation</a> along with all the keywords provided
+by the library.</p>
+<p>When using Robot Framework, it is generally recommended to write as
+easy-to-understand tests as possible. The keywords provided by
+SeleniumLibrary are pretty low level, though, and often require
+implementation specific arguments like element locators to be passed
+as arguments. It is thus typically a good idea to write tests using
+Robot Framework's higher level keywords that utilize SeleniumLibrary
+keywords internally. This is illustrated by the following example
+where SeleniumLibrary keywords like <span class="docutils literal">Input Text</span> are primarily
+used by higher level keywords like <span class="docutils literal">Input Username</span>.</p>
+<pre class="code robotframework literal-block"><code><span class="generic heading">*** Settings ***</span><span class="punctuation">
+</span><span class="keyword namespace">Documentation</span><span class="punctuation">     </span><span class="literal string">Simple example using SeleniumLibrary.</span><span class="punctuation">
+</span><span class="keyword namespace">Library</span><span class="punctuation">           </span><span class="name namespace">SeleniumLibrary</span><span class="punctuation">
+
+</span><span class="generic heading">*** Variables ***</span><span class="punctuation">
+${</span><span class="name variable">LOGIN URL</span><span class="punctuation">}      </span><span class="literal string">http://localhost:7272</span><span class="punctuation">
+${</span><span class="name variable">BROWSER</span><span class="punctuation">}        </span><span class="literal string">Chrome</span><span class="punctuation">
+
+</span><span class="generic heading">*** Test Cases ***</span><span class="punctuation">
+</span><span class="generic subheading">Valid Login</span><span class="punctuation">
+    </span><span class="name function">Open Browser To Login Page</span><span class="punctuation">
+    </span><span class="name function">Input Username</span><span class="punctuation">    </span><span class="literal string">demo</span><span class="punctuation">
+    </span><span class="name function">Input Password</span><span class="punctuation">    </span><span class="literal string">mode</span><span class="punctuation">
+    </span><span class="name function">Submit Credentials</span><span class="punctuation">
+    </span><span class="name function">Welcome Page Should Be Open</span><span class="punctuation">
+    [</span><span class="keyword namespace">Teardown</span><span class="punctuation">]    </span><span class="name function">Close Browser</span><span class="punctuation">
+
+</span><span class="generic heading">*** Keywords ***</span><span class="punctuation">
+</span><span class="generic subheading">Open Browser To Login Page</span><span class="punctuation">
+    </span><span class="name function">Open Browser</span><span class="punctuation">    ${</span><span class="name variable">LOGIN URL</span><span class="punctuation">}    ${</span><span class="name variable">BROWSER</span><span class="punctuation">}
+    </span><span class="name function">Title Should Be</span><span class="punctuation">    </span><span class="literal string">Login Page</span><span class="punctuation">
+
+</span><span class="generic subheading">Input Username</span><span class="punctuation">
+    [</span><span class="keyword namespace">Arguments</span><span class="punctuation">]    ${</span><span class="name variable">username</span><span class="punctuation">}
+    </span><span class="name function">Input Text</span><span class="punctuation">    </span><span class="literal string">username_field</span><span class="punctuation">    ${</span><span class="name variable">username</span><span class="punctuation">}
+
+</span><span class="generic subheading">Input Password</span><span class="punctuation">
+    [</span><span class="keyword namespace">Arguments</span><span class="punctuation">]    ${</span><span class="name variable">password</span><span class="punctuation">}
+    </span><span class="name function">Input Text</span><span class="punctuation">    </span><span class="literal string">password_field</span><span class="punctuation">    ${</span><span class="name variable">password</span><span class="punctuation">}
+
+</span><span class="generic subheading">Submit Credentials</span><span class="punctuation">
+    </span><span class="name function">Click Button</span><span class="punctuation">    </span><span class="literal string">login_button</span><span class="punctuation">
+
+</span><span class="generic subheading">Welcome Page Should Be Open</span><span class="punctuation">
+    </span><span class="name function">Title Should Be</span><span class="punctuation">    </span><span class="literal string">Welcome Page</span></code></pre>
+<p>The above example is a slightly modified version of an example in a
+<a class="reference external" href="https://bitbucket.org/robotframework/webdemo">demo project</a> that illustrates using Robot Framework and SeleniumLibrary.
+See the demo for more examples that you can also execute on your own
+machine. For more information about Robot Framework test data syntax in
+general see the <a class="reference external" href="http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html">Robot Framework User Guide</a>.</p>
+</div>
+<div class="section" id="support">
+<h1><a class="toc-backref" href="#id10">Support</a></h1>
+<p>If the provided documentation is not enough, there are various support forums
+available:</p>
+<ul class="simple">
+<li><p><a class="reference external" href="http://groups.google.com/group/robotframework-users">robotframework-users</a> mailing list</p></li>
+<li><p><span class="docutils literal">#seleniumlibrary</span> and <span class="docutils literal"><span class="pre">#seleniumlibrary-dev</span></span> channels in
+Robot Framework <a class="reference external" href="https://robotframework-slack-invite.herokuapp.com">Slack community</a></p></li>
+<li><p>SeleniumLibrary <a class="reference external" href="https://github.com/robotframework/SeleniumLibrary/issues">issue tracker</a> for bug reports and concrete enhancement
+requests</p></li>
+<li><p><a class="reference external" href="http://robotframework.org/#support">Other support forums</a> including paid support</p></li>
+</ul>
+</div>
+<div class="section" id="versions">
+<h1><a class="toc-backref" href="#id11">Versions</a></h1>
+<p>SeleniumLibrary has over the years lived under SeleniumLibrary and
+Selenium2Library names and different library versions have supported
+different Selenium and Python versions. This is summarized in the table
+below and the <a class="reference internal" href="#history">History</a> section afterwards explains the project history
+a bit more.</p>
+<table>
+<colgroup>
+<col style="width: 24%" />
+<col style="width: 11%" />
+<col style="width: 13%" />
+<col style="width: 51%" />
+</colgroup>
+<thead>
+<tr><th class="head"><p>Project</p></th>
+<th class="head"><p>Selenium Version</p></th>
+<th class="head"><p>Python Version</p></th>
+<th class="head"><p>Comment</p></th>
+</tr>
+</thead>
+<tbody>
+<tr><td><p>SeleniumLibrary 2.9.2 and earlier</p></td>
+<td><p>Selenium 1 and 2</p></td>
+<td><p>Python 2.5-2.7</p></td>
+<td><p>The original SeleniumLibrary using Selenium RC API.</p></td>
+</tr>
+<tr><td><p>Selenium2Library 1.8.0 and earlier</p></td>
+<td><p>Selenium 2 and 3</p></td>
+<td><p>Python 2.6-2.7</p></td>
+<td><p>Fork of SeleniumLibrary using Selenium WebDriver API.</p></td>
+</tr>
+<tr><td><p>SeleniumLibrary 3.0 and newer</p></td>
+<td><p>Selenium 2 and 3</p></td>
+<td><p>Python 2.7 and 3.3+</p></td>
+<td><p>Selenium2Library renamed and with Python 3 support and new architecture.</p></td>
+</tr>
+<tr><td><p>Selenium2Library 3.0 and newer</p></td>
+<td><p>Selenium 2 and 3</p></td>
+<td><p>Python 2.7 and 3.3+</p></td>
+<td><p>Thin wrapper for SeleniumLibrary 3.0 to ease transition.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="section" id="history">
+<h1><a class="toc-backref" href="#id12">History</a></h1>
+<p>SeleniumLibrary originally used the Selenium Remote Controller (RC) API.
+When Selenium 2 was introduced with the new but backwards incompatible
+WebDriver API, SeleniumLibrary kept using Selenium RC and separate
+Selenium2Library using WebDriver was forked. These projects contained
+mostly the same keywords and in most cases Selenium2Library was a drop-in
+replacement for SeleniumLibrary.</p>
+<p>Over the years development of the old SeleniumLibrary stopped and also
+the Selenium RC API it used was deprecated. Selenium2Library was developed
+further and replaced the old library as the de facto web testing library
+for Robot Framework.</p>
+<p>When Selenium 3 was released in 2016, it was otherwise backwards compatible
+with Selenium 2, but the deprecated Selenium RC API was removed. This had two
+important effects:</p>
+<ul class="simple">
+<li><p>The old SeleniumLibrary could not anymore be used with new Selenium versions.
+This project was pretty much dead.</p></li>
+<li><p>Selenium2Library was badly named as it supported Selenium 3 just fine.
+This project needed a new name.</p></li>
+</ul>
+<p>At the same time when Selenium 3 was released, Selenium2Library was going
+through larger architecture changes in order to ease future maintenance and
+to make adding Python 3 support easier. With all these big internal and
+external changes, it made sense to rename Selenium2Library back to
+SeleniumLibrary. This decision basically meant following changes:</p>
+<ul class="simple">
+<li><p>Create separate repository for the <a class="reference external" href="https://github.com/robotframework/OldSeleniumLibrary">old SeleniumLibrary</a> to preserve
+its history since Selenium2Library was forked.</p></li>
+<li><p>Rename Selenium2Library project and the library itself to <a class="reference external" href="https://github.com/robotframework/SeleniumLibrary">SeleniumLibrary</a>.</p></li>
+<li><p>Add new <a class="reference external" href="https://github.com/robotframework/Selenium2Library">Selenium2Library</a> project to ease transitioning from Selenium2Library
+to SeleniumLibrary.</p></li>
+</ul>
+<p>Going forward, all new development will happen in the new SeleniumLibrary
+project.</p>
+</div>
+</div>
+</body>
 </html>
diff --git a/docs/style.css b/docs/style.css
new file mode 100644
index 00000000..9f8549fe
--- /dev/null
+++ b/docs/style.css
@@ -0,0 +1,936 @@
+/*
+:Author: Chad Skeeters
+:Contact: goobsoft@gmail.com
+
+Stylesheet for use with Docutils/rst2html.
+
+https://bitbucket.org/cskeeters/rst2html-style/
+*/
+
+html {
+  font-size: 100%;
+  -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+}
+
+a:focus {
+  outline: thin dotted #333;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+
+a:hover,
+a:active {
+  outline: 0;
+}
+
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline;
+}
+
+sup {
+  top: -0.5em;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+img {
+  width: auto\9;
+  height: auto;
+  max-width: 100%;
+  vertical-align: middle;
+  border: 0;
+  -ms-interpolation-mode: bicubic;
+}
+
+@media print {
+  * {
+    color: #000 !important;
+    text-shadow: none !important;
+    background: transparent !important;
+    box-shadow: none !important;
+  }
+  a,
+  a:visited {
+    text-decoration: underline;
+  }
+  a[href]:after {
+    content: " (" attr(href) ")";
+  }
+  abbr[title]:after {
+    content: " (" attr(title) ")";
+  }
+  .ir a:after,
+  a[href^="javascript:"]:after,
+  a[href^="#"]:after {
+    content: "";
+  }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  @page  {
+    margin: 0.5cm;
+  }
+  h1 {
+    page-break-before:always;
+  }
+  h1.title {
+    page-break-before:avoid;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+}
+
+body {
+  margin: 40px;
+  margin-right: auto;
+  margin-left: auto;
+  width: 700px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  line-height: 20px;
+  color: #333333;
+  background-color: #ffffff;
+}
+
+a {
+  color: #0088cc;
+  text-decoration: none;
+}
+
+a:hover,
+a:focus {
+  color: #005580;
+  text-decoration: underline;
+}
+
+.img-rounded {
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+}
+
+.img-polaroid {
+  padding: 4px;
+  background-color: #fff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+p {
+  margin: 0 0 10px;
+}
+
+small {
+  font-size: 85%;
+}
+
+strong {
+  font-weight: bold;
+}
+
+em {
+  font-style: italic;
+}
+
+cite {
+  font-style: normal;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  font-family: inherit;
+  font-weight: bold;
+  line-height: 20px;
+  color: inherit;
+  text-rendering: optimizelegibility;
+}
+h1 {
+  font-size: 2em;
+  padding-bottom:.2em;
+  border-bottom:1px solid grey;
+}
+h1.title {
+  padding-bottom:1em;
+  border-bottom:0px;
+}
+h2 {
+  font-size: 1.5em;
+}
+
+h3 {
+  font-size: 1.3em;
+  font-family:Georgia, serif;
+  font-style:italic;
+  /*font-weight:normal;*/
+}
+
+h4 {
+  font-size: 1.3em;
+}
+
+h5 {
+  font-size: 1.2em;
+}
+
+h6 {
+  font-size: 1.1em;
+}
+
+ul,
+ol {
+  padding: 0;
+  margin: 0 0 10px 25px;
+}
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+  margin-bottom: 0;
+}
+
+li {
+  line-height: 20px;
+}
+
+dl {
+  margin-bottom: 20px;
+}
+
+dt,
+dd {
+  line-height: 20px;
+}
+
+dt {
+  font-weight: bold;
+}
+
+dd {
+  margin-left: 10px;
+}
+
+hr {
+  margin: 20px 0;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+  border-bottom: 1px solid #ffffff;
+}
+
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #999999;
+}
+
+abbr.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+
+blockquote {
+  padding: 0 0 0 15px;
+  margin: 0 0 20px;
+  border-left: 5px solid #eeeeee;
+}
+
+blockquote p {
+  margin-bottom: 0;
+  font-size: 17.5px;
+  font-weight: 300;
+  line-height: 1.25;
+}
+
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+  content: "";
+}
+
+address {
+  display: block;
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 20px;
+}
+
+code,
+pre {
+  padding: 0 3px 2px;
+  font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
+  font-size: 12px;
+  color: #333333;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+}
+
+code {
+  padding: 2px 4px;
+  color: #d14;
+  white-space: nowrap;
+  background-color: #f7f7f9;
+  border: 1px solid #e1e1e8;
+}
+
+pre {
+  display: block;
+  padding: 9.5px;
+  margin: 0 0 10px;
+  font-size: 13px;
+  line-height: 20px;
+  word-break: break-all;
+  word-wrap: break-word;
+  white-space: pre;
+  white-space: pre-wrap;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+pre.prettyprint {
+  margin-bottom: 20px;
+}
+
+pre code {
+  padding: 0;
+  color: inherit;
+  white-space: pre;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border: 0;
+}
+
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+
+table {
+  max-width: 100%;
+  background-color: transparent;
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+.table {
+  width: 100%;
+  margin-bottom: 20px;
+}
+
+.table th,
+.table td {
+  padding: 8px;
+  line-height: 20px;
+  text-align: left;
+  vertical-align: top;
+  border-top: 1px solid #dddddd;
+}
+
+.table th {
+  font-weight: bold;
+}
+
+.table thead th {
+  vertical-align: bottom;
+}
+
+.table caption + thead tr:first-child th,
+.table caption + thead tr:first-child td,
+.table colgroup + thead tr:first-child th,
+.table colgroup + thead tr:first-child td,
+.table thead:first-child tr:first-child th,
+.table thead:first-child tr:first-child td {
+  border-top: 0;
+}
+
+.table tbody + tbody {
+  border-top: 2px solid #dddddd;
+}
+
+.table .table {
+  background-color: #ffffff;
+}
+
+.table-condensed th,
+.table-condensed td {
+  padding: 4px 5px;
+}
+
+.table-bordered {
+  border: 1px solid #dddddd;
+  border-collapse: separate;
+  *border-collapse: collapse;
+  border-left: 0;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.table-bordered th,
+.table-bordered td {
+  border-left: 1px solid #dddddd;
+}
+
+.table-bordered caption + thead tr:first-child th,
+.table-bordered caption + tbody tr:first-child th,
+.table-bordered caption + tbody tr:first-child td,
+.table-bordered colgroup + thead tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child td,
+.table-bordered thead:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child td {
+  border-top: 0;
+}
+
+.table-bordered thead:first-child tr:first-child > th:first-child,
+.table-bordered tbody:first-child tr:first-child > td:first-child,
+.table-bordered tbody:first-child tr:first-child > th:first-child {
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.table-bordered thead:first-child tr:first-child > th:last-child,
+.table-bordered tbody:first-child tr:first-child > td:last-child,
+.table-bordered tbody:first-child tr:first-child > th:last-child {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child > th:first-child,
+.table-bordered tbody:last-child tr:last-child > td:first-child,
+.table-bordered tbody:last-child tr:last-child > th:first-child,
+.table-bordered tfoot:last-child tr:last-child > td:first-child,
+.table-bordered tfoot:last-child tr:last-child > th:first-child {
+  -webkit-border-bottom-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child > th:last-child,
+.table-bordered tbody:last-child tr:last-child > td:last-child,
+.table-bordered tbody:last-child tr:last-child > th:last-child,
+.table-bordered tfoot:last-child tr:last-child > td:last-child,
+.table-bordered tfoot:last-child tr:last-child > th:last-child {
+  -webkit-border-bottom-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+  -moz-border-radius-bottomright: 4px;
+}
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
+  -webkit-border-bottom-left-radius: 0;
+          border-bottom-left-radius: 0;
+  -moz-border-radius-bottomleft: 0;
+}
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
+  -webkit-border-bottom-right-radius: 0;
+          border-bottom-right-radius: 0;
+  -moz-border-radius-bottomright: 0;
+}
+
+.table-bordered caption + thead tr:first-child th:first-child,
+.table-bordered caption + tbody tr:first-child td:first-child,
+.table-bordered colgroup + thead tr:first-child th:first-child,
+.table-bordered colgroup + tbody tr:first-child td:first-child {
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.table-bordered caption + thead tr:first-child th:last-child,
+.table-bordered caption + tbody tr:first-child td:last-child,
+.table-bordered colgroup + thead tr:first-child th:last-child,
+.table-bordered colgroup + tbody tr:first-child td:last-child {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+}
+
+.table-striped tbody > tr:nth-child(odd) > td,
+.table-striped tbody > tr:nth-child(odd) > th {
+  background-color: #f9f9f9;
+}
+
+.table-hover tbody tr:hover > td,
+.table-hover tbody tr:hover > th {
+  background-color: #f5f5f5;
+}
+
+table td[class*="span"],
+table th[class*="span"],
+.row-fluid table td[class*="span"],
+.row-fluid table th[class*="span"] {
+  display: table-cell;
+  float: none;
+  margin-left: 0;
+}
+
+.hero-unit {
+  padding: 60px;
+  margin-bottom: 30px;
+  font-size: 18px;
+  font-weight: 200;
+  line-height: 30px;
+  color: inherit;
+  background-color: #eeeeee;
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+}
+
+.hero-unit h1 {
+  margin-bottom: 0;
+  font-size: 60px;
+  line-height: 1;
+  letter-spacing: -1px;
+  color: inherit;
+}
+
+.hero-unit li {
+  line-height: 30px;
+}
+
+
+/* rst2html default used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0 }
+
+table.borderless td, table.borderless th {
+  /* Override padding for "table.docutils td" with "! important".
+     The right padding separates the table cells. */
+  padding: 0 0.5em 0 0 ! important }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
+  overflow: hidden;
+}
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.note, div.warning {
+  margin:1.5em 0px;
+  border: none;
+}
+
+div.note p.admonition-title,
+div.warning p.admonition-title
+{
+  display:none;
+}
+
+/* Clearfix
+ * http://css-tricks.com/snippets/css/clear-fix/
+ */
+
+div.note:after,
+div.warning:after {
+  content:"";
+  display:table;
+  clear:both;
+}
+
+div.note p:before,
+div.warning p:before {
+  display:block;
+  float:left;
+  font-size:4em;
+  line-height:1em;
+  margin-right:20px;
+  margin-left: 0em;
+  margin-top:-10px;
+  content:'\0270D'; /*handwriting*/
+}
+
+div.warning p:before {
+  content:'\026A0'; /*warning*/
+}
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title, .code .error {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin: 0 0 0.5em 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left, .figure.align-left, object.align-left {
+  clear: left ;
+  float: left ;
+  margin-right: 1em }
+
+img.align-right, .figure.align-right, object.align-right {
+  clear: right ;
+  float: right ;
+  margin-left: 1em }
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.align-left {
+  text-align: left }
+
+.align-center {
+  clear: both ;
+  text-align: center }
+
+.align-right {
+  text-align: right }
+
+/* reset inner alignment in figures */
+div.align-right {
+  text-align: inherit }
+
+/* div.align-center * { */
+/*   text-align: left } */
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font: inherit }
+
+pre.literal-block, pre.doctest-block, pre.math, pre.code {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+pre.code .ln { color: grey; } /* line numbers */
+pre.code, code { background-color: #eeeeee }
+pre.code .comment, code .comment { color: #5C6576 }
+pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
+pre.code .literal.string, code .literal.string { color: #0C5404 }
+pre.code .name.builtin, code .name.builtin { color: #352B84 }
+pre.code .deleted, code .deleted { background-color: #DEB0A1}
+pre.code .inserted, code .inserted { background-color: #A3D289}
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid 1px gray;
+  margin-left: 1px }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid 1px black;
+  margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+ul.auto-toc {
+  list-style-type: none }
+
+.code .pygments-hll { background-color: #ffffcc }
+.code .pygments-c { color: #60a0b0; font-style: italic } /* Comment */
+.code .pygments-err { border: 1px solid #FF0000 } /* Error */
+.code .pygments-k { color: #007020; font-weight: bold } /* Keyword */
+.code .pygments-o { color: #666666 } /* Operator */
+.code .pygments-cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
+.code .pygments-cp { color: #007020 } /* Comment.Preproc */
+.code .pygments-c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
+.code .pygments-cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
+.code .pygments-gd { color: #A00000 } /* Generic.Deleted */
+.code .pygments-ge { font-style: italic } /* Generic.Emph */
+.code .pygments-gr { color: #FF0000 } /* Generic.Error */
+.code .pygments-gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.code .pygments-gi { color: #00A000 } /* Generic.Inserted */
+.code .pygments-go { color: #888888 } /* Generic.Output */
+.code .pygments-gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.code .pygments-gs { font-weight: bold } /* Generic.Strong */
+.code .pygments-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.code .pygments-gt { color: #0044DD } /* Generic.Traceback */
+.code .pygments-kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.code .pygments-kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.code .pygments-kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.code .pygments-kp { color: #007020 } /* Keyword.Pseudo */
+.code .pygments-kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.code .pygments-kt { color: #902000 } /* Keyword.Type */
+.code .pygments-m { color: #40a070 } /* Literal.Number */
+.code .pygments-s { color: #4070a0 } /* Literal.String */
+.code .pygments-na { color: #4070a0 } /* Name.Attribute */
+.code .pygments-nb { color: #007020 } /* Name.Builtin */
+.code .pygments-nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.code .pygments-no { color: #60add5 } /* Name.Constant */
+.code .pygments-nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.code .pygments-ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.code .pygments-ne { color: #007020 } /* Name.Exception */
+.code .pygments-nf { color: #06287e } /* Name.Function */
+.code .pygments-nl { color: #002070; font-weight: bold } /* Name.Label */
+.code .pygments-nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.code .pygments-nt { color: #062873; font-weight: bold } /* Name.Tag */
+.code .pygments-nv { color: #bb60d5 } /* Name.Variable */
+.code .pygments-ow { color: #007020; font-weight: bold } /* Operator.Word */
+.code .pygments-w { color: #bbbbbb } /* Text.Whitespace */
+.code .pygments-mf { color: #40a070 } /* Literal.Number.Float */
+.code .pygments-mh { color: #40a070 } /* Literal.Number.Hex */
+.code .pygments-mi { color: #40a070 } /* Literal.Number.Integer */
+.code .pygments-mo { color: #40a070 } /* Literal.Number.Oct */
+.code .pygments-sb { color: #4070a0 } /* Literal.String.Backtick */
+.code .pygments-sc { color: #4070a0 } /* Literal.String.Char */
+.code .pygments-sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.code .pygments-s2 { color: #4070a0 } /* Literal.String.Double */
+.code .pygments-se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.code .pygments-sh { color: #4070a0 } /* Literal.String.Heredoc */
+.code .pygments-si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.code .pygments-sx { color: #c65d09 } /* Literal.String.Other */
+.code .pygments-sr { color: #235388 } /* Literal.String.Regex */
+.code .pygments-s1 { color: #4070a0 } /* Literal.String.Single */
+.code .pygments-ss { color: #517918 } /* Literal.String.Symbol */
+.code .pygments-bp { color: #007020 } /* Name.Builtin.Pseudo */
+.code .pygments-vc { color: #bb60d5 } /* Name.Variable.Class */
+.code .pygments-vg { color: #bb60d5 } /* Name.Variable.Global */
+.code .pygments-vi { color: #bb60d5 } /* Name.Variable.Instance */
+.code .pygments-il { color: #40a070 } /* Literal.Number.Integer.Long */
diff --git a/requirements-build.txt b/requirements-build.txt
index 209e5b8d..43394f35 100644
--- a/requirements-build.txt
+++ b/requirements-build.txt
@@ -3,6 +3,8 @@ invoke >= 0.20
 rellu >= 0.6
 twine
 wheel
+docutils >= 0.14
+pygments
 
 # Include other dev dependencies from requirements-dev.txt which in turn
 # includes normal dependencies from requirements.txt.
diff --git a/src/SeleniumLibrary/__init__.py b/src/SeleniumLibrary/__init__.py
index 29cd21df..fc4ecb36 100644
--- a/src/SeleniumLibrary/__init__.py
+++ b/src/SeleniumLibrary/__init__.py
@@ -210,17 +210,17 @@ class SeleniumLibrary(DynamicCore):
     It also explains the `time format` that can be used when setting various
     timeouts, waits and delays.
 
-    == Timeouts ==
+    == Timeout ==
 
-    SeleniumLibrary contains various ``Wait ...`` keywords that can be used
-    to wait, for example, for a dynamically created elements to appear on
-    a page. All these keywords accept an optional ``timeout`` argument that
-    tells the maximum time to wait.
+    SeleniumLibrary contains various keywords that have an optional
+    ``timeout`` argument that specifies how long these keywords should
+    wait for certain events or actions. These keywords include, for example,
+    ``Wait ...`` keywords and keywords related to alerts.
 
     The default timeout these keywords use can be set globally either by
     using the `Set Selenium Timeout` keyword or with the ``timeout`` argument
-    when `importing` the library. The same timeout also applies to the
-    `Execute Async Javascript` keyword.
+    when `importing` the library. See `time format` below for supported
+    timeout syntax.
 
     == Implicit wait ==
 
@@ -230,6 +230,8 @@ class SeleniumLibrary(DynamicCore):
     the library. See [http://seleniumhq.org/docs/04_webdriver_advanced.html|
     Selenium documentation] for more information about this functionality.
 
+    See `time format` below for supported syntax.
+
     == Selenium speed ==
 
     Selenium execution speed can be slowed down globally by using `Set
@@ -238,6 +240,8 @@ class SeleniumLibrary(DynamicCore):
     appear on a page is not a good idea, and the above explained timeouts
     and waits should be used instead.
 
+    See `time format` below for supported syntax.
+
     == Time format ==
 
     All timeouts and waits can be given as numbers considered seconds
diff --git a/src/SeleniumLibrary/base/librarycomponent.py b/src/SeleniumLibrary/base/librarycomponent.py
index b51ef383..1273fe36 100644
--- a/src/SeleniumLibrary/base/librarycomponent.py
+++ b/src/SeleniumLibrary/base/librarycomponent.py
@@ -19,6 +19,8 @@ import os
 from robot.api import logger
 from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError
 
+from SeleniumLibrary.utils import is_noney, timestr_to_secs
+
 from .context import ContextAware
 from .robotlibcore import PY2
 
@@ -54,6 +56,11 @@ class LibraryComponent(ContextAware):
         self.element_finder.assert_page_not_contains(locator, tag, message,
                                                      loglevel)
 
+    def get_timeout(self, timeout=None):
+        if is_noney(timeout):
+            return self.ctx.timeout
+        return timestr_to_secs(timeout)
+
     @property
     def log_dir(self):
         try:
diff --git a/src/SeleniumLibrary/keywords/alert.py b/src/SeleniumLibrary/keywords/alert.py
index fe45a624..f64ab5c3 100644
--- a/src/SeleniumLibrary/keywords/alert.py
+++ b/src/SeleniumLibrary/keywords/alert.py
@@ -14,152 +14,202 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import time
-
 from selenium.common.exceptions import WebDriverException
 from selenium.webdriver.support import expected_conditions as EC
 from selenium.webdriver.support.ui import WebDriverWait
 
-from SeleniumLibrary.base import keyword
-from SeleniumLibrary.base import LibraryComponent
-from SeleniumLibrary.utils import is_truthy
+from SeleniumLibrary.base import keyword, LibraryComponent
+from SeleniumLibrary.utils import is_truthy, secs_to_timestr, timestr_to_secs
 
 
 class AlertKeywords(LibraryComponent):
+    ACCEPT = 'ACCEPT'
+    DISMISS = 'DISMISS'
+    LEAVE = 'LEAVE'
+    _next_alert_action = ACCEPT
 
-    ACCEPT_ALERT = 'accept'
-    DISMISS_ALERT = 'dismiss'
+    @keyword
+    def input_text_into_prompt(self, text):
+        """Deprecated. Use `Input Text Into Alert` instead.
 
-    def __init__(self, ctx):
-        LibraryComponent.__init__(self, ctx)
-        self._next_alert_dismiss_type = self.ACCEPT_ALERT
+        Types the given ``text`` into an input field in an alert.
+        Leaves the alert open.
+        """
+        self.input_text_into_alert(text, self.LEAVE)
 
     @keyword
-    def input_text_into_prompt(self, text):
-        """Types the given `text` into alert box.  """
-        try:
-            alert = self._wait_alert()
-            alert.send_keys(text)
-        except WebDriverException:
-            raise RuntimeError('There were no alerts')
+    def input_text_into_alert(self, text, action=ACCEPT, timeout=None):
+        """Types the given ``text`` into an input field in an alert.
+
+        The alert is accepted by default, but that behavior can be controlled
+        by using the ``action`` argument same way as with `Handle Alert`.
+
+        ``timeout`` specifies how long to wait for the alert to appear.
+        If it is not given, the global default `timeout` is used instead.
+
+        New in SeleniumLibrary 3.0.
+        """
+        alert = self._wait_alert(timeout)
+        alert.send_keys(text)
+        self._handle_alert(alert, action)
+
+    @keyword
+    def alert_should_be_present(self, text='', action=ACCEPT, timeout=None):
+        """Verifies that an alert is present and, by default, accepts it.
+
+        Fails if no alert is present. If ``text`` is a non-empty string,
+        then it is used to verify alert's message. The alert is accepted
+        by default, but that behavior can be controlled by using the
+        ``action`` argument same way as with `Handle Alert`.
+
+        ``timeout`` specifies how long to wait for the alert to appear.
+        If it is not given, the global default `timeout` is used instead.
+
+        ``action`` and ``timeout`` arguments are new in SeleniumLibrary 3.0.
+        In earlier versions the alert was always accepted and timeout was
+        hard coded to one second.
+        """
+        message = self.handle_alert(action, timeout)
+        if text and text != message:
+            raise AssertionError("Alert message should have been '%s' but it "
+                                 "was '%s'." % (text, message))
 
     @keyword
-    def alert_should_be_present(self, text=''):
-        """Verifies an alert is present and dismisses it.
+    def alert_should_not_be_present(self, action=ACCEPT, timeout=0):
+        """Verifies that no alert is present.
 
-        If `text` is a non-empty string, then it is also verified that the
-        message of the alert equals to `text`.
+        If the alert actually exists, the ``action`` argument determines
+        how it should be handled. By default the alert is accepted, but
+        it can be also dismissed or left open the same way as with the
+        `Handle Alert` keyword.
 
-        Will fail if no alert is present. Note that following keywords
-        will fail unless the alert is dismissed by this
-        keyword or another like `Get Alert Message`.
+        ``timeout`` specifies how long to wait for the alert to appear.
+        By default the alert is not waited at all, but a custom time can
+        be given if alert may be delayed. See the `time format` section
+        for information about the syntax.
+
+        New in SeleniumLibrary 3.0.
         """
-        alert_text = self._handle_alert(self.ACCEPT_ALERT)
-        if text and alert_text != text:
-            raise AssertionError("Alert text should have been "
-                                 "'%s' but was '%s'"
-                                 % (text, alert_text))
+        try:
+            alert = self._wait_alert(timeout)
+        except AssertionError:
+            return
+        text = self._handle_alert(alert, action)
+        raise AssertionError("Alert with message '%s' present." % text)
 
     @keyword
     def choose_cancel_on_next_confirmation(self):
-        """Cancel will be selected the next time `Confirm Action` is used."""
-        self._next_alert_dismiss_type = self.DISMISS_ALERT
+        """Deprecated. Use `Handle Alert` directly instead.
+
+        In versions prior to SeleniumLibrary 3.0, the alert handling
+        approach needed to be set separately before using the `Confirm
+        Action` keyword. New `Handle Alert` keyword accepts the action how
+        to handle the alert as a normal argument and should be used instead.
+        """
+        self._next_alert_action = self.DISMISS
 
     @keyword
     def choose_ok_on_next_confirmation(self):
-        """Undo the effect of using keywords `Choose Cancel On Next Confirmation`. Note
-        that Selenium's overridden window.confirm() function will normally
-        automatically return true, as if the user had manually clicked OK, so
-        you shouldn't need to use this command unless for some reason you need
-        to change your mind prior to the next confirmation. After any
-        confirmation, Selenium will resume using the default behavior for
-        future confirmations, automatically returning true (OK) unless/until
-        you explicitly use `Choose Cancel On Next Confirmation` for each
-        confirmation.
-
-        Note that every time a confirmation comes up, you must
-        consume it by using a keywords such as `Get Alert Message`, or else
-        the following selenium operations will fail.
+        """Deprecated. Use `Handle Alert` directly instead.
+
+        In versions prior to SeleniumLibrary 3.0, the alert handling
+        approach needed to be set separately before using the `Confirm
+        Action` keyword. New `Handle Alert` keyword accepts the action how
+        to handle the alert as a normal argument and should be used instead.
         """
-        self._next_alert_dismiss_type = self.ACCEPT_ALERT
+        self._next_alert_action = self.ACCEPT
 
     @keyword
     def confirm_action(self):
-        """Dismisses currently shown confirmation dialog and returns it's message.
+        """Deprecated. Use `Handle Alert` instead.
 
-        By default, this keyword chooses 'OK' option from the dialog. If
-        'Cancel' needs to be chosen, keyword `Choose Cancel On Next
-        Confirmation` must be called before the action that causes the
-        confirmation dialog to be shown.
-
-        Examples:
-        | Click Button | Send | # Shows a confirmation dialog |
-        | ${message}= | Confirm Action | # Chooses Ok |
-        | Should Be Equal | ${message} | Are your sure? |
-        |                |    |              |
-        | Choose Cancel On Next Confirmation | | |
-        | Click Button | Send | # Shows a confirmation dialog |
-        | Confirm Action |    | # Chooses Cancel |
+        By default accepts an alert, but this behavior can be altered
+        with `Choose Cancel On Next Confirmation` and `Choose Ok On Next
+        Confirmation` keywords. New `Handle Alert` keyword accepts the action
+        how to handle the alert as a normal argument and should be used
+        instead.
         """
-        text = self._handle_alert(self._next_alert_dismiss_type)
-        self._next_alert_dismiss_type = self.DISMISS_ALERT
+        text = self.handle_alert(self._next_alert_action)
+        self._next_alert_action = self.ACCEPT
         return text
 
     @keyword
     def get_alert_message(self, dismiss=True):
-        """Returns the text of current JavaScript alert.
+        """Deprecated. Use `Handle Alert` instead.
 
-        By default the current JavaScript alert will be dismissed.
-        This keyword will fail if no alert is present. Note that
-        following keywords will fail unless the alert is
-        dismissed by this keyword or another like `Dismiss Alert`.
+        Returns the message the alert has. Dismisses the alert by default
+        (i.e. presses ``Cancel``) and setting ``dismiss`` to false leaves
+        the alert open. There is no support to accept the alert (i.e. to
+        press ``Ok``).
+
+        `Handle Alert` has better support for controlling should the alert
+        be accepted, dismissed, or left open.
         """
-        if is_truthy(dismiss):
-            return self._handle_alert(self.DISMISS_ALERT)
-        else:
-            return self._handle_alert()
+        action = self.DISMISS if is_truthy(dismiss) else self.LEAVE
+        return self.handle_alert(action)
 
     @keyword
     def dismiss_alert(self, accept=True):
-        """ Returns true if alert was confirmed, false if it was dismissed
+        """Deprecated. Use `Handle Alert` instead.
+
+        Contrary to its name, this keyword accepts the alert by default
+        (i.e. presses ``Ok``). ``accept`` can be set to a false value
+        to dismiss the alert (i.e. to press ``Cancel``).
 
-        This keyword will fail if no alert is present. Note that
-        following keywords will fail unless the alert is
-        dismissed by this keyword or another like `Get Alert Message`.
+        `Handle Alert` has better support for controlling should the alert
+        be accepted, dismissed, or left open.
         """
         if is_truthy(accept):
-            return self._handle_alert(self.ACCEPT_ALERT)
-        else:
-            return self._handle_alert()
+            self.handle_alert(self.ACCEPT)
+            return True
+        self.handle_alert(self.DISMISS)
+        return False
 
-    def _handle_alert(self, dismiss_type=None):
-        """Alert re-try for Chrome
+    @keyword
+    def handle_alert(self, action=ACCEPT, timeout=None):
+        """Handles the current alert and returns its message.
+
+        By default the alert is accepted, but this can be controlled
+        with the ``action`` argument that supports the following
+        case-insensitive values:
 
-        Because Chrome has difficulties to handle alerts, like::
+        - ``ACCEPT``: Accept the alert i.e. press ``Ok``. Default.
+        - ``DISMISS``: Dismiss the alert i.e. press ``Cancel``.
+        - ``LEAVE``: Leave the alert open.
 
-        alert.text
-        alert.dismiss
+        The ``timeout`` argument specifies how long to wait for the alert
+        to appear. If it is not given, the global default `timeout` is used
+        instead.
 
-        This function creates a re-try functionality to better support
-        alerts in Chrome.
+        Examples:
+        | Handle Alert |                |       | # Accept alert.  |
+        | Handle Alert | action=DISMISS |       | # Dismiss alert. |
+        | Handle Alert | timeout=10 s   |       | # Use custom timeout and accept alert.  |
+        | Handle Alert | DISMISS        | 1 min | # Use custom timeout and dismiss alert. |
+        | ${message} = | Handle Alert   |       | # Accept alert and get its message.     |
+        | ${message} = | Handle Alert   | LEAVE | # Leave alert open and get its message. |
+
+        New in SeleniumLibrary 3.0.
         """
-        retry = 0
-        while retry < 4:
-            try:
-                return self._alert_worker(dismiss_type)
-            except WebDriverException:
-                time.sleep(0.2)
-                retry += 1
-        raise RuntimeError('There were no alerts')
-
-    def _alert_worker(self, dismiss_type=None):
-        alert = self._wait_alert()
+        alert = self._wait_alert(timeout)
+        return self._handle_alert(alert, action)
+
+    def _handle_alert(self, alert, action):
+        action = action.upper()
         text = ' '.join(alert.text.splitlines())
-        if dismiss_type == self.DISMISS_ALERT:
-            alert.dismiss()
-        elif dismiss_type == self.ACCEPT_ALERT:
+        if action == self.ACCEPT:
             alert.accept()
+        elif action == self.DISMISS:
+            alert.dismiss()
+        elif action != self.LEAVE:
+            raise ValueError("Invalid alert action '%s'." % action)
         return text
 
-    def _wait_alert(self):
-        return WebDriverWait(self.browser, 1).until(EC.alert_is_present())
+    def _wait_alert(self, timeout=None):
+        timeout = self.get_timeout(timeout)
+        wait = WebDriverWait(self.browser, timeout)
+        try:
+            return wait.until(EC.alert_is_present())
+        except WebDriverException:
+            raise AssertionError('Alert not found in %s.'
+                                 % secs_to_timestr(timeout))
diff --git a/src/SeleniumLibrary/keywords/browsermanagement.py b/src/SeleniumLibrary/keywords/browsermanagement.py
index 95f7fb79..f4fa0ea8 100644
--- a/src/SeleniumLibrary/keywords/browsermanagement.py
+++ b/src/SeleniumLibrary/keywords/browsermanagement.py
@@ -322,6 +322,16 @@ class BrowserManagementKeywords(LibraryComponent):
 
         Key attributes for frames are `id` and `name.` See `introduction` for
         details about locating elements.
+        
+        See `Unselect Frame` to cancel the frame selection and return to the Main frame.
+        
+        Please note that the frame search always start from the document root or main frame.
+        
+        Example:
+        | Select Frame   | xpath: //frame[@name='top]/iframe[@name='left'] | # Selects the 'left' iframe |
+        | Click Link     | foo                                             | # Clicks link 'foo' in 'left' iframe |
+        | Unselect Frame |                                                 | # Returns to main frame |
+        | Select Frame   | left                                            | # Selects the 'top' frame |        
         """
         self.info("Selecting frame '%s'." % locator)
         element = self.find_element(locator)
@@ -387,7 +397,10 @@ class BrowserManagementKeywords(LibraryComponent):
 
     @keyword
     def unselect_frame(self):
-        """Sets the top frame as the current frame."""
+        """Sets the top frame as the current frame.
+        
+        Cancels a previous `Select Frame` call, returning to the Main frame.
+        """
         self.browser.switch_to.default_content()
 
     @keyword
@@ -522,7 +535,7 @@ class BrowserManagementKeywords(LibraryComponent):
         Example:
         | Set Selenium Speed | .5 seconds |
         """
-        old_speed = self.ctx.speed
+        old_speed = self.get_selenium_speed()
         self.ctx.speed = timestr_to_secs(seconds)
         for browser in self.browsers.browsers:
             self._monkey_patch_speed(browser)
diff --git a/src/SeleniumLibrary/keywords/cookie.py b/src/SeleniumLibrary/keywords/cookie.py
index eeff2de7..b5531e0a 100644
--- a/src/SeleniumLibrary/keywords/cookie.py
+++ b/src/SeleniumLibrary/keywords/cookie.py
@@ -16,6 +16,7 @@
 
 from SeleniumLibrary.base import LibraryComponent, keyword
 from SeleniumLibrary.utils import is_truthy
+from robot.libraries.DateTime import convert_date
 
 
 class CookieKeywords(LibraryComponent):
@@ -53,11 +54,25 @@ class CookieKeywords(LibraryComponent):
         raise ValueError("Cookie with name %s not found." % name)
 
     @keyword
-    def add_cookie(self, name, value, path=None, domain=None, secure=None):
+    def get_cookie(self, name):
+        """Returns the cookie found with `name` in extended variable format.
+
+        If no cookie is found with `name`, this keyword fails.
+        """
+        cookie = self.browser.get_cookie(name)
+        if cookie:
+            cookie_information = CookieInformation(cookie)
+            return cookie_information
+        raise ValueError("Cookie with name %s not found." % name)
+
+    @keyword
+    def add_cookie(self, name, value, path=None, domain=None, secure=None,
+                   expiry=None):
         """Adds a cookie to your current session.
 
-        "name" and "value" are required, "path", "domain" and "secure" are
-        optional
+        "name" and "value" are required, "path", "domain", "secure" and
+         "expiry" are optional.  Expiry supports the same formats as
+         the DateTime library.
         """
         new_cookie = {'name': name, 'value': value}
         if is_truthy(path):
@@ -67,4 +82,27 @@ class CookieKeywords(LibraryComponent):
         # Secure should be True or False
         if is_truthy(secure):
             new_cookie['secure'] = secure
+        if is_truthy(expiry):
+            expiry_datetime = int(convert_date(expiry, result_format='epoch'))
+            new_cookie['expiry'] = expiry_datetime
         self.browser.add_cookie(new_cookie)
+
+
+class CookieInformation(object):
+    def __init__(self, cookie):
+        self.domain = cookie['domain'] if 'domain' in cookie else None
+        self.expiry = cookie['expiry'] if 'expiry' in cookie else None
+        self.httpOnly = cookie['httpOnly'] if 'httpOnly' in cookie else None
+        self.name = cookie['name'] if 'name' in cookie else None
+        self.path = cookie['path'] if 'path' in cookie else None
+        self.secure = cookie['secure'] if 'secure' in cookie else None
+        self.value = cookie['value'] if 'value' in cookie else None
+
+    @property
+    def full_info(self):
+        cookie_info = ', '.join("{}={}".format(key, value) for
+                                (key, value) in self.__dict__.items())
+        return cookie_info
+
+    def __str__(self):
+        return '{}={}'.format(self.name, self.value)
diff --git a/src/SeleniumLibrary/keywords/waiting.py b/src/SeleniumLibrary/keywords/waiting.py
index 38d6a5a0..4bf9b631 100644
--- a/src/SeleniumLibrary/keywords/waiting.py
+++ b/src/SeleniumLibrary/keywords/waiting.py
@@ -30,22 +30,24 @@ class WaitingKeywords(LibraryComponent):
 
     @keyword
     def wait_for_condition(self, condition, timeout=None, error=None):
-        """Waits until the given `condition` is true or `timeout` expires.
+        """Waits until the given ``condition`` is true or ``timeout`` expires.
 
-        The `condition` can be arbitrary JavaScript expression but must contain a
-        return statement (with the value to be returned) at the end.
-        See `Execute JavaScript` for information about accessing the
-        actual contents of the window through JavaScript.
+        The ``condition`` can be arbitrary JavaScript expression but it
+        must return a value to be evaluated. See `Execute JavaScript` for
+        information about accessing content on pages.
 
-        `error` can be used to override the default error message.
+        ``error`` can be used to override the default error message.
 
-        See `introduction` for more information about `timeout` and its
+        See `timeouts` for more information about using timeouts and their
         default value.
 
         See also `Wait Until Page Contains`, `Wait Until Page Contains
         Element`, `Wait Until Element Is Visible` and BuiltIn keyword
         `Wait Until Keyword Succeeds`.
         """
+        if 'return' not in condition:
+            raise ValueError("Condition '%s' did not have mandatory 'return'."
+                             % condition)
         if is_falsy(error):
             error = "Condition '%s' did not become true in <TIMEOUT>" % condition
         self._wait_until(
@@ -263,8 +265,7 @@ class WaitingKeywords(LibraryComponent):
         self._wait_until_no_error(timeout, wait_func)
 
     def _wait_until_no_error(self, timeout, wait_func, *args):
-        timeout = timestr_to_secs(timeout) if is_truthy(timeout) else self.ctx.timeout
-        maxtime = time.time() + timeout
+        maxtime = time.time() + self.get_timeout(timeout)
         while True:
             timeout_error = wait_func(*args)
             if not timeout_error:
@@ -274,5 +275,4 @@ class WaitingKeywords(LibraryComponent):
             time.sleep(0.2)
 
     def _format_timeout(self, timeout):
-        timeout = timestr_to_secs(timeout) if is_truthy(timeout) else self.ctx.timeout
-        return secs_to_timestr(timeout)
+        return secs_to_timestr(self.get_timeout(timeout))
diff --git a/src/SeleniumLibrary/utils/__init__.py b/src/SeleniumLibrary/utils/__init__.py
index f827f0b1..377f9d42 100644
--- a/src/SeleniumLibrary/utils/__init__.py
+++ b/src/SeleniumLibrary/utils/__init__.py
@@ -20,7 +20,7 @@ from .browsercache import BrowserCache
 from .deprecated import Deprecated
 from .librarylistener import LibraryListener
 from .seleniumversion import SELENIUM_VERSION
-from .types import is_string, is_truthy, is_falsy
+from .types import is_falsy, is_noney, is_string, is_truthy
 
 
 def escape_xpath_value(value):
diff --git a/src/SeleniumLibrary/utils/types.py b/src/SeleniumLibrary/utils/types.py
index 86e1890f..266c55a4 100644
--- a/src/SeleniumLibrary/utils/types.py
+++ b/src/SeleniumLibrary/utils/types.py
@@ -37,3 +37,7 @@ def is_truthy(item):
 
 def is_falsy(item):
     return not is_truthy(item)
+
+
+def is_noney(item):
+    return item is None or is_string(item) and item.upper() == 'NONE'
diff --git a/tasks.py b/tasks.py
index 256f91d8..9265c893 100644
--- a/tasks.py
+++ b/tasks.py
@@ -1,6 +1,7 @@
 import sys
 from pathlib import Path
 
+from docutils.core import publish_cmdline
 from invoke import task
 from rellu import initialize_labels, ReleaseNotesGenerator, Version
 from rellu.tasks import clean
@@ -52,7 +53,7 @@ SeleniumLibrary {version} was released on {date}.
 
 
 @task
-def keyword_documentation(ctx):
+def kw_docs(ctx):
     """Generates the library keyword documentation
 
     Documentation is generated by using the Libdoc tool.
@@ -61,6 +62,20 @@ def keyword_documentation(ctx):
            str(Path('docs/SeleniumLibrary.html')))
 
 
+@task
+def project_docs(ctx):
+    """Generate project documentation.
+
+     These docs are visible at http://robotframework.org/SeleniumLibrary/.
+     """
+    args = ['--stylesheet=style.css,extra.css',
+            '--link-stylesheet',
+            'README.rst',
+            'docs/index.html']
+    publish_cmdline(writer_name='html5', argv=args)
+    print(Path(args[-1]).absolute())
+
+
 @task
 def set_version(ctx, version):
     """Set project version in `src/SeleniumLibrary/__init__.py`` file.


Test patch:
diff --git a/test/acceptance/keywords/alerts.robot b/test/acceptance/keywords/alerts.robot
new file mode 100644
index 00000000..316618bc
--- /dev/null
+++ b/test/acceptance/keywords/alerts.robot
@@ -0,0 +1,232 @@
+*** Settings ***
+Force Tags        Known Issue Safari
+Suite Setup       Set Global Timeout    1 second
+Test Setup        Go To Page "javascript/alert.html"
+Suite Teardown    Restore Global Timeout
+Resource          ../resource.robot
+
+*** Test Cases ***
+Handle Alert accepts by default
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    Handle Alert
+    Alert Should Not Be Present
+    Wait For Title Change    Original Changed!
+
+Handle Alert can dismiss
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    Handle Alert    action=DISMISS
+    Alert Should Not Be Present
+    Wait For Title Change    Original
+
+Handle Alert can leave open
+    Click Link    Click Me!
+    Handle Alert    Leave
+    Alert Should Be Present
+
+Handle Alert with invalid action
+    Click Link    Click Me!
+    Run Keyword And Expect Error
+    ...    ValueError: Invalid alert action 'INVALID'.
+    ...    Handle Alert    INVALID
+    Alert Should Be Present
+
+Handle Alert returns message
+    Click Link    Click Me!
+    ${message} =    Handle Alert
+    Should Be Equal    ${message}    ALERT!
+    Click Link    Click Me Too!
+    ${message} =    Handle Alert    action=LEAVE
+    Should Be Equal    ${message}    MULTILINE ALERT!
+    Alert Should Be Present
+
+Handle Alert with custom timeout
+    Click Button    Slow alert
+    Handle Alert    timeout=1s
+    Click Button    Slow alert
+    Run Keyword And Expect Error
+    ...    Alert not found in 1 millisecond.
+    ...    Handle Alert    ACCEPT    1 ms
+    Handle Alert    timeout=3.14 seconds
+
+Alert Should Not Be Present
+    Alert Should Not Be Present
+    Click Link    Click Me!
+    Run Keyword And Expect Error
+    ...    Alert with message 'ALERT!' present.
+    ...    Alert Should Not Be Present
+
+Alert Should Not Be Present with custom actions
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    Run Keyword And Expect Error
+    ...    Alert with message 'Really change the title?' present.
+    ...    Alert Should Not Be Present    action=LEAVE
+    Run Keyword And Expect Error
+    ...    Alert with message 'Really change the title?' present.
+    ...    Alert Should Not Be Present    action=DISmiss
+    Wait For Title Change    Original
+
+Alert Should Not Be Present with custom timeout
+    Alert Should Not Be Present    timeout=0.1s
+    Click Button    Slow alert
+    Alert Should Not Be Present    DISMISS    ${0.001}
+    Run Keyword And Expect Error
+    ...    Alert with message 'Alert after 500ms!' present.
+    ...    Alert Should Not Be Present    timeout=0.99999
+
+Alert Should Be Present
+    Run Keyword And Expect Error
+    ...    Alert not found in 1 second.
+    ...    Alert Should Be Present
+    Click Link    Click Me!
+    Alert Should Be Present
+
+Alert Should Be Present with message validation
+    Click Link    Click Me!
+    Alert Should Be Present    ALERT!
+    Click Link    Click Me Too!
+    Alert Should Be Present    MULTILINE ALERT!
+    Click Link    Click Me!
+    Run Keyword And Expect Error
+    ...    Alert message should have been 'foo bar' but it was 'ALERT!'.
+    ...    Alert Should Be Present    foo bar
+
+Alert Should Be Present accepts by default
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    Alert Should Be Present    Really change the title?
+    Wait For Title Change    Original Changed!
+    Alert Should Not Be Present
+
+Alert Should Be Present can dismiss
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    Alert Should Be Present    Really change the title?    action=DISMISS
+    Wait For Title Change    Original
+    Alert Should Not Be Present
+
+Alert Should Be Present can leave alert open
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    Alert Should Be Present    action=LEAVE
+    Alert Should Be Present
+
+Alert Should Be Present with custom timeout
+    Click Button    Slow alert
+    Run Keyword And Expect Error
+    ...    Alert not found in 1 millisecond.
+    ...    Alert Should Be Present    timeout=1ms
+    Alert Should Be Present    Alert after 500ms!    ACCEPT    3s
+
+Get Alert Message
+    [Documentation]    DEPRECATED!
+    Click Link    Click Me!
+    ${msg} =    Get Alert Message
+    Should Be Equal    ${msg}    ALERT!
+    Click Link    Click Me Too!
+    ${msg} =    Get Alert Message
+    Should Be Equal    ${msg}    MULTILINE ALERT!
+    Run Keyword And Expect Error
+    ...    Alert not found in 1 second.
+    ...    Get Alert Message
+
+Get Alet Message dismisses by default
+    [Documentation]    DEPRECATED!
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    ${msg} =    Get Alert Message
+    Should Be Equal    ${msg}    Really change the title?
+    Wait For Title Change    Original
+
+Get Alert Message can leave alert open
+    [Documentation]    DEPRECATED!
+    Click Link    Click Me!
+    ${msg} =    Get Alert Message    ${FALSE}
+    Should Be Equal    ${msg}    ALERT!
+    Alert Should Be Present
+
+Input Text Into Alert
+    [Setup]    Go To Page "javascript/alert_prompt.html"
+    Click Button    css=button
+    Input Text Into Alert    Robot
+    Alert Should Not Be Present
+    Page Should Contain    Hello Robot! How are you today?
+
+Input Text Into Alert can leave alert open
+    [Setup]    Go To Page "javascript/alert_prompt.html"
+    Click Button    css=button
+    Input Text Into Alert    Robot    action=LEAVE
+    Alert Should Be Present
+    Page Should Contain    Hello Robot! How are you today?
+
+Input Text Into Alert can dismiss
+    [Setup]    Go To Page "javascript/alert_prompt.html"
+    Click Button    css=button
+    Input Text Into Alert    Robot    action=DISMISS
+    Alert Should Not Be Present
+    Page Should Not Contain    Robot
+
+Input Text Into Alert with custom timeout
+    [Setup]    Go To Page "javascript/alert_prompt.html"
+    Run Keyword And Expect Error
+    ...    Alert not found in 7 milliseconds.
+    ...    Input Text Into Alert    This is not found    timeout=007ms
+
+Input Text Into Prompt
+    [Documentation]    DEPRECATED! Always leaves the alert open.
+    [Setup]    Go To Page "javascript/alert_prompt.html"
+    Click Button    css=button
+    Input Text Into Prompt    Robot
+    Alert Should Be Present
+    Page Should Contain    Hello Robot! How are you today?
+
+Confirm Action
+    [Documentation]    DEPRECATED!
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    ${msg}=    Confirm Action
+    Should Be Equal    ${msg}    Really change the title?
+    Wait For Title Change    Original Changed!
+
+Confirm Action multiple times
+    [Documentation]    DEPRECATED!
+    [Setup]    Go To Page "javascript/alert_prompt.html"
+    Click Button    css=button
+    Input Text Into Alert    Robot    action=LEAVE
+    Confirm Action
+    Page Should Contain    Hello Robot! How are you today?
+    Click Button    css=button
+    Input Text Into Alert    Mr. Roboto    action=LEAVE
+    Confirm Action
+    Page Should Contain    Hello Mr. Roboto! How are you today?
+
+Cancel Action
+    [Documentation]    DEPRECATED!
+    [Setup]    Go To Page "javascript/alert_prompt.html"
+    Choose Cancel On Next Confirmation
+    Click Button    css=button
+    Input Text Into Alert    Robot    action=LEAVE
+    Confirm Action
+    Page Should Not Contain    Robot
+
+Dismiss Alert
+    [Documentation]    DEPRECATED!
+    [Setup]    Go To Page "javascript/dynamic_content.html"
+    Click Button    Change the title
+    ${accepted} =    Dismiss Alert    # This actually accepts the alert
+    Should Be Equal    ${accepted}    ${TRUE}
+    Wait For Title Change    Original Changed!
+    Click Button    Change the title
+    ${accepted} =    Dismiss Alert    accept=${FALSE}
+    Wait For Title Change    Original Changed!
+    Should Be Equal    ${accepted}    ${FALSE}
+    Click Button    Change the title
+    Dismiss Alert    true
+    Wait For Title Change    Original Changed! Changed!
+
+*** Keywords ***
+Wait For Title Change
+    [Arguments]    ${expected}
+    Wait For Condition    return document.title == '${expected}'
diff --git a/test/acceptance/keywords/cookies.robot b/test/acceptance/keywords/cookies.robot
index e3fb40dc..2992ca11 100644
--- a/test/acceptance/keywords/cookies.robot
+++ b/test/acceptance/keywords/cookies.robot
@@ -5,6 +5,7 @@ Suite Teardown    Delete All Cookies
 Test Setup        Add Cookies
 Resource          ../resource.robot
 
+
 *** Test Cases ***
 Get Cookies
     [Documentation]    Get Cookies
@@ -48,9 +49,16 @@ Get Cookies When There Are None
     ${cookies}=    Get Cookies
     Should Be Equal    ${cookies}    ${EMPTY}
 
+Get Cookie Expiry Set By Selenium
+    [Documentation]    Get Cookie Expiry Set By Selenium
+    [Tags]  Known Issue Firefox
+    ${cookie}=    Get Cookie    another
+    ${date}=  Convert Date  2027-09-28 16:21:35  epoch
+    Should Be Equal As Integers   ${cookie.expiry}  ${date}
+
 *** Keyword ***
 Add Cookies
     [Documentation]    Add Cookies
     Delete All Cookies
     Add Cookie    test    seleniumlibrary
-    Add Cookie    another    value
+    Add Cookie    another    value   expiry=2027-09-28 16:21:35
diff --git a/test/acceptance/keywords/javascript.robot b/test/acceptance/keywords/javascript.robot
index 59b49585..d16de95c 100644
--- a/test/acceptance/keywords/javascript.robot
+++ b/test/acceptance/keywords/javascript.robot
@@ -1,56 +1,14 @@
 *** Settings ***
-Documentation     Tests javascript
 Test Setup        Go To Page "javascript/dynamic_content.html"
 Resource          ../resource.robot
 
 *** Test Cases ***
 Clicking Elements Should Activate Javascript
-    [Documentation]    Clicking Elements Should Activate Javascript
     Title Should Be    Original
     Click Element    link=change title
     Title Should Be    Changed
 
-Alert Should Be Present
-    [Documentation]    Alert Should Be Present
-    [Tags]    Known Issue Safari
-    [Setup]    Go To Page "javascript/alert.html"
-    Click Link    Click Me!
-    Alert Should Be Present
-    Click Link    Click Me Too!
-    Alert Should Be Present    MULTILINE ALERT!
-    Click Link    Click Me!
-    Run Keyword And Expect Error    Alert text should have been 'foo bar' but was 'ALERT!'    Alert Should Be Present    foo bar
-
-Get Alert Message
-    [Documentation]    Get Alert Message
-    [Tags]    Known Issue Safari
-    [Setup]    Go To Page "javascript/alert.html"
-    Click Link    Click Me!
-    ${msg} =    Get Alert Message
-    Should Be Equal    ${msg}    ALERT!
-    Run Keyword And Expect Error    There were no alerts    Get Alert Message
-
-Read Alert Message
-    [Documentation]    Read Alert Message
-    [Tags]    Known Issue Safari
-    [Setup]    Go To Page "javascript/alert.html"
-    Click Link    Click Me!
-    ${msg} =    Get Alert Message    ${FALSE}
-    Should Be Equal    ${msg}    ALERT!
-    Dismiss Alert
-    Run Keyword And Expect Error    There were no alerts    Get Alert Message
-
-Input Text Into Prompt
-    [Documentation]    Input Text Into Prompt
-    [Tags]    Known Issue Safari
-    [Setup]    Go To Page "javascript/alert_prompt.html"
-    Click Element    css=button
-    Input Text Into Prompt    myname
-    Dismiss Alert
-    Page Should Contain    myname
-
 Mouse Down On Link
-    [Documentation]    Mouse Down On Link
     [Tags]    Known Issue Safari
     [Setup]    Go To Page "javascript/mouse_events.html"
     Mouse Down On Image    image_mousedown
@@ -61,23 +19,6 @@ Mouse Down On Link
     Text Field Should Contain    textfield    onmousedown
     Mouse Up    link_mousedown
 
-Confirm Action
-    [Documentation]    Confirm Action
-    [Tags]    Known Issue Safari
-    Click Button    Change the title
-    ${msg}=    Confirm Action
-    Title Should Be    Changed after confirmation
-    Should Be Equal    ${msg}    Really change the title?
-
-Cancel Action
-    [Documentation]    Cancel Action
-    [Tags]    Known Issue Safari
-    Choose Cancel On Next Confirmation
-    Click Button    Change the title
-    ${msg}=    Confirm Action
-    Title Should Be    Original
-    Should Be Equal    ${msg}    Really change the title?
-
 Execute Javascript
     [Documentation]    LOG 2 Executing JavaScript:
     ...    window.add_content('button_target', 'Inserted directly')
@@ -92,13 +33,11 @@ Execute Javascript from File
     Page Should Contain    Inserted via file
 
 Open Context Menu
-    [Documentation]    Open Context Menu
     [Tags]    Known Issue Safari
     Go To Page "javascript/context_menu.html"
     Open Context Menu    myDiv
 
 Drag and Drop
-    [Documentation]    Drag and Drop
     [Tags]    Known Issue Internet Explorer    Known Issue Safari
     [Setup]    Go To Page "javascript/drag_and_drop.html"
     Element Text Should Be    id=droppable    Drop here
@@ -106,7 +45,6 @@ Drag and Drop
     Element Text Should Be    id=droppable    Dropped!
 
 Drag and Drop by Offset
-    [Documentation]    Drag and Drop by Offset
     [Tags]    Known Issue Firefox    Known Issue Internet Explorer    Known Issue Safari
     [Setup]    Go To Page "javascript/drag_and_drop.html"
     Element Text Should Be    id=droppable    Drop here
@@ -117,7 +55,7 @@ Drag and Drop by Offset
 
 Verify Console Log Can be Caught
     [Tags]    Known Issue Firefox
-    ${message}    Set Variable    Sample Console Error
+    ${message}=    Set Variable    Sample Console Error
     Execute Javascript    console.error('${message}')
     ${logs}=    Get Log    browser
     ${err}=    Convert To string    ${logs}
diff --git a/test/acceptance/keywords/set_selenium_speed.robot b/test/acceptance/keywords/set_selenium_speed.robot
index a9cbf02f..8d3da88f 100644
--- a/test/acceptance/keywords/set_selenium_speed.robot
+++ b/test/acceptance/keywords/set_selenium_speed.robot
@@ -1,15 +1,15 @@
 *** Settings ***
 Suite Setup       Go To Page "forms/prefilled_email_form.html"
-Suite Teardown    Set Selenium Speed    0
+Test Teardown     Set Selenium Speed    0
 Resource          ../resource.robot
 
 *** Test Cases ***
 Settimg selenium speed is possible multiple times
     Set Selenium Speed    10
-    ${speed} =    Set Selenium Speed    5
-    Should Be Equal     ${speed}    ${10}
-    ${speed} =    Set Selenium Speed    1
-    Should Be Equal     ${speed}    ${5}
+    ${old} =    Set Selenium Speed    1
+    Should Be Equal     ${old}    10 seconds
+    ${old} =    Set Selenium Speed    100
+    Should Be Equal     ${old}    1 second
 
 Selenium speed should affect execution
     [Documentation]    Click Element executes two selenium commands and
diff --git a/test/acceptance/keywords/waiting.robot b/test/acceptance/keywords/waiting.robot
index 69c4fa7f..386850b7 100644
--- a/test/acceptance/keywords/waiting.robot
+++ b/test/acceptance/keywords/waiting.robot
@@ -1,26 +1,27 @@
 *** Settings ***
-Documentation     Tests waiting
 Test Setup        Go To Page "javascript/delayed_events.html"
 Resource          ../resource.robot
 Force Tags        Known Issue Internet Explorer
 
 *** Test Cases ***
 Wait For Condition
-    [Documentation]    Wait For Condition
     Title Should Be    Original
     Wait For Condition    return window.document.title == "Changed"
     Run Keyword And Expect Error
     ...    Condition 'return window.document.title == "Invalid"' did not become true in 100 milliseconds
     ...    Wait For Condition    return window.document.title == "Invalid"    ${0.1}
 
+Wait For Condition requires `return`
+    Run Keyword And Expect Error
+    ...    ValueError: Condition 'window.document.title == "Changed"' did not have mandatory 'return'.
+    ...    Wait For Condition    window.document.title == "Changed"
+
 Wait Until Page Contains
-    [Documentation]    Wait Until Page Contains
     Wait Until Page Contains    New Content    2 s
     Run Keyword And Expect Error    Text 'invalid' did not appear in 100 milliseconds
     ...    Wait Until Page Contains    invalid    0.1
 
 Wait Until Page Does Not Contain
-    [Documentation]    Wait Until Page Does Not Contain
     Wait Until Page Does Not Contain    This is content    2 s
     Run Keyword And Expect Error    Text 'Initially hidden' did not disappear in 100 milliseconds
     ...    Wait Until Page Does Not Contain    Initially hidden    0.1
@@ -32,14 +33,12 @@ Wait Until Page Contains Element
     ...    Wait Until Page Contains Element    %cnon-existent    0.1 seconds
 
 Wait Until Page Does Not Contain Element
-    [Documentation]    Tests also that format characters (e.g. %c) are handled correctly in error
-    ...    messages
+    [Documentation]    Tests also that format characters (e.g. %c) are handled correctly in error messages
     Wait Until Page Does Not Contain Element    not_present    2 seconds
     Run Keyword And Expect Error    Element 'content' did not disappear in 100 milliseconds
     ...    Wait Until Page Does Not Contain Element    content    0.1 seconds
 
 Wait Until Element Is Visible
-    [Documentation]    Wait Until Element Is Visible
     Run Keyword And Expect Error    Element 'hidden' was not visible in 100 milliseconds
     ...    Wait Until Element Is Visible    hidden    0.1
     Wait Until Element Is Visible    hidden    2 s
@@ -57,7 +56,6 @@ Wait Until Element Is Visible with locator only
     Wait Until Element Is Visible    hidden
 
 Wait Until Element Is Enabled
-    [Documentation]    Wait Until Element Is Enabled
     Run Keyword And Expect Error    Element 'id=disabled' was not enabled in 100 milliseconds
     ...    Wait Until Element Is Enabled    id=disabled    0.1
     Wait Until Element Is Enabled    id=disabled    2 s
@@ -68,7 +66,6 @@ Wait Until Element Is Enabled
     ...    id=invalid    0.1    User error message
 
 Wait Until Element Contains
-    [Documentation]    Wait Until Element Contains
     Run Keyword And Expect Error
     ...    Text 'New' did not appear in 100 milliseconds to element 'id=content'. Its text was 'This is content'.
     ...    Wait Until Element Contains    id=content    New    0.1
@@ -82,7 +79,6 @@ Wait Until Element Contains
     ...    Wait Until Element Contains    id=invalid    content    0.1
 
 Wait Until Element Does Not Contain
-    [Documentation]    Wait Until Element Does Not Contain
     Run Keyword And Expect Error
     ...    Text 'This is' did not disappear in 100 milliseconds from element 'id=content'.
     ...    Wait Until Element Does Not Contain    id=content    This is    0.1
@@ -90,3 +86,11 @@ Wait Until Element Does Not Contain
     Wait Until Element Does Not Contain    id=content    content    2 s
     Run Keyword And Expect Error    User error message    Wait Until Element Does Not Contain
     ...    content    New Content    0.1    User error message
+
+Timeout can be zero
+    Run Keyword And Expect Error
+    ...    Text 'New Content' did not appear in 0 seconds to element 'content'. Its text was 'This is content'.
+    ...    Wait Until Element Contains    content    New Content    0
+    Run Keyword And Expect Error
+    ...    Text 'New Content' did not appear in 0 seconds to element 'content'. Its text was 'This is content'.
+    ...    Wait Until Element Contains    content    New Content    ${0}
diff --git a/test/acceptance/resource.robot b/test/acceptance/resource.robot
index ce76d1ac..f5630f96 100644
--- a/test/acceptance/resource.robot
+++ b/test/acceptance/resource.robot
@@ -1,7 +1,8 @@
 *** Setting ***
-Library           SeleniumLibrary    run_on_failure=Nothing    implicit_wait=0
+Library           SeleniumLibrary    run_on_failure=Nothing    implicit_wait=0.2 seconds
 Library           Collections
 Library           OperatingSystem
+Library           DateTime
 
 *** Variable ***
 ${SERVER}=         localhost:7000
@@ -17,7 +18,9 @@ Open Browser To Start Page
     [Documentation]    This keyword also tests 'Set Selenium Speed' and 'Set Selenium Timeout'
     ...    against all reason.
     ${default speed}    ${default timeout}=    Open Browser To Start Page Without Testing Default Options
-    Should Be Equal    ${default speed}    ${0.0}
+    # FIXME: We shouldn't test anything here. If this stuff isn't tested elsewhere, new *tests* needs to be added.
+    # FIXME: The second test below verifies a hard coded return value!!?!
+    Should Be Equal    ${default speed}    0 seconds
     Should Be Equal    ${default timeout}    5 seconds
 
 Open Browser To Start Page Without Testing Default Options
@@ -70,3 +73,11 @@ Set ${level} Loglevel
 Verify Location Is "${relative url}"
     [Documentation]    Verifies location
     Wait Until Keyword Succeeds    5    1    Location Should Be    ${ROOT}/${relative url}
+
+Set Global Timeout
+    [Arguments]    ${timeout}
+    ${previous} =    Set Selenium timeout    ${timeout}
+    Set Suite Variable    ${PREVIOUS TIMEOUT}    ${previous}
+
+Restore Global Timeout
+    Set Selenium timeout    ${PREVIOUS TIMEOUT}
diff --git a/test/resources/html/javascript/alert.html b/test/resources/html/javascript/alert.html
index bc0f14f3..0913271e 100644
--- a/test/resources/html/javascript/alert.html
+++ b/test/resources/html/javascript/alert.html
@@ -5,5 +5,6 @@
 	<body>
         <p><a href="javascript:alert('ALERT!')">Click Me!</a></p>
         <p><a href="javascript:alert('MULTILINE\nALERT!')">Click Me Too!</a></p>
+        <p><button onclick="setTimeout(function(){ alert('Alert after 500ms!'); }, 500)">Slow alert</button></p>
 	</body>
-</html>
\ No newline at end of file
+</html>
diff --git a/test/resources/html/javascript/dynamic_content.html b/test/resources/html/javascript/dynamic_content.html
index 07b235d2..97d317bd 100644
--- a/test/resources/html/javascript/dynamic_content.html
+++ b/test/resources/html/javascript/dynamic_content.html
@@ -28,7 +28,7 @@
         <form name=myform>
             <input type=button value="Change the title" 
             onClick="if(confirm('Really change the title?'))
-            document.title='Changed after confirmation';" >
+            document.title += ' Changed!';" >
         </form>
 
 	</body>
diff --git a/test/run_tests.py b/test/run_tests.py
index b622d3c7..c8578720 100755
--- a/test/run_tests.py
+++ b/test/run_tests.py
@@ -97,7 +97,7 @@ def acceptance_tests(interpreter, browser, rf_options=[],
     with http_server():
         execute_tests(interpreter, browser, rf_options,
                       sauce_username, sauce_key)
-    failures = process_output(browser, rf_options)
+    failures = process_output(browser)
     if failures:
         print('\n{} critical test{} failed.'
               .format(failures, 's' if failures != 1 else ''))
@@ -162,13 +162,12 @@ def get_sauce_conf(browser, sauce_username, sauce_key):
     ]
 
 
-def process_output(browser, rf_options):
+def process_output(browser):
     print('Verifying results...')
     options = []
     output = os.path.join(RESULTS_DIR, 'output.xml')
     robotstatuschecker.process_output(output, verbose=False)
     options.extend([opt.format(browser=browser) for opt in REBOT_OPTIONS])
-    options += rf_options
     try:
         rebot_cli(options + [output])
     except SystemExit as exit:
diff --git a/test/unit/keywords/test_keyword_arguments_alert.py b/test/unit/keywords/test_keyword_arguments_alert.py
index 5ec5c3b1..a9b04485 100644
--- a/test/unit/keywords/test_keyword_arguments_alert.py
+++ b/test/unit/keywords/test_keyword_arguments_alert.py
@@ -7,6 +7,9 @@ from SeleniumLibrary.keywords import AlertKeywords
 
 TRUES = ['True', True, '1', 1, 'text']
 FALSES = ['False', False, '', None, 'NONE']
+ACCEPT = AlertKeywords.ACCEPT
+DISMISS = AlertKeywords.DISMISS
+LEAVE = AlertKeywords.LEAVE
 
 
 class KeywordArgumentsAlertTest(unittest.TestCase):
@@ -19,37 +22,37 @@ class KeywordArgumentsAlertTest(unittest.TestCase):
         unstub()
 
     def test_get_alert_message_dismiss_true(self):
-        when(AlertKeywords)._handle_alert('dismiss').thenReturn('text')
+        when(AlertKeywords).handle_alert(DISMISS).thenReturn('text')
         count = 1
         for true in TRUES:
             self.alert.get_alert_message(true)
-            verify(AlertKeywords, times=count)._handle_alert('dismiss')
+            verify(AlertKeywords, times=count).handle_alert(DISMISS)
             count += 1
         self.alert.get_alert_message()
-        verify(AlertKeywords, times=count)._handle_alert('dismiss')
+        verify(AlertKeywords, times=count).handle_alert(DISMISS)
 
     def test_get_alert_message_dismiss_false(self):
-        when(AlertKeywords)._handle_alert().thenReturn('text')
+        when(AlertKeywords).handle_alert(LEAVE).thenReturn('text')
         count = 1
         for false in FALSES:
             self.alert.get_alert_message(false)
-            verify(AlertKeywords, times=count)._handle_alert()
+            verify(AlertKeywords, times=count).handle_alert(LEAVE)
             count += 1
 
     def test_dismiss_alert_true(self):
-        when(AlertKeywords)._handle_alert('accept').thenReturn('text')
+        when(AlertKeywords).handle_alert(ACCEPT).thenReturn('text')
         count = 1
         for true in TRUES:
             self.alert.dismiss_alert(true)
-            verify(AlertKeywords, times=count)._handle_alert('accept')
+            verify(AlertKeywords, times=count).handle_alert(ACCEPT)
             count += 1
         self.alert.dismiss_alert()
-        verify(AlertKeywords, times=count)._handle_alert('accept')
+        verify(AlertKeywords, times=count).handle_alert(ACCEPT)
 
     def test_dismiss_alert_false(self):
-        when(AlertKeywords)._handle_alert().thenReturn('text')
+        when(AlertKeywords).handle_alert(DISMISS).thenReturn('text')
         count = 1
         for false in FALSES:
             self.alert.dismiss_alert(false)
-            verify(AlertKeywords, times=count)._handle_alert()
+            verify(AlertKeywords, times=count).handle_alert(DISMISS)
             count += 1
diff --git a/test/unit/utils/test_types.py b/test/unit/utils/test_types.py
index 0cca4fbf..b7b97621 100644
--- a/test/unit/utils/test_types.py
+++ b/test/unit/utils/test_types.py
@@ -1,6 +1,6 @@
 import unittest
 
-from SeleniumLibrary.utils import is_string, is_truthy, is_falsy
+from SeleniumLibrary.utils import is_string, is_truthy, is_falsy, is_noney
 
 
 class IsstringTests(unittest.TestCase):
@@ -16,27 +16,24 @@ class IsstringTests(unittest.TestCase):
             self.assertFalse(is_string(item))
 
 
-class IsTruthyTests(unittest.TestCase):
+class IsTruthyFalsyNoneyTests(unittest.TestCase):
+    truthy = ['0', 'foo', ' ', 1, 2.3, True, [1], 'True', {'k': 'v'}]
+    falsy = [0, False, None, [], {}, (), u'', '', 'False', 'None']
 
     def test_is_truthy(self):
-        truthys = ['1', 'foo', ' ', 1, 23.45, True, [1, 2], 'True', {'k': 'v'}]
-        for item in truthys:
-            self.assertTrue(is_truthy(item))
-
-    def test_is_not_truthy(self):
-        not_truthys = [0, False, None, [], {}, u'', '', 'False', 'None']
-        for item in not_truthys:
-            self.assertFalse(is_truthy(item))
-
-
-class IsFalsyTest(unittest.TestCase):
+        for item in self.truthy:
+            self.assertTrue(is_truthy(item) is True)
+        for item in self.falsy:
+            self.assertTrue(is_truthy(item) is False)
 
     def test_is_falsy(self):
-        truthys = ['1', 'foo', ' ', 1, 23.45, True, [1, 2], 'True', {'k': 'v'}]
-        for item in truthys:
-            self.assertFalse(is_falsy(item))
-
-    def test_is_not_falsy(self):
-        not_truthys = [0, False, None, [], {}, u'', '', 'False', 'None']
-        for item in not_truthys:
-            self.assertTrue(is_falsy(item))
+        for item in self.truthy:
+            self.assertTrue(is_falsy(item) is False)
+        for item in self.falsy:
+            self.assertTrue(is_falsy(item) is True)
+
+    def test_is_noney(self):
+        for item in [None, 'None', 'NONE', 'none']:
+            self.assertTrue(is_noney(item) is True)
+        for item in self.truthy + [False, 0, 'False', '', [], {}, ()]:
+            self.assertTrue(is_noney(item) is False)