Skip to content

Commit 72e48bb

Browse files
committed
Add SeleniumBase "Chart Maker" for pie charts
1 parent 0df878e commit 72e48bb

File tree

5 files changed

+292
-2
lines changed

5 files changed

+292
-2
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,10 @@ allure-report
9090
allure_results
9191
allure-results
9292

93+
# Charts
94+
saved_charts
95+
9396
# Presentations
94-
presentations_saved
9597
saved_presentations
9698

9799
# Tours

help_docs/method_summary.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,18 @@ self.begin_presentation(name=None, filename=None, show_notes=False, interval=0)
371371

372372
############
373373

374+
self.create_pie_chart(chart_name=None, title=None)
375+
376+
self.add_data_point(label, value, color=None, chart_name=None)
377+
378+
self.save_chart(chart_name=None, filename=None)
379+
380+
self.display_chart(chart_name=None, filename=None)
381+
382+
self.extract_chart(chart_name=None)
383+
384+
############
385+
374386
self.create_tour(name=None, theme=None)
375387

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

seleniumbase/console_scripts/sb_mkdir.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def main():
195195
data.append("allure-report")
196196
data.append("allure_results")
197197
data.append("allure-results")
198-
data.append("presentations_saved")
198+
data.append("saved_charts")
199199
data.append("saved_presentations")
200200
data.append("tours_exported")
201201
data.append("images_exported")

seleniumbase/fixtures/base_case.py

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ def __init__(self, *args, **kwargs):
8787
self._html_report_extra = [] # (Used by pytest_plugin.py)
8888
self._default_driver = None
8989
self._drivers_list = []
90+
self._chart_data = {}
9091
self._tour_steps = {}
9192

9293
def open(self, url):
@@ -3437,6 +3438,265 @@ def begin_presentation(
34373438

34383439
############
34393440

3441+
def create_pie_chart(self, chart_name=None, title=None):
3442+
""" Creates a JavaScript pie chart using "HighCharts". """
3443+
if not chart_name:
3444+
chart_name = "default"
3445+
style = "pie"
3446+
unit = "Count"
3447+
self.__create_highchart(
3448+
chart_name=chart_name, title=title, style=style, unit=unit)
3449+
3450+
def __create_highchart(
3451+
self, chart_name=None, title=None, style=None, unit=None):
3452+
""" Creates a JavaScript chart using the "HighCharts" library. """
3453+
if not chart_name:
3454+
chart_name = "default"
3455+
if not title:
3456+
title = ""
3457+
if not style:
3458+
style = "pie"
3459+
if not unit:
3460+
unit = "Count"
3461+
chart_libs = (
3462+
"""
3463+
<script src="%s"></script>
3464+
<script src="%s"></script>
3465+
<script src="%s"></script>
3466+
<script src="%s"></script>
3467+
<script src="%s"></script>
3468+
""" % (
3469+
constants.JQuery.MIN_JS,
3470+
constants.HighCharts.HC_JS,
3471+
constants.HighCharts.EXPORTING_JS,
3472+
constants.HighCharts.EXPORT_DATA_JS,
3473+
constants.HighCharts.ACCESSIBILITY_JS))
3474+
chart_css = (
3475+
"""
3476+
<style>
3477+
.highcharts-figure, .highcharts-data-table table {
3478+
min-width: 320px;
3479+
max-width: 660px;
3480+
margin: 1em auto;
3481+
}
3482+
.highcharts-data-table table {
3483+
font-family: Verdana, sans-serif;
3484+
border-collapse: collapse;
3485+
border: 1px solid #EBEBEB;
3486+
margin: 10px auto;
3487+
text-align: center;
3488+
width: 100%;
3489+
max-width: 500px;
3490+
}
3491+
.highcharts-data-table caption {
3492+
padding: 1em 0;
3493+
font-size: 1.2em;
3494+
color: #555;
3495+
}
3496+
.highcharts-data-table th {
3497+
font-weight: 600;
3498+
padding: 0.5em;
3499+
}
3500+
.highcharts-data-table td, .highcharts-data-table th,
3501+
.highcharts-data-table caption {
3502+
padding: 0.5em;
3503+
}
3504+
.highcharts-data-table thead tr,
3505+
.highcharts-data-table tr:nth-child(even) {
3506+
background: #f8f8f8;
3507+
}
3508+
.highcharts-data-table tr:hover {
3509+
background: #f1f7ff;
3510+
}
3511+
</style>
3512+
""")
3513+
chart_description = ""
3514+
chart_figure = (
3515+
"""
3516+
<figure class="highcharts-figure">
3517+
<div id="container"></div>
3518+
<p class="highcharts-description">%s</p>
3519+
</figure>
3520+
""" % chart_description)
3521+
chart_init_1 = (
3522+
"""
3523+
<script>
3524+
// Build the chart
3525+
Highcharts.chart('container', {
3526+
credits: {
3527+
enabled: false
3528+
},
3529+
title: {
3530+
text: '%s'
3531+
},
3532+
chart: {
3533+
renderTo: 'statusChart',
3534+
plotBackgroundColor: null,
3535+
plotBorderWidth: null,
3536+
plotShadow: false,
3537+
type: '%s'
3538+
},
3539+
""" % (title, style))
3540+
# "{series.name}:" => "Count:" (based on unit)
3541+
point_format = (r'<b>{point.y}</b><br />'
3542+
r'<b>{point.percentage:.1f}%</b>')
3543+
chart_init_2 = (
3544+
"""
3545+
tooltip: {
3546+
pointFormat: '%s'
3547+
},
3548+
""" % point_format)
3549+
chart_init_3 = (
3550+
r"""
3551+
accessibility: {
3552+
point: {
3553+
valueSuffix: '%'
3554+
}
3555+
},
3556+
plotOptions: {
3557+
pie: {
3558+
allowPointSelect: true,
3559+
cursor: 'pointer',
3560+
dataLabels: {
3561+
enabled: false,
3562+
format: '{point.name}: {point.y:.1f}%'
3563+
},
3564+
showInLegend: true
3565+
}
3566+
},
3567+
""")
3568+
chart_init = chart_init_1 + chart_init_2 + chart_init_3
3569+
series = (
3570+
"""
3571+
series: [{
3572+
name: '%s',
3573+
colorByPoint: true,
3574+
data: [
3575+
""" % unit)
3576+
new_chart = chart_libs + chart_css + chart_figure + chart_init + series
3577+
self._chart_data[chart_name] = []
3578+
self._chart_data[chart_name].append(new_chart)
3579+
3580+
def add_data_point(self, label, value, color=None, chart_name=None):
3581+
""" Add a data point to a SeleniumBase-generated chart.
3582+
@Params
3583+
label - The label name for the data point.
3584+
value - The numeric value of the data point.
3585+
color - The HTML color of the data point.
3586+
Can be an RGB color. Eg: "#55ACDC".
3587+
Can also be a named color. Eg: "Teal".
3588+
chart_name - If creating multiple charts,
3589+
use this to select which one.
3590+
"""
3591+
if not chart_name:
3592+
chart_name = "default"
3593+
if chart_name not in self._chart_data:
3594+
# Create a chart if it doesn't already exist
3595+
self.create_pie_chart(chart_name=chart_name)
3596+
if not color:
3597+
color = ""
3598+
data_point = (
3599+
"""
3600+
{
3601+
name: '%s',
3602+
y: %s,
3603+
color: '%s'
3604+
},
3605+
""" % (label, value, color))
3606+
self._chart_data[chart_name].append(data_point)
3607+
3608+
def save_chart(self, chart_name=None, filename=None):
3609+
""" Saves a SeleniumBase-generated chart to a file for later use.
3610+
@Params
3611+
chart_name - If creating multiple charts at the same time,
3612+
use this to select the one you wish to use.
3613+
filename - The name of the HTML file that you wish to
3614+
save the chart to. (filename must end in ".html")
3615+
"""
3616+
if not chart_name:
3617+
chart_name = "default"
3618+
if not filename:
3619+
filename = "my_chart.html"
3620+
if chart_name not in self._chart_data:
3621+
raise Exception("Chart {%s} does not exist!" % chart_name)
3622+
if not filename.endswith('.html'):
3623+
raise Exception('Chart file must end in ".html"!')
3624+
the_html = ""
3625+
for chart_data_point in self._chart_data[chart_name]:
3626+
the_html += chart_data_point
3627+
the_html += (
3628+
"""
3629+
]
3630+
}]
3631+
});
3632+
</script>
3633+
""")
3634+
saved_charts_folder = constants.Charts.SAVED_FOLDER
3635+
if saved_charts_folder.endswith("/"):
3636+
saved_charts_folder = saved_charts_folder[:-1]
3637+
if not os.path.exists(saved_charts_folder):
3638+
try:
3639+
os.makedirs(saved_charts_folder)
3640+
except Exception:
3641+
pass
3642+
file_path = saved_charts_folder + "/" + filename
3643+
out_file = codecs.open(file_path, "w+", encoding="utf-8")
3644+
out_file.writelines(the_html)
3645+
out_file.close()
3646+
print('\n>>> [%s] was saved!' % file_path)
3647+
return file_path
3648+
3649+
def display_chart(self, chart_name=None, filename=None):
3650+
""" Displays a SeleniumBase-generated chart in the browser window.
3651+
@Params
3652+
chart_name - If creating multiple charts at the same time,
3653+
use this to select the one you wish to use.
3654+
filename - The name of the HTML file that you wish to
3655+
save the chart to. (filename must end in ".html")
3656+
"""
3657+
if not chart_name:
3658+
chart_name = "default"
3659+
if not filename:
3660+
filename = "my_chart.html"
3661+
if chart_name not in self._chart_data:
3662+
raise Exception("Chart {%s} does not exist!" % chart_name)
3663+
if not filename.endswith('.html'):
3664+
raise Exception('Chart file must end in ".html"!')
3665+
file_path = self.save_chart(chart_name=chart_name, filename=filename)
3666+
self.open_html_file(file_path)
3667+
chart_folder = constants.Charts.SAVED_FOLDER
3668+
try:
3669+
print("\n*** Close the browser window to continue ***")
3670+
while (len(self.driver.window_handles) > 0 and (
3671+
chart_folder in self.get_current_url())):
3672+
time.sleep(0.05)
3673+
except Exception:
3674+
pass
3675+
3676+
def extract_chart(self, chart_name=None):
3677+
""" Extracts the HTML from a SeleniumBase-generated chart.
3678+
@Params
3679+
chart_name - If creating multiple charts at the same time,
3680+
use this to select the one you wish to use.
3681+
"""
3682+
if not chart_name:
3683+
chart_name = "default"
3684+
if chart_name not in self._chart_data:
3685+
raise Exception("Chart {%s} does not exist!" % chart_name)
3686+
the_html = ""
3687+
for chart_data_point in self._chart_data[chart_name]:
3688+
the_html += chart_data_point
3689+
the_html += (
3690+
"""
3691+
]
3692+
}]
3693+
});
3694+
</script>
3695+
""")
3696+
return the_html
3697+
3698+
############
3699+
34403700
def create_tour(self, name=None, theme=None):
34413701
""" Creates a tour for a website. By default, the Shepherd JavaScript
34423702
Library is used with the Shepherd "Light" / "Arrows" theme.

seleniumbase/fixtures/constants.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ class Presentations:
2323
SAVED_FOLDER = "saved_presentations"
2424

2525

26+
class Charts:
27+
SAVED_FOLDER = "saved_charts"
28+
29+
2630
class SavedCookies:
2731
STORAGE_FOLDER = "saved_cookies"
2832

@@ -123,6 +127,18 @@ class Reveal:
123127
"reveal.js/%s/js/reveal.min.js" % VER)
124128

125129

130+
class HighCharts:
131+
VER = "8.1.2"
132+
HC_CSS = ("https://code.highcharts.com/%s/css/highcharts.css" % VER)
133+
HC_JS = ("https://code.highcharts.com/%s/highcharts.js" % VER)
134+
EXPORTING_JS = ("https://code.highcharts.com/"
135+
"%s/modules/exporting.js" % VER)
136+
EXPORT_DATA_JS = ("https://code.highcharts.com/"
137+
"%s/modules/export-data.js" % VER)
138+
ACCESSIBILITY_JS = ("https://code.highcharts.com/"
139+
"%s/modules/accessibility.js" % VER)
140+
141+
126142
class BootstrapTour:
127143
VER = "0.11.0"
128144
MIN_CSS = ("https://cdnjs.cloudflare.com/ajax/libs/"

0 commit comments

Comments
 (0)