LiveTest register device

This commit is contained in:
Tom Irgang 2023-04-25 11:06:31 +02:00
parent f852a89e8a
commit 904d009fc9
13 changed files with 213 additions and 68 deletions

View file

@ -7,13 +7,13 @@ For documentation see https://makes-hacks-hip.github.io/RepApp/.
## Setup for development ## Setup for development
- Clone repo - Clone repo
- python -m venv venv - `python -m venv venv`
- source venv/bin/activate - `source venv/bin/activate`
- cd rc_hip - `cd rc_hip`
- python manage.py makemigrations - `python manage.py makemigrations`
- python manage.py migrate - `python manage.py migrate`
- python manage.py createsuperuser - `python manage.py createsuperuser`
- python manage.py runserver - `python manage.py runserver`
## Build Docker image ## Build Docker image
@ -30,3 +30,13 @@ docker run --rm -d \
repapp` repapp`
``` ```
- Open `http://127.0.0.1:8020/` in your browser - Open `http://127.0.0.1:8020/` in your browser
## Run tests
### Unit tests
Run `python manage.py test`
### LiveServer Tests
Run `python manage.py test repapp.live_tests.WorkflowTests`

View file

@ -8,6 +8,21 @@ from .models import (Organisator, Cafe, Question, Device, CustomUser,
Reparateur, Appointment, Guest, Candidate, OneTimeLogin, Message) Reparateur, Appointment, Guest, Candidate, OneTimeLogin, Message)
class CafeResource(resources.ModelResource):
"""
Resource wrapper for Cafe model.
"""
class Meta:
"""
Meta data for resource model.
"""
model = Cafe
@staticmethod
def get_display_name():
return "Repair-Café"
class GuestResource(resources.ModelResource): class GuestResource(resources.ModelResource):
""" """
Resource wrapper for Guest model. Resource wrapper for Guest model.
@ -93,17 +108,18 @@ class ExportAdmin(ImportExportModelAdmin, ExportActionMixin):
QuestionResource, QuestionResource,
AppointmentResource, AppointmentResource,
CandidateResource, CandidateResource,
CafeResource,
] ]
# Register all models of RepApp for the admin interface. # Register all models of RepApp for the admin interface.
admin.site.register(Organisator) admin.site.register(Organisator)
admin.site.register(Cafe)
admin.site.register(Reparateur) admin.site.register(Reparateur)
admin.site.register(CustomUser) admin.site.register(CustomUser)
admin.site.register(OneTimeLogin) admin.site.register(OneTimeLogin)
admin.site.register(Message) admin.site.register(Message)
# Make the "data" models exportable. # Make the "data" models exportable.
admin.site.register(Cafe, ExportAdmin)
admin.site.register(Question, ExportAdmin) admin.site.register(Question, ExportAdmin)
admin.site.register(Guest, ExportAdmin) admin.site.register(Guest, ExportAdmin)
admin.site.register(Device, ExportAdmin) admin.site.register(Device, ExportAdmin)

View file

@ -14,7 +14,6 @@ class OneTimeLoginBackend(ModelBackend):
""" """
def authenticate(self, request, username=None, password=None, **kwargs): def authenticate(self, request, username=None, password=None, **kwargs):
print(f'authenticate {username}')
login = OneTimeLogin.objects.filter(secret=username).first() login = OneTimeLogin.objects.filter(secret=username).first()
if login: if login:
return login.user return login.user

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

View file

@ -0,0 +1,11 @@
[
{
"model": "repapp.cafe",
"pk": 1,
"fields": {
"location": "Haus Einstein' (beim Gymnasium)",
"address": "Patersholzer Weg 19, Hilpoltstein",
"event_date": "2023-05-13"
}
}
]

112
rc_hip/repapp/live_tests.py Normal file
View file

@ -0,0 +1,112 @@
import time
import os
from pathlib import Path
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.webdriver import WebDriver
class WorkflowTests(StaticLiveServerTestCase):
fixtures = ["cafe-data.json"]
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.selenium = WebDriver()
cls.selenium.implicitly_wait(10)
@classmethod
def tearDownClass(cls):
cls.selenium.quit()
super().tearDownClass()
def test_register_device(self):
# Open landing page
self.selenium.get(f"{self.live_server_url}/")
# Click on a register link
self.selenium.find_element(By.CLASS_NAME, "register_link").click()
time.sleep(1)
# Enter new device
# Enter guest mail address
mail = self.selenium.find_element(By.NAME, "mail")
mail.send_keys("guest@example.com")
# Enter device
device = self.selenium.find_element(By.NAME, "device")
device.send_keys("A Test Device")
# Enter manufacturer
manufacturer = self.selenium.find_element(By.NAME, "manufacturer")
manufacturer.send_keys("A Test Manufacturer")
# Enter a error description
error = self.selenium.find_element(By.NAME, "error")
error.send_keys("A description of the issue\nof the device.")
# Skip device picture and device type plate
# No follow up repair
# Accept repair conditions
self.selenium.find_element(By.NAME, "confirm_repair").click()
# Accept data protection notice
self.selenium.find_element(By.NAME, "confirm_data").click()
time.sleep(1)
# Send form
self.selenium.find_element(By.CLASS_NAME, 'submit_button').click()
time.sleep(1)
# Register new guest
# Enter guest name
name = self.selenium.find_element(By.NAME, "name")
name.send_keys("A Guest")
# Enter guest phone
phone = self.selenium.find_element(By.NAME, "phone")
phone.send_keys("0911 123 456")
# Enter guest residence
residence = self.selenium.find_element(By.NAME, "residence")
residence.send_keys("Musterstadt")
time.sleep(1)
# Send form
self.selenium.find_element(By.CLASS_NAME, 'submit_button').click()
time.sleep(1)
self.assertTrue("confirm" in self.selenium.current_url)
self.assertTrue("Anmeldung erfolgreich!" in self.selenium.page_source)
# Register second device
# Open landing page again
self.selenium.get(f"{self.live_server_url}/")
# Click on a register link
self.selenium.find_element(By.CLASS_NAME, "register_link").click()
time.sleep(1)
# Enter new device
# Enter guest mail address
mail = self.selenium.find_element(By.NAME, "mail")
mail.send_keys("guest@example.com")
# Enter device
device = self.selenium.find_element(By.NAME, "device")
device.send_keys("Another Test Device")
# Enter manufacturer
manufacturer = self.selenium.find_element(By.NAME, "manufacturer")
manufacturer.send_keys("Another Test Manufacturer")
# Enter a error description
error = self.selenium.find_element(By.NAME, "error")
error.send_keys("Another issue description.")
# Add device picture
test_script_folder = Path(__file__).resolve().parent
fixtures_folder = os.path.join(test_script_folder, "fixtures")
device_picture_file = os.path.join(fixtures_folder, "Hummingbird.jpg")
device_picture = self.selenium.find_element(By.NAME, "device_picture")
device_picture.send_keys(device_picture_file)
print(f"Using device picture {device_picture_file}")
# Add type plate picture
type_plate_picture_file = os.path.join(fixtures_folder, "Nut.jpg")
type_plate_picture = self.selenium.find_element(
By.NAME, "type_plate_picture")
type_plate_picture.send_keys(type_plate_picture_file)
print(f"Using type plate picture {type_plate_picture_file}")
# Select as follow up repair
self.selenium.find_element(By.NAME, "follow_up").click()
# Accept repair conditions
self.selenium.find_element(By.NAME, "confirm_repair").click()
# Accept data protection notice
self.selenium.find_element(By.NAME, "confirm_data").click()
time.sleep(1)
# Send form
self.selenium.find_element(By.CLASS_NAME, 'submit_button').click()
time.sleep(1)
# Guest is known, no guest registration needed.
self.assertTrue("confirm" in self.selenium.current_url)
self.assertTrue("Anmeldung erfolgreich!" in self.selenium.page_source)

View file

@ -1,9 +1,9 @@
{% extends "repapp/base.html" %} {% extends "repapp/base.html" %}
{% block title %} {% block title %}
- Repair-Cafés - Repair-Cafés
{% endblock title %} {% endblock title %}
{% block head %} {% block head %}
<style> <style>
@font-face { @font-face {
font-family:'Source Sans Pro'; font-family:'Source Sans Pro';
font-style:normal; font-style:normal;
@ -280,45 +280,45 @@
color: #ffffff!important; color: #ffffff!important;
} }
} }
</style> </style>
{% endblock head %} {% endblock head %}
{% block content %} {% block content %}
<h1 class="mt-2">Repair-Cafés</h1> <h1 class="mt-2">Repair-Cafés</h1>
<hr class="mt-0 mb-4"> <hr class="mt-0 mb-4">
<ul class="list-group"> <ul class="list-group">
{% for cafe in object_list %} {% for cafe in object_list %}
<li class="list-group-item"> <li class="list-group-item">
<div class="news-list-view eventhome snipcss-aSNzE" id="news-container-82"> <div class="news-list-view eventhome snipcss-aSNzE" id="news-container-82">
<div class="rc-date"> <div class="rc-date">
<div class="article event rc-date " <div class="article event rc-date "
itemscope="itemscope" itemscope="itemscope"
itemtype="http://schema.org/Article"> itemtype="http://schema.org/Article">
<div class="dtdate"> <div class="dtdate">
<time itemprop="datePublished" datetime="13.05.2023"> <time itemprop="datePublished" datetime="13.05.2023">
{{ cafe.event_date|date:"l" }}, {{ cafe.event_date|date }}, 14.00 - 17.00 Uhr {{ cafe.event_date|date:"l" }}, {{ cafe.event_date|date }}, 14.00 - 17.00 Uhr
</time> </time>
</div> </div>
<div class="ort"> <div class="ort">
{{ cafe.location }} {{ cafe.location }}
<br> <br>
{{ cafe.address }} {{ cafe.address }}
</div> </div>
<div class="teaser-text"> <div class="teaser-text">
<div itemprop="description"> <div itemprop="description">
<p> <p>
<strong> <strong>
Nur per Voranmeldung. Nur per Voranmeldung.
<a href="{% url 'register_device' cafe.id %}">Zum Anmeldeformular</a> <a class="register_link" href="{% url 'register_device' cafe.id %}">Zum Anmeldeformular</a>
</strong> </strong>
</p> </p>
</div>
</div>
</div>
</div>
</div> </div>
</li> </div>
{% empty %} </div>
<li class="list-group-item">Es gibt keine geplanten Repair-Cafés.</li> </div>
{% endfor %} </div>
</ul> </li>
{% empty %}
<li class="list-group-item">Es gibt keine geplanten Repair-Cafés.</li>
{% endfor %}
</ul>
{% endblock content %} {% endblock content %}

View file

@ -11,6 +11,6 @@
enctype="multipart/form-data"> enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<button type="submit" class="btn btn-primary">Absenden</button> <button type="submit" class="btn btn-primary submit_button">Absenden</button>
</form> </form>
{% endblock content %} {% endblock content %}

View file

@ -1,15 +1,15 @@
{% extends "repapp/base.html" %} {% extends "repapp/base.html" %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block title %}
{% block title %}- Gast anmelden{% endblock title %} - Gast anmelden
{% endblock title %}
{% block content %} {% block content %}
<h1 class="mt-2">Ihre Daten</h1> <h1 class="mt-2">Ihre Daten</h1>
<hr class="mt-0 mb-4"> <hr class="mt-0 mb-4">
<form action="{% url 'register_guest' cafe.id device.identifier mail %}" method="post"> <form action="{% url 'register_guest' cafe.id device.identifier mail %}"
{% csrf_token %} method="post">
{{ form|crispy }} {% csrf_token %}
<button type="submit" class="btn btn-primary">Absenden</button> {{ form|crispy }}
</form> <button type="submit" class="btn btn-primary submit_button">Absenden</button>
{% endblock content %} </form>
{% endblock content %}

View file

@ -3,9 +3,11 @@ Tests for RepApp.
""" """
from datetime import datetime, timedelta from datetime import datetime, timedelta
import django.utils.timezone import django.utils.timezone
from django.test import TestCase from django.test import TestCase
from django.test import Client from django.test import Client
from django.urls import reverse from django.urls import reverse
from .backends import OneTimeLoginBackend, EmailBackend from .backends import OneTimeLoginBackend, EmailBackend
from .models import OneTimeLogin, CustomUser, Cafe from .models import OneTimeLogin, CustomUser, Cafe

View file

@ -65,23 +65,17 @@ class RegisterDeviceFormView(generic.edit.FormView):
guest = Guest.objects.filter(mail=mail).first() guest = Guest.objects.filter(mail=mail).first()
print(f'Register: Dev: {device}, Guest: {guest}')
if guest: if guest:
print('Guest already known')
device.guest = guest device.guest = guest
device.save() device.save()
send_confirmation_mails(device, guest, cafe, self.request) send_confirmation_mails(device, guest, cafe, self.request)
print('Mails sent')
resp = HttpResponseRedirect( resp = HttpResponseRedirect(
reverse_lazy('register_device_final', kwargs={ reverse_lazy('register_device_final', kwargs={
'cafe': cafe.pk, 'cafe': cafe.pk,
'device_identifier': device.identifier}) 'device_identifier': device.identifier})
) )
print(resp)
return resp return resp
else: else:
return HttpResponseRedirect( return HttpResponseRedirect(

View file

@ -9,3 +9,4 @@ crispy-bootstrap4==2022.1
mozilla-django-oidc==3.0.0 mozilla-django-oidc==3.0.0
djlint==1.23.3 djlint==1.23.3
django-import-export==3.2.0 django-import-export==3.2.0
selenium==4.9.0