├── .gitignore ├── BUILD.rst ├── README.rst ├── demoapp.png ├── demoapp ├── html │ ├── demo.css │ ├── error.html │ ├── index.html │ └── welcome.html └── server.py ├── docs ├── extra.css ├── index.html ├── log.html ├── report.html └── style.css ├── login_tests ├── gherkin_login.robot ├── invalid_login.robot ├── resource.robot └── valid_login.robot ├── requirements.txt └── tasks.py /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | build 3 | dist 4 | .idea 5 | .*project 6 | *.pyc 7 | *$py.class 8 | .DS_Store 9 | .spyderworkspace 10 | log.html 11 | report.html 12 | output.xml 13 | *.log 14 | -------------------------------------------------------------------------------- /BUILD.rst: -------------------------------------------------------------------------------- 1 | Instructions to create releases 2 | =============================== 3 | 4 | 5 | Preconditions 6 | ------------- 7 | 8 | Operating system and Python requirements 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | 11 | Generating releases has only been tested on Linux, but it ought to work the 12 | same way also on OSX and other unixes. Creating releases is only supported 13 | with Python 3.6 or newer. 14 | 15 | The ``pip`` and ``invoke`` commands below are also expected to run on Python 16 | 3.6+. Alternatively, it's possible to use the ``python3.6 -m pip`` approach 17 | to run these commands. 18 | 19 | Python dependencies 20 | ~~~~~~~~~~~~~~~~~~~ 21 | 22 | Many steps are automated using the generic `Invoke `_ 23 | tool with a help by our `rellu `_ 24 | utilities, but also other tools and modules are needed. A pre-condition is 25 | installing all these, and that's easiest done using `pip 26 | `_ and the provided ``_ file:: 27 | 28 | pip install -r requirements.txt 29 | 30 | Using Invoke 31 | ~~~~~~~~~~~~ 32 | 33 | Invoke tasks are defined in the ``_ file and they are executed from 34 | the command line like:: 35 | 36 | inv[oke] task [options] 37 | 38 | Creating release 39 | ---------------- 40 | 41 | 1. Test that everything works:: 42 | 43 | python demoapp/server.py 44 | robot login_tests 45 | 46 | 2. Move regenerated log and report to docs:: 47 | 48 | inv move-docs 49 | 50 | 5. If README.rst has changed, generate project documentation based on it:: 51 | 52 | inv project-docs 53 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ==================================================== 2 | Web testing with Robot Framework and SeleniumLibrary 3 | ==================================================== 4 | 5 | `Robot Framework`_ is a generic open source test automation framework and 6 | SeleniumLibrary_ is one of the many test libraries that can be used with 7 | it. In addition to showing how they can be used together for web testing, 8 | this demo introduces the basic Robot Framework test data syntax, how tests 9 | are executed, and how logs and reports look like. 10 | 11 | .. contents:: **Contents:** 12 | :depth: 1 13 | :local: 14 | 15 | Downloading demo package 16 | ======================== 17 | 18 | To get the demo, you can either `download`_ the repository from GitHub or checkout 19 | the `source code`_ directly. As a result you get ``WebDemo`` directory with 20 | ``demoapp`` and ``login_tests`` sub directories. 21 | 22 | Example `test cases`_ and `generated results`_ are available also online. 23 | There is thus no need to download the demo if you are not interested in 24 | `running it`__ yourself. 25 | 26 | __ `running demo`_ 27 | 28 | Demo application 29 | ================ 30 | 31 | The demo application is a very simple login page shown below. With 32 | user name ``demo`` and password ``mode`` you get into a welcome page, and 33 | otherwise you end up to an error page. How to start and stop the 34 | application yourself is explained in the `Starting demo application`_ 35 | section. 36 | 37 | .. figure:: demoapp.png 38 | 39 | Test cases 40 | ========== 41 | 42 | Test case files as well as a resource file used by them are located in 43 | the ``login_tests`` directory. Click file names below to see the latest versions 44 | online. 45 | 46 | `valid_login.robot`_ 47 | A test suite with a single test for valid login. 48 | 49 | This test has a workflow that is created using keywords in 50 | the imported resource file. 51 | 52 | `invalid_login.robot`_ 53 | A test suite containing tests related to invalid login. 54 | 55 | These tests are data-driven by their nature. They use a single 56 | keyword, specified with the ``Test Template`` setting, that is called 57 | with different arguments to cover different scenarios. 58 | 59 | This suite also demonstrates using setups and teardowns in 60 | different levels. 61 | 62 | `gherkin_login.robot`_ 63 | A test suite with a single Gherkin style test. 64 | 65 | This test is functionally identical to the example in the 66 | `valid_login.robot`_ file. 67 | 68 | `resource.robot`_ 69 | A resource file with reusable keywords and variables. 70 | 71 | The system specific keywords created here form our own 72 | domain specific language. They utilize keywords provided 73 | by the imported SeleniumLibrary_. 74 | 75 | See `Robot Framework User Guide`_ for more details about the test data syntax. 76 | 77 | Generated results 78 | ================= 79 | 80 | After `running tests`_ you will get report and log in HTML format. Example 81 | files are also visible online in case you are not interested in running 82 | the demo yourself: 83 | 84 | - `report.html`_ 85 | - `log.html`_ 86 | 87 | Running demo 88 | ============ 89 | 90 | Preconditions 91 | ------------- 92 | 93 | A precondition for running the tests is having `Robot Framework`_ and 94 | SeleniumLibrary_ installed, and they in turn require 95 | Python_. Robot Framework `installation instructions`__ cover both 96 | Robot and Python installations, and SeleniumLibrary has its own 97 | `installation instructions`__. 98 | 99 | In practice it is easiest to install Robot Framework and 100 | SeleniumLibrary along with its dependencies using `pip`_ package 101 | manager. Once you have pip installed, all you need to do is running 102 | these commands:: 103 | 104 | pip install -r requirements.txt 105 | 106 | __ https://github.com/robotframework/robotframework/blob/master/INSTALL.rst 107 | __ https://github.com/robotframework/SeleniumLibrary#installation 108 | 109 | Starting demo application 110 | ------------------------- 111 | 112 | Running tests requires the `demo application`_ located under ``demoapp`` 113 | directory to be running. It can be started either by double clicking 114 | ``demoapp/server.py`` file in a file manager or by executing it from the 115 | command line:: 116 | 117 | python demoapp/server.py 118 | 119 | After the demo application is started, it is be available in URL 120 | http://localhost:7272. You can test it manually, valid credentials are 121 | ``demo/mode``, and it needs to be running while executing the automated 122 | tests. 123 | 124 | If the application was started by double-clicking ``demoapp/server.py`` 125 | file, it can be shut down by closing the opened window. If it was 126 | executed from the command line, using ``Ctrl-C`` is enough. 127 | 128 | Running tests 129 | ------------- 130 | 131 | The `test cases`_ are located in the ``login_tests`` directory. They can be 132 | executed using the ``robot`` command:: 133 | 134 | robot login_tests 135 | 136 | .. note:: If you are using Robot Framework 2.9 or earlier, you need to 137 | use the ``pybot`` command instead. 138 | 139 | You can also run an individual test case file and use various command line 140 | options supported by Robot Framework:: 141 | 142 | robot login_tests/valid_login.robot 143 | robot --test InvalidUserName --loglevel DEBUG login_tests 144 | 145 | Run ``robot --help`` for more information about the command line usage and see 146 | `Robot Framework User Guide`_ for more details about test execution in general. 147 | 148 | Using different browsers 149 | ------------------------ 150 | 151 | The browser that is used is controlled by ``${BROWSER}`` variable defined in 152 | `resource.robot`_ resource file. Firefox browser is used by default, but that 153 | can be easily overridden from the command line:: 154 | 155 | robot --variable BROWSER:Chrome login_tests 156 | robot --variable BROWSER:IE login_tests 157 | 158 | Consult SeleniumLibrary_ documentation about supported browsers. 159 | 160 | .. _Robot Framework: http://robotframework.org 161 | .. _SeleniumLibrary: https://github.com/robotframework/SeleniumLibrary 162 | .. _Python: http://python.org 163 | .. _pip: http://pip-installer.org 164 | .. _download: https://github.com/robotframework/WebDemo/archive/master.zip 165 | .. _source code: https://github.com/robotframework/WebDemo.git 166 | .. _valid_login.robot: https://github.com/robotframework/WebDemo/blob/master/login_tests/valid_login.robot 167 | .. _invalid_login.robot: https://github.com/robotframework/WebDemo/blob/master/login_tests/invalid_login.robot 168 | .. _gherkin_login.robot: https://github.com/robotframework/WebDemo/blob/master/login_tests/gherkin_login.robot 169 | .. _resource.robot: https://github.com/robotframework/WebDemo/blob/master/login_tests/resource.robot 170 | .. _report.html: http://robotframework.org/WebDemo/report.html 171 | .. _log.html: http://robotframework.org/WebDemo/log.html 172 | .. _Robot Framework User Guide: http://robotframework.org/robotframework/#user-guide 173 | -------------------------------------------------------------------------------- /demoapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robotframework/WebDemo/c8d46736c8248c1ebdcd67ac77fcb5bdafdd4851/demoapp.png -------------------------------------------------------------------------------- /demoapp/html/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | color: black; 4 | background: #DDDDDD; 5 | } 6 | #container { 7 | width: 30em; 8 | height: 15em; 9 | margin: 5em auto; 10 | background: white; 11 | border: 1px solid gray; 12 | padding: 0.5em 2em; 13 | } 14 | -------------------------------------------------------------------------------- /demoapp/html/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error Page 5 | 6 | 7 | 8 |
9 |

Error Page

10 |

Login failed. Invalid user name and/or password.

11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /demoapp/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Login Page 5 | 6 | 15 | 16 | 17 |
18 |

Login Page

19 |

Please input your user name and password and click the login button.

20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
 
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /demoapp/html/welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Welcome Page 5 | 6 | 7 | 8 |
9 |

Welcome Page

10 |

Login succeeded. Now you can logout.

11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /demoapp/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Simple HTTP server for Robot Framework web testing demo. 4 | 5 | Usage: server.py [port] 6 | 7 | This server serves HTML pages under `html` directory. Server is started simply 8 | by running this script from the command line or double-clicking it in a file 9 | manager. In the former case the server can be shut down with Ctrl-C and in the 10 | latter case by closing the opened window. 11 | 12 | By default the server uses port 7272, but a custom port can be given as 13 | an argument from the command line. 14 | """ 15 | 16 | from __future__ import print_function 17 | 18 | from os import chdir 19 | from os.path import abspath, dirname, join 20 | try: 21 | from SocketServer import ThreadingMixIn 22 | from BaseHTTPServer import HTTPServer 23 | from SimpleHTTPServer import SimpleHTTPRequestHandler 24 | except ImportError: 25 | from socketserver import ThreadingMixIn 26 | from http.server import SimpleHTTPRequestHandler, HTTPServer 27 | 28 | 29 | ROOT = join(dirname(abspath(__file__)), 'html') 30 | PORT = 7272 31 | 32 | 33 | class DemoServer(ThreadingMixIn, HTTPServer): 34 | allow_reuse_address = True 35 | 36 | def __init__(self, port=PORT): 37 | HTTPServer.__init__(self, ('localhost', int(port)), 38 | SimpleHTTPRequestHandler) 39 | 40 | def serve(self, directory=ROOT): 41 | chdir(directory) 42 | print('Demo server starting on port %d.' % self.server_address[1]) 43 | try: 44 | server.serve_forever() 45 | except KeyboardInterrupt: 46 | server.server_close() 47 | print('Demo server stopped.') 48 | 49 | 50 | if __name__ == '__main__': 51 | import sys 52 | try: 53 | server = DemoServer(*sys.argv[1:]) 54 | except (TypeError, ValueError): 55 | print(__doc__) 56 | else: 57 | server.serve() 58 | -------------------------------------------------------------------------------- /docs/extra.css: -------------------------------------------------------------------------------- 1 | /* Additional styles to use with style.css. */ 2 | 3 | .contents li p, table p { 4 | margin: 0; 5 | } 6 | th, td { 7 | padding: 0.2em 0.4em; 8 | border-width: 1px; 9 | border-style: solid; 10 | vertical-align: top; 11 | } 12 | th { 13 | white-space: nowrap; 14 | vertical-align: middle; 15 | } 16 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web testing with Robot Framework and SeleniumLibrary 7 | 8 | 9 | 10 | 11 |
12 |

Web testing with Robot Framework and SeleniumLibrary

13 | 14 |

Robot Framework is a generic open source test automation framework and 15 | SeleniumLibrary is one of the many test libraries that can be used with 16 | it. In addition to showing how they can be used together for web testing, 17 | this demo introduces the basic Robot Framework test data syntax, how tests 18 | are executed, and how logs and reports look like.

19 |
20 |

Contents:

21 | 28 |
29 |
30 |

Downloading demo package

31 |

To get the demo, you can either download the repository from GitHub or checkout 32 | the source code directly. As a result you get WebDemo directory with 33 | demoapp and login_tests sub directories.

34 |

Example test cases and generated results are available also online. 35 | There is thus no need to download the demo if you are not interested in 36 | running it yourself.

37 |
38 |
39 |

Demo application

40 |

The demo application is a very simple login page shown below. With 41 | user name demo and password mode you get into a welcome page, and 42 | otherwise you end up to an error page. How to start and stop the 43 | application yourself is explained in the Starting demo application 44 | section.

45 |
46 | demoapp.png 47 |
48 |
49 |
50 |

Test cases

51 |

Test case files as well as a resource file used by them are located in 52 | the login_test directory. Click file names below to see the latest versions 53 | online.

54 |
55 |
valid_login.robot
56 |

A test suite with a single test for valid login.

57 |

This test has a workflow that is created using keywords in 58 | the imported resource file.

59 |
60 |
invalid_login.robot
61 |

A test suite containing tests related to invalid login.

62 |

These tests are data-driven by their nature. They use a single 63 | keyword, specified with the Test Template setting, that is called 64 | with different arguments to cover different scenarios.

65 |

This suite also demonstrates using setups and teardowns in 66 | different levels.

67 |
68 |
gherkin_login.robot
69 |

A test suite with a single Gherkin style test.

70 |

This test is functionally identical to the example in the 71 | valid_login.robot file.

72 |
73 |
resource.robot
74 |

A resource file with reusable keywords and variables.

75 |

The system specific keywords created here form our own 76 | domain specific language. They utilize keywords provided 77 | by the imported SeleniumLibrary.

78 |
79 |
80 |

See Robot Framework User Guide for more details about the test data syntax.

81 |
82 |
83 |

Generated results

84 |

After running tests you will get report and log in HTML format. Example 85 | files are also visible online in case you are not interested in running 86 | the demo yourself:

87 | 91 |
92 |
93 |

Running demo

94 |
95 |

Preconditions

96 |

A precondition for running the tests is having Robot Framework and 97 | SeleniumLibrary installed, and they in turn require 98 | Python. Robot Framework installation instructions cover both 99 | Robot and Python installations, and SeleniumLibrary has its own 100 | installation instructions.

101 |

In practice it is easiest to install Robot Framework and 102 | SeleniumLibrary along with its dependencies using pip package 103 | manager. Once you have pip installed, all you need to do is running 104 | these commands:

105 |
pip install robotframework
106 | pip install robotframework-seleniumlibrary
107 |
108 |
109 |

Starting demo application

110 |

Running tests requires the demo application located under demoapp 111 | directory to be running. It can be started either by double clicking 112 | demoapp/server.py file in a file manager or by executing it from the 113 | command line:

114 |
python demoapp/server.py
115 |

After the demo application is started, it is be available in URL 116 | http://localhost:7272. You can test it manually, valid credentials are 117 | demo/mode, and it needs to be running while executing the automated 118 | tests.

119 |

If the application was started by double-clicking demoapp/server.py 120 | file, it can be shut down by closing the opened window. If it was 121 | executed from the command line, using Ctrl-C is enough.

122 |
123 |
124 |

Running tests

125 |

The test cases are located in the login_tests directory. They can be 126 | executed using the robot command:

127 |
robot login_tests
128 |
129 |

Note

130 |

If you are using Robot Framework 2.9 or earlier, you need to 131 | use the pybot command instead.

132 |
133 |

You can also run an individual test case file and use various command line 134 | options supported by Robot Framework:

135 |
robot login_tests/valid_login.robot
136 | robot --test InvalidUserName --loglevel DEBUG login_tests
137 |

Run robot --help for more information about the command line usage and see 138 | Robot Framework User Guide for more details about test execution in general.

139 |
140 |
141 |

Using different browsers

142 |

The browser that is used is controlled by ${BROWSER} variable defined in 143 | resource.robot resource file. Firefox browser is used by default, but that 144 | can be easily overridden from the command line:

145 |
robot --variable BROWSER:Chrome login_tests
146 | robot --variable BROWSER:IE login_tests
147 |

Consult SeleniumLibrary documentation about supported browsers.

148 |
149 |
150 |
151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | :Author: Chad Skeeters 3 | :Contact: goobsoft@gmail.com 4 | 5 | Stylesheet for use with Docutils/rst2html. 6 | 7 | https://bitbucket.org/cskeeters/rst2html-style/ 8 | */ 9 | 10 | html { 11 | font-size: 100%; 12 | -webkit-text-size-adjust: 100%; 13 | -ms-text-size-adjust: 100%; 14 | } 15 | 16 | a:focus { 17 | outline: thin dotted #333; 18 | outline: 5px auto -webkit-focus-ring-color; 19 | outline-offset: -2px; 20 | } 21 | 22 | a:hover, 23 | a:active { 24 | outline: 0; 25 | } 26 | 27 | sub, 28 | sup { 29 | position: relative; 30 | font-size: 75%; 31 | line-height: 0; 32 | vertical-align: baseline; 33 | } 34 | 35 | sup { 36 | top: -0.5em; 37 | } 38 | 39 | sub { 40 | bottom: -0.25em; 41 | } 42 | 43 | img { 44 | width: auto\9; 45 | height: auto; 46 | max-width: 100%; 47 | vertical-align: middle; 48 | border: 0; 49 | -ms-interpolation-mode: bicubic; 50 | } 51 | 52 | @media print { 53 | * { 54 | color: #000 !important; 55 | text-shadow: none !important; 56 | background: transparent !important; 57 | box-shadow: none !important; 58 | } 59 | a, 60 | a:visited { 61 | text-decoration: underline; 62 | } 63 | a[href]:after { 64 | content: " (" attr(href) ")"; 65 | } 66 | abbr[title]:after { 67 | content: " (" attr(title) ")"; 68 | } 69 | .ir a:after, 70 | a[href^="javascript:"]:after, 71 | a[href^="#"]:after { 72 | content: ""; 73 | } 74 | pre, 75 | blockquote { 76 | border: 1px solid #999; 77 | page-break-inside: avoid; 78 | } 79 | thead { 80 | display: table-header-group; 81 | } 82 | tr, 83 | img { 84 | page-break-inside: avoid; 85 | } 86 | img { 87 | max-width: 100% !important; 88 | } 89 | @page { 90 | margin: 0.5cm; 91 | } 92 | h1 { 93 | page-break-before:always; 94 | } 95 | h1.title { 96 | page-break-before:avoid; 97 | } 98 | p, 99 | h2, 100 | h3 { 101 | orphans: 3; 102 | widows: 3; 103 | } 104 | h2, 105 | h3 { 106 | page-break-after: avoid; 107 | } 108 | } 109 | 110 | body { 111 | margin: 40px; 112 | margin-right: auto; 113 | margin-left: auto; 114 | width: 700px; 115 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 116 | font-size: 14px; 117 | line-height: 20px; 118 | color: #333333; 119 | background-color: #ffffff; 120 | } 121 | 122 | a { 123 | color: #0088cc; 124 | text-decoration: none; 125 | } 126 | 127 | a:hover, 128 | a:focus { 129 | color: #005580; 130 | text-decoration: underline; 131 | } 132 | 133 | .img-rounded { 134 | -webkit-border-radius: 6px; 135 | -moz-border-radius: 6px; 136 | border-radius: 6px; 137 | } 138 | 139 | .img-polaroid { 140 | padding: 4px; 141 | background-color: #fff; 142 | border: 1px solid #ccc; 143 | border: 1px solid rgba(0, 0, 0, 0.2); 144 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 145 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 146 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 147 | } 148 | 149 | p { 150 | margin: 0 0 10px; 151 | } 152 | 153 | small { 154 | font-size: 85%; 155 | } 156 | 157 | strong { 158 | font-weight: bold; 159 | } 160 | 161 | em { 162 | font-style: italic; 163 | } 164 | 165 | cite { 166 | font-style: normal; 167 | } 168 | 169 | h1, 170 | h2, 171 | h3, 172 | h4, 173 | h5, 174 | h6 { 175 | font-family: inherit; 176 | font-weight: bold; 177 | line-height: 20px; 178 | color: inherit; 179 | text-rendering: optimizelegibility; 180 | } 181 | h1 { 182 | font-size: 2em; 183 | padding-bottom:.2em; 184 | border-bottom:1px solid grey; 185 | } 186 | h1.title { 187 | padding-bottom:1em; 188 | border-bottom:0px; 189 | } 190 | h2 { 191 | font-size: 1.5em; 192 | } 193 | 194 | h3 { 195 | font-size: 1.3em; 196 | font-family:Georgia, serif; 197 | font-style:italic; 198 | /*font-weight:normal;*/ 199 | } 200 | 201 | h4 { 202 | font-size: 1.3em; 203 | } 204 | 205 | h5 { 206 | font-size: 1.2em; 207 | } 208 | 209 | h6 { 210 | font-size: 1.1em; 211 | } 212 | 213 | ul, 214 | ol { 215 | padding: 0; 216 | margin: 0 0 10px 25px; 217 | } 218 | 219 | ul ul, 220 | ul ol, 221 | ol ol, 222 | ol ul { 223 | margin-bottom: 0; 224 | } 225 | 226 | li { 227 | line-height: 20px; 228 | } 229 | 230 | dl { 231 | margin-bottom: 20px; 232 | } 233 | 234 | dt, 235 | dd { 236 | line-height: 20px; 237 | } 238 | 239 | dt { 240 | font-weight: bold; 241 | } 242 | 243 | dd { 244 | margin-left: 10px; 245 | } 246 | 247 | hr { 248 | margin: 20px 0; 249 | border: 0; 250 | border-top: 1px solid #eeeeee; 251 | border-bottom: 1px solid #ffffff; 252 | } 253 | 254 | abbr[title], 255 | abbr[data-original-title] { 256 | cursor: help; 257 | border-bottom: 1px dotted #999999; 258 | } 259 | 260 | abbr.initialism { 261 | font-size: 90%; 262 | text-transform: uppercase; 263 | } 264 | 265 | blockquote { 266 | padding: 0 0 0 15px; 267 | margin: 0 0 20px; 268 | border-left: 5px solid #eeeeee; 269 | } 270 | 271 | blockquote p { 272 | margin-bottom: 0; 273 | font-size: 17.5px; 274 | font-weight: 300; 275 | line-height: 1.25; 276 | } 277 | 278 | q:before, 279 | q:after, 280 | blockquote:before, 281 | blockquote:after { 282 | content: ""; 283 | } 284 | 285 | address { 286 | display: block; 287 | margin-bottom: 20px; 288 | font-style: normal; 289 | line-height: 20px; 290 | } 291 | 292 | code, 293 | pre { 294 | padding: 0 3px 2px; 295 | font-family: Monaco, Menlo, Consolas, "Courier New", monospace; 296 | font-size: 12px; 297 | color: #333333; 298 | -webkit-border-radius: 3px; 299 | -moz-border-radius: 3px; 300 | border-radius: 3px; 301 | } 302 | 303 | code { 304 | padding: 2px 4px; 305 | color: #d14; 306 | white-space: nowrap; 307 | background-color: #f7f7f9; 308 | border: 1px solid #e1e1e8; 309 | } 310 | 311 | pre { 312 | display: block; 313 | padding: 9.5px; 314 | margin: 0 0 10px; 315 | font-size: 13px; 316 | line-height: 20px; 317 | word-break: break-all; 318 | word-wrap: break-word; 319 | white-space: pre; 320 | white-space: pre-wrap; 321 | background-color: #f5f5f5; 322 | border: 1px solid #ccc; 323 | border: 1px solid rgba(0, 0, 0, 0.15); 324 | -webkit-border-radius: 4px; 325 | -moz-border-radius: 4px; 326 | border-radius: 4px; 327 | } 328 | 329 | pre.prettyprint { 330 | margin-bottom: 20px; 331 | } 332 | 333 | pre code { 334 | padding: 0; 335 | color: inherit; 336 | white-space: pre; 337 | white-space: pre-wrap; 338 | background-color: transparent; 339 | border: 0; 340 | } 341 | 342 | .pre-scrollable { 343 | max-height: 340px; 344 | overflow-y: scroll; 345 | } 346 | 347 | table { 348 | max-width: 100%; 349 | background-color: transparent; 350 | border-collapse: collapse; 351 | border-spacing: 0; 352 | } 353 | 354 | .table { 355 | width: 100%; 356 | margin-bottom: 20px; 357 | } 358 | 359 | .table th, 360 | .table td { 361 | padding: 8px; 362 | line-height: 20px; 363 | text-align: left; 364 | vertical-align: top; 365 | border-top: 1px solid #dddddd; 366 | } 367 | 368 | .table th { 369 | font-weight: bold; 370 | } 371 | 372 | .table thead th { 373 | vertical-align: bottom; 374 | } 375 | 376 | .table caption + thead tr:first-child th, 377 | .table caption + thead tr:first-child td, 378 | .table colgroup + thead tr:first-child th, 379 | .table colgroup + thead tr:first-child td, 380 | .table thead:first-child tr:first-child th, 381 | .table thead:first-child tr:first-child td { 382 | border-top: 0; 383 | } 384 | 385 | .table tbody + tbody { 386 | border-top: 2px solid #dddddd; 387 | } 388 | 389 | .table .table { 390 | background-color: #ffffff; 391 | } 392 | 393 | .table-condensed th, 394 | .table-condensed td { 395 | padding: 4px 5px; 396 | } 397 | 398 | .table-bordered { 399 | border: 1px solid #dddddd; 400 | border-collapse: separate; 401 | *border-collapse: collapse; 402 | border-left: 0; 403 | -webkit-border-radius: 4px; 404 | -moz-border-radius: 4px; 405 | border-radius: 4px; 406 | } 407 | 408 | .table-bordered th, 409 | .table-bordered td { 410 | border-left: 1px solid #dddddd; 411 | } 412 | 413 | .table-bordered caption + thead tr:first-child th, 414 | .table-bordered caption + tbody tr:first-child th, 415 | .table-bordered caption + tbody tr:first-child td, 416 | .table-bordered colgroup + thead tr:first-child th, 417 | .table-bordered colgroup + tbody tr:first-child th, 418 | .table-bordered colgroup + tbody tr:first-child td, 419 | .table-bordered thead:first-child tr:first-child th, 420 | .table-bordered tbody:first-child tr:first-child th, 421 | .table-bordered tbody:first-child tr:first-child td { 422 | border-top: 0; 423 | } 424 | 425 | .table-bordered thead:first-child tr:first-child > th:first-child, 426 | .table-bordered tbody:first-child tr:first-child > td:first-child, 427 | .table-bordered tbody:first-child tr:first-child > th:first-child { 428 | -webkit-border-top-left-radius: 4px; 429 | border-top-left-radius: 4px; 430 | -moz-border-radius-topleft: 4px; 431 | } 432 | 433 | .table-bordered thead:first-child tr:first-child > th:last-child, 434 | .table-bordered tbody:first-child tr:first-child > td:last-child, 435 | .table-bordered tbody:first-child tr:first-child > th:last-child { 436 | -webkit-border-top-right-radius: 4px; 437 | border-top-right-radius: 4px; 438 | -moz-border-radius-topright: 4px; 439 | } 440 | 441 | .table-bordered thead:last-child tr:last-child > th:first-child, 442 | .table-bordered tbody:last-child tr:last-child > td:first-child, 443 | .table-bordered tbody:last-child tr:last-child > th:first-child, 444 | .table-bordered tfoot:last-child tr:last-child > td:first-child, 445 | .table-bordered tfoot:last-child tr:last-child > th:first-child { 446 | -webkit-border-bottom-left-radius: 4px; 447 | border-bottom-left-radius: 4px; 448 | -moz-border-radius-bottomleft: 4px; 449 | } 450 | 451 | .table-bordered thead:last-child tr:last-child > th:last-child, 452 | .table-bordered tbody:last-child tr:last-child > td:last-child, 453 | .table-bordered tbody:last-child tr:last-child > th:last-child, 454 | .table-bordered tfoot:last-child tr:last-child > td:last-child, 455 | .table-bordered tfoot:last-child tr:last-child > th:last-child { 456 | -webkit-border-bottom-right-radius: 4px; 457 | border-bottom-right-radius: 4px; 458 | -moz-border-radius-bottomright: 4px; 459 | } 460 | 461 | .table-bordered tfoot + tbody:last-child tr:last-child td:first-child { 462 | -webkit-border-bottom-left-radius: 0; 463 | border-bottom-left-radius: 0; 464 | -moz-border-radius-bottomleft: 0; 465 | } 466 | 467 | .table-bordered tfoot + tbody:last-child tr:last-child td:last-child { 468 | -webkit-border-bottom-right-radius: 0; 469 | border-bottom-right-radius: 0; 470 | -moz-border-radius-bottomright: 0; 471 | } 472 | 473 | .table-bordered caption + thead tr:first-child th:first-child, 474 | .table-bordered caption + tbody tr:first-child td:first-child, 475 | .table-bordered colgroup + thead tr:first-child th:first-child, 476 | .table-bordered colgroup + tbody tr:first-child td:first-child { 477 | -webkit-border-top-left-radius: 4px; 478 | border-top-left-radius: 4px; 479 | -moz-border-radius-topleft: 4px; 480 | } 481 | 482 | .table-bordered caption + thead tr:first-child th:last-child, 483 | .table-bordered caption + tbody tr:first-child td:last-child, 484 | .table-bordered colgroup + thead tr:first-child th:last-child, 485 | .table-bordered colgroup + tbody tr:first-child td:last-child { 486 | -webkit-border-top-right-radius: 4px; 487 | border-top-right-radius: 4px; 488 | -moz-border-radius-topright: 4px; 489 | } 490 | 491 | .table-striped tbody > tr:nth-child(odd) > td, 492 | .table-striped tbody > tr:nth-child(odd) > th { 493 | background-color: #f9f9f9; 494 | } 495 | 496 | .table-hover tbody tr:hover > td, 497 | .table-hover tbody tr:hover > th { 498 | background-color: #f5f5f5; 499 | } 500 | 501 | table td[class*="span"], 502 | table th[class*="span"], 503 | .row-fluid table td[class*="span"], 504 | .row-fluid table th[class*="span"] { 505 | display: table-cell; 506 | float: none; 507 | margin-left: 0; 508 | } 509 | 510 | .hero-unit { 511 | padding: 60px; 512 | margin-bottom: 30px; 513 | font-size: 18px; 514 | font-weight: 200; 515 | line-height: 30px; 516 | color: inherit; 517 | background-color: #eeeeee; 518 | -webkit-border-radius: 6px; 519 | -moz-border-radius: 6px; 520 | border-radius: 6px; 521 | } 522 | 523 | .hero-unit h1 { 524 | margin-bottom: 0; 525 | font-size: 60px; 526 | line-height: 1; 527 | letter-spacing: -1px; 528 | color: inherit; 529 | } 530 | 531 | .hero-unit li { 532 | line-height: 30px; 533 | } 534 | 535 | 536 | /* rst2html default used to remove borders from tables and images */ 537 | .borderless, table.borderless td, table.borderless th { 538 | border: 0 } 539 | 540 | table.borderless td, table.borderless th { 541 | /* Override padding for "table.docutils td" with "! important". 542 | The right padding separates the table cells. */ 543 | padding: 0 0.5em 0 0 ! important } 544 | 545 | .first { 546 | /* Override more specific margin styles with "! important". */ 547 | margin-top: 0 ! important } 548 | 549 | .last, .with-subtitle { 550 | margin-bottom: 0 ! important } 551 | 552 | .hidden { 553 | display: none } 554 | 555 | a.toc-backref { 556 | text-decoration: none ; 557 | color: black } 558 | 559 | blockquote.epigraph { 560 | margin: 2em 5em ; } 561 | 562 | dl.docutils dd { 563 | margin-bottom: 0.5em } 564 | 565 | object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { 566 | overflow: hidden; 567 | } 568 | 569 | /* Uncomment (and remove this text!) to get bold-faced definition list terms 570 | dl.docutils dt { 571 | font-weight: bold } 572 | */ 573 | 574 | div.abstract { 575 | margin: 2em 5em } 576 | 577 | div.abstract p.topic-title { 578 | font-weight: bold ; 579 | text-align: center } 580 | 581 | div.admonition, div.attention, div.caution, div.danger, div.error, 582 | div.hint, div.important, div.note, div.tip, div.warning { 583 | margin: 2em ; 584 | border: medium outset ; 585 | padding: 1em } 586 | 587 | div.note, div.warning { 588 | margin:1.5em 0px; 589 | border: none; 590 | } 591 | 592 | div.note p.admonition-title, 593 | div.warning p.admonition-title 594 | { 595 | display:none; 596 | } 597 | 598 | /* Clearfix 599 | * http://css-tricks.com/snippets/css/clear-fix/ 600 | */ 601 | 602 | div.note:after, 603 | div.warning:after { 604 | content:""; 605 | display:table; 606 | clear:both; 607 | } 608 | 609 | div.note p:before, 610 | div.warning p:before { 611 | display:block; 612 | float:left; 613 | font-size:4em; 614 | line-height:1em; 615 | margin-right:20px; 616 | margin-left: 0em; 617 | margin-top:-10px; 618 | content:'\0270D'; /*handwriting*/ 619 | } 620 | 621 | div.warning p:before { 622 | content:'\026A0'; /*warning*/ 623 | } 624 | 625 | div.admonition p.admonition-title, div.hint p.admonition-title, 626 | div.important p.admonition-title, div.note p.admonition-title, 627 | div.tip p.admonition-title { 628 | font-weight: bold ; 629 | font-family: sans-serif } 630 | 631 | div.attention p.admonition-title, div.caution p.admonition-title, 632 | div.danger p.admonition-title, div.error p.admonition-title, 633 | div.warning p.admonition-title, .code .error { 634 | color: red ; 635 | font-weight: bold ; 636 | font-family: sans-serif } 637 | 638 | /* Uncomment (and remove this text!) to get reduced vertical space in 639 | compound paragraphs. 640 | div.compound .compound-first, div.compound .compound-middle { 641 | margin-bottom: 0.5em } 642 | 643 | div.compound .compound-last, div.compound .compound-middle { 644 | margin-top: 0.5em } 645 | */ 646 | 647 | div.dedication { 648 | margin: 2em 5em ; 649 | text-align: center ; 650 | font-style: italic } 651 | 652 | div.dedication p.topic-title { 653 | font-weight: bold ; 654 | font-style: normal } 655 | 656 | div.figure { 657 | margin-left: 2em ; 658 | margin-right: 2em } 659 | 660 | div.footer, div.header { 661 | clear: both; 662 | font-size: smaller } 663 | 664 | div.line-block { 665 | display: block ; 666 | margin-top: 1em ; 667 | margin-bottom: 1em } 668 | 669 | div.line-block div.line-block { 670 | margin-top: 0 ; 671 | margin-bottom: 0 ; 672 | margin-left: 1.5em } 673 | 674 | div.sidebar { 675 | margin: 0 0 0.5em 1em ; 676 | border: medium outset ; 677 | padding: 1em ; 678 | background-color: #ffffee ; 679 | width: 40% ; 680 | float: right ; 681 | clear: right } 682 | 683 | div.sidebar p.rubric { 684 | font-family: sans-serif ; 685 | font-size: medium } 686 | 687 | div.system-messages { 688 | margin: 5em } 689 | 690 | div.system-messages h1 { 691 | color: red } 692 | 693 | div.system-message { 694 | border: medium outset ; 695 | padding: 1em } 696 | 697 | div.system-message p.system-message-title { 698 | color: red ; 699 | font-weight: bold } 700 | 701 | div.topic { 702 | margin: 2em } 703 | 704 | h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, 705 | h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { 706 | margin-top: 0.4em } 707 | 708 | h1.title { 709 | text-align: center } 710 | 711 | h2.subtitle { 712 | text-align: center } 713 | 714 | hr.docutils { 715 | width: 75% } 716 | 717 | img.align-left, .figure.align-left, object.align-left { 718 | clear: left ; 719 | float: left ; 720 | margin-right: 1em } 721 | 722 | img.align-right, .figure.align-right, object.align-right { 723 | clear: right ; 724 | float: right ; 725 | margin-left: 1em } 726 | 727 | img.align-center, .figure.align-center, object.align-center { 728 | display: block; 729 | margin-left: auto; 730 | margin-right: auto; 731 | } 732 | 733 | .align-left { 734 | text-align: left } 735 | 736 | .align-center { 737 | clear: both ; 738 | text-align: center } 739 | 740 | .align-right { 741 | text-align: right } 742 | 743 | /* reset inner alignment in figures */ 744 | div.align-right { 745 | text-align: inherit } 746 | 747 | /* div.align-center * { */ 748 | /* text-align: left } */ 749 | 750 | ol.simple, ul.simple { 751 | margin-bottom: 1em } 752 | 753 | ol.arabic { 754 | list-style: decimal } 755 | 756 | ol.loweralpha { 757 | list-style: lower-alpha } 758 | 759 | ol.upperalpha { 760 | list-style: upper-alpha } 761 | 762 | ol.lowerroman { 763 | list-style: lower-roman } 764 | 765 | ol.upperroman { 766 | list-style: upper-roman } 767 | 768 | p.attribution { 769 | text-align: right ; 770 | margin-left: 50% } 771 | 772 | p.caption { 773 | font-style: italic } 774 | 775 | p.credits { 776 | font-style: italic ; 777 | font-size: smaller } 778 | 779 | p.label { 780 | white-space: nowrap } 781 | 782 | p.rubric { 783 | font-weight: bold ; 784 | font-size: larger ; 785 | color: maroon ; 786 | text-align: center } 787 | 788 | p.sidebar-title { 789 | font-family: sans-serif ; 790 | font-weight: bold ; 791 | font-size: larger } 792 | 793 | p.sidebar-subtitle { 794 | font-family: sans-serif ; 795 | font-weight: bold } 796 | 797 | p.topic-title { 798 | font-weight: bold } 799 | 800 | pre.address { 801 | margin-bottom: 0 ; 802 | margin-top: 0 ; 803 | font: inherit } 804 | 805 | pre.literal-block, pre.doctest-block, pre.math, pre.code { 806 | margin-left: 2em ; 807 | margin-right: 2em } 808 | 809 | pre.code .ln { color: grey; } /* line numbers */ 810 | pre.code, code { background-color: #eeeeee } 811 | pre.code .comment, code .comment { color: #5C6576 } 812 | pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } 813 | pre.code .literal.string, code .literal.string { color: #0C5404 } 814 | pre.code .name.builtin, code .name.builtin { color: #352B84 } 815 | pre.code .deleted, code .deleted { background-color: #DEB0A1} 816 | pre.code .inserted, code .inserted { background-color: #A3D289} 817 | 818 | span.classifier { 819 | font-family: sans-serif ; 820 | font-style: oblique } 821 | 822 | span.classifier-delimiter { 823 | font-family: sans-serif ; 824 | font-weight: bold } 825 | 826 | span.interpreted { 827 | font-family: sans-serif } 828 | 829 | span.option { 830 | white-space: nowrap } 831 | 832 | span.pre { 833 | white-space: pre } 834 | 835 | span.problematic { 836 | color: red } 837 | 838 | span.section-subtitle { 839 | /* font-size relative to parent (h1..h6 element) */ 840 | font-size: 80% } 841 | 842 | table.citation { 843 | border-left: solid 1px gray; 844 | margin-left: 1px } 845 | 846 | table.docinfo { 847 | margin: 2em 4em } 848 | 849 | table.docutils { 850 | margin-top: 0.5em ; 851 | margin-bottom: 0.5em } 852 | 853 | table.footnote { 854 | border-left: solid 1px black; 855 | margin-left: 1px } 856 | 857 | table.docutils td, table.docutils th, 858 | table.docinfo td, table.docinfo th { 859 | padding-left: 0.5em ; 860 | padding-right: 0.5em ; 861 | vertical-align: top } 862 | 863 | table.docutils th.field-name, table.docinfo th.docinfo-name { 864 | font-weight: bold ; 865 | text-align: left ; 866 | white-space: nowrap ; 867 | padding-left: 0 } 868 | 869 | h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, 870 | h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { 871 | font-size: 100% } 872 | 873 | ul.auto-toc { 874 | list-style-type: none } 875 | 876 | .code .pygments-hll { background-color: #ffffcc } 877 | .code .pygments-c { color: #60a0b0; font-style: italic } /* Comment */ 878 | .code .pygments-err { border: 1px solid #FF0000 } /* Error */ 879 | .code .pygments-k { color: #007020; font-weight: bold } /* Keyword */ 880 | .code .pygments-o { color: #666666 } /* Operator */ 881 | .code .pygments-cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ 882 | .code .pygments-cp { color: #007020 } /* Comment.Preproc */ 883 | .code .pygments-c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ 884 | .code .pygments-cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ 885 | .code .pygments-gd { color: #A00000 } /* Generic.Deleted */ 886 | .code .pygments-ge { font-style: italic } /* Generic.Emph */ 887 | .code .pygments-gr { color: #FF0000 } /* Generic.Error */ 888 | .code .pygments-gh { color: #000080; font-weight: bold } /* Generic.Heading */ 889 | .code .pygments-gi { color: #00A000 } /* Generic.Inserted */ 890 | .code .pygments-go { color: #888888 } /* Generic.Output */ 891 | .code .pygments-gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 892 | .code .pygments-gs { font-weight: bold } /* Generic.Strong */ 893 | .code .pygments-gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 894 | .code .pygments-gt { color: #0044DD } /* Generic.Traceback */ 895 | .code .pygments-kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 896 | .code .pygments-kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 897 | .code .pygments-kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 898 | .code .pygments-kp { color: #007020 } /* Keyword.Pseudo */ 899 | .code .pygments-kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 900 | .code .pygments-kt { color: #902000 } /* Keyword.Type */ 901 | .code .pygments-m { color: #40a070 } /* Literal.Number */ 902 | .code .pygments-s { color: #4070a0 } /* Literal.String */ 903 | .code .pygments-na { color: #4070a0 } /* Name.Attribute */ 904 | .code .pygments-nb { color: #007020 } /* Name.Builtin */ 905 | .code .pygments-nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 906 | .code .pygments-no { color: #60add5 } /* Name.Constant */ 907 | .code .pygments-nd { color: #555555; font-weight: bold } /* Name.Decorator */ 908 | .code .pygments-ni { color: #d55537; font-weight: bold } /* Name.Entity */ 909 | .code .pygments-ne { color: #007020 } /* Name.Exception */ 910 | .code .pygments-nf { color: #06287e } /* Name.Function */ 911 | .code .pygments-nl { color: #002070; font-weight: bold } /* Name.Label */ 912 | .code .pygments-nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 913 | .code .pygments-nt { color: #062873; font-weight: bold } /* Name.Tag */ 914 | .code .pygments-nv { color: #bb60d5 } /* Name.Variable */ 915 | .code .pygments-ow { color: #007020; font-weight: bold } /* Operator.Word */ 916 | .code .pygments-w { color: #bbbbbb } /* Text.Whitespace */ 917 | .code .pygments-mf { color: #40a070 } /* Literal.Number.Float */ 918 | .code .pygments-mh { color: #40a070 } /* Literal.Number.Hex */ 919 | .code .pygments-mi { color: #40a070 } /* Literal.Number.Integer */ 920 | .code .pygments-mo { color: #40a070 } /* Literal.Number.Oct */ 921 | .code .pygments-sb { color: #4070a0 } /* Literal.String.Backtick */ 922 | .code .pygments-sc { color: #4070a0 } /* Literal.String.Char */ 923 | .code .pygments-sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 924 | .code .pygments-s2 { color: #4070a0 } /* Literal.String.Double */ 925 | .code .pygments-se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 926 | .code .pygments-sh { color: #4070a0 } /* Literal.String.Heredoc */ 927 | .code .pygments-si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 928 | .code .pygments-sx { color: #c65d09 } /* Literal.String.Other */ 929 | .code .pygments-sr { color: #235388 } /* Literal.String.Regex */ 930 | .code .pygments-s1 { color: #4070a0 } /* Literal.String.Single */ 931 | .code .pygments-ss { color: #517918 } /* Literal.String.Symbol */ 932 | .code .pygments-bp { color: #007020 } /* Name.Builtin.Pseudo */ 933 | .code .pygments-vc { color: #bb60d5 } /* Name.Variable.Class */ 934 | .code .pygments-vg { color: #bb60d5 } /* Name.Variable.Global */ 935 | .code .pygments-vi { color: #bb60d5 } /* Name.Variable.Instance */ 936 | .code .pygments-il { color: #40a070 } /* Literal.Number.Integer.Long */ 937 | -------------------------------------------------------------------------------- /login_tests/gherkin_login.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation A test suite with a single Gherkin style test. 3 | ... 4 | ... This test is functionally identical to the example in 5 | ... valid_login.robot file. 6 | Resource resource.robot 7 | Test Teardown Close Browser 8 | 9 | *** Test Cases *** 10 | Valid Login 11 | Given browser is opened to login page 12 | When user "demo" logs in with password "mode" 13 | Then welcome page should be open 14 | 15 | *** Keywords *** 16 | Browser is opened to login page 17 | Open browser to login page 18 | 19 | User "${username}" logs in with password "${password}" 20 | Input username ${username} 21 | Input password ${password} 22 | Submit credentials 23 | -------------------------------------------------------------------------------- /login_tests/invalid_login.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation A test suite containing tests related to invalid login. 3 | ... 4 | ... These tests are data-driven by their nature. They use a single 5 | ... keyword, specified with Test Template setting, that is called 6 | ... with different arguments to cover different scenarios. 7 | ... 8 | ... This suite also demonstrates using setups and teardowns in 9 | ... different levels. 10 | Suite Setup Open Browser To Login Page 11 | Suite Teardown Close Browser 12 | Test Setup Go To Login Page 13 | Test Template Login With Invalid Credentials Should Fail 14 | Resource resource.robot 15 | 16 | *** Test Cases *** USER NAME PASSWORD 17 | Invalid Username invalid ${VALID PASSWORD} 18 | Invalid Password ${VALID USER} invalid 19 | Invalid Username And Password invalid whatever 20 | Empty Username ${EMPTY} ${VALID PASSWORD} 21 | Empty Password ${VALID USER} ${EMPTY} 22 | Empty Username And Password ${EMPTY} ${EMPTY} 23 | 24 | *** Keywords *** 25 | Login With Invalid Credentials Should Fail 26 | [Arguments] ${username} ${password} 27 | Input Username ${username} 28 | Input Password ${password} 29 | Submit Credentials 30 | Login Should Have Failed 31 | 32 | Login Should Have Failed 33 | Location Should Be ${ERROR URL} 34 | Title Should Be Error Page 35 | -------------------------------------------------------------------------------- /login_tests/resource.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation A resource file with reusable keywords and variables. 3 | ... 4 | ... The system specific keywords created here form our own 5 | ... domain specific language. They utilize keywords provided 6 | ... by the imported SeleniumLibrary. 7 | Library SeleniumLibrary 8 | 9 | *** Variables *** 10 | ${SERVER} localhost:7272 11 | ${BROWSER} Firefox 12 | ${DELAY} 0 13 | ${VALID USER} demo 14 | ${VALID PASSWORD} mode 15 | ${LOGIN URL} http://${SERVER}/ 16 | ${WELCOME URL} http://${SERVER}/welcome.html 17 | ${ERROR URL} http://${SERVER}/error.html 18 | 19 | *** Keywords *** 20 | Open Browser To Login Page 21 | Open Browser ${LOGIN URL} ${BROWSER} 22 | Maximize Browser Window 23 | Set Selenium Speed ${DELAY} 24 | Login Page Should Be Open 25 | 26 | Login Page Should Be Open 27 | Title Should Be Login Page 28 | 29 | Go To Login Page 30 | Go To ${LOGIN URL} 31 | Login Page Should Be Open 32 | 33 | Input Username 34 | [Arguments] ${username} 35 | Input Text username_field ${username} 36 | 37 | Input Password 38 | [Arguments] ${password} 39 | Input Text password_field ${password} 40 | 41 | Submit Credentials 42 | Click Button login_button 43 | 44 | Welcome Page Should Be Open 45 | Location Should Be ${WELCOME URL} 46 | Title Should Be Welcome Page 47 | -------------------------------------------------------------------------------- /login_tests/valid_login.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation A test suite with a single test for valid login. 3 | ... 4 | ... This test has a workflow that is created using keywords in 5 | ... the imported resource file. 6 | Resource resource.robot 7 | 8 | *** Test Cases *** 9 | Valid Login 10 | Open Browser To Login Page 11 | Input Username demo 12 | Input Password mode 13 | Submit Credentials 14 | Welcome Page Should Be Open 15 | [Teardown] Close Browser 16 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Requirements needed when generating releases. See BUILD.rst for details. 2 | invoke >= 0.20 3 | rellu >= 0.6 4 | docutils >= 0.14 5 | robotframework >= 3.1.1 6 | robotframework-seleniumlibrary >= 3.3.1 7 | -------------------------------------------------------------------------------- /tasks.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import shutil 3 | 4 | from docutils.core import publish_cmdline 5 | from invoke import task 6 | from rellu.tasks import clean 7 | 8 | 9 | assert Path.cwd() == Path(__file__).parent 10 | 11 | @task 12 | def project_docs(ctx): 13 | """Generate project documentation. 14 | 15 | These docs are visible at http://robotframework.org/WebDemo/. 16 | """ 17 | args = ['--stylesheet=style.css,extra.css', 18 | '--link-stylesheet', 19 | 'README.rst', 20 | 'docs/index.html'] 21 | publish_cmdline(writer_name='html5', argv=args) 22 | print(Path(args[-1]).absolute()) 23 | 24 | @task 25 | def move_docs(ctx): 26 | """Move report.html and log.html to docs 27 | 28 | These docs are visible http://robotframework.org/WebDemo/. 29 | """ 30 | log = Path('./log.html') 31 | report = Path('./report.html') 32 | dest = Path('.') / 'docs' 33 | print(log.absolute()) 34 | shutil.copy(log.absolute(), str(dest)) 35 | print(report.absolute()) 36 | shutil.copy(report.absolute(), str(dest)) 37 | --------------------------------------------------------------------------------