Skip to content

Commit 61384e4

Browse files
committed
Add the ability to create presentations with SeleniumBase
1 parent 16436b7 commit 61384e4

File tree

6 files changed

+388
-0
lines changed

6 files changed

+388
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ archived_logs
7474
geckodriver.log
7575
pytestdebug.log
7676

77+
# Presentations
78+
presentations_saved
79+
7780
# Reports
7881
latest_report
7982
report_archives

examples/presenter/ReadMe.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<h3 align="left"><img src="https://cdn2.hubspot.net/hubfs/100006/images/super_logo_sb23.png" alt="SeleniumBase" width="290" /></h3>
2+
3+
# 📰 Presenter 📰
4+
5+
SeleniumBase Presenter allows you to create an HTML presentation with only a few lines of Python.
6+
The Reveal-JS library is used for running the presentations.
7+
8+
**Here's a sample slide:**
9+
10+
<img src="https://seleniumbase.io/other/presenter_screen.png" title="Screenshot"><br>
11+
12+
Slides can include HTML, code, images, and iframes.
13+
14+
Here's how to run the example presentation:
15+
```
16+
cd examples/presenter
17+
pytest my_presentation.py
18+
```
19+
20+
21+
### Creating a new presentation:
22+
23+
```python
24+
self.create_presentation(name=None, show_notes=True)
25+
""" Creates a Reveal-JS presentation that you can add slides to.
26+
@Params
27+
name - If creating multiple presentations at the same time,
28+
use this to specify the name of the current presentation.
29+
show_notes - When set to True, the Notes feature becomes enabled,
30+
which allows presenters to see notes next to slides.
31+
"""
32+
```
33+
34+
If creating multiple presentations at the same time, you can pass the ``name`` parameter to distinguish between different presentations.
35+
Notes are enabled by default unless you specify:
36+
``show_notes=False`` when calling.
37+
38+
39+
### Adding a slide to a presentation:
40+
41+
```python
42+
self.add_slide(content=None, image=None, code=None, iframe=None,
43+
notes=None, name=None)
44+
""" Allows the user to add slides to a presentation.
45+
@Params
46+
content - The HTML content to display on the presentation slide.
47+
image - Attach an image (from a URL link) to the slide.
48+
code - Attach code of any programming language to the slide.
49+
Language-detection will be used to add syntax formatting.
50+
iframe - Attach an iFrame (from a URL link) to the slide.
51+
notes - Additional notes to include with the slide.
52+
ONLY SEEN if show_notes is set for the presentation.
53+
name - If creating multiple presentations at the same time,
54+
use this to select the presentation to add slides to.
55+
"""
56+
```
57+
58+
59+
### Running a presentation:
60+
61+
```python
62+
self.begin_presentation(filename="my_presentation.html", name=None)
63+
""" Begin a Reveal-JS Presentation in the web browser. """
64+
```
65+
66+
Before the presentation is run, the full HTML is saved to the ``presentations_saved/`` folder.
67+
68+
69+
All methods have the optional ``name`` argument, which is only needed if you're creating multiple presentations at once.
70+
71+
### Here's an example of using SeleniumBase Presenter:
72+
73+
```python
74+
from seleniumbase import BaseCase
75+
76+
77+
class MyPresenterClass(BaseCase):
78+
79+
def test_presenter(self):
80+
self.create_presentation()
81+
self.add_slide(
82+
"<h2>Welcome!</h2>"
83+
"<h4>Enjoy the Presentation!</h4>")
84+
self.add_slide(
85+
'<h3>SeleniumBase "Presenter"</h3>'
86+
'<img src="https://seleniumbase.io/img/logo3a.png"></img>'
87+
'<h4>A tool for creating presentations</h4>')
88+
self.add_slide(
89+
'<h3>You can add HTML to any slide:</h3><br />'
90+
'<table style="padding:10px;border:4px solid black;font-size:60;">'
91+
'<tr><th>Row 1</th><th>Row 2</th></tr>'
92+
'<tr><td>Value 1</td><td>Value 2</td></tr></table><br />'
93+
'<h4>(HTML table example)</h4>')
94+
self.add_slide(
95+
"<h3>You can display code:</h3>",
96+
code=(
97+
'from seleniumbase import BaseCase\n\n'
98+
'class MyTestClass(BaseCase):\n\n'
99+
' def test_basic(self):\n'
100+
' self.open("https://store.xkcd.com/search")\n'
101+
' self.type(\'input[name="q"]\', "xkcd book\\n")\n'
102+
' self.assert_text("xkcd: volume 0", "h3")\n'
103+
' self.open("https://xkcd.com/353/")\n'
104+
' self.assert_title("xkcd: Python")\n'
105+
' self.assert_element(\'img[alt="Python"]\')\n'
106+
' self.click(\'a[rel="license"]\')\n'
107+
' self.assert_text("free to copy and reuse")\n'
108+
' self.go_back()\n'
109+
' self.click_link_text("About")\n'
110+
' self.assert_exact_text("xkcd.com", "h2")\n'))
111+
self.add_slide(
112+
"<h3>You can highlight code:</h3>",
113+
code=(
114+
'from seleniumbase import BaseCase\n\n'
115+
'<mark>class MyTestClass(BaseCase):</mark>\n\n'
116+
' def test_basic(self):\n'
117+
' self.open("https://store.xkcd.com/search")\n'
118+
' self.type(\'input[name="q"]\', "xkcd book\\n")\n'))
119+
self.add_slide(
120+
"<h3>You can add notes to slides:</h3>",
121+
notes="<h2><ul><li>Note A!<li>Note B!<li>Note C!<li>Note D!</h2>")
122+
self.add_slide(
123+
"<h3>You can add images to slides:</h3>",
124+
image="https://seleniumbase.io/img/sb_logo_10.png")
125+
self.add_slide(
126+
"<h3>You can add iframes to slides:</h3>",
127+
iframe="https://seleniumbase.io/demo_page")
128+
self.add_slide("<h1>The End</h1>")
129+
self.begin_presentation()
130+
```
131+
132+
#### This example is from [my_presentation.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/presenter/my_presentation.py), which you can run from the ``examples/presenter`` folder with the following command:
133+
134+
```bash
135+
pytest my_presentation.py
136+
```
137+
138+
### Saving a presentation:
139+
140+
If you want to save the presentation you created as an HTML file, use:
141+
142+
```python
143+
self.save_presentation(filename="my_presentation.html", name=None)
144+
```
145+
146+
Presentations automatically get saved when calling:
147+
```python
148+
self.begin_presentation()
149+
```

examples/presenter/my_presentation.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from seleniumbase import BaseCase
2+
3+
4+
class MyPresenterClass(BaseCase):
5+
6+
def test_presenter(self):
7+
self.create_presentation()
8+
self.add_slide(
9+
"<h2>Welcome!</h2>"
10+
"<h4>Enjoy the Presentation!</h4>")
11+
self.add_slide(
12+
'<h3>SeleniumBase "Presenter"</h3>'
13+
'<img src="https://seleniumbase.io/img/logo3a.png"></img>'
14+
'<h4>A tool for creating presentations</h4>')
15+
self.add_slide(
16+
'<h3>You can add HTML to any slide:</h3><br />'
17+
'<table style="padding:10px;border:4px solid black;font-size:60;">'
18+
'<tr><th>Row 1</th><th>Row 2</th></tr>'
19+
'<tr><td>Value 1</td><td>Value 2</td></tr></table><br />'
20+
'<h4>(HTML table example)</h4>')
21+
self.add_slide(
22+
"<h3>You can display code:</h3>",
23+
code=(
24+
'from seleniumbase import BaseCase\n\n'
25+
'class MyTestClass(BaseCase):\n\n'
26+
' def test_basic(self):\n'
27+
' self.open("https://store.xkcd.com/search")\n'
28+
' self.type(\'input[name="q"]\', "xkcd book\\n")\n'
29+
' self.assert_text("xkcd: volume 0", "h3")\n'
30+
' self.open("https://xkcd.com/353/")\n'
31+
' self.assert_title("xkcd: Python")\n'
32+
' self.assert_element(\'img[alt="Python"]\')\n'
33+
' self.click(\'a[rel="license"]\')\n'
34+
' self.assert_text("free to copy and reuse")\n'
35+
' self.go_back()\n'
36+
' self.click_link_text("About")\n'
37+
' self.assert_exact_text("xkcd.com", "h2")\n'))
38+
self.add_slide(
39+
"<h3>You can highlight code:</h3>",
40+
code=(
41+
'from seleniumbase import BaseCase\n\n'
42+
'<mark>class MyTestClass(BaseCase):</mark>\n\n'
43+
' def test_basic(self):\n'
44+
' self.open("https://store.xkcd.com/search")\n'
45+
' self.type(\'input[name="q"]\', "xkcd book\\n")\n'))
46+
self.add_slide(
47+
"<h3>You can add notes to slides:</h3>",
48+
notes="<h2><ul><li>Note A!<li>Note B!<li>Note C!<li>Note D!</h2>")
49+
self.add_slide(
50+
"<h3>You can add images to slides:</h3>",
51+
image="https://seleniumbase.io/img/sb_logo_10.png")
52+
self.add_slide(
53+
"<h3>You can add iframes to slides:</h3>",
54+
iframe="https://seleniumbase.io/demo_page")
55+
self.add_slide("<h1>The End</h1>")
56+
self.begin_presentation()

help_docs/method_summary.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,16 @@ self.add_meta_tag(http_equiv=None, content=None)
356356

357357
############
358358

359+
self.create_presentation(name=None, show_notes=True)
360+
361+
self.add_slide(content=None, image=None, code=None, iframe=None, notes=None, name=None)
362+
363+
self.save_presentation(filename="my_presentation.html", name=None)
364+
365+
self.begin_presentation(filename="my_presentation.html", name=None)
366+
367+
############
368+
359369
self.create_tour(name=None, theme=None)
360370

361371
self.create_shepherd_tour(name=None, theme=None)

seleniumbase/fixtures/base_case.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(self, *args, **kwargs):
8383
self.__device_pixel_ratio = None
8484
# Requires self._* instead of self.__* for external class use
8585
self._language = "English"
86+
self._presentation_slides = {}
8687
self._html_report_extra = [] # (Used by pytest_plugin.py)
8788
self._default_driver = None
8889
self._drivers_list = []
@@ -3150,6 +3151,152 @@ def add_meta_tag(self, http_equiv=None, content=None):
31503151

31513152
############
31523153

3154+
def create_presentation(self, name=None, show_notes=True):
3155+
""" Creates a Reveal-JS presentation that you can add slides to.
3156+
@Params
3157+
name - If creating multiple presentations at the same time,
3158+
use this to specify the name of the current presentation.
3159+
show_notes - When set to True, the Notes feature becomes enabled,
3160+
which allows presenters to see notes next to slides.
3161+
"""
3162+
if not name:
3163+
name = "default"
3164+
3165+
new_presentation = (
3166+
"""
3167+
<html>
3168+
<head>
3169+
<link rel="stylesheet" href="%s">
3170+
<link rel="stylesheet" href="%s">
3171+
<style>
3172+
pre{background-color:#fbe8d4;border-radius:8px;}
3173+
div[flex_div],{height:100vh;margin:0;align-items:center;
3174+
justify-content:center;display:flex;background:#fafafa;}
3175+
img[rounded]{border-radius:16px;max-width:90%%;}
3176+
</style>
3177+
</head>
3178+
<body>
3179+
<div class="reveal">
3180+
<div class="slides">
3181+
""" % (constants.Reveal.MIN_CSS, constants.Reveal.WHITE_MIN_CSS))
3182+
3183+
self._presentation_slides[name] = []
3184+
self._presentation_slides[name].append(new_presentation)
3185+
3186+
def add_slide(self, content=None, image=None, code=None, iframe=None,
3187+
notes=None, name=None):
3188+
""" Allows the user to add slides to a presentation.
3189+
@Params
3190+
content - The HTML content to display on the presentation slide.
3191+
image - Attach an image (from a URL link) to the slide.
3192+
code - Attach code of any programming language to the slide.
3193+
Language-detection will be used to add syntax formatting.
3194+
iframe - Attach an iFrame (from a URL link) to the slide.
3195+
notes - Additional notes to include with the slide.
3196+
ONLY SEEN if show_notes is set for the presentation.
3197+
name - If creating multiple presentations at the same time,
3198+
use this to select the presentation to add slides to.
3199+
"""
3200+
3201+
if not name:
3202+
name = "default"
3203+
if name not in self._presentation_slides:
3204+
# Create a presentation if it doesn't already exist
3205+
self.create_presentation(name=name, show_notes=True)
3206+
if not content:
3207+
content = ""
3208+
if not notes:
3209+
notes = ""
3210+
3211+
html = ('<section data-transition="none">%s' % content)
3212+
if image:
3213+
html += '<div flex_div><img rounded src="%s"></div>' % image
3214+
if code:
3215+
html += '<div></div>'
3216+
html += '<pre class="prettyprint">%s</pre>' % code
3217+
if iframe:
3218+
html += ('<div></div>'
3219+
'<iframe src="%s" style="width:92%%;height:550;'
3220+
'title="iframe content"></iframe>' % iframe)
3221+
html += '<aside class="notes">%s</aside>' % notes
3222+
html += '</section>'
3223+
3224+
self._presentation_slides[name].append(html)
3225+
3226+
def save_presentation(self, filename="my_presentation.html", name=None):
3227+
""" Saves a Reveal-JS Presentation to a folder for later use. """
3228+
3229+
if not name:
3230+
name = "default"
3231+
if name not in self._presentation_slides:
3232+
raise Exception("Presentation {%s} does not exist!" % name)
3233+
if not filename.endswith('.html'):
3234+
raise Exception('Presentation file must end in ".html"!')
3235+
3236+
the_html = ""
3237+
for slide in self._presentation_slides[name]:
3238+
the_html += slide
3239+
3240+
the_html += (
3241+
"""
3242+
</div>
3243+
</div>
3244+
<script src="%s"></script>
3245+
<script src="%s"></script>
3246+
<script src="%s"></script>
3247+
<script>Reveal.initialize(
3248+
{showNotes: true, slideNumber: true,});
3249+
</script>
3250+
</body>
3251+
</html>
3252+
""" % (constants.Reveal.MIN_JS,
3253+
constants.Reveal.MARKED_JS,
3254+
constants.PrettifyJS.RUN_PRETTIFY_JS))
3255+
3256+
saved_presentations_folder = constants.Presentations.SAVED_FOLDER
3257+
if saved_presentations_folder.endswith("/"):
3258+
saved_presentations_folder = saved_presentations_folder[:-1]
3259+
if not os.path.exists(saved_presentations_folder):
3260+
try:
3261+
os.makedirs(saved_presentations_folder)
3262+
except Exception:
3263+
pass
3264+
file_path = saved_presentations_folder + "/" + filename
3265+
out_file = codecs.open(file_path, "w+")
3266+
out_file.writelines(the_html)
3267+
out_file.close()
3268+
print('\n>>> [%s] was saved!\n' % file_path)
3269+
return file_path
3270+
3271+
def begin_presentation(self, filename="my_presentation.html", name=None):
3272+
""" Begin a Reveal-JS Presentation in the web browser. """
3273+
3274+
if self.headless:
3275+
return # Presentations should not run in headless mode.
3276+
if not name:
3277+
name = "default"
3278+
if name not in self._presentation_slides:
3279+
raise Exception("Presentation {%s} does not exist!" % name)
3280+
if not filename.endswith('.html'):
3281+
raise Exception('Presentation file must end in ".html"!')
3282+
3283+
end_slide = (
3284+
'<section data-transition="none">'
3285+
'<p class="End_Presentation_Now"> </p></section>')
3286+
self._presentation_slides[name].append(end_slide)
3287+
file_path = self.save_presentation(name=name, filename=filename)
3288+
self._presentation_slides[name].pop()
3289+
3290+
self.open_html_file(file_path)
3291+
presentation_folder = constants.Presentations.SAVED_FOLDER
3292+
while (len(self.driver.window_handles) > 0 and (
3293+
presentation_folder in self.get_current_url())):
3294+
time.sleep(0.1)
3295+
if self.is_element_visible("p.End_Presentation_Now"):
3296+
break
3297+
3298+
############
3299+
31533300
def create_tour(self, name=None, theme=None):
31543301
""" Creates a tour for a website. By default, the Shepherd JavaScript
31553302
Library is used with the Shepherd "Light" / "Arrows" theme.

0 commit comments

Comments
 (0)