side-builder 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- side_builder-0.1.0/.gitignore +176 -0
- side_builder-0.1.0/.python-version +1 -0
- side_builder-0.1.0/PKG-INFO +205 -0
- side_builder-0.1.0/README.md +192 -0
- side_builder-0.1.0/demo1_async.py +26 -0
- side_builder-0.1.0/demo1_sel_sync.py +37 -0
- side_builder-0.1.0/demo1_sync.py +24 -0
- side_builder-0.1.0/pyproject.toml +36 -0
- side_builder-0.1.0/sides/demo1_step_1.side +27 -0
- side_builder-0.1.0/sides/demo1_step_2.side +51 -0
- side_builder-0.1.0/sides/demo1_step_3.side +27 -0
- side_builder-0.1.0/sides/demo1_step_4.side +27 -0
- side_builder-0.1.0/sides/demo1_step_5.side +27 -0
- side_builder-0.1.0/sides/demo1_step_6.side +51 -0
- side_builder-0.1.0/sides/demo1_step_7.side +27 -0
- side_builder-0.1.0/sides/demo1_step_8.side +27 -0
- side_builder-0.1.0/sides/demo1_step_9.side +35 -0
- side_builder-0.1.0/src/side_player/__init__.py +0 -0
- side_builder-0.1.0/src/side_player/builder.py +262 -0
- side_builder-0.1.0/src/side_player/common.py +62 -0
- side_builder-0.1.0/src/side_player/playwright/__init__.py +0 -0
- side_builder-0.1.0/src/side_player/playwright/async_api.py +53 -0
- side_builder-0.1.0/src/side_player/playwright/sync_api.py +51 -0
- side_builder-0.1.0/src/side_player/selenium/__init__.py +0 -0
- side_builder-0.1.0/src/side_player/selenium/sync_api.py +61 -0
- side_builder-0.1.0/uv.lock +699 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Created by https://www.toptal.com/developers/gitignore/api/python
|
|
2
|
+
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
|
3
|
+
|
|
4
|
+
### Python ###
|
|
5
|
+
# Byte-compiled / optimized / DLL files
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*$py.class
|
|
9
|
+
|
|
10
|
+
# C extensions
|
|
11
|
+
*.so
|
|
12
|
+
|
|
13
|
+
# Distribution / packaging
|
|
14
|
+
.Python
|
|
15
|
+
build/
|
|
16
|
+
develop-eggs/
|
|
17
|
+
dist/
|
|
18
|
+
downloads/
|
|
19
|
+
eggs/
|
|
20
|
+
.eggs/
|
|
21
|
+
lib/
|
|
22
|
+
lib64/
|
|
23
|
+
parts/
|
|
24
|
+
sdist/
|
|
25
|
+
var/
|
|
26
|
+
wheels/
|
|
27
|
+
share/python-wheels/
|
|
28
|
+
*.egg-info/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg
|
|
31
|
+
MANIFEST
|
|
32
|
+
|
|
33
|
+
# PyInstaller
|
|
34
|
+
# Usually these files are written by a python script from a template
|
|
35
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
36
|
+
*.manifest
|
|
37
|
+
*.spec
|
|
38
|
+
|
|
39
|
+
# Installer logs
|
|
40
|
+
pip-log.txt
|
|
41
|
+
pip-delete-this-directory.txt
|
|
42
|
+
|
|
43
|
+
# Unit test / coverage reports
|
|
44
|
+
htmlcov/
|
|
45
|
+
.tox/
|
|
46
|
+
.nox/
|
|
47
|
+
.coverage
|
|
48
|
+
.coverage.*
|
|
49
|
+
.cache
|
|
50
|
+
nosetests.xml
|
|
51
|
+
coverage.xml
|
|
52
|
+
*.cover
|
|
53
|
+
*.py,cover
|
|
54
|
+
.hypothesis/
|
|
55
|
+
.pytest_cache/
|
|
56
|
+
cover/
|
|
57
|
+
|
|
58
|
+
# Translations
|
|
59
|
+
*.mo
|
|
60
|
+
*.pot
|
|
61
|
+
|
|
62
|
+
# Django stuff:
|
|
63
|
+
*.log
|
|
64
|
+
local_settings.py
|
|
65
|
+
db.sqlite3
|
|
66
|
+
db.sqlite3-journal
|
|
67
|
+
|
|
68
|
+
# Flask stuff:
|
|
69
|
+
instance/
|
|
70
|
+
.webassets-cache
|
|
71
|
+
|
|
72
|
+
# Scrapy stuff:
|
|
73
|
+
.scrapy
|
|
74
|
+
|
|
75
|
+
# Sphinx documentation
|
|
76
|
+
docs/_build/
|
|
77
|
+
|
|
78
|
+
# PyBuilder
|
|
79
|
+
.pybuilder/
|
|
80
|
+
target/
|
|
81
|
+
|
|
82
|
+
# Jupyter Notebook
|
|
83
|
+
.ipynb_checkpoints
|
|
84
|
+
|
|
85
|
+
# IPython
|
|
86
|
+
profile_default/
|
|
87
|
+
ipython_config.py
|
|
88
|
+
|
|
89
|
+
# pyenv
|
|
90
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
91
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
92
|
+
# .python-version
|
|
93
|
+
|
|
94
|
+
# pipenv
|
|
95
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
96
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
97
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
98
|
+
# install all needed dependencies.
|
|
99
|
+
#Pipfile.lock
|
|
100
|
+
|
|
101
|
+
# poetry
|
|
102
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
103
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
104
|
+
# commonly ignored for libraries.
|
|
105
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
106
|
+
#poetry.lock
|
|
107
|
+
|
|
108
|
+
# pdm
|
|
109
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
110
|
+
#pdm.lock
|
|
111
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
112
|
+
# in version control.
|
|
113
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
114
|
+
.pdm.toml
|
|
115
|
+
|
|
116
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
117
|
+
__pypackages__/
|
|
118
|
+
|
|
119
|
+
# Celery stuff
|
|
120
|
+
celerybeat-schedule
|
|
121
|
+
celerybeat.pid
|
|
122
|
+
|
|
123
|
+
# SageMath parsed files
|
|
124
|
+
*.sage.py
|
|
125
|
+
|
|
126
|
+
# Environments
|
|
127
|
+
.env
|
|
128
|
+
.venv
|
|
129
|
+
env/
|
|
130
|
+
venv/
|
|
131
|
+
ENV/
|
|
132
|
+
env.bak/
|
|
133
|
+
venv.bak/
|
|
134
|
+
|
|
135
|
+
# Spyder project settings
|
|
136
|
+
.spyderproject
|
|
137
|
+
.spyproject
|
|
138
|
+
|
|
139
|
+
# Rope project settings
|
|
140
|
+
.ropeproject
|
|
141
|
+
|
|
142
|
+
# mkdocs documentation
|
|
143
|
+
/site
|
|
144
|
+
|
|
145
|
+
# mypy
|
|
146
|
+
.mypy_cache/
|
|
147
|
+
.dmypy.json
|
|
148
|
+
dmypy.json
|
|
149
|
+
|
|
150
|
+
# Pyre type checker
|
|
151
|
+
.pyre/
|
|
152
|
+
|
|
153
|
+
# pytype static type analyzer
|
|
154
|
+
.pytype/
|
|
155
|
+
|
|
156
|
+
# Cython debug symbols
|
|
157
|
+
cython_debug/
|
|
158
|
+
|
|
159
|
+
# PyCharm
|
|
160
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
161
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
162
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
163
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
164
|
+
#.idea/
|
|
165
|
+
|
|
166
|
+
### Python Patch ###
|
|
167
|
+
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
|
168
|
+
poetry.toml
|
|
169
|
+
|
|
170
|
+
# ruff
|
|
171
|
+
.ruff_cache/
|
|
172
|
+
|
|
173
|
+
# LSP config files
|
|
174
|
+
pyrightconfig.json
|
|
175
|
+
|
|
176
|
+
# End of https://www.toptal.com/developers/gitignore/api/python
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.10
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: side-builder
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AI-powered Selenium IDE (.side) player and builder for Selenium and Playwright
|
|
5
|
+
Author-email: Soonki Ji <soonki.ji@gmail.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: click>=8.3.1
|
|
8
|
+
Requires-Dist: openai>=2.24.0
|
|
9
|
+
Requires-Dist: playwright>=1.58.0
|
|
10
|
+
Requires-Dist: python-dotenv>=1.2.2
|
|
11
|
+
Requires-Dist: selenium>=4.41.0
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# Side Player (side-builder)
|
|
15
|
+
|
|
16
|
+
side-player is a next-generation automation tool that bridges the gap between AI-driven intent and rock-solid execution. It allows you to create Selenium IDE (.side) scripts interactively using natural language and execute them anywhere using Playwright or Selenium.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### 1. Installation
|
|
23
|
+
Install the package via pip or uv:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install side-player
|
|
27
|
+
# or using uv
|
|
28
|
+
uv tool install side-player
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Demo #1: Generate *.side files and demo1_{sync,async,sel_sync}.py
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
% side-builder --output demo1
|
|
35
|
+
Using OPENAI_API_KEY=sk-proj-OlHCz-hz******************************
|
|
36
|
+
|
|
37
|
+
[Step 1] AI prompt for browser action [exit]: Go to the home of https://saucedemo.com
|
|
38
|
+
Playing: sides\demo1_step_1.side ()
|
|
39
|
+
Success: open https://saucedemo.com
|
|
40
|
+
Save sides\demo1_step_1.side? [Y/n]:
|
|
41
|
+
|
|
42
|
+
[Step 2] AI prompt for browser action [exit]: Log in
|
|
43
|
+
Playing: sides\demo1_step_2.side ()
|
|
44
|
+
Success: open https://www.saucedemo.com/
|
|
45
|
+
Success: type id=user-name
|
|
46
|
+
Success: type id=password
|
|
47
|
+
Success: click id=login-button
|
|
48
|
+
Save sides\demo1_step_2.side? [Y/n]:
|
|
49
|
+
|
|
50
|
+
[Step 3] AI prompt for browser action [exit]: Add a backpack to the cart
|
|
51
|
+
Playing: sides\demo1_step_3.side ()
|
|
52
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
53
|
+
Save sides\demo1_step_3.side? [Y/n]:
|
|
54
|
+
|
|
55
|
+
[Step 4] AI prompt for browser action [exit]: Go to cart for checkout
|
|
56
|
+
Playing: sides\demo1_step_4.side ()
|
|
57
|
+
Success: click css=.shopping_cart_link
|
|
58
|
+
Save sides\demo1_step_4.side? [Y/n]:
|
|
59
|
+
|
|
60
|
+
[Step 5] AI prompt for browser action [exit]: Click Checkout
|
|
61
|
+
Playing: sides\demo1_step_5.side ()
|
|
62
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
63
|
+
Save sides\demo1_step_5.side? [Y/n]:
|
|
64
|
+
|
|
65
|
+
[Step 6] AI prompt for browser action [exit]: Enter John as first name, Doe as last name, 11111 as zip code and click Continue
|
|
66
|
+
Playing: sides\demo1_step_6.side ()
|
|
67
|
+
Success: type id=first-name
|
|
68
|
+
Success: type id=last-name
|
|
69
|
+
Success: type id=postal-code
|
|
70
|
+
Success: click id=continue
|
|
71
|
+
Save sides\demo1_step_6.side? [Y/n]:
|
|
72
|
+
|
|
73
|
+
[Step 7] AI prompt for browser action [exit]: Click Finish
|
|
74
|
+
Playing: sides\demo1_step_7.side ()
|
|
75
|
+
Success: click id=finish
|
|
76
|
+
Save sides\demo1_step_7.side? [Y/n]:
|
|
77
|
+
|
|
78
|
+
[Step 8] AI prompt for browser action [exit]: Click Back Home
|
|
79
|
+
Playing: sides\demo1_step_8.side ()
|
|
80
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
81
|
+
Save sides\demo1_step_8.side? [Y/n]:
|
|
82
|
+
|
|
83
|
+
[Step 9] AI prompt for browser action [exit]: Log out
|
|
84
|
+
Playing: sides\demo1_step_9.side ()
|
|
85
|
+
Success: click id=react-burger-menu-btn
|
|
86
|
+
Success: click id=logout_sidebar_link
|
|
87
|
+
Save sides\demo1_step_9.side? [Y/n]:
|
|
88
|
+
|
|
89
|
+
[Step 10] AI prompt for browser action [exit]:
|
|
90
|
+
|
|
91
|
+
Scripts created: demo1_sync.py, demo1_async.py, demo1_sel_sync.py
|
|
92
|
+
Side files saved in: sides/
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Demo #2: Playing *.side files using Playwright Sync API
|
|
96
|
+
```
|
|
97
|
+
% uv run demo1_sync.py
|
|
98
|
+
Playing: sides/demo1_step_1.side (Go to the home of https://saucedemo.com)
|
|
99
|
+
Success: open https://saucedemo.com
|
|
100
|
+
Playing: sides/demo1_step_2.side (Log in)
|
|
101
|
+
Success: open https://www.saucedemo.com/
|
|
102
|
+
Success: type id=user-name
|
|
103
|
+
Success: type id=password
|
|
104
|
+
Success: click id=login-button
|
|
105
|
+
Playing: sides/demo1_step_3.side (Add a backpack to the cart)
|
|
106
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
107
|
+
Playing: sides/demo1_step_4.side (Go to cart for checkout)
|
|
108
|
+
Success: click css=.shopping_cart_link
|
|
109
|
+
Playing: sides/demo1_step_5.side (Click Checkout)
|
|
110
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
111
|
+
Playing: sides/demo1_step_6.side (Enter John as first name, Doe as last name, 11111 as zip code and click Continue)
|
|
112
|
+
Success: type id=first-name
|
|
113
|
+
Success: type id=last-name
|
|
114
|
+
Success: type id=postal-code
|
|
115
|
+
Success: click id=continue
|
|
116
|
+
Playing: sides/demo1_step_7.side (Click Finish)
|
|
117
|
+
Success: click id=finish
|
|
118
|
+
Playing: sides/demo1_step_8.side (Click Back Home)
|
|
119
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
120
|
+
Playing: sides/demo1_step_9.side (Log out)
|
|
121
|
+
Success: click id=react-burger-menu-btn
|
|
122
|
+
Success: click id=logout_sidebar_link
|
|
123
|
+
Done.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Demo #3: Playing *.side files using Playwright Async API
|
|
127
|
+
```
|
|
128
|
+
% uv run demo1_async.py
|
|
129
|
+
Playing (Async): sides/demo1_step_1.side (Go to the home of https://saucedemo.com)
|
|
130
|
+
Success: open https://saucedemo.com
|
|
131
|
+
Playing (Async): sides/demo1_step_2.side (Log in)
|
|
132
|
+
Success: open https://www.saucedemo.com/
|
|
133
|
+
Success: type id=user-name
|
|
134
|
+
Success: type id=password
|
|
135
|
+
Success: click id=login-button
|
|
136
|
+
Playing (Async): sides/demo1_step_3.side (Add a backpack to the cart)
|
|
137
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
138
|
+
Playing (Async): sides/demo1_step_4.side (Go to cart for checkout)
|
|
139
|
+
Success: click css=.shopping_cart_link
|
|
140
|
+
Playing (Async): sides/demo1_step_5.side (Click Checkout)
|
|
141
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
142
|
+
Playing (Async): sides/demo1_step_6.side (Enter John as first name, Doe as last name, 11111 as zip code and click Continue)
|
|
143
|
+
Success: type id=first-name
|
|
144
|
+
Success: type id=last-name
|
|
145
|
+
Success: type id=postal-code
|
|
146
|
+
Success: click id=continue
|
|
147
|
+
Playing (Async): sides/demo1_step_7.side (Click Finish)
|
|
148
|
+
Success: click id=finish
|
|
149
|
+
Playing (Async): sides/demo1_step_8.side (Click Back Home)
|
|
150
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
151
|
+
Playing (Async): sides/demo1_step_9.side (Log out)
|
|
152
|
+
Success: click id=react-burger-menu-btn
|
|
153
|
+
Success: click id=logout_sidebar_link
|
|
154
|
+
Done.
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Demo #4: Play *.side files using Selenium
|
|
158
|
+
```
|
|
159
|
+
>uv run demo1_sel_sync.py
|
|
160
|
+
Playing: sides/demo1_step_1.side (Go to the home of https://saucedemo.com)
|
|
161
|
+
Success: open https://saucedemo.com
|
|
162
|
+
Playing: sides/demo1_step_2.side (Log in)
|
|
163
|
+
Success: open https://www.saucedemo.com/
|
|
164
|
+
Success: type id=user-name
|
|
165
|
+
Success: type id=password
|
|
166
|
+
Success: click id=login-button
|
|
167
|
+
Playing: sides/demo1_step_3.side (Add a backpack to the cart)
|
|
168
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
169
|
+
Playing: sides/demo1_step_4.side (Go to cart for checkout)
|
|
170
|
+
Success: click css=.shopping_cart_link
|
|
171
|
+
Playing: sides/demo1_step_5.side (Click Checkout)
|
|
172
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
173
|
+
Playing: sides/demo1_step_6.side (Enter John as first name, Doe as last name, 11111 as zip code and click Continue)
|
|
174
|
+
Success: type id=first-name
|
|
175
|
+
Success: type id=last-name
|
|
176
|
+
Success: type id=postal-code
|
|
177
|
+
Success: click id=continue
|
|
178
|
+
Playing: sides/demo1_step_7.side (Click Finish)
|
|
179
|
+
Success: click id=finish
|
|
180
|
+
Playing: sides/demo1_step_8.side (Click Back Home)
|
|
181
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
182
|
+
Playing: sides/demo1_step_9.side (Log out)
|
|
183
|
+
Success: click id=react-burger-menu-btn
|
|
184
|
+
Success: click id=logout_sidebar_link
|
|
185
|
+
Done.
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Key Features
|
|
189
|
+
|
|
190
|
+
* Zero-config Selectors: AI finds the best ID, CSS, or XPath for you automatically.
|
|
191
|
+
* Cost Efficient: Use AI only for recording. Execution is 100% local and free.
|
|
192
|
+
* Standard Format: Generates standard .side files compatible with the Selenium IDE.
|
|
193
|
+
* Developer Friendly: Provides both Sync and Async Playwright APIs.
|
|
194
|
+
* Extensible: Built with a modular structure to support Playwright and Selenium.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Prerequisites
|
|
199
|
+
|
|
200
|
+
- Python 3.12+
|
|
201
|
+
- OpenAI API Key (required only for the side-builder recording phase)
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Side Player (side-builder)
|
|
2
|
+
|
|
3
|
+
side-player is a next-generation automation tool that bridges the gap between AI-driven intent and rock-solid execution. It allows you to create Selenium IDE (.side) scripts interactively using natural language and execute them anywhere using Playwright or Selenium.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. Installation
|
|
10
|
+
Install the package via pip or uv:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install side-player
|
|
14
|
+
# or using uv
|
|
15
|
+
uv tool install side-player
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Demo #1: Generate *.side files and demo1_{sync,async,sel_sync}.py
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
% side-builder --output demo1
|
|
22
|
+
Using OPENAI_API_KEY=sk-proj-OlHCz-hz******************************
|
|
23
|
+
|
|
24
|
+
[Step 1] AI prompt for browser action [exit]: Go to the home of https://saucedemo.com
|
|
25
|
+
Playing: sides\demo1_step_1.side ()
|
|
26
|
+
Success: open https://saucedemo.com
|
|
27
|
+
Save sides\demo1_step_1.side? [Y/n]:
|
|
28
|
+
|
|
29
|
+
[Step 2] AI prompt for browser action [exit]: Log in
|
|
30
|
+
Playing: sides\demo1_step_2.side ()
|
|
31
|
+
Success: open https://www.saucedemo.com/
|
|
32
|
+
Success: type id=user-name
|
|
33
|
+
Success: type id=password
|
|
34
|
+
Success: click id=login-button
|
|
35
|
+
Save sides\demo1_step_2.side? [Y/n]:
|
|
36
|
+
|
|
37
|
+
[Step 3] AI prompt for browser action [exit]: Add a backpack to the cart
|
|
38
|
+
Playing: sides\demo1_step_3.side ()
|
|
39
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
40
|
+
Save sides\demo1_step_3.side? [Y/n]:
|
|
41
|
+
|
|
42
|
+
[Step 4] AI prompt for browser action [exit]: Go to cart for checkout
|
|
43
|
+
Playing: sides\demo1_step_4.side ()
|
|
44
|
+
Success: click css=.shopping_cart_link
|
|
45
|
+
Save sides\demo1_step_4.side? [Y/n]:
|
|
46
|
+
|
|
47
|
+
[Step 5] AI prompt for browser action [exit]: Click Checkout
|
|
48
|
+
Playing: sides\demo1_step_5.side ()
|
|
49
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
50
|
+
Save sides\demo1_step_5.side? [Y/n]:
|
|
51
|
+
|
|
52
|
+
[Step 6] AI prompt for browser action [exit]: Enter John as first name, Doe as last name, 11111 as zip code and click Continue
|
|
53
|
+
Playing: sides\demo1_step_6.side ()
|
|
54
|
+
Success: type id=first-name
|
|
55
|
+
Success: type id=last-name
|
|
56
|
+
Success: type id=postal-code
|
|
57
|
+
Success: click id=continue
|
|
58
|
+
Save sides\demo1_step_6.side? [Y/n]:
|
|
59
|
+
|
|
60
|
+
[Step 7] AI prompt for browser action [exit]: Click Finish
|
|
61
|
+
Playing: sides\demo1_step_7.side ()
|
|
62
|
+
Success: click id=finish
|
|
63
|
+
Save sides\demo1_step_7.side? [Y/n]:
|
|
64
|
+
|
|
65
|
+
[Step 8] AI prompt for browser action [exit]: Click Back Home
|
|
66
|
+
Playing: sides\demo1_step_8.side ()
|
|
67
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
68
|
+
Save sides\demo1_step_8.side? [Y/n]:
|
|
69
|
+
|
|
70
|
+
[Step 9] AI prompt for browser action [exit]: Log out
|
|
71
|
+
Playing: sides\demo1_step_9.side ()
|
|
72
|
+
Success: click id=react-burger-menu-btn
|
|
73
|
+
Success: click id=logout_sidebar_link
|
|
74
|
+
Save sides\demo1_step_9.side? [Y/n]:
|
|
75
|
+
|
|
76
|
+
[Step 10] AI prompt for browser action [exit]:
|
|
77
|
+
|
|
78
|
+
Scripts created: demo1_sync.py, demo1_async.py, demo1_sel_sync.py
|
|
79
|
+
Side files saved in: sides/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Demo #2: Playing *.side files using Playwright Sync API
|
|
83
|
+
```
|
|
84
|
+
% uv run demo1_sync.py
|
|
85
|
+
Playing: sides/demo1_step_1.side (Go to the home of https://saucedemo.com)
|
|
86
|
+
Success: open https://saucedemo.com
|
|
87
|
+
Playing: sides/demo1_step_2.side (Log in)
|
|
88
|
+
Success: open https://www.saucedemo.com/
|
|
89
|
+
Success: type id=user-name
|
|
90
|
+
Success: type id=password
|
|
91
|
+
Success: click id=login-button
|
|
92
|
+
Playing: sides/demo1_step_3.side (Add a backpack to the cart)
|
|
93
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
94
|
+
Playing: sides/demo1_step_4.side (Go to cart for checkout)
|
|
95
|
+
Success: click css=.shopping_cart_link
|
|
96
|
+
Playing: sides/demo1_step_5.side (Click Checkout)
|
|
97
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
98
|
+
Playing: sides/demo1_step_6.side (Enter John as first name, Doe as last name, 11111 as zip code and click Continue)
|
|
99
|
+
Success: type id=first-name
|
|
100
|
+
Success: type id=last-name
|
|
101
|
+
Success: type id=postal-code
|
|
102
|
+
Success: click id=continue
|
|
103
|
+
Playing: sides/demo1_step_7.side (Click Finish)
|
|
104
|
+
Success: click id=finish
|
|
105
|
+
Playing: sides/demo1_step_8.side (Click Back Home)
|
|
106
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
107
|
+
Playing: sides/demo1_step_9.side (Log out)
|
|
108
|
+
Success: click id=react-burger-menu-btn
|
|
109
|
+
Success: click id=logout_sidebar_link
|
|
110
|
+
Done.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Demo #3: Playing *.side files using Playwright Async API
|
|
114
|
+
```
|
|
115
|
+
% uv run demo1_async.py
|
|
116
|
+
Playing (Async): sides/demo1_step_1.side (Go to the home of https://saucedemo.com)
|
|
117
|
+
Success: open https://saucedemo.com
|
|
118
|
+
Playing (Async): sides/demo1_step_2.side (Log in)
|
|
119
|
+
Success: open https://www.saucedemo.com/
|
|
120
|
+
Success: type id=user-name
|
|
121
|
+
Success: type id=password
|
|
122
|
+
Success: click id=login-button
|
|
123
|
+
Playing (Async): sides/demo1_step_3.side (Add a backpack to the cart)
|
|
124
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
125
|
+
Playing (Async): sides/demo1_step_4.side (Go to cart for checkout)
|
|
126
|
+
Success: click css=.shopping_cart_link
|
|
127
|
+
Playing (Async): sides/demo1_step_5.side (Click Checkout)
|
|
128
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
129
|
+
Playing (Async): sides/demo1_step_6.side (Enter John as first name, Doe as last name, 11111 as zip code and click Continue)
|
|
130
|
+
Success: type id=first-name
|
|
131
|
+
Success: type id=last-name
|
|
132
|
+
Success: type id=postal-code
|
|
133
|
+
Success: click id=continue
|
|
134
|
+
Playing (Async): sides/demo1_step_7.side (Click Finish)
|
|
135
|
+
Success: click id=finish
|
|
136
|
+
Playing (Async): sides/demo1_step_8.side (Click Back Home)
|
|
137
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
138
|
+
Playing (Async): sides/demo1_step_9.side (Log out)
|
|
139
|
+
Success: click id=react-burger-menu-btn
|
|
140
|
+
Success: click id=logout_sidebar_link
|
|
141
|
+
Done.
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Demo #4: Play *.side files using Selenium
|
|
145
|
+
```
|
|
146
|
+
>uv run demo1_sel_sync.py
|
|
147
|
+
Playing: sides/demo1_step_1.side (Go to the home of https://saucedemo.com)
|
|
148
|
+
Success: open https://saucedemo.com
|
|
149
|
+
Playing: sides/demo1_step_2.side (Log in)
|
|
150
|
+
Success: open https://www.saucedemo.com/
|
|
151
|
+
Success: type id=user-name
|
|
152
|
+
Success: type id=password
|
|
153
|
+
Success: click id=login-button
|
|
154
|
+
Playing: sides/demo1_step_3.side (Add a backpack to the cart)
|
|
155
|
+
Success: click id=add-to-cart-sauce-labs-backpack
|
|
156
|
+
Playing: sides/demo1_step_4.side (Go to cart for checkout)
|
|
157
|
+
Success: click css=.shopping_cart_link
|
|
158
|
+
Playing: sides/demo1_step_5.side (Click Checkout)
|
|
159
|
+
Success: click css=.btn.btn_action.btn_medium.checkout_button
|
|
160
|
+
Playing: sides/demo1_step_6.side (Enter John as first name, Doe as last name, 11111 as zip code and click Continue)
|
|
161
|
+
Success: type id=first-name
|
|
162
|
+
Success: type id=last-name
|
|
163
|
+
Success: type id=postal-code
|
|
164
|
+
Success: click id=continue
|
|
165
|
+
Playing: sides/demo1_step_7.side (Click Finish)
|
|
166
|
+
Success: click id=finish
|
|
167
|
+
Playing: sides/demo1_step_8.side (Click Back Home)
|
|
168
|
+
Success: click css=.btn.btn_primary.btn_small[id='back-to-products']
|
|
169
|
+
Playing: sides/demo1_step_9.side (Log out)
|
|
170
|
+
Success: click id=react-burger-menu-btn
|
|
171
|
+
Success: click id=logout_sidebar_link
|
|
172
|
+
Done.
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Key Features
|
|
176
|
+
|
|
177
|
+
* Zero-config Selectors: AI finds the best ID, CSS, or XPath for you automatically.
|
|
178
|
+
* Cost Efficient: Use AI only for recording. Execution is 100% local and free.
|
|
179
|
+
* Standard Format: Generates standard .side files compatible with the Selenium IDE.
|
|
180
|
+
* Developer Friendly: Provides both Sync and Async Playwright APIs.
|
|
181
|
+
* Extensible: Built with a modular structure to support Playwright and Selenium.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Prerequisites
|
|
186
|
+
|
|
187
|
+
- Python 3.12+
|
|
188
|
+
- OpenAI API Key (required only for the side-builder recording phase)
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from playwright.async_api import async_playwright
|
|
4
|
+
|
|
5
|
+
from side_player.playwright.async_api import play_side_async
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def main():
|
|
9
|
+
async with async_playwright() as p:
|
|
10
|
+
browser = await p.chromium.launch(headless=False)
|
|
11
|
+
page = await browser.new_page()
|
|
12
|
+
await play_side_async(page, 'sides/demo1_step_1.side', name='Go to the home of https://saucedemo.com')
|
|
13
|
+
await play_side_async(page, 'sides/demo1_step_2.side', name='Log in')
|
|
14
|
+
await play_side_async(page, 'sides/demo1_step_3.side', name='Add a backpack to the cart')
|
|
15
|
+
await play_side_async(page, 'sides/demo1_step_4.side', name='Go to cart for checkout')
|
|
16
|
+
await play_side_async(page, 'sides/demo1_step_5.side', name='Click Checkout')
|
|
17
|
+
await play_side_async(page, 'sides/demo1_step_6.side', name='Enter John as first name, Doe as last name, 11111 as zip code and click Continue')
|
|
18
|
+
await play_side_async(page, 'sides/demo1_step_7.side', name='Click Finish')
|
|
19
|
+
await play_side_async(page, 'sides/demo1_step_8.side', name='Click Back Home')
|
|
20
|
+
await play_side_async(page, 'sides/demo1_step_9.side', name='Log out')
|
|
21
|
+
await browser.close()
|
|
22
|
+
print("Done.")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from selenium import webdriver
|
|
2
|
+
from selenium.webdriver.chrome.options import Options
|
|
3
|
+
|
|
4
|
+
from side_player.selenium.sync_api import play_side
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
chrome_options = Options()
|
|
9
|
+
prefs = {
|
|
10
|
+
"credentials_enable_service": False,
|
|
11
|
+
"profile.password_manager_enabled": False,
|
|
12
|
+
"profile.password_manager_leak_detection": False,
|
|
13
|
+
}
|
|
14
|
+
chrome_options.add_experimental_option("prefs", prefs)
|
|
15
|
+
chrome_options.add_argument("--disable-features=PasswordLeakDetection")
|
|
16
|
+
chrome_options.add_argument("--disable-features=SafeBrowsingPasswordProtection")
|
|
17
|
+
chrome_options.add_argument("--disable-save-password-bubble")
|
|
18
|
+
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
|
|
19
|
+
chrome_options.use_automation_extension = False
|
|
20
|
+
driver = webdriver.Chrome(options=chrome_options)
|
|
21
|
+
try:
|
|
22
|
+
play_side(driver, 'sides/demo1_step_1.side', name='Go to the home of https://saucedemo.com')
|
|
23
|
+
play_side(driver, 'sides/demo1_step_2.side', name='Log in')
|
|
24
|
+
play_side(driver, 'sides/demo1_step_3.side', name='Add a backpack to the cart')
|
|
25
|
+
play_side(driver, 'sides/demo1_step_4.side', name='Go to cart for checkout')
|
|
26
|
+
play_side(driver, 'sides/demo1_step_5.side', name='Click Checkout')
|
|
27
|
+
play_side(driver, 'sides/demo1_step_6.side', name='Enter John as first name, Doe as last name, 11111 as zip code and click Continue')
|
|
28
|
+
play_side(driver, 'sides/demo1_step_7.side', name='Click Finish')
|
|
29
|
+
play_side(driver, 'sides/demo1_step_8.side', name='Click Back Home')
|
|
30
|
+
play_side(driver, 'sides/demo1_step_9.side', name='Log out')
|
|
31
|
+
finally:
|
|
32
|
+
driver.quit()
|
|
33
|
+
print("Done.")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
main()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from playwright.sync_api import sync_playwright
|
|
2
|
+
|
|
3
|
+
from side_player.playwright.sync_api import play_side
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
with sync_playwright() as p:
|
|
8
|
+
browser = p.chromium.launch(headless=False)
|
|
9
|
+
page = browser.new_page()
|
|
10
|
+
play_side(page, 'sides/demo1_step_1.side', name='Go to the home of https://saucedemo.com')
|
|
11
|
+
play_side(page, 'sides/demo1_step_2.side', name='Log in')
|
|
12
|
+
play_side(page, 'sides/demo1_step_3.side', name='Add a backpack to the cart')
|
|
13
|
+
play_side(page, 'sides/demo1_step_4.side', name='Go to cart for checkout')
|
|
14
|
+
play_side(page, 'sides/demo1_step_5.side', name='Click Checkout')
|
|
15
|
+
play_side(page, 'sides/demo1_step_6.side', name='Enter John as first name, Doe as last name, 11111 as zip code and click Continue')
|
|
16
|
+
play_side(page, 'sides/demo1_step_7.side', name='Click Finish')
|
|
17
|
+
play_side(page, 'sides/demo1_step_8.side', name='Click Back Home')
|
|
18
|
+
play_side(page, 'sides/demo1_step_9.side', name='Log out')
|
|
19
|
+
browser.close()
|
|
20
|
+
print("Done.")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
main()
|