Skip to content

Commit c309fd6

Browse files
committed
REFACTOR : Cleaned up stories and generated changelog + readme.
1 parent d7b234d commit c309fd6

18 files changed

+321
-1
lines changed

CHANGELOG.md

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Changelog
2+
3+
4+
### Latest
5+
6+
7+
No relevant code changes.
8+
9+
### 0.10.0
10+
11+
* FEATURE : Hover functionality to identify and reveal the secondary element
12+
13+
14+
### 0.9.0
15+
16+
* FEATURE : Sub-elements - pick out elements within elements by specifying a selector within a selector.
17+
* FEATURE : Selectors can use iframes.
18+
19+
20+
### 0.8.0
21+
22+
* FEATURE : Should contain now usable with timeout.
23+
24+
25+
### 0.7.0
26+
27+
* FEATURE : should_disappear()
28+
* FEATURE : Added timeouts to 'should_*'
29+
30+
31+
### 0.6.1
32+
33+
* FEATURE : Clearer exceptions on should_contain and should_be_on_page.
34+
* FEATURE : Timeout on explicit wait to appear on page.
35+
36+
37+
### 0.6.0
38+
39+
* FEATURE : Clearer timeout exceptions.
40+
* FEATURE : Added a clearer exception for 'not found in selectors'.
41+
* FEATURE : Handle 'which' property on 'text is' attributes.
42+
* FEATURE : Handle 'which' property on attributes.
43+
* FEATURE : Selects 2nd, 3rd, 4th ... last of elements that contain text.
44+
* FEATURE : Ability to select 'last' element matching a class name.
45+
* FEATURE : Allow default timeout to be set up front.
46+
* FEATURE : Added the ability to pick a single element when more than one is matched by a class.
47+
48+
49+
### 0.5.1
50+
51+
* FEATURE : Add the ability to select by text contents or what elements contain.
52+
53+
54+
### 0.4.0
55+
56+
* BUGFIX : Locked down the execution space so that invalid conditions cause a true exception.
57+
* FEATURE : Added time travel to selenium.
58+
59+
60+
### 0.3.0
61+
62+
* FEATURE : Classes selector.
63+
64+
65+
### 0.2.0
66+
67+
* FEATURE : Handle more than one element with the same ID.
68+
69+
70+
### 0.1.3
71+
72+
* FEATURE : .should_appear()
73+
74+
75+
### 0.1.2
76+
77+
* FEATURE : Selection by xpath.
78+
79+
80+
### 0.1.1
81+
82+
* FEATURE : Do selectors using attributes.
83+

README.md

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# SeleniumDirector
2+
3+
4+
SeleniumDirector is a python 3 library that makes it straightforward to write easily maintainable
5+
python code to interact with websites in a non-brittle way using the screenplay pattern with
6+
selenium.
7+
8+
Seleniumdirector reads YAML "selector" files which associate readable labels with complex selectors
9+
- i.e. class name selectors, id selectors, attribute selectors, text and xpath.
10+
11+
Separating the "element selection" concern from element interaction allows for simpler, more straightforward
12+
and more readable code.
13+
14+
SeleniumDirector was built to be used with [HitchStory](https://hitchdev.com/hitchstory) as a means
15+
of writing straightforward to maintain integration/browser tests, but it completely agnostic about
16+
where it is used. It can be used in py.test, nose or unittest or it could be used to direct other forms
17+
of automated website interaction - e.g. as a scraper.
18+
19+
20+
21+
## Example
22+
23+
24+
25+
26+
This example demonstrates how to look for of HTML IDs to
27+
select and use HTML elements by using 'id=class_name' or 'id: class_name'.
28+
29+
This is often the ideal kind of selector to use if an element has an ID, since IDs tend to be
30+
relatively unchanging and the likelihood of accidentally selecting the wrong element is low.
31+
32+
If there is more than one element matching a ID (shouldn't be common since that's a
33+
violation of HTML semantics, but it still happens!), the element to use can be
34+
specified using 'which: [ number ]' or which: last.
35+
36+
37+
38+
HTML:
39+
40+
41+
42+
index.html:
43+
44+
```html
45+
<div class="form-login">
46+
<input type="text" id="id_username" class="form-control input-sm chat-input" placeholder="username" /></br>
47+
<input type="text" id="id_password" class="form-control input-sm chat-input" placeholder="password" /></br>
48+
<div class="wrapper">
49+
<span class="group-btn">
50+
<a id="id_ok_button" href="/dashboard.html" class="btn btn-primary btn-md">login <i class="fa fa-sign-in"></i></a>
51+
</span>
52+
</div>
53+
</div>
54+
55+
```
56+
57+
58+
dashboard.html:
59+
60+
```html
61+
<div class="form-login">
62+
<h4 id="id_this_is_a_dashboard_element">Dashboard</h4> <p id="id_dashboard_message">hello!</a>
63+
</div>
64+
65+
```
66+
67+
68+
69+
70+
71+
selectors.yml:
72+
73+
```yaml
74+
login:
75+
appears when: login page identifier
76+
elements:
77+
login page identifier: id=id_username
78+
username: id=id_username
79+
password: id=id_password
80+
ok: id=id_ok_button
81+
dashboard:
82+
appears when: dashboard identifier
83+
elements:
84+
dashboard identifier:
85+
id: id_this_is_a_dashboard_element
86+
message:
87+
id: id_dashboard_message
88+
89+
```
90+
91+
set up:
92+
93+
```yaml
94+
from seleniumdirector import WebDirector
95+
from selenium import webdriver
96+
97+
driver = webdriver.Chrome()
98+
selector = WebDirector(driver, "../selectors.yml", default_timeout=5)
99+
100+
```
101+
102+
103+
104+
105+
Successful:
106+
107+
108+
109+
110+
```python
111+
selector.visit("http://localhost:8000")
112+
selector.wait_for_page("login")
113+
selector.the("username").send_keys("login")
114+
selector.the("password").send_keys("password")
115+
selector.the("ok").click()
116+
selector.wait_for_page("dashboard")
117+
selector.the("message").should_be_on_page()
118+
selector.the("message").should_contain("hello!")
119+
driver.quit()
120+
121+
```
122+
123+
124+
125+
126+
127+
128+
More than one ID:
129+
130+
131+
132+
133+
```python
134+
selector.visit("http://localhost:8000")
135+
selector.wait_for_page("login")
136+
selector.the("username").send_keys("login")
137+
selector.the("password").send_keys("password")
138+
selector.the("ok").click()
139+
selector.wait_for_page("dashboard")
140+
selector.the("message").should_be_on_page()
141+
142+
```
143+
144+
145+
Raises:
146+
147+
```python
148+
seleniumdirector.exceptions.MoreThanOneElement:
149+
More than one element matches your query '//*[@id='id_dashboard_message']'.
150+
```
151+
152+
153+
154+
155+
156+
157+
158+
159+
160+
161+
162+
163+
164+
## Install with pip
165+
166+
```bash
167+
$ pip install seleniumdirector
168+
```
169+
170+
You can also use hitchkey to generate a skeleton project structure along
171+
with [hitchstory](https://hitchdev.com/hitchstory/).
172+
173+
Either install hitchkey with [pipsi](https://github.com/mitsuhiko/pipsi):
174+
175+
```bash
176+
pipsi install hitchkey
177+
```
178+
179+
Or, if you'd prefer, you can safely install with "sudo pip" (deactivate any virtualenvs you're in):
180+
181+
```bash
182+
sudo pip install hitchkey
183+
```
184+
185+
Once hitchkey is installed:
186+
187+
```bash
188+
cd /your/project/directory
189+
hk --demo seleniumdirector
190+
```
191+
192+
This will create a directory called "hitch" and put three files in it, including one story, which you can play by running:
193+
194+
```bash
195+
hk bdd logged in
196+
```
197+
198+
199+
## Using SeleniumDirector
200+
201+
- [Selector for element inside iframe](https://hitchdev.com/seleniumdirector/using/alpha/iframe)
202+
- [Sub-elements](https://hitchdev.com/seleniumdirector/using/alpha/subelements)
203+
- [Selectors with HTML classes](https://hitchdev.com/seleniumdirector/using/alpha/html-classes)
204+
- [With HTML attributes](https://hitchdev.com/seleniumdirector/using/alpha/attributes)
205+
- [Overlay - should_be_on_top](https://hitchdev.com/seleniumdirector/using/alpha/element-should-be-on-top)
206+
- [Element should not be on page](https://hitchdev.com/seleniumdirector/using/alpha/disappearing-element)
207+
- [Selectors using HTML contents](https://hitchdev.com/seleniumdirector/using/alpha/html-element-contents)
208+
- [Using a selenium element object](https://hitchdev.com/seleniumdirector/using/alpha/using-selenium-element-object)
209+
- [Hover - hovering over an element](https://hitchdev.com/seleniumdirector/using/alpha/hovering-over-an-element)
210+
- [Should contain text](https://hitchdev.com/seleniumdirector/using/alpha/should-contain-text)
211+
- [Selectors with HTML IDs](https://hitchdev.com/seleniumdirector/using/alpha/html-ids)
212+
213+
214+
215+
## Why not X instead?
216+
217+
- [Why not use Robot SeleniumLibrary?](https://hitchdev.com/seleniumdirector/why-not/robot)
218+
- [Why not use the page object pattern?](https://hitchdev.com/seleniumdirector/why-not/page-object)
219+
- [Why not use Capybara-Py or Splinter?](https://hitchdev.com/seleniumdirector/why-not/capybara-py-or-splinter)

hitch/hitchreqs.in

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
hitchpylibrarytoolkit
12
dirtemplate==0.1.4
23
strictyaml>=0.11.0
34
hitchstory>=0.11.1

hitch/hitchreqs.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ dirtemplate==0.1.4
1616
docutils==0.16 # via readme-renderer
1717
entrypoints==0.3 # via flake8
1818
flake8==3.7.9
19+
gitdb2==2.0.6 # via gitpython
20+
gitpython==3.0.7 # via hitchpylibrarytoolkit
1921
hitchbuild==0.4.0
2022
hitchbuildpy==0.4.6
2123
hitchdoc==0.1.1
24+
hitchpylibrarytoolkit==0.3.1
2225
hitchrun==0.3.2
2326
hitchrunpy==0.10.0
2427
hitchstory==0.12.1
@@ -27,13 +30,14 @@ idna==2.8 # via requests
2730
importlib-metadata==1.5.0 # via argcomplete, keyring, path, twine
2831
ipykernel==5.1.4 # via jupyter-console
2932
ipython-genutils==0.2.0 # via traitlets
30-
ipython==7.12.0 # via ipykernel, jupyter-console
33+
ipython==7.12.0 # via hitchpylibrarytoolkit, ipykernel, jupyter-console
3134
jedi==0.16.0 # via ipython
3235
jeepney==0.4.2 # via keyring, secretstorage
3336
jinja2==2.11.1 # via dirtemplate, hitchdoc, hitchrunpy, hitchstory, prettystack
3437
jupyter-client==5.3.4 # via ipykernel, jupyter-console
3538
jupyter-console==6.1.0
3639
jupyter-core==4.6.1 # via jupyter-client
40+
kaching==0.4.2 # via hitchpylibrarytoolkit
3741
keyring==21.1.0 # via twine
3842
markupsafe==1.1.1 # via jinja2
3943
mccabe==0.6.1 # via flake8
@@ -71,6 +75,7 @@ ruamel.yaml==0.16.7 # via strictyaml
7175
secretstorage==3.1.2 # via keyring
7276
simex==0.3.5
7377
six==1.14.0 # via bleach, cryptography, pip-tools, python-dateutil, readme-renderer, traitlets
78+
smmap2==2.0.5 # via gitdb2
7479
strictyaml==1.0.6
7580
templex==0.2.0
7681
text-unidecode==1.3 # via python-slugify

hitch/key.py

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import dirtemplate
2121
import signal
2222

23+
PROJECT_NAME = "seleniumdirector"
2324

2425
def project_build(paths, python_version, selenium_version=None):
2526
pylibrary = (
@@ -425,3 +426,14 @@ def rerun(version="3.7.0"):
425426
Command(DIR.gen.joinpath("py{0}".format(version), "bin", "python"))(
426427
DIR.gen.joinpath("state", "working", "examplepythoncode.py")
427428
).in_dir(DIR.gen.joinpath("state", "working")).run()
429+
430+
431+
@expected(dirtemplate.exceptions.DirTemplateException)
432+
def readmegen():
433+
"""
434+
Build README.md and CHANGELOG.md.
435+
"""
436+
import hitchpylibrarytoolkit
437+
hitchpylibrarytoolkit.readmegen(
438+
_storybook({}), DIR.project, DIR.key / "story", DIR.gen, PROJECT_NAME
439+
)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)