Merge branch '11_Redirect_to_edit_vehicle_page_if_no_consumable_is_configured' into 'development'
11 redirect to edit vehicle page if no consumable is configured See merge request !28
This commit is contained in:
commit
bb7c2780e8
|
@ -1,4 +1,6 @@
|
||||||
.idea/
|
.idea/
|
||||||
|
tests/results/
|
||||||
**.DS_Store
|
**.DS_Store
|
||||||
**.swp
|
**.swp
|
||||||
**.pyc
|
**.pyc
|
||||||
|
*.sqlite
|
|
@ -1,6 +1,4 @@
|
||||||
from datetime import date
|
from flask import Flask, flash
|
||||||
|
|
||||||
from flask import Flask
|
|
||||||
from flask import redirect, g
|
from flask import redirect, g
|
||||||
from flask import render_template
|
from flask import render_template
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
@ -58,6 +56,10 @@ def user_registered_sighandler(app, user, confirm_token):
|
||||||
"""
|
"""
|
||||||
role = user_datastore.find_role('user')
|
role = user_datastore.find_role('user')
|
||||||
user_datastore.add_role_to_user(user, role)
|
user_datastore.add_role_to_user(user, role)
|
||||||
|
if user.email == app.config['ADMIN_MAIL']:
|
||||||
|
# if the user selected the preconfigured email for the admin account
|
||||||
|
role = user_datastore.find_role('admin')
|
||||||
|
user_datastore.add_role_to_user(user, role)
|
||||||
new_vehicle = Vehicle('default vehicle')
|
new_vehicle = Vehicle('default vehicle')
|
||||||
db.session.add(new_vehicle)
|
db.session.add(new_vehicle)
|
||||||
user.vehicles.append(new_vehicle)
|
user.vehicles.append(new_vehicle)
|
||||||
|
@ -237,6 +239,10 @@ def select_consumable_for_new_pitstop(vid):
|
||||||
if vehicle is None or vehicle not in current_user.vehicles:
|
if vehicle is None or vehicle not in current_user.vehicles:
|
||||||
return redirect(url_for('select_vehicle_for_new_pitstop'))
|
return redirect(url_for('select_vehicle_for_new_pitstop'))
|
||||||
|
|
||||||
|
if len(vehicle.consumables) == 0:
|
||||||
|
flash('Please choose at least one consumable!', 'warning')
|
||||||
|
return redirect(url_for('edit_vehicle', vid=vid))
|
||||||
|
|
||||||
if len(vehicle.consumables) == 1:
|
if len(vehicle.consumables) == 1:
|
||||||
return redirect(url_for('create_pit_stop_form', vid=vid, cid=vehicle.consumables[0].id))
|
return redirect(url_for('create_pit_stop_form', vid=vid, cid=vehicle.consumables[0].id))
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.starter-template {
|
.starter-template {
|
||||||
padding-top: 30px;
|
padding-top: 0px;
|
||||||
padding-bottom: 60px;
|
padding-bottom: 60px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,14 @@ h3:after{
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
margin-bottom:0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topspace {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
// for small devices
|
// for small devices
|
||||||
@media only screen
|
@media only screen
|
||||||
and (min-device-width : 320px)
|
and (min-device-width : 320px)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Password</div>
|
<div class="panel-heading">Password</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<a href='{{ url_for('security.change_password') }}' class="btn btn-primary " role="button">
|
<a href="{{ url_for('security.change_password') }}" id="change_password" class="btn btn-primary " role="button">
|
||||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Change
|
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Change
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Vehicles</div>
|
<div class="panel-heading">Vehicles</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<a href="{{ url_for('create_vehicle') }}" class="btn btn-primary " role="button">
|
<a href="{{ url_for('create_vehicle') }}" id="create_vehicle" class="btn btn-primary " role="button">
|
||||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> create
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> create
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -40,11 +40,11 @@
|
||||||
{{ vehicle.consumables | length }} consumables
|
{{ vehicle.consumables | length }} consumables
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('edit_vehicle', vid=vehicle.id) }}" class="btn btn-primary " role="button">
|
<a href="{{ url_for('edit_vehicle', vid=vehicle.id) }}" id="edit_vehicle_{{loop.index}}" class="btn btn-primary " role="button">
|
||||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
||||||
</a>
|
</a>
|
||||||
{% if current_user.vehicles | length > 1 %}
|
{% if current_user.vehicles | length > 1 %}
|
||||||
<a href="{{ url_for('delete_vehicle', vid=vehicle.id) }}" class="btn btn-primary btn-warning " role="button">
|
<a href="{{ url_for('delete_vehicle', vid=vehicle.id) }}" id="delete_vehicle_{{loop.index}}" class="btn btn-primary btn-warning " role="button">
|
||||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Account</div>
|
<div class="panel-heading">Account</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<a href='{{ url_for('delete_account') }}' class="btn btn-primary " role="button">
|
<a href="{{ url_for('delete_account') }}" id="delete_account" class="btn btn-primary " role="button">
|
||||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Delete
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Delete
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Consumables</div>
|
<div class="panel-heading">Consumables</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<a href="{{ url_for('create_consumable') }}" class="btn btn-primary " role="button">
|
<a href="{{ url_for('create_consumable') }}" id="create_consumable" class="btn btn-primary " role="button">
|
||||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> create
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> create
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,22 +38,16 @@
|
||||||
</tr>
|
</tr>
|
||||||
{% for consumable in consumables %}
|
{% for consumable in consumables %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td id="name_{{loop.index}}">{{ consumable.name }}</td>
|
||||||
{{ consumable.name }}
|
<td id="unit_{{loop.index}}">{{ consumable.unit }}</td>
|
||||||
</td>
|
<td id="count_{{loop.index}}">{{ consumable.vehicles | length }} vehicles</td>
|
||||||
<td>
|
|
||||||
{{ consumable.unit }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ consumable.vehicles | length }} vehicles
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
{% if not consumable.in_use %}
|
{% if not consumable.in_use %}
|
||||||
<a href="{{ url_for('delete_consumable', cid=consumable.id) }}" class="btn btn-primary btn-warning " role="button">
|
<a href="{{ url_for('delete_consumable', cid=consumable.id) }}" id="delete_consumable{{loop.index}}" class="btn btn-primary btn-warning " role="button">
|
||||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ url_for('edit_consumable', cid=consumable.id) }}" class="btn btn-primary " role="button">
|
<a href="{{ url_for('edit_consumable', cid=consumable.id) }}" id="edit_consumable{{loop.index}}" class="btn btn-primary " role="button">
|
||||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<h3>Delete vehicle '{{consumable.name}}'?</h3>
|
<h3>Delete consumable '{{consumable.name}}'?</h3>
|
||||||
<form class='form-horizontal' method="POST">
|
<form class='form-horizontal' method="POST">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ render_field_with_errors(form.submit) }}
|
{{ render_field_with_errors(form.submit) }}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<h3>Edit consumable </h3>
|
<h3>Edit consumable</h3>
|
||||||
<form class='form-horizontal' method="POST">
|
<form class='form-horizontal' method="POST">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ render_field_with_errors(form.name) }}
|
{{ render_field_with_errors(form.name) }}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<h3>Edit vehicle</h3>
|
<h3>Edit vehicle '{{vehicle.name}}'</h3>
|
||||||
<form class='form-horizontal' method="POST">
|
<form class='form-horizontal' method="POST">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ render_field_with_errors(form.name) }}
|
{{ render_field_with_errors(form.name) }}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
{% macro navigation() -%}
|
{% macro navigation() -%}
|
||||||
{% if current_user.email %}
|
{% if current_user.email %}
|
||||||
<li><a href='{{ url_for('select_vehicle_for_new_pitstop') }}'>Create Pitstop</a></li>
|
<li><a id='new_pitstop_link' href='{{ url_for('select_vehicle_for_new_pitstop') }}'>Create Pitstop</a></li>
|
||||||
<li><a href='{{ url_for('get_statistics') }}'>Statistics</a></li>
|
<li><a id='statistics_limk' href='{{ url_for('get_statistics') }}'>Statistics</a></li>
|
||||||
<li><a href='{{ url_for('get_account_page') }}'>Account</a></li>
|
<li><a id='account_link' href='{{ url_for('get_account_page') }}'>Account</a></li>
|
||||||
{% if current_user.has_role('admin') %}
|
{% if current_user.has_role('admin') %}
|
||||||
<li><a href='{{ url_for('get_admin_page') }}'>Admin</a></li>
|
<li><a id='admin_link' href='{{ url_for('get_admin_page') }}'>Admin</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href='{{ url_for('security.logout') }}'>Logout</a></li>
|
<li><a id='logout_link' href='{{ url_for('security.logout') }}'>Logout</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a href='{{ url_for('security.login') }}'>Login</a></li>
|
<li><a id='login_link' href='{{ url_for('security.login') }}'>Login</a></li>
|
||||||
<li><a href='{{ url_for('security.register') }}'>Register</a></li>
|
<li><a id='register_link' href='{{ url_for('security.register') }}'>Register</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
@ -151,8 +151,23 @@
|
||||||
</div><!--/.nav-collapse -->
|
</div><!--/.nav-collapse -->
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
<div class="container">
|
{% if messages %}
|
||||||
|
{% for category, message in messages %}
|
||||||
|
<div class="row topspace">
|
||||||
|
<div class="col-md-4" ></div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="alert alert-{{category}} alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4" ></div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
<div class="container topspace">
|
||||||
<div class="starter-template">
|
<div class="starter-template">
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
<div id="my-tab-content" class="tab-content">
|
<div id="my-tab-content" class="tab-content">
|
||||||
{% for vehicle in current_user.vehicles %}
|
{% for vehicle in current_user.vehicles %}
|
||||||
|
{% set vehicleloop = loop %}
|
||||||
<div class="tab-pane {% if loop.first %}active{% endif %}" id="v{{vehicle.id}}">
|
<div class="tab-pane {% if loop.first %}active{% endif %}" id="v{{vehicle.id}}">
|
||||||
<h3>{{vehicle.name}}</h3>
|
<h3>{{vehicle.name}}</h3>
|
||||||
{% if vehicle.pitstops %}
|
{% if vehicle.pitstops %}
|
||||||
|
@ -22,19 +23,19 @@
|
||||||
<table class="table table-striped table-bordered table-condensed">
|
<table class="table table-striped table-bordered table-condensed">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<td>{{pitstop.date}}</td>
|
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_date">{{pitstop.date}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Odometer</th>
|
<th>Odometer</th>
|
||||||
<td>{{pitstop.odometer}} km</td>
|
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_odo">{{pitstop.odometer}} km</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ pitstop.consumable.name }}</th>
|
<th>{{ pitstop.consumable.name }}</th>
|
||||||
<td>{{pitstop.amount}} {{ pitstop.consumable.unit }}</td>
|
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_anmount">{{pitstop.amount}} {{ pitstop.consumable.unit }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Costs</th>
|
<th>Costs</th>
|
||||||
<td>
|
<td id="vehicle_{{vehicleloop.index}}_pitstop_{{loop.index}}_cost">
|
||||||
{% if pitstop.costs %}
|
{% if pitstop.costs %}
|
||||||
{{pitstop.costs}} €
|
{{pitstop.costs}} €
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -44,10 +45,10 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
{% if loop.first %}
|
{% if loop.first %}
|
||||||
<a href="{{ url_for('edit_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary">
|
<a id="vehicle_{{vehicleloop.index}}_edit_pitstop_{{loop.index}}" href="{{ url_for('edit_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary">
|
||||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> edit
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ url_for('delete_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary btn-warning ">
|
<a id="vehicle_{{vehicleloop.index}}_delete_pitstop_{{loop.index}}" href="{{ url_for('delete_pit_stop_form', pid=pitstop.id) }}" class="btn btn-primary btn-warning ">
|
||||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> delete
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -17,6 +17,7 @@ class Config:
|
||||||
MAIL_USE_SSL = False
|
MAIL_USE_SSL = False
|
||||||
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
||||||
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
|
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
|
||||||
|
ADMIN_MAIL = 'joachim@lusiardi.de'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def init_app(app):
|
def init_app(app):
|
||||||
|
@ -26,7 +27,7 @@ class Config:
|
||||||
class DevelopmentConfig(Config):
|
class DevelopmentConfig(Config):
|
||||||
SECURITY_SEND_REGISTER_EMAIL = False
|
SECURITY_SEND_REGISTER_EMAIL = False
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:%s@database/pitstops' % (os.environ['DATABASE_ENV_MYSQL_ROOT_PASSWORD'])
|
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:%s@database/pitstops' % (os.environ.get('DATABASE_ENV_MYSQL_ROOT_PASSWORD'))
|
||||||
|
|
||||||
|
|
||||||
class TestingConfig(Config):
|
class TestingConfig(Config):
|
||||||
|
|
|
@ -2,19 +2,11 @@ version: '2'
|
||||||
services:
|
services:
|
||||||
rollerverbrauch:
|
rollerverbrauch:
|
||||||
build: .
|
build: .
|
||||||
depends_on:
|
|
||||||
- database
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./compose_config/:/config
|
- ./compose_config/:/config
|
||||||
environment:
|
environment:
|
||||||
- config=/config/config.py
|
- config=/config/config.py
|
||||||
- DATABASE_ENV_MYSQL_ROOT_PASSWORD=foobar123
|
- DATABASE_ENV_MYSQL_ROOT_PASSWORD=foobar123
|
||||||
|
- FLASK_CONFIG=testing
|
||||||
ports:
|
ports:
|
||||||
- 5000
|
- 5000:5000
|
||||||
database:
|
|
||||||
image: mysql
|
|
||||||
environment:
|
|
||||||
- MYSQL_ROOT_PASSWORD=foobar123
|
|
||||||
- MYSQL_DATABASE=pitstops
|
|
||||||
ports:
|
|
||||||
- 3306
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM debian8_python3
|
||||||
|
|
||||||
|
COPY app/requirements.txt /requirements.txt
|
||||||
|
RUN pip3 install -r /requirements.txt; \
|
||||||
|
mkdir /data
|
||||||
|
|
||||||
|
ADD app /app
|
||||||
|
|
||||||
|
VOLUME ["/data"]
|
||||||
|
VOLUME ["/app/config]
|
||||||
|
EXPOSE 5000
|
||||||
|
ENTRYPOINT python3 /app/main.py
|
|
@ -0,0 +1,137 @@
|
||||||
|
import unittest
|
||||||
|
import inspect
|
||||||
|
from selenium import webdriver
|
||||||
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
|
from selenium.webdriver.support import expected_conditions
|
||||||
|
|
||||||
|
|
||||||
|
def wait_net_service(server, port, timeout=None):
|
||||||
|
""" Wait for network service to appear
|
||||||
|
@param timeout: in seconds, if None or 0 wait forever
|
||||||
|
@return: True of False, if timeout is None may return only True or
|
||||||
|
throw unhandled network exception
|
||||||
|
"""
|
||||||
|
import socket
|
||||||
|
import errno
|
||||||
|
|
||||||
|
s = socket.socket()
|
||||||
|
if timeout:
|
||||||
|
from time import time as now
|
||||||
|
# time module is needed to calc timeout shared between two exceptions
|
||||||
|
end = now() + timeout
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if timeout:
|
||||||
|
next_timeout = end - now()
|
||||||
|
if next_timeout < 0:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
s.settimeout(next_timeout)
|
||||||
|
|
||||||
|
s.connect((server, port))
|
||||||
|
|
||||||
|
except socket.timeout as err:
|
||||||
|
# this exception occurs only if timeout is set
|
||||||
|
if timeout:
|
||||||
|
return False
|
||||||
|
|
||||||
|
except socket.error as err:
|
||||||
|
# catch timeout exception from underlying network library
|
||||||
|
# this one is different from socket.timeout
|
||||||
|
if type(err.args) != tuple or err[0] != errno.ETIMEDOUT:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
s.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.screen_shot_counter = 0
|
||||||
|
self.driver = webdriver.Remote(
|
||||||
|
command_executor='http://selenium:4444/wd/hub',
|
||||||
|
desired_capabilities=DesiredCapabilities.FIREFOX)
|
||||||
|
self.driver.get("http://rollerverbrauch:5000")
|
||||||
|
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "email")))
|
||||||
|
|
||||||
|
def create_screenshot(self):
|
||||||
|
self.driver.get_screenshot_as_file(
|
||||||
|
'/results/%s_%s_%s.png' % (self.__class__.__name__, inspect.stack()[1][3], str(self.screen_shot_counter)))
|
||||||
|
self.screen_shot_counter += 1
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.driver.close()
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterCheck(BaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.screen_shot_counter = 0
|
||||||
|
self.driver = webdriver.Remote(
|
||||||
|
command_executor='http://selenium:4444/wd/hub',
|
||||||
|
desired_capabilities=DesiredCapabilities.FIREFOX)
|
||||||
|
self.driver.get("http://rollerverbrauch:5000")
|
||||||
|
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "email")))
|
||||||
|
|
||||||
|
def test_page_loads(self):
|
||||||
|
self.driver.get("http://rollerverbrauch:5000")
|
||||||
|
self.create_screenshot()
|
||||||
|
self.assertIn("refuel", self.driver.title, "Title must contain reload")
|
||||||
|
|
||||||
|
def test_can_register(self):
|
||||||
|
self.driver.get("http://rollerverbrauch:5000")
|
||||||
|
self.driver.find_element_by_partial_link_text('Register').click()
|
||||||
|
self.create_screenshot()
|
||||||
|
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "submit")))
|
||||||
|
self.create_screenshot()
|
||||||
|
self.driver.find_element_by_id('email').send_keys('test@test.com')
|
||||||
|
self.driver.find_element_by_id('password').send_keys('test123')
|
||||||
|
self.driver.find_element_by_id('password_confirm').send_keys('test123')
|
||||||
|
self.create_screenshot()
|
||||||
|
self.driver.find_element_by_id('submit').click()
|
||||||
|
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "i1")))
|
||||||
|
self.create_screenshot()
|
||||||
|
|
||||||
|
def test_register_must_repeat_pwd(self):
|
||||||
|
self.driver.get("http://rollerverbrauch:5000")
|
||||||
|
self.driver.find_element_by_partial_link_text('Register').click()
|
||||||
|
self.create_screenshot()
|
||||||
|
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "submit")))
|
||||||
|
self.create_screenshot()
|
||||||
|
self.driver.find_element_by_id('email').send_keys('test1@test.com')
|
||||||
|
self.driver.find_element_by_id('password').send_keys('test123')
|
||||||
|
self.create_screenshot()
|
||||||
|
self.driver.find_element_by_id('submit').click()
|
||||||
|
self.create_screenshot()
|
||||||
|
error = self.driver.find_elements_by_class_name('error')
|
||||||
|
self.assertIsNotNone(error[0], 'we expect an error')
|
||||||
|
self.assertIn('Passwords do not match', error[0].text, 'wrong error message')
|
||||||
|
|
||||||
|
def test_register_must_be_equal_pwd(self):
|
||||||
|
self.driver.get("http://rollerverbrauch:5000")
|
||||||
|
self.driver.find_element_by_partial_link_text('Register').click()
|
||||||
|
self.create_screenshot()
|
||||||
|
WebDriverWait(self.driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "submit")))
|
||||||
|
self.create_screenshot()
|
||||||
|
self.driver.find_element_by_id('email').send_keys('test1@test.com')
|
||||||
|
self.driver.find_element_by_id('password').send_keys('test123')
|
||||||
|
self.driver.find_element_by_id('password_confirm').send_keys('test1234')
|
||||||
|
self.create_screenshot()
|
||||||
|
self.driver.find_element_by_id('submit').click()
|
||||||
|
self.create_screenshot()
|
||||||
|
error = self.driver.find_elements_by_class_name('error')
|
||||||
|
self.assertIsNotNone(error[0], 'we expect an error')
|
||||||
|
self.assertIn('Passwords do not match', error[0].text, 'wrong error message')
|
||||||
|
|
||||||
|
|
||||||
|
class LoginCheck(BaseTestCase):
|
||||||
|
|
||||||
|
def can_login(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
wait_net_service('selenium', 4444)
|
||||||
|
unittest.main()
|
|
@ -0,0 +1 @@
|
||||||
|
selenium
|
|
@ -0,0 +1,16 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
#SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:%s@database/pitstops' % (os.environ['DATABASE_ENV_MYSQL_ROOT_PASSWORD'])
|
||||||
|
SQLALCHEMY_DATABASE_URI = 'sqlite:////data/rollerverbrauch.db'
|
||||||
|
|
||||||
|
MAIL_SERVER = ''
|
||||||
|
MAIL_PORT= 25
|
||||||
|
MAIL_USE_TLS = True
|
||||||
|
MAIL_USE_SSL = False
|
||||||
|
MAIL_USERNAME = ''
|
||||||
|
MAIL_PASSWORD = ''
|
||||||
|
SECURITY_EMAIL_SENDER = ''
|
||||||
|
SECURITY_PASSWORD_SALT = 'SecretSalt'
|
||||||
|
SECRET_KEY = 'SecretKey'
|
||||||
|
|
||||||
|
SECURITY_SEND_REGISTER_EMAIL = False
|
|
@ -0,0 +1,22 @@
|
||||||
|
version: '2'
|
||||||
|
services:
|
||||||
|
tests:
|
||||||
|
build: .
|
||||||
|
depends_on:
|
||||||
|
- selenium
|
||||||
|
volumes:
|
||||||
|
- ./results:/results
|
||||||
|
selenium:
|
||||||
|
image: selenium/standalone-firefox
|
||||||
|
depends_on:
|
||||||
|
- rollerverbrauch
|
||||||
|
rollerverbrauch:
|
||||||
|
build: ..
|
||||||
|
volumes:
|
||||||
|
- ./compose_config/:/config
|
||||||
|
environment:
|
||||||
|
- config=/config/config.py
|
||||||
|
- DATABASE_ENV_MYSQL_ROOT_PASSWORD=foobar123
|
||||||
|
ports:
|
||||||
|
- 5000
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
rm -f results/*
|
||||||
|
docker-compose build
|
||||||
|
docker-compose up --abort-on-container-exit
|
||||||
|
docker-compose down
|
||||||
|
docker-compose rm --all
|
Loading…
Reference in New Issue