Skip to content

Commit 348a6aa

Browse files
committed
[#570] NEW: command.paste, command.paste(text)
+ the corresponding methods built into web.Element
1 parent 442d554 commit 348a6aa

11 files changed

+488
-66
lines changed

CHANGELOG.md

+15-5
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ Next:
206206
- ensure query.* and command.* use proper classes
207207
- rename context.py to client.py
208208

209+
### pyperclip as dependency in Selene
210+
211+
Mainly for `command.paste(text)` command to work out of the box with clipboard.
212+
209213
### Deprecated conditions
210214

211215
- `be.present` in favor of `be.present_in_dom`
@@ -528,8 +532,11 @@ See a practical example of usage in [FAQ: How to simplify search by Test IDs?](h
528532

529533
### More commands among browser.element(selector).*
530534

535+
web.Element built in methods:
531536
- `press_sequentially(text)`
532537
- `select_all()`
538+
- `copy()`
539+
- `paste(text=None)`
533540
- `drag_and_drop_to(target, _assert_location_changed=False)`
534541
- with option to `.with(drag_and_drop_by_js=True).drag_and_drop_to(target)`
535542
- `drag_and_drop_by_offset(x, y)`
@@ -540,15 +547,18 @@ See a practical example of usage in [FAQ: How to simplify search by Test IDs?](h
540547

541548
### More commands in command.py
542549

550+
web.Element or web.Browser commands:
543551
- `command.copy`
544552
- `command.paste`
545-
- `command.copy_and_paste(text)`
546-
Requires 3rd party `pyperclip` package to be used,
547-
in order to copy to clipboard before pasting
548-
via simulating `ctrl+v` or `cmd+v` shortcut pressed.
553+
- `command.paste(text)`
554+
The `pyperclip` package was added to Selene as dependency to achieve it.
555+
556+
Element commands:
557+
- `command.press_sequentially(text: str)`
558+
559+
mobile.Element commands:
549560
- `command.long_press(duration=0.1)` alias to `command._long_press(duration=0.1)`
550561
actually the _long_press is now an outdated alias and probably will be deprecated in future releases
551-
- `command.press_sequentially(text: str)`
552562

553563
### More collection queries in query.py
554564

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# How to work with clipboard in Selene? {: #clipboard-copy-and-paste-howto}
2+
3+
{% include-markdown 'warn-from-next-release.md' %}
4+
5+
## Summary
6+
7+
Selene works with clipboard via the [pyperclip](https://pypi.org/project/pyperclip/) package. And there is only one command in Selene that uses it under the hood – [command.paste(text)][selene.core.command.paste]. In other cases you can use `pyperclip` directly to achieve your goals via `paperclip.copy(text)` and `paperclip.paste(text)`.
8+
9+
Let's consider the main scenarios to work with clipboard...
10+
11+
## Main Scenarios
12+
13+
### Copy a text into clipboard
14+
15+
```python
16+
import pyperclip
17+
...
18+
19+
pyperclip.copy('text to copy')
20+
```
21+
22+
### Copy a text of element into clipboard
23+
24+
```python
25+
from selene import browser, query
26+
import pyperclip
27+
...
28+
29+
pyperclip.copy(browser.element('.message').get(query.text))
30+
```
31+
32+
See also [#573](https://github.com/yashaka/selene/issues/573)
33+
34+
### Copy a value of an input element into clipboard
35+
36+
```python
37+
from selene import browser, query
38+
import pyperclip
39+
...
40+
41+
pyperclip.copy(browser.element('input').get(query.value))
42+
```
43+
44+
### Copy currently selected text on the page into clipboard via OS-based shortcut
45+
46+
```python
47+
from selene import browser, command
48+
...
49+
50+
browser.perform(command.copy)
51+
```
52+
53+
See also [#575](https://github.com/yashaka/selene/issues/575)
54+
55+
### Paste into currently focused element a text from the clipboard via OS-based shortcut
56+
57+
```python
58+
from selene import browser, command
59+
...
60+
61+
browser.perform(command.paste)
62+
```
63+
64+
See also [#575](https://github.com/yashaka/selene/issues/575)
65+
66+
### Put a text in the clipboard, then paste it into currently focused element via OS-based shortcut
67+
68+
```python
69+
from selene import browser, command
70+
...
71+
72+
browser.perform(command.paste('some text to put into clipboard first'))
73+
```
74+
75+
See also [#575](https://github.com/yashaka/selene/issues/575)
76+
77+
### Select value of an input element, then copy it into clipboard via OS-based shortcut
78+
79+
```python
80+
from selene import browser, command
81+
...
82+
83+
browser.element('input').select_all().copy()
84+
# OR:
85+
browser.element('input').select_all().perform(command.copy)
86+
```
87+
88+
### Type a text stored in the clipboard into text input at the current cursor position
89+
90+
```python
91+
from selene import browser
92+
import pyperclip
93+
...
94+
95+
browser.element('input').type(pyperclip.paste())
96+
```
97+
98+
### Set a new value to the text input getting this value from the clipboard
99+
100+
```python
101+
from selene import browser
102+
import pyperclip
103+
...
104+
105+
browser.element('input').set_value(pyperclip.paste())
106+
```
107+
108+
### Paste via OS-based shortcut a text stored in the clipboard into text input at the current cursor position
109+
110+
```python
111+
from selene import browser, command
112+
...
113+
114+
browser.element('input').paste()
115+
# OR:
116+
browser.element('input').perform(command.paste)
117+
```
118+
119+
### Paste via OS-based shortcut a text stored in the clipboard into text input substituting the current text via "select all" OS-based shortcut
120+
121+
```python
122+
from selene import browser, command
123+
...
124+
125+
browser.element('input').select_all().paste()
126+
# OR:
127+
browser.element('input').select_all().perform(command.paste)
128+
```
129+
130+
### Copy a text into clipboard, then paste it via OS-based shortcut into text input at the current cursor position
131+
132+
```python
133+
from selene import browser, command
134+
...
135+
text = 'text to append'
136+
browser.element('input').paste(text)
137+
# OR:
138+
browser.element('input').perform(command.paste(text))
139+
```
140+
141+
### Copy a text into clipboard, then paste it via OS-based shortcut into text input substituting the current text via "select all" OS-based shortcut
142+
143+
```python
144+
from selene import browser, command
145+
...
146+
text = 'new text value'
147+
browser.element('input').select_all().paste(text)
148+
# OR:
149+
browser.element('input').select_all().perform(command.paste(text))
150+
```

mkdocs.yml

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ nav:
2323
# - Stub Title 1: learn-advanced/automate-testing-guide.md
2424
- FAQ:
2525
- How to simplify search by Test IDs?: faq/custom-test-id-selectors-howto.md
26+
- How to work with clipboard in Selene?: faq/clipboard-copy-and-paste-howto.md
2627
- How to work with iFrames: faq/iframes-howto.md
2728
- How to work with Shadow DOM: faq/shadow-dom-howto.md
2829
- How to use custom profile: faq/custom-user-profile-howto.md
@@ -130,6 +131,7 @@ plugins:
130131

131132
# Extensions
132133
markdown_extensions:
134+
- attr_list
133135
- toc:
134136
permalink: "#"
135137
- admonition

poetry.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Changelog = "https://github.com/yashaka/selene/releases"
4848
[tool.poetry.dependencies]
4949
python = "^3.8"
5050
selenium = ">=4.12.0"
51+
pyperclip = "^1.9.0"
5152
future = "*"
5253
typing-extensions = ">=4.12.2"
5354

@@ -62,7 +63,6 @@ mypy = "*"
6263
pydantic = "^1.10.7"
6364
python-dotenv = "0.21.1"
6465
Appium-Python-Client = "^4.2.0"
65-
pyperclip = "^1.8.2"
6666
setuptools = "^70.0.0"
6767

6868
[tool.poetry.group.docs]
@@ -83,6 +83,7 @@ requires = ["poetry-core>=1.0.0"]
8383
build-backend = "poetry.core.masonry.api"
8484

8585
[tool.mypy]
86+
follow_untyped_imports = true
8687
disable_error_code = 'annotation-unchecked'
8788
allow_redefinition = true # TODO: how to properly make it work o_O ?
8889
color_output=1

selene/common/fp.py

+8
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ def pipe(*functions) -> Optional[Callable[[Any], Any]]:
121121
)
122122

123123

124+
def perform(*functions) -> Callable[[], None]:
125+
def one_by_one():
126+
for fn in functions:
127+
fn()
128+
129+
return one_by_one
130+
131+
124132
# TODO: support "detailed history of prev calls on failures"
125133
# TODO: support tuple form of functions
126134
# TODO: support ... as arg placeholder in tuple form of functions

0 commit comments

Comments
 (0)