Merge pull request #636 from seleniumbase/chart-maker

Add SeleniumBase "Chart Maker" for creating pie charts
This commit is contained in:
Michael Mintz 2020-07-26 11:41:00 -04:00 committed by GitHub
commit 6b5eaf61f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 568 additions and 23 deletions

4
.gitignore vendored
View File

@ -90,8 +90,10 @@ allure-report
allure_results
allure-results
# Charts
saved_charts
# Presentations
presentations_saved
saved_presentations
# Tours

View File

@ -1,6 +1,6 @@
livereload==2.6.2;python_version>="3.6"
mkdocs==1.1.2
mkdocs-material==5.4.0
mkdocs-material==5.5.0
mkdocs-simple-hooks==0.1.1
mkdocs-material-extensions==1.0
mkdocs-minify-plugin==0.3.0

View File

@ -1,4 +1,4 @@
<p align="center"><a align="center" href="https://github.com/seleniumbase/SeleniumBase/blob/master/README.md"><img align="center" src="https://cdn2.hubspot.net/hubfs/100006/images/super_logo_sb8.png" alt="SeleniumBase" width="290" /></a></p>
<p align="center"><a align="center" href="https://github.com/seleniumbase/SeleniumBase/blob/master/README.md"><img align="center" src="https://cdn2.hubspot.net/hubfs/100006/images/SeleniumBaseText_F.png" alt="SeleniumBase" width="290" /></a></p>
<h2><img src="https://seleniumbase.io/img/sb_icon.png" title="SeleniumBase" width="30" /> Running Example Tests:</h2>
@ -131,7 +131,7 @@ python gui_test_runner.py
--------
<img src="https://cdn2.hubspot.net/hubfs/100006/images/SeleniumBaseText_F.png" title="SeleniumBase" width="290" />
<img src="https://cdn2.hubspot.net/hubfs/100006/images/super_logo_sb8.png" title="SeleniumBase" width="290" />
<a href="https://github.com/seleniumbase/SeleniumBase">
<img src="https://img.shields.io/badge/tested%20with-SeleniumBase-04C38E.svg" alt="Tested with SeleniumBase" /></a>

116
examples/chart_maker/ReadMe.md Executable file
View File

@ -0,0 +1,116 @@
<h3 align="left"><img src="https://cdn2.hubspot.net/hubfs/100006/images/super_logo_sb23.png" alt="SeleniumBase" width="290" /></h3>
# 📊 Chart Maker 📊
SeleniumBase Chart Maker allows you to create HTML charts with Python.<br />
The HighCharts library is used for creating charts.
(Currently only <b>pie charts</b> are supported.)
**Here's a sample chart:**
<a href="https://seleniumbase.io/other/chart_presentation.html"><img width="500" src="https://seleniumbase.io/other/sample_pie_chart.png" title="Screenshot"></a><br>
([Click on the image for the actual chart](https://seleniumbase.io/other/chart_presentation.html))
Here's how to run the example (a chart in a presentation):
```
cd examples/chart_maker
pytest my_chart.py
```
### Creating a new chart:
```python
self.create_pie_chart(chart_name=None, title="My Chart")
""" Creates a JavaScript pie chart using "HighCharts". """
```
If creating multiple charts at the same time, you can pass the ``chart_name`` parameter to distinguish between different charts.
### Adding a data point to a chart:
```python
self.add_data_point(label, value, color=None, chart_name=None):
""" Add a data point to a SeleniumBase-generated chart.
@Params
label - The label name for the data point.
value - The numeric value of the data point.
color - The HTML color of the data point.
Can be an RGB color. Eg: "#55ACDC".
Can also be a named color. Eg: "Teal".
chart_name - If creating multiple charts,
use this to select which one.
"""
```
### Saving a chart to a file:
```python
self.save_chart(chart_name=None, filename=None):
""" Saves a SeleniumBase-generated chart to a file for later use.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the chart to. (filename must end in ".html")
"""
```
The full HTML of the chart is saved to the ``saved_charts/`` folder.
### Extracting the HTML of a chart:
```python
self.extract_chart(chart_name=None):
""" Extracts the HTML from a SeleniumBase-generated chart.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
"""
```
### Displaying a chart in the browser window:
```python
self.display_chart(chart_name=None, filename=None):
""" Displays a SeleniumBase-generated chart in the browser window.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the chart to. (filename must end in ".html")
"""
```
All methods have the optional ``chart_name`` argument, which is only needed if you're creating multiple charts at once.
### Here's an example of using SeleniumBase Chart Maker:
```python
from seleniumbase import BaseCase
class MyChartMakerClass(BaseCase):
def test_chart_maker(self):
self.create_pie_chart(title="Automated Tests")
self.add_data_point("Passed", 7, color="#95d96f")
self.add_data_point("Untested", 2, color="#eaeaea")
self.add_data_point("Failed", 1, color="#f1888f")
self.create_presentation()
self.add_slide(self.extract_chart())
self.begin_presentation()
```
#### This example is from [my_chart.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/chart_maker/my_chart.py), which you can run from the ``examples/chart_maker`` folder with the following command:
```bash
pytest my_chart.py
```

View File

@ -0,0 +1,13 @@
from seleniumbase import BaseCase
class MyChartMakerClass(BaseCase):
def test_chart_maker(self):
self.create_pie_chart(title="Automated Tests")
self.add_data_point("Passed", 7, color="#95d96f")
self.add_data_point("Untested", 2, color="#eaeaea")
self.add_data_point("Failed", 1, color="#f1888f")
self.create_presentation()
self.add_slide(self.extract_chart())
self.begin_presentation()

View File

@ -9,6 +9,8 @@ The Reveal-JS library is used for running the presentations.
<a href="https://seleniumbase.io/other/presenter.html"><img width="500" src="https://seleniumbase.io/other/presenter.gif" title="Screenshot"></a><br>
([Click on the image/GIF for the actual presentation](https://seleniumbase.io/other/presenter.html))
Slides can include HTML, code, images, and iframes.
Here's how to run the example presentation:

116
help_docs/chart_maker.md Executable file
View File

@ -0,0 +1,116 @@
<h3 align="left"><img src="https://cdn2.hubspot.net/hubfs/100006/images/super_logo_sb23.png" alt="SeleniumBase" width="290" /></h3>
# 📊 Chart Maker 📊
SeleniumBase Chart Maker allows you to create HTML charts with Python.<br />
The HighCharts library is used for creating charts.
(Currently only <b>pie charts</b> are supported.)
**Here's a sample chart:**
<a href="https://seleniumbase.io/other/chart_presentation.html"><img width="500" src="https://seleniumbase.io/other/sample_pie_chart.png" title="Screenshot"></a><br>
([Click on the image for the actual chart](https://seleniumbase.io/other/chart_presentation.html))
Here's how to run the example (a chart in a presentation):
```
cd examples/chart_maker
pytest my_chart.py
```
### Creating a new chart:
```python
self.create_pie_chart(chart_name=None, title="My Chart")
""" Creates a JavaScript pie chart using "HighCharts". """
```
If creating multiple charts at the same time, you can pass the ``chart_name`` parameter to distinguish between different charts.
### Adding a data point to a chart:
```python
self.add_data_point(label, value, color=None, chart_name=None):
""" Add a data point to a SeleniumBase-generated chart.
@Params
label - The label name for the data point.
value - The numeric value of the data point.
color - The HTML color of the data point.
Can be an RGB color. Eg: "#55ACDC".
Can also be a named color. Eg: "Teal".
chart_name - If creating multiple charts,
use this to select which one.
"""
```
### Saving a chart to a file:
```python
self.save_chart(chart_name=None, filename=None):
""" Saves a SeleniumBase-generated chart to a file for later use.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the chart to. (filename must end in ".html")
"""
```
The full HTML of the chart is saved to the ``saved_charts/`` folder.
### Extracting the HTML of a chart:
```python
self.extract_chart(chart_name=None):
""" Extracts the HTML from a SeleniumBase-generated chart.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
"""
```
### Displaying a chart in the browser window:
```python
self.display_chart(chart_name=None, filename=None):
""" Displays a SeleniumBase-generated chart in the browser window.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the chart to. (filename must end in ".html")
"""
```
All methods have the optional ``chart_name`` argument, which is only needed if you're creating multiple charts at once.
### Here's an example of using SeleniumBase Chart Maker:
```python
from seleniumbase import BaseCase
class MyChartMakerClass(BaseCase):
def test_chart_maker(self):
self.create_pie_chart(title="Automated Tests")
self.add_data_point("Passed", 7, color="#95d96f")
self.add_data_point("Untested", 2, color="#eaeaea")
self.add_data_point("Failed", 1, color="#f1888f")
self.create_presentation()
self.add_slide(self.extract_chart())
self.begin_presentation()
```
#### This example is from [my_chart.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/chart_maker/my_chart.py), which you can run from the ``examples/chart_maker`` folder with the following command:
```bash
pytest my_chart.py
```

View File

@ -371,6 +371,18 @@ self.begin_presentation(name=None, filename=None, show_notes=False, interval=0)
############
self.create_pie_chart(chart_name=None, title=None)
self.add_data_point(label, value, color=None, chart_name=None)
self.save_chart(chart_name=None, filename=None)
self.display_chart(chart_name=None, filename=None)
self.extract_chart(chart_name=None)
############
self.create_tour(name=None, theme=None)
self.create_shepherd_tour(name=None, theme=None)

View File

@ -74,6 +74,7 @@ nav:
- JS Package Manager: help_docs/js_package_manager.md
- Site Tours: examples/tour_examples/ReadMe.md
- Presenter: examples/presenter/ReadMe.md
- Chart Maker: help_docs/chart_maker.md
- Visual Testing: examples/visual_testing/ReadMe.md
- Integrations:
- Logging and Reports: examples/example_logs/ReadMe.md

View File

@ -7,6 +7,7 @@ wheel>=0.34.2
six==1.15.0
nose==1.3.7
ipdb==0.13.3
parso==0.7.1
jedi==0.17.2
idna==2.10
chardet==3.0.4
@ -38,17 +39,17 @@ pygments==2.5.2;python_version<"3.5"
pygments==2.6.1;python_version>="3.5"
colorama==0.4.3
pymysql==0.10.0
coverage==5.2.1
brython>=3.8.9
coverage==5.2
pyotp==2.3.0
boto==2.49.0
cffi==1.14.0
rich==3.4.1;python_version>="3.6" and python_version<"4.0"
rich==4.1.0;python_version>="3.6" and python_version<"4.0"
flake8==3.7.9;python_version<"3.5"
flake8==3.8.3;python_version>="3.5"
pyflakes==2.1.1;python_version<"3.5"
pyflakes==2.2.0;python_version>="3.5"
certifi>=2020.6.20
allure-pytest==2.8.16
allure-pytest==2.8.17
pdfminer.six==20191110;python_version<"3.5"
pdfminer.six==20200720;python_version>="3.5"
pdfminer.six==20200726;python_version>="3.5"

View File

@ -195,7 +195,7 @@ def main():
data.append("allure-report")
data.append("allure_results")
data.append("allure-results")
data.append("presentations_saved")
data.append("saved_charts")
data.append("saved_presentations")
data.append("tours_exported")
data.append("images_exported")

View File

@ -87,6 +87,7 @@ class BaseCase(unittest.TestCase):
self._html_report_extra = [] # (Used by pytest_plugin.py)
self._default_driver = None
self._drivers_list = []
self._chart_data = {}
self._tour_steps = {}
def open(self, url):
@ -3319,7 +3320,7 @@ class BaseCase(unittest.TestCase):
""" Saves a Reveal-JS Presentation to a file for later use.
@Params
name - If creating multiple presentations at the same time,
use this to select the one you wish to add slides to.
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the presentation to. (filename must end in ".html")
show_notes - When set to True, the Notes feature becomes enabled,
@ -3388,7 +3389,7 @@ class BaseCase(unittest.TestCase):
""" Begin a Reveal-JS Presentation in the web browser.
@Params
name - If creating multiple presentations at the same time,
use this to select the one you wish to add slides to.
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the presentation to. (filename must end in ".html")
show_notes - When set to True, the Notes feature becomes enabled,
@ -3437,6 +3438,265 @@ class BaseCase(unittest.TestCase):
############
def create_pie_chart(self, chart_name=None, title=None):
""" Creates a JavaScript pie chart using "HighCharts". """
if not chart_name:
chart_name = "default"
style = "pie"
unit = "Count"
self.__create_highchart(
chart_name=chart_name, title=title, style=style, unit=unit)
def __create_highchart(
self, chart_name=None, title=None, style=None, unit=None):
""" Creates a JavaScript chart using the "HighCharts" library. """
if not chart_name:
chart_name = "default"
if not title:
title = ""
if not style:
style = "pie"
if not unit:
unit = "Count"
chart_libs = (
"""
<script src="%s"></script>
<script src="%s"></script>
<script src="%s"></script>
<script src="%s"></script>
<script src="%s"></script>
""" % (
constants.JQuery.MIN_JS,
constants.HighCharts.HC_JS,
constants.HighCharts.EXPORTING_JS,
constants.HighCharts.EXPORT_DATA_JS,
constants.HighCharts.ACCESSIBILITY_JS))
chart_css = (
"""
<style>
.highcharts-figure, .highcharts-data-table table {
min-width: 320px;
max-width: 660px;
margin: 1em auto;
}
.highcharts-data-table table {
font-family: Verdana, sans-serif;
border-collapse: collapse;
border: 1px solid #EBEBEB;
margin: 10px auto;
text-align: center;
width: 100%;
max-width: 500px;
}
.highcharts-data-table caption {
padding: 1em 0;
font-size: 1.2em;
color: #555;
}
.highcharts-data-table th {
font-weight: 600;
padding: 0.5em;
}
.highcharts-data-table td, .highcharts-data-table th,
.highcharts-data-table caption {
padding: 0.5em;
}
.highcharts-data-table thead tr,
.highcharts-data-table tr:nth-child(even) {
background: #f8f8f8;
}
.highcharts-data-table tr:hover {
background: #f1f7ff;
}
</style>
""")
chart_description = ""
chart_figure = (
"""
<figure class="highcharts-figure">
<div id="container"></div>
<p class="highcharts-description">%s</p>
</figure>
""" % chart_description)
chart_init_1 = (
"""
<script>
// Build the chart
Highcharts.chart('container', {
credits: {
enabled: false
},
title: {
text: '%s'
},
chart: {
renderTo: 'statusChart',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: '%s'
},
""" % (title, style))
# "{series.name}:" => "Count:" (based on unit)
point_format = (r'<b>{point.y}</b><br />'
r'<b>{point.percentage:.1f}%</b>')
chart_init_2 = (
"""
tooltip: {
pointFormat: '%s'
},
""" % point_format)
chart_init_3 = (
r"""
accessibility: {
point: {
valueSuffix: '%'
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false,
format: '{point.name}: {point.y:.1f}%'
},
showInLegend: true
}
},
""")
chart_init = chart_init_1 + chart_init_2 + chart_init_3
series = (
"""
series: [{
name: '%s',
colorByPoint: true,
data: [
""" % unit)
new_chart = chart_libs + chart_css + chart_figure + chart_init + series
self._chart_data[chart_name] = []
self._chart_data[chart_name].append(new_chart)
def add_data_point(self, label, value, color=None, chart_name=None):
""" Add a data point to a SeleniumBase-generated chart.
@Params
label - The label name for the data point.
value - The numeric value of the data point.
color - The HTML color of the data point.
Can be an RGB color. Eg: "#55ACDC".
Can also be a named color. Eg: "Teal".
chart_name - If creating multiple charts,
use this to select which one.
"""
if not chart_name:
chart_name = "default"
if chart_name not in self._chart_data:
# Create a chart if it doesn't already exist
self.create_pie_chart(chart_name=chart_name)
if not color:
color = ""
data_point = (
"""
{
name: '%s',
y: %s,
color: '%s'
},
""" % (label, value, color))
self._chart_data[chart_name].append(data_point)
def save_chart(self, chart_name=None, filename=None):
""" Saves a SeleniumBase-generated chart to a file for later use.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the chart to. (filename must end in ".html")
"""
if not chart_name:
chart_name = "default"
if not filename:
filename = "my_chart.html"
if chart_name not in self._chart_data:
raise Exception("Chart {%s} does not exist!" % chart_name)
if not filename.endswith('.html'):
raise Exception('Chart file must end in ".html"!')
the_html = ""
for chart_data_point in self._chart_data[chart_name]:
the_html += chart_data_point
the_html += (
"""
]
}]
});
</script>
""")
saved_charts_folder = constants.Charts.SAVED_FOLDER
if saved_charts_folder.endswith("/"):
saved_charts_folder = saved_charts_folder[:-1]
if not os.path.exists(saved_charts_folder):
try:
os.makedirs(saved_charts_folder)
except Exception:
pass
file_path = saved_charts_folder + "/" + filename
out_file = codecs.open(file_path, "w+", encoding="utf-8")
out_file.writelines(the_html)
out_file.close()
print('\n>>> [%s] was saved!' % file_path)
return file_path
def display_chart(self, chart_name=None, filename=None):
""" Displays a SeleniumBase-generated chart in the browser window.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
filename - The name of the HTML file that you wish to
save the chart to. (filename must end in ".html")
"""
if not chart_name:
chart_name = "default"
if not filename:
filename = "my_chart.html"
if chart_name not in self._chart_data:
raise Exception("Chart {%s} does not exist!" % chart_name)
if not filename.endswith('.html'):
raise Exception('Chart file must end in ".html"!')
file_path = self.save_chart(chart_name=chart_name, filename=filename)
self.open_html_file(file_path)
chart_folder = constants.Charts.SAVED_FOLDER
try:
print("\n*** Close the browser window to continue ***")
while (len(self.driver.window_handles) > 0 and (
chart_folder in self.get_current_url())):
time.sleep(0.05)
except Exception:
pass
def extract_chart(self, chart_name=None):
""" Extracts the HTML from a SeleniumBase-generated chart.
@Params
chart_name - If creating multiple charts at the same time,
use this to select the one you wish to use.
"""
if not chart_name:
chart_name = "default"
if chart_name not in self._chart_data:
raise Exception("Chart {%s} does not exist!" % chart_name)
the_html = ""
for chart_data_point in self._chart_data[chart_name]:
the_html += chart_data_point
the_html += (
"""
]
}]
});
</script>
""")
return the_html
############
def create_tour(self, name=None, theme=None):
""" Creates a tour for a website. By default, the Shepherd JavaScript
Library is used with the Shepherd "Light" / "Arrows" theme.
@ -3456,25 +3716,30 @@ class BaseCase(unittest.TestCase):
if theme:
if theme.lower() == "bootstrap":
self.create_bootstrap_tour(name)
return
elif theme.lower() == "hopscotch":
self.create_hopscotch_tour(name)
return
elif theme.lower() == "intro":
self.create_introjs_tour(name)
return
elif theme.lower() == "introjs":
self.create_introjs_tour(name)
return
elif theme.lower() == "driver":
self.create_driverjs_tour(name)
return
elif theme.lower() == "driverjs":
self.create_driverjs_tour(name)
return
elif theme.lower() == "shepherd":
self.create_shepherd_tour(name, theme="light")
return
elif theme.lower() == "light":
self.create_shepherd_tour(name, theme="light")
elif theme.lower() == "dark":
self.create_shepherd_tour(name, theme="dark")
elif theme.lower() == "arrows":
self.create_shepherd_tour(name, theme="light")
elif theme.lower() == "square":
self.create_shepherd_tour(name, theme="square")
elif theme.lower() == "square-dark":
self.create_shepherd_tour(name, theme="square-dark")
elif theme.lower() == "default":
self.create_shepherd_tour(name, theme="default")
else:
self.create_shepherd_tour(name, theme)
else:

View File

@ -23,6 +23,10 @@ class Presentations:
SAVED_FOLDER = "saved_presentations"
class Charts:
SAVED_FOLDER = "saved_charts"
class SavedCookies:
STORAGE_FOLDER = "saved_cookies"
@ -123,6 +127,18 @@ class Reveal:
"reveal.js/%s/js/reveal.min.js" % VER)
class HighCharts:
VER = "8.1.2"
HC_CSS = ("https://code.highcharts.com/%s/css/highcharts.css" % VER)
HC_JS = ("https://code.highcharts.com/%s/highcharts.js" % VER)
EXPORTING_JS = ("https://code.highcharts.com/"
"%s/modules/exporting.js" % VER)
EXPORT_DATA_JS = ("https://code.highcharts.com/"
"%s/modules/export-data.js" % VER)
ACCESSIBILITY_JS = ("https://code.highcharts.com/"
"%s/modules/accessibility.js" % VER)
class BootstrapTour:
VER = "0.11.0"
MIN_CSS = ("https://cdnjs.cloudflare.com/ajax/libs/"

View File

@ -54,7 +54,7 @@ if sys.argv[-1] == 'publish':
setup(
name='seleniumbase',
version='1.43.1',
version='1.44.0',
description='Fast, Easy, and Reliable Browser Automation & Testing.',
long_description=long_description,
long_description_content_type='text/markdown',
@ -99,6 +99,7 @@ setup(
'six',
'nose',
'ipdb',
'parso==0.7.1', # The last version for Python 2 and 3.5
'jedi==0.17.2', # The last version for Python 2 and 3.5
'idna==2.10', # Must stay in sync with "requests"
'chardet==3.0.4', # Must stay in sync with "requests"
@ -130,20 +131,20 @@ setup(
'pygments==2.6.1;python_version>="3.5"',
'colorama==0.4.3',
'pymysql==0.10.0',
'coverage==5.2.1',
'brython>=3.8.9',
'coverage==5.2',
'pyotp==2.3.0',
'boto==2.49.0',
'cffi==1.14.0',
'rich==3.4.1;python_version>="3.6" and python_version<"4.0"',
'rich==4.1.0;python_version>="3.6" and python_version<"4.0"',
'flake8==3.7.9;python_version<"3.5"',
'flake8==3.8.3;python_version>="3.5"',
'pyflakes==2.1.1;python_version<"3.5"',
'pyflakes==2.2.0;python_version>="3.5"',
'certifi>=2020.6.20',
'allure-pytest==2.8.16',
'allure-pytest==2.8.17',
'pdfminer.six==20191110;python_version<"3.5"',
'pdfminer.six==20200720;python_version>="3.5"',
'pdfminer.six==20200726;python_version>="3.5"',
],
packages=[
'seleniumbase',