Resolve merge conflicts
This commit is contained in:
commit
729cce46b7
13 changed files with 695 additions and 280 deletions
|
@ -1,4 +1,4 @@
|
||||||
EMAIL_HOST_USER=accountemail@youremail.com
|
EMAIL_HOST_USER=accountemail@yourmail.com
|
||||||
EMAIL_HOST_PASSWORD=yourpassword
|
EMAIL_HOST_PASSWORD=accountpasswordhere
|
||||||
SUBMIT_REPORT_DESTINATION_EMAIL=administratoremail@yourmail.com
|
SUBMIT_REPORT_DESTINATION_EMAIL=to-address@yourmail.com
|
||||||
SUBMIT_REPORT_FROM_EMAIL=from-address@yourmail.com
|
SUBMIT_REPORT_FROM_EMAIL=from-address@yourmail.com
|
|
@ -1,8 +1,12 @@
|
||||||
from datetime import date
|
import datetime
|
||||||
|
import datetime as mydate
|
||||||
|
|
||||||
#### Classes for policy, sections. Do not edit these.
|
#### Classes for policy, sections. Do not edit these.
|
||||||
#####################################################
|
#####################################################
|
||||||
|
|
||||||
|
def to_date(iso8601):
|
||||||
|
return mydate.datetime.strptime(iso8601, "%Y-%m-%d")
|
||||||
|
|
||||||
class Policy():
|
class Policy():
|
||||||
"""
|
"""
|
||||||
Represents the policy for the company/organization.
|
Represents the policy for the company/organization.
|
||||||
|
@ -97,6 +101,7 @@ planning_section = Section(
|
||||||
"preferred_flight_fare": {"number": 6, "label": "Fare of your preferred flight", "field_type": "decimal"},
|
"preferred_flight_fare": {"number": 6, "label": "Fare of your preferred flight", "field_type": "decimal"},
|
||||||
"preferred_flight_duration": {"number": 7, "label": "Flight duration of your preferred flight (hours)", "field_type": "decimal"},
|
"preferred_flight_duration": {"number": 7, "label": "Flight duration of your preferred flight (hours)", "field_type": "decimal"},
|
||||||
"international_flight": {"number": 8, "label": "Is this an international flight?", "field_type": "boolean"},
|
"international_flight": {"number": 8, "label": "Is this an international flight?", "field_type": "boolean"},
|
||||||
|
"economy_class": {"number": 9, "label": "Is your ticket in economy/coach?", "field_type": "boolean"},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -127,21 +132,27 @@ def lowest_fare_rule(report, fields):
|
||||||
maximum = lowest_fare + 350
|
maximum = lowest_fare + 350
|
||||||
else:
|
else:
|
||||||
maximum = lowest_fare + 600
|
maximum = lowest_fare + 600
|
||||||
if fields['preferred_fare'] > maximum:
|
if fields['preferred_flight_fare'] > maximum:
|
||||||
return "For the lowest fare you have provided, your maximum in-policy fare amount is {} USD.".format(maximum)
|
return "For the lowest fare you have provided, your maximum in-policy fare amount is {} USD.".format(maximum)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
planning_section.add_rule(title="Lowest fare check", rule=lowest_fare_rule)
|
planning_section.add_rule(title="Lowest fare check", rule=lowest_fare_rule)
|
||||||
|
|
||||||
def departure_date_limit_rule(report, fields):
|
def departure_date_limit_rule(report, fields):
|
||||||
days_to_departure = date(fields['departure_date']) - date(fields['screenshot_date'])
|
days_to_departure = to_date(fields['departure_date']) - to_date(fields['screenshot_date'])
|
||||||
if days_to_departure < 14:
|
if days_to_departure < datetime.timedelta(days=14):
|
||||||
return "Flights must be booked at least 14 days in advance."
|
return "Flights must be booked at least 14 days in advance."
|
||||||
if days_to_departure > 365:
|
if days_to_departure > datetime.timedelta(days=365):
|
||||||
return "Flights must be booked no more than 365 days in advance."
|
return "Flights must be booked no more than 365 days in advance."
|
||||||
return None
|
return None
|
||||||
|
|
||||||
planning_section.add_rule(title="Departure date limit", rule=departure_date_limit_rule)
|
planning_section.add_rule(title="Departure date limit", rule=departure_date_limit_rule)
|
||||||
|
|
||||||
|
def economy_class_rule(report, fields):
|
||||||
|
if not fields['economy_class']:
|
||||||
|
return "Only economy or coach class tickets are within policy."
|
||||||
|
|
||||||
|
planning_section.add_rule(title="Economy class check", rule=economy_class_rule)
|
||||||
pol.add_section(planning_section)
|
pol.add_section(planning_section)
|
||||||
|
|
||||||
#### Flight Info
|
#### Flight Info
|
||||||
|
@ -173,9 +184,9 @@ def actual_fare_limit_rule(report, fields):
|
||||||
flight_section.add_rule(title="Fare limits", rule=actual_fare_limit_rule)
|
flight_section.add_rule(title="Fare limits", rule=actual_fare_limit_rule)
|
||||||
|
|
||||||
def request_date_rule(report, fields):
|
def request_date_rule(report, fields):
|
||||||
now = date.today()
|
now = datetime.datetime.now()
|
||||||
last_travel = date(fields['return_date'])
|
last_travel = to_date(fields['return_date'])
|
||||||
if now - last_travel > 90:
|
if now - last_travel > datetime.timedelta(days=90):
|
||||||
return "Reimbursement requests must be made within 90 days of the last day of travel."
|
return "Reimbursement requests must be made within 90 days of the last day of travel."
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -198,9 +209,9 @@ lodging_section = Section(
|
||||||
)
|
)
|
||||||
|
|
||||||
def nightly_rate_check(report, fields):
|
def nightly_rate_check(report, fields):
|
||||||
checkin_date = date(fields['check_in_date'])
|
check_in_date = to_date(fields['check_in_date'])
|
||||||
checkout_date = date(fields['check_out_date'])
|
check_out_date = to_date(fields['check_out_date'])
|
||||||
duration = checkout_date - checkin_date
|
duration = (check_out_date - check_in_date).days
|
||||||
if fields['cost'] > duration * fields['per_diem_rate']:
|
if fields['cost'] > duration * fields['per_diem_rate']:
|
||||||
return "The average nightly rate cannot exceed the U.S. GSA rate."
|
return "The average nightly rate cannot exceed the U.S. GSA rate."
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
from policy import pol
|
|
||||||
|
|
||||||
print(pol)
|
|
84
back/backend/test_policy.py
Normal file
84
back/backend/test_policy.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from .policy import pol
|
||||||
|
from unittest import mock
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class PolicyTests(TestCase):
|
||||||
|
report = {"key":"value"}
|
||||||
|
|
||||||
|
def test_general_section_pre_post_trip_check(self):
|
||||||
|
fields = {'after_trip':True}
|
||||||
|
result = pol.sections[0].rules[0]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "If you have already take the trip your request will require special approval by the administrator. You may skip the following 'Pre-trip Planning' section.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_fare_limit_domestic(self):
|
||||||
|
fields = {'preferred_flight_fare':751,'international_flight':False}
|
||||||
|
result = pol.sections[1].rules[0]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "Fares for domestic flights over 750 USD require Conservancy pre-approval, even if other policy conditions have been met.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_fare_limit_international(self):
|
||||||
|
fields = {'preferred_flight_fare':1651,'international_flight':True}
|
||||||
|
result = pol.sections[1].rules[0]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "Fares for international flights over 1,650 USD require Conservancy pre-approval, even if other policy conditions have been met.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_lowest_fare_check_less_than_zero(self):
|
||||||
|
fields = {'lowest_fare_duration':10,'preferred_flight_duration':11,'lowest_fare':100,'preferred_flight_fare':1000}
|
||||||
|
result = pol.sections[1].rules[1]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 200 USD.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_lowest_fare_check_less_than_three(self):
|
||||||
|
fields = {'lowest_fare_duration':10,'preferred_flight_duration':8,'lowest_fare':100,'preferred_flight_fare':1000}
|
||||||
|
result = pol.sections[1].rules[1]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 200 USD.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_lowest_fare_check_less_than_six(self):
|
||||||
|
fields = {'lowest_fare_duration':10,'preferred_flight_duration':5,'lowest_fare':100,'preferred_flight_fare':1000}
|
||||||
|
result = pol.sections[1].rules[1]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 300 USD.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_lowest_fare_check_less_than_ten(self):
|
||||||
|
fields = {'lowest_fare_duration':10,'preferred_flight_duration':2,'lowest_fare':100,'preferred_flight_fare':1000}
|
||||||
|
result = pol.sections[1].rules[1]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 450 USD.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_lowest_fare_check_other(self):
|
||||||
|
fields = {'lowest_fare_duration':12,'preferred_flight_duration':1,'lowest_fare':100,'preferred_flight_fare':1000}
|
||||||
|
result = pol.sections[1].rules[1]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 700 USD.")
|
||||||
|
|
||||||
|
def test_pre_flight_section_departure_date_too_late(self):
|
||||||
|
fields = {'departure_date':'2019-03-13','screenshot_date':'2019-03-01'}
|
||||||
|
result = pol.sections[1].rules[2]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "Flights must be booked at least 14 days in advance.")
|
||||||
|
|
||||||
|
@mock.patch('datetime.date')
|
||||||
|
def test_pre_flight_section_departure_date_too_early(self, mocked_date):
|
||||||
|
mocked_date.today = mock.Mock(return_value=datetime.date(2019,1,1))
|
||||||
|
fields = {'departure_date':'2020-03-10','screenshot_date':'2019-03-01'}
|
||||||
|
result = pol.sections[1].rules[2]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "Flights must be booked no more than 365 days in advance.")
|
||||||
|
|
||||||
|
def test_flight_info_section_fare_limit_domestic(self):
|
||||||
|
fields = {'fare':751,'international_flight':False}
|
||||||
|
result = pol.sections[2].rules[0]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "Fares for domestic flights over 750 USD require Conservancy pre-approval, even if other policy conditions have been met.")
|
||||||
|
|
||||||
|
def test_flight_info_section_fare_limit_international(self):
|
||||||
|
fields = {'fare':1651,'international_flight':True}
|
||||||
|
result = pol.sections[2].rules[0]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "Fares for international flights over 1,650 USD require Conservancy pre-approval, even if other policy conditions have been met.")
|
||||||
|
|
||||||
|
def test_flight_info_section_request_date(self):
|
||||||
|
fields = {'return_date':'2018-01-01'}
|
||||||
|
result = pol.sections[2].rules[1]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "Reimbursement requests must be made within 90 days of the last day of travel.")
|
||||||
|
|
||||||
|
def test_hotels_lodging_section_average_nightly_rate(self):
|
||||||
|
fields = {'check_in_date':'2019-03-01','check_out_date':'2019-03-11','cost':1100,'per_diem_rate':100}
|
||||||
|
result = pol.sections[3].rules[0]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "The average nightly rate cannot exceed the U.S. GSA rate.")
|
||||||
|
|
||||||
|
def test_other_expenses_section_per_diem_check(self):
|
||||||
|
fields = {'rate':100,'full_days':3,'partial_days':2,'cost':451}
|
||||||
|
result = pol.sections[5].rules[0]['rule'](self.report, fields)
|
||||||
|
self.assertEqual(result, "You may only request a maximum of 450.0 USD for the rate and trip duration provided.")
|
59
back/backend/test_report.py
Normal file
59
back/backend/test_report.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from rest_framework.test import APIRequestFactory, force_authenticate
|
||||||
|
from backend.models import Report
|
||||||
|
from users.models import CustomUser
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
from datetime import date
|
||||||
|
from backend.views import *
|
||||||
|
|
||||||
|
class ReportTests(TestCase):
|
||||||
|
|
||||||
|
def create_test_user(self, email, first, last, password):
|
||||||
|
user = CustomUser.objects.create_user(username=email, email=email, first_name=first, last_name=last, password=password)
|
||||||
|
return user
|
||||||
|
|
||||||
|
def mock_report():
|
||||||
|
r = Mock()
|
||||||
|
r.report_pk = 1
|
||||||
|
r.title = 'Report Title'
|
||||||
|
r.date_created = '2019-03-01'
|
||||||
|
r.date_submitted = '2019-03-01'
|
||||||
|
r.submitted = False
|
||||||
|
r.reference_number = '12345'
|
||||||
|
return r
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.test_user_1 = self.create_test_user('one@one.com', 'One', 'Mr. One', '1password')
|
||||||
|
self.test_user_1.save()
|
||||||
|
|
||||||
|
def test_create_report_logged_in(self):
|
||||||
|
factory = APIRequestFactory()
|
||||||
|
request = factory.post('/api/v1/report', {'title':'Test Report', 'reference':'12345'})
|
||||||
|
user = CustomUser.objects.get(email='one@one.com')
|
||||||
|
force_authenticate(request, user=user)
|
||||||
|
response = create_report(request)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
report = Report.objects.get(user_id=user)
|
||||||
|
self.assertEqual(report.title, 'Test Report')
|
||||||
|
|
||||||
|
def test_create_report_logged_out(self):
|
||||||
|
factory = APIRequestFactory()
|
||||||
|
request = factory.post('/api/v1/report', {'title':'Test Report', 'reference':'12345'})
|
||||||
|
response = create_report(request)
|
||||||
|
self.assertEqual(response.status_code, 401)
|
||||||
|
|
||||||
|
@patch('backend.models.Report.objects.filter', Mock(return_value=[mock_report()]))
|
||||||
|
@patch('backend.views.get_sections', Mock(return_value={}))
|
||||||
|
def test_get_report(self):
|
||||||
|
result = get_report(1)
|
||||||
|
self.assertEqual(
|
||||||
|
result,
|
||||||
|
{
|
||||||
|
'date_created':'2019-03-01',
|
||||||
|
'reference_number':'12345',
|
||||||
|
'report_pk':1,
|
||||||
|
'title':'Report Title',
|
||||||
|
'date_submitted':'2019-03-01',
|
||||||
|
'submitted':False
|
||||||
|
}
|
||||||
|
)
|
|
@ -1,3 +0,0 @@
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
|
@ -5,9 +5,10 @@ from rest_framework.urlpatterns import format_suffix_patterns
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('report', views.report),
|
path('report', views.create_report),
|
||||||
path('reports', views.reports),
|
path('reports', views.reports),
|
||||||
path('report/<int:report_pk>', views.report_detail),
|
path('report/<int:report_pk>', views.report_detail),
|
||||||
|
path('report/<int:report_pk>/final', views.finalize_report),
|
||||||
path('report/<int:report_pk>/section/<int:section_pk>', views.section),
|
path('report/<int:report_pk>/section/<int:section_pk>', views.section),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ from django.http import JsonResponse
|
||||||
from .models import *
|
from .models import *
|
||||||
from .policy import pol
|
from .policy import pol
|
||||||
import os
|
import os
|
||||||
from rest_framework.exceptions import ParseError
|
|
||||||
from rest_framework.parsers import FileUploadParser, MultiPartParser
|
|
||||||
from django.core.mail import EmailMultiAlternatives
|
from django.core.mail import EmailMultiAlternatives
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from decouple import config
|
from decouple import config
|
||||||
|
@ -99,7 +97,6 @@ def get_fields(s_id):
|
||||||
|
|
||||||
return field_set
|
return field_set
|
||||||
|
|
||||||
|
|
||||||
def generate_named_fields_for_section(fields):
|
def generate_named_fields_for_section(fields):
|
||||||
"""
|
"""
|
||||||
Prepares a dictionary of key-value pairs based on the raw fields
|
Prepares a dictionary of key-value pairs based on the raw fields
|
||||||
|
@ -115,7 +112,7 @@ def generate_named_fields_for_section(fields):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def report(request):
|
def create_report(request):
|
||||||
"""
|
"""
|
||||||
Generates a new empty report for the current user and returns it
|
Generates a new empty report for the current user and returns it
|
||||||
in json format. The title of the report should be provided as
|
in json format. The title of the report should be provided as
|
||||||
|
@ -205,17 +202,11 @@ def report_detail(request, report_pk):
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
# PUT: Submits a report to the administrator for review,
|
# PUT: Submits a report to the administrator for review,
|
||||||
# and marks it as "submitted", after which changes may
|
# but is still allowed to make further changes
|
||||||
# not be made.
|
|
||||||
elif request.method == 'PUT':
|
elif request.method == 'PUT':
|
||||||
rep = Report.objects.get(id=report_pk)
|
|
||||||
if rep.submitted == True:
|
|
||||||
return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409)
|
|
||||||
rep.submitted = True;
|
|
||||||
rep.save()
|
|
||||||
# Send email
|
# Send email
|
||||||
send_report_to_admin(request, report_pk)
|
send_report_to_admin(request, report_pk, status="REVIEW")
|
||||||
return JsonResponse({"message": "Report submitted."})
|
return JsonResponse({"message": "Request for review is submitted."})
|
||||||
|
|
||||||
# DELETE: Deletes a report from the user's account.
|
# DELETE: Deletes a report from the user's account.
|
||||||
elif request.method == 'DELETE':
|
elif request.method == 'DELETE':
|
||||||
|
@ -237,6 +228,26 @@ def report_detail(request, report_pk):
|
||||||
r.delete()
|
r.delete()
|
||||||
return JsonResponse({"message": "Deleted report: {0}.".format(title)})
|
return JsonResponse({"message": "Deleted report: {0}.".format(title)})
|
||||||
|
|
||||||
|
@api_view(['PUT'])
|
||||||
|
def finalize_report(request, report_pk):
|
||||||
|
"""
|
||||||
|
This function serves as an API endpoint for submitting
|
||||||
|
the final report.
|
||||||
|
|
||||||
|
:param request: incoming request packet
|
||||||
|
:param report_pk: report ID
|
||||||
|
:return: JSON response containing user message
|
||||||
|
"""
|
||||||
|
r = Report.objects.get(id=report_pk)
|
||||||
|
if r.submitted:
|
||||||
|
return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409)
|
||||||
|
r.submitted = True
|
||||||
|
r.save()
|
||||||
|
# Send email
|
||||||
|
send_report_to_admin(request, report_pk, status="FINAL")
|
||||||
|
return JsonResponse({"message": "Final report submitted."})
|
||||||
|
|
||||||
|
|
||||||
def user_owns_section(user, section):
|
def user_owns_section(user, section):
|
||||||
"""
|
"""
|
||||||
Returns true if the specified user is owner of the section.
|
Returns true if the specified user is owner of the section.
|
||||||
|
@ -383,7 +394,7 @@ def section_complete(section_pk):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def send_report_to_admin(request, report_pk):
|
def send_report_to_admin(request, report_pk, status):
|
||||||
"""
|
"""
|
||||||
Sends an email message to admin with html/txt version of report,
|
Sends an email message to admin with html/txt version of report,
|
||||||
along with file attachments. Cc sent to user.
|
along with file attachments. Cc sent to user.
|
||||||
|
@ -400,7 +411,7 @@ def send_report_to_admin(request, report_pk):
|
||||||
message = None
|
message = None
|
||||||
if params['reference_number'] == '':
|
if params['reference_number'] == '':
|
||||||
message = EmailMultiAlternatives(
|
message = EmailMultiAlternatives(
|
||||||
"{}".format(params['title']),
|
"{} ({})".format(params['title'], status),
|
||||||
msg_plain,
|
msg_plain,
|
||||||
from_email,
|
from_email,
|
||||||
[to_email],
|
[to_email],
|
||||||
|
@ -408,7 +419,7 @@ def send_report_to_admin(request, report_pk):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
message = EmailMultiAlternatives(
|
message = EmailMultiAlternatives(
|
||||||
"[RT - Request Tracker #{}] {}".format(params['reference_number'], params['title']),
|
"[Reimbursinator #{}] {} ({})".format(params['reference_number'], params['title'], status),
|
||||||
msg_plain,
|
msg_plain,
|
||||||
from_email,
|
from_email,
|
||||||
[to_email],
|
[to_email],
|
||||||
|
|
BIN
back/db.sqlite3
BIN
back/db.sqlite3
Binary file not shown.
|
@ -232,7 +232,7 @@ function createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, rul
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCollapsibleCardBody(form, type, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations) {
|
function createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations) {
|
||||||
// Create wrapper div
|
// Create wrapper div
|
||||||
const collapseDiv = document.createElement("div");
|
const collapseDiv = document.createElement("div");
|
||||||
collapseDiv.id = sectionIdStr + "collapse";
|
collapseDiv.id = sectionIdStr + "collapse";
|
||||||
|
@ -342,13 +342,6 @@ function createReportForm(parsedData, type) {
|
||||||
// Traverse the fields of this section
|
// Traverse the fields of this section
|
||||||
let fields = sections[i].fields;
|
let fields = sections[i].fields;
|
||||||
for (let j = 0; j < fields.length; j++) {
|
for (let j = 0; j < fields.length; j++) {
|
||||||
|
|
||||||
/*
|
|
||||||
console.log("Field label: " + fields[j].label);
|
|
||||||
console.log("Field type: " + fields[j].field_type);
|
|
||||||
console.log("Field value: " + fields[j].value);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Create a form group for each field and add it to the form
|
// Create a form group for each field and add it to the form
|
||||||
form.appendChild(createFormGroup(sectionIdStr, fields[j]));
|
form.appendChild(createFormGroup(sectionIdStr, fields[j]));
|
||||||
}
|
}
|
||||||
|
@ -361,7 +354,7 @@ function createReportForm(parsedData, type) {
|
||||||
form.appendChild(saveButton);
|
form.appendChild(saveButton);
|
||||||
|
|
||||||
// Create collapsible card body, append form to it, append card to accordion
|
// Create collapsible card body, append form to it, append card to accordion
|
||||||
let cardBody = createCollapsibleCardBody(form, type, sectionIdStr,
|
let cardBody = createCollapsibleCardBody(form, sectionIdStr,
|
||||||
sections[i].html_description, sections[i].completed, sections[i].rule_violations);
|
sections[i].html_description, sections[i].completed, sections[i].rule_violations);
|
||||||
let cardFooter = createCardFooter(sections[i].rule_violations);
|
let cardFooter = createCardFooter(sections[i].rule_violations);
|
||||||
if (cardFooter) {
|
if (cardFooter) {
|
||||||
|
|
|
@ -1,233 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>QUnit Tests</title>
|
|
||||||
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.9.2.css">
|
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
|
|
||||||
<script src="../js/viewHistory.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="qunit"></div>
|
|
||||||
<div id="qunit-fixture"></div>
|
|
||||||
<script src="https://code.jquery.com/qunit/qunit-2.9.2.js"></script>
|
|
||||||
<script>
|
|
||||||
|
|
||||||
// BEGIN createFormGroup unit tests
|
|
||||||
QUnit.module("createFormGroup");
|
|
||||||
|
|
||||||
// BEGIN: Test rendering of fields with type boolean
|
|
||||||
QUnit.test("boolean input group false renders", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"label": "Have you taken this trip already?",
|
|
||||||
"field_name": "after_trip",
|
|
||||||
"field_type": "boolean",
|
|
||||||
"value": false
|
|
||||||
};
|
|
||||||
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-after_trip">Have you taken this trip already?: </label><div class="col-sm-6"><select name="after_trip" id="section-1-after_trip" class="form-control"><option value="true">Yes</option><option value="false" selected="selected">No</option></select></div></div>`
|
|
||||||
assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean false renders as no option selected");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("boolean input group true renders", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"label": "Have you taken this trip already?",
|
|
||||||
"field_name": "after_trip",
|
|
||||||
"field_type": "boolean",
|
|
||||||
"value": true
|
|
||||||
};
|
|
||||||
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-after_trip">Have you taken this trip already?: </label><div class="col-sm-6"><select name="after_trip" id="section-1-after_trip" class="form-control"><option value="true" selected="selected">Yes</option><option value="false">No</option></select></div></div>`
|
|
||||||
assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean true renders as yes option selected");
|
|
||||||
});
|
|
||||||
|
|
||||||
// END: Test rendering of fields with type boolean
|
|
||||||
|
|
||||||
|
|
||||||
// BEGIN: Test rendering of fields with type date
|
|
||||||
QUnit.test("date input group renders", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"label": "Departure date",
|
|
||||||
"field_name": "departure_date",
|
|
||||||
"field_type": "date",
|
|
||||||
"value": "None"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-departure_date">Departure date: </label><div class="col-sm-6"><input name="departure_date" id="section-1-departure_date" type="date" placeholder="mm-dd-yyyy" class="form-control"></div></div>`
|
|
||||||
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("date value None", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"label": "Departure date",
|
|
||||||
"field_name": "departure_date",
|
|
||||||
"field_type": "date",
|
|
||||||
"value": "None"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector("#section-1-departure_date").value;
|
|
||||||
assert.deepEqual(value, "", "date initialized to None has null value");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("date value assignment", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"label": "Departure date",
|
|
||||||
"field_name": "departure_date",
|
|
||||||
"field_type": "date",
|
|
||||||
"value": "2019-02-28"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector("#section-1-departure_date").value;
|
|
||||||
assert.deepEqual(value, field.value, "date input initialized to a value is rendered with that value");
|
|
||||||
});
|
|
||||||
// END: Test rendering of fields with type date
|
|
||||||
|
|
||||||
// BEGIN: Test rendering of fields with type string
|
|
||||||
QUnit.test("string input group renders", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"label": "City",
|
|
||||||
"field_name": "city",
|
|
||||||
"field_type": "string",
|
|
||||||
"value": "Portland"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-city">City: </label><div class="col-sm-6"><input name="city" id="section-1-city" type="text" class="form-control"></div></div>`
|
|
||||||
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("string value assignment", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"label": "City",
|
|
||||||
"field_name": "city",
|
|
||||||
"field_type": "string",
|
|
||||||
"value": "Portland"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector("#section-1-city").value;
|
|
||||||
assert.deepEqual(value, field.value, "text input initialized to a value is rendered with that value");
|
|
||||||
});
|
|
||||||
// END: Test rendering of fields with type date
|
|
||||||
|
|
||||||
// BEGIN: Test rendering of fields with type decimal
|
|
||||||
QUnit.test("decimal input group renders", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": "0.00",
|
|
||||||
"field_type": "decimal",
|
|
||||||
"label": "Lowest fare",
|
|
||||||
"field_name": "lowest_fare"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-lowest_fare">Lowest fare: </label><div class="col-sm-6"><input name="lowest_fare" id="section-1-lowest_fare" type="number" class="form-control" step="0.01" min="0"></div></div>`
|
|
||||||
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("decimal input group initialized to default", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": "0.00",
|
|
||||||
"field_type": "decimal",
|
|
||||||
"label": "Lowest fare",
|
|
||||||
"field_name": "lowest_fare"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector("#section-1-lowest_fare").value;
|
|
||||||
assert.deepEqual(value, "", "decimal input initialized to 0.00 has null value");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("decimal input group initialized to value", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": "1337",
|
|
||||||
"field_type": "decimal",
|
|
||||||
"label": "Lowest fare",
|
|
||||||
"field_name": "lowest_fare"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector("#section-1-lowest_fare").value;
|
|
||||||
assert.deepEqual(value, field.value, "decimal input initialized to 1337 has value 1337");
|
|
||||||
});
|
|
||||||
// END: Test rendering of fields with type decimal
|
|
||||||
|
|
||||||
// BEGIN: Test rendering of fields with type integer
|
|
||||||
QUnit.test("integer input group renders", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": 0,
|
|
||||||
"field_type": "integer",
|
|
||||||
"label": "Number of full days of travel",
|
|
||||||
"field_name": "full_days"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-full_days">Number of full days of travel: </label><div class="col-sm-6"><input name="full_days" id="section-1-full_days" type="number" class="form-control" step="1" min="0"></div></div>`
|
|
||||||
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("integer input group initialized to default", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": 0,
|
|
||||||
"field_type": "integer",
|
|
||||||
"label": "Number of full days of travel",
|
|
||||||
"field_name": "full_days"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector("#section-1-full_days").value;
|
|
||||||
assert.deepEqual(value, "", "integer input initialized to 0 has null value");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("integer input group initialized to value", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": 1234,
|
|
||||||
"field_type": "integer",
|
|
||||||
"label": "Number of full days of travel",
|
|
||||||
"field_name": "full_days"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector("#section-1-full_days").value;
|
|
||||||
assert.deepEqual(value, field.value.toString(), "integer input initialized to 1234 has string value 1234");
|
|
||||||
});
|
|
||||||
// END: Test rendering of fields with type integer
|
|
||||||
|
|
||||||
|
|
||||||
// BEGIN: Test rendering of fields with type file
|
|
||||||
QUnit.test("file input group renders", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": "",
|
|
||||||
"field_type": "file",
|
|
||||||
"label": "Screenshot of invoice",
|
|
||||||
"field_name": "invoice_screenshot"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-invoice_screenshot">Screenshot of invoice: </label><div class="col-sm-6"><input name="invoice_screenshot" id="section-1-invoice_screenshot" type="file" class="form-control-file"><p class="form-text"></p></div></div>`
|
|
||||||
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test("file input group form text assignment", function(assert) {
|
|
||||||
let sectionIdStr = "section-1-";
|
|
||||||
let field = {
|
|
||||||
"value": "screenshot.jpg",
|
|
||||||
"field_type": "file",
|
|
||||||
"label": "Screenshot of invoice",
|
|
||||||
"field_name": "invoice_screenshot"
|
|
||||||
};
|
|
||||||
let formGroup = createFormGroup(sectionIdStr, field);
|
|
||||||
let value = formGroup.querySelector(".form-text").innerHTML;
|
|
||||||
assert.deepEqual(value, field.value, "file input initialized to screenshot.jpg has string value screenshot.jpg");
|
|
||||||
});
|
|
||||||
// END: Test rendering of fields with type file
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
451
front/tests/qunit_tests.html
Normal file
451
front/tests/qunit_tests.html
Normal file
|
@ -0,0 +1,451 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>QUnit Tests</title>
|
||||||
|
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.9.2.css">
|
||||||
|
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
|
||||||
|
<script src="../static/js/viewHistory.js"></script>
|
||||||
|
<script src="testObjects.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<div id="qunit-fixture">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="text-center">
|
||||||
|
<i class="fas fa-spinner fa-3x fa-spin"></i>
|
||||||
|
</div>
|
||||||
|
<table class="table table-striped table-responsive-sm" style="visibility:hidden">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Date Created</th>
|
||||||
|
<th class="d-none d-md-table-cell">Date Submitted</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="modal fade" id="newReportModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="newReportModalLabel"></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="newReportModalBody">
|
||||||
|
<div class="text-center">
|
||||||
|
<i class="fas fa-spinner fa-3x fa-spin"></i>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<h5>Creating Report ...</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary submit-report-button">Submit Report</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal fade" id="editReportModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="editReportModalLabel"></h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="editReportModalBody">
|
||||||
|
<div class="text-center">
|
||||||
|
<i class="fas fa-spinner fa-3x fa-spin"></i>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<h5>Loading Report ...</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger delete-report">Delete Report</button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary submit-report-button">Submit Report</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://code.jquery.com/qunit/qunit-2.9.2.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
// BEGIN createFormGroup unit tests
|
||||||
|
QUnit.module("createFormGroup");
|
||||||
|
|
||||||
|
// BEGIN: Test rendering of fields with type boolean
|
||||||
|
QUnit.test("boolean input group false renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"label": "Have you taken this trip already?",
|
||||||
|
"field_name": "after_trip",
|
||||||
|
"field_type": "boolean",
|
||||||
|
"value": false
|
||||||
|
};
|
||||||
|
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-after_trip">Have you taken this trip already?: </label><div class="col-sm-6"><select name="after_trip" id="section-1-after_trip" class="form-control"><option value="true">Yes</option><option value="false" selected="selected">No</option></select></div></div>`
|
||||||
|
assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean false renders as no option selected");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("boolean input group true renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"label": "Have you taken this trip already?",
|
||||||
|
"field_name": "after_trip",
|
||||||
|
"field_type": "boolean",
|
||||||
|
"value": true
|
||||||
|
};
|
||||||
|
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-after_trip">Have you taken this trip already?: </label><div class="col-sm-6"><select name="after_trip" id="section-1-after_trip" class="form-control"><option value="true" selected="selected">Yes</option><option value="false">No</option></select></div></div>`
|
||||||
|
assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean true renders as yes option selected");
|
||||||
|
});
|
||||||
|
|
||||||
|
// BEGIN: Test rendering of fields with type date
|
||||||
|
QUnit.test("date input group renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"label": "Departure date",
|
||||||
|
"field_name": "departure_date",
|
||||||
|
"field_type": "date",
|
||||||
|
"value": "None"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-departure_date">Departure date: </label><div class="col-sm-6"><input name="departure_date" id="section-1-departure_date" type="date" placeholder="mm-dd-yyyy" class="form-control"></div></div>`
|
||||||
|
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("date value None", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"label": "Departure date",
|
||||||
|
"field_name": "departure_date",
|
||||||
|
"field_type": "date",
|
||||||
|
"value": "None"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector("#section-1-departure_date").value;
|
||||||
|
assert.deepEqual(value, "", "date initialized to None has null value");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("date value assignment", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"label": "Departure date",
|
||||||
|
"field_name": "departure_date",
|
||||||
|
"field_type": "date",
|
||||||
|
"value": "2019-02-28"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector("#section-1-departure_date").value;
|
||||||
|
assert.deepEqual(value, field.value, "date input initialized to a value is rendered with that value");
|
||||||
|
});
|
||||||
|
|
||||||
|
// BEGIN: Test rendering of fields with type string
|
||||||
|
QUnit.test("string input group renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"label": "City",
|
||||||
|
"field_name": "city",
|
||||||
|
"field_type": "string",
|
||||||
|
"value": "Portland"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-city">City: </label><div class="col-sm-6"><input name="city" id="section-1-city" type="text" class="form-control"></div></div>`
|
||||||
|
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("string value assignment", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"label": "City",
|
||||||
|
"field_name": "city",
|
||||||
|
"field_type": "string",
|
||||||
|
"value": "Portland"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector("#section-1-city").value;
|
||||||
|
assert.deepEqual(value, field.value, "text input initialized to a value is rendered with that value");
|
||||||
|
});
|
||||||
|
|
||||||
|
// BEGIN: Test rendering of fields with type decimal
|
||||||
|
QUnit.test("decimal input group renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": "0.00",
|
||||||
|
"field_type": "decimal",
|
||||||
|
"label": "Lowest fare",
|
||||||
|
"field_name": "lowest_fare"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-lowest_fare">Lowest fare: </label><div class="col-sm-6"><input name="lowest_fare" id="section-1-lowest_fare" type="number" class="form-control" step="0.01" min="0"></div></div>`
|
||||||
|
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("decimal input group initialized to default", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": "0.00",
|
||||||
|
"field_type": "decimal",
|
||||||
|
"label": "Lowest fare",
|
||||||
|
"field_name": "lowest_fare"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector("#section-1-lowest_fare").value;
|
||||||
|
assert.deepEqual(value, "", "decimal input initialized to 0.00 has null value");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("decimal input group initialized to value", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": "1337",
|
||||||
|
"field_type": "decimal",
|
||||||
|
"label": "Lowest fare",
|
||||||
|
"field_name": "lowest_fare"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector("#section-1-lowest_fare").value;
|
||||||
|
assert.deepEqual(value, field.value, "decimal input initialized to 1337 has value 1337");
|
||||||
|
});
|
||||||
|
|
||||||
|
// BEGIN: Test rendering of fields with type integer
|
||||||
|
QUnit.test("integer input group renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": 0,
|
||||||
|
"field_type": "integer",
|
||||||
|
"label": "Number of full days of travel",
|
||||||
|
"field_name": "full_days"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-full_days">Number of full days of travel: </label><div class="col-sm-6"><input name="full_days" id="section-1-full_days" type="number" class="form-control" step="1" min="0"></div></div>`
|
||||||
|
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("integer input group initialized to default", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": 0,
|
||||||
|
"field_type": "integer",
|
||||||
|
"label": "Number of full days of travel",
|
||||||
|
"field_name": "full_days"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector("#section-1-full_days").value;
|
||||||
|
assert.deepEqual(value, "", "integer input initialized to 0 has null value");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("integer input group initialized to value", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": 1234,
|
||||||
|
"field_type": "integer",
|
||||||
|
"label": "Number of full days of travel",
|
||||||
|
"field_name": "full_days"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector("#section-1-full_days").value;
|
||||||
|
assert.deepEqual(value, field.value.toString(), "integer input initialized to 1234 has string value 1234");
|
||||||
|
});
|
||||||
|
|
||||||
|
// BEGIN: Test rendering of fields with type file
|
||||||
|
QUnit.test("file input group renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": "",
|
||||||
|
"field_type": "file",
|
||||||
|
"label": "Screenshot of invoice",
|
||||||
|
"field_name": "invoice_screenshot"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let expectedHTML = `<div class="form-group row"><label class="col-sm-4 col-form" for="section-1-invoice_screenshot">Screenshot of invoice: </label><div class="col-sm-6"><input name="invoice_screenshot" id="section-1-invoice_screenshot" type="file" class="form-control-file"><p class="form-text"></p></div></div>`
|
||||||
|
assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("file input group form text assignment", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let field = {
|
||||||
|
"value": "screenshot.jpg",
|
||||||
|
"field_type": "file",
|
||||||
|
"label": "Screenshot of invoice",
|
||||||
|
"field_name": "invoice_screenshot"
|
||||||
|
};
|
||||||
|
let formGroup = createFormGroup(sectionIdStr, field);
|
||||||
|
let value = formGroup.querySelector(".form-text").innerHTML;
|
||||||
|
assert.deepEqual(value, field.value, "file input initialized to screenshot.jpg has string value screenshot.jpg");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// BEGIN createCollapsibleCard unit tests
|
||||||
|
QUnit.module("createCollapsibleCard");
|
||||||
|
|
||||||
|
QUnit.test("incomplete section renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let sectionTitle = "General Info";
|
||||||
|
let sectionCompleted = false;
|
||||||
|
let ruleViolations = [];
|
||||||
|
|
||||||
|
let card = createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, ruleViolations);
|
||||||
|
let expectedHTML = `<div class="card"><div class="card-header"><h2 class="mb-0"><button class="btn btn-link" type="button" data-toggle="collapse" data-target="#section-1-collapse">General Info</button><i id="section-1-state"></i></h2></div></div>`;
|
||||||
|
assert.deepEqual(card.outerHTML, expectedHTML, "card html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("complete section with no rule violations renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let sectionTitle = "General Info";
|
||||||
|
let sectionCompleted = true;
|
||||||
|
let ruleViolations = [];
|
||||||
|
|
||||||
|
let card = createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, ruleViolations);
|
||||||
|
let expectedHTML = `<div class="card"><div class="card-header"><h2 class="mb-0"><button class="btn btn-link" type="button" data-toggle="collapse" data-target="#section-1-collapse">General Info</button><i id="section-1-state" class="fas fa-check-square"></i></h2></div></div>`
|
||||||
|
assert.deepEqual(card.outerHTML, expectedHTML, "card html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("complete section with a violation renders", function(assert) {
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let sectionTitle = "General Info";
|
||||||
|
let sectionCompleted = true;
|
||||||
|
let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}]
|
||||||
|
|
||||||
|
let card = createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, ruleViolations);
|
||||||
|
let expectedHTML = `<div class="card"><div class="card-header"><h2 class="mb-0"><button class="btn btn-link" type="button" data-toggle="collapse" data-target="#section-1-collapse">General Info</button><i id="section-1-state" class="fas fa-exclamation-triangle"></i></h2></div></div>`
|
||||||
|
assert.deepEqual(card.outerHTML, expectedHTML, "card html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// BEGIN createCollapsibleCard unit tests
|
||||||
|
QUnit.module("createCollapsibleCardBody");
|
||||||
|
|
||||||
|
QUnit.test("incomplete section renders", function(assert) {
|
||||||
|
let form = document.createElement("form");
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let sectionDescription = "<p>Section Description</p>";
|
||||||
|
let sectionCompleted = false;
|
||||||
|
let ruleViolations = [];
|
||||||
|
let collapseDiv = createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations);
|
||||||
|
let expectedHTML = `<div id="section-1-collapse" class="collapse show"><div class="card-body"><div class="alert alert-danger section-alert">This section is not complete</div><p>Section Description</p><form></form></div></div>`;
|
||||||
|
assert.deepEqual(collapseDiv.outerHTML, expectedHTML, "collapseDiv html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("complete section with no rule violations renders", function(assert) {
|
||||||
|
let form = document.createElement("form");
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let sectionDescription = "<p>Section Description</p>";
|
||||||
|
let sectionCompleted = true;
|
||||||
|
let ruleViolations = [];
|
||||||
|
let collapseDiv = createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations);
|
||||||
|
let expectedHTML = `<div id="section-1-collapse" class="collapse"><div class="card-body"><div></div><p>Section Description</p><form></form></div></div>`;
|
||||||
|
assert.deepEqual(collapseDiv.outerHTML, expectedHTML, "collapseDiv html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("complete section with rule violation renders", function(assert) {
|
||||||
|
let form = document.createElement("form");
|
||||||
|
let sectionIdStr = "section-1-";
|
||||||
|
let sectionDescription = "<p>Section Description</p>";
|
||||||
|
let sectionCompleted = true;
|
||||||
|
let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}]
|
||||||
|
let collapseDiv = createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations);
|
||||||
|
let expectedHTML = `<div id="section-1-collapse" class="collapse show"><div class="card-body"><div></div><p>Section Description</p><form></form></div></div>`;
|
||||||
|
assert.deepEqual(collapseDiv.outerHTML, expectedHTML, "collapseDiv html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// BEGIN createCardFooter unit tests
|
||||||
|
QUnit.module("createCardFooter");
|
||||||
|
|
||||||
|
QUnit.test("card footer no rule violations does not render", function(assert) {
|
||||||
|
let ruleViolations = [];
|
||||||
|
let cardFooter = createCardFooter(ruleViolations);
|
||||||
|
assert.strictEqual(cardFooter, null, "cardFooter is null");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("card footer with one rule violation renders", function(assert) {
|
||||||
|
let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}];
|
||||||
|
let cardFooter = createCardFooter(ruleViolations);
|
||||||
|
let expectedHTML = `<div class="card-footer"><div class="alert alert-danger"><div class="alert-heading">Rule Violations</div><hr><p><strong>Fare limits</strong><br>You did a bad thing</p></div></div>`;
|
||||||
|
assert.deepEqual(cardFooter.outerHTML, expectedHTML, "cardFooter html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("card footer with multiple rule violation renders", function(assert) {
|
||||||
|
let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}, {"label": "Fare limits", "rule_break_text": "Now you've done it"}];
|
||||||
|
let cardFooter = createCardFooter(ruleViolations);
|
||||||
|
let expectedHTML = `<div class="card-footer"><div class="alert alert-danger"><div class="alert-heading">Rule Violations</div><hr><p><strong>Fare limits</strong><br>You did a bad thing</p><p><strong>Fare limits</strong><br>Now you've done it</p></div></div>`;
|
||||||
|
assert.deepEqual(cardFooter.outerHTML, expectedHTML, "cardFooter html and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// BEGIN createReportForm unit tests
|
||||||
|
QUnit.module("createReportForm");
|
||||||
|
|
||||||
|
QUnit.test("new report renders", function(assert) {
|
||||||
|
createReportForm(testReport, reportType.NEW);
|
||||||
|
let newReportModal = document.getElementById("newReportModal");
|
||||||
|
let expectedHTML = typeNewExpectedHTML;
|
||||||
|
assert.deepEqual(newReportModal.outerHTML, expectedHTML, "new report form and expectedHTML are identical")
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("edit report renders", function(assert) {
|
||||||
|
createReportForm(testReport, reportType.EDIT);
|
||||||
|
let editReportModal = document.getElementById("editReportModal");
|
||||||
|
let expectedHTML = typeEditExpectedHTML;
|
||||||
|
assert.deepEqual(editReportModal.outerHTML, expectedHTML, "edit report form and expectedHTML are identical")
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("undefined report does not render", function(assert) {
|
||||||
|
let qunitFixture = document.getElementById("qunit-fixture");
|
||||||
|
let expectedHTML = qunitFixture.outerHTML;
|
||||||
|
createReportForm(testReport, undefined);
|
||||||
|
assert.deepEqual(qunitFixture.outerHTML, expectedHTML, "report forms and expectedHTML are identical")
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// BEGIN displayListOfReports unit tests
|
||||||
|
QUnit.module("displayListOfReports");
|
||||||
|
|
||||||
|
QUnit.test("empty reports", function(assert) {
|
||||||
|
let expectedHTML = `<div class="card-body"><h5 class="text-center">No reports found.</h5></div>`;
|
||||||
|
let parsedData = {"reports": []};
|
||||||
|
displayListOfReports(parsedData);
|
||||||
|
let cardBody = document.querySelector(".card-body");
|
||||||
|
assert.deepEqual(cardBody.outerHTML.replace(/>\s+</g, "><"), expectedHTML, "card body and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("one editable report", function(assert) {
|
||||||
|
let parsedData = {"reports": [{"date_created": "2019-03-05T08:00:00Z", "title": "TEST1", "reference_number": "1234", "date_submitted": "2019-03-05T08:00:00Z", "user_id": 2, "submitted": false, "report_pk": 4}]};
|
||||||
|
let expectedHTML = displayReportsOneReportExpected;
|
||||||
|
displayListOfReports(parsedData);
|
||||||
|
let cardBody = document.querySelector(".card-body");
|
||||||
|
assert.deepEqual(cardBody.outerHTML.replace(/>\s+</g, "><"), expectedHTML, "card body and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
QUnit.test("two editable reports", function(assert) {
|
||||||
|
let parsedData = {"reports": [{"date_created": "2019-03-05T08:00:00Z", "title": "TEST1", "reference_number": "1234", "date_submitted": "2019-03-05T08:00:00Z", "user_id": 2, "submitted": false, "report_pk": 4}, {"date_created": "2019-03-05T08:00:00Z", "title": "TEST2", "reference_number": "12345", "date_submitted": "2019-03-05T08:00:00Z", "user_id": 2, "submitted": false, "report_pk": 5}]};
|
||||||
|
let expectedHTML = displayReportsTwoReportsExpected;
|
||||||
|
displayListOfReports(parsedData);
|
||||||
|
let cardBody = document.querySelector(".card-body");
|
||||||
|
assert.deepEqual(cardBody.outerHTML.replace(/>\s+</g, "><"), expectedHTML, "card body and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("one viewable report", function(assert) {
|
||||||
|
let parsedData = {"reports": [{"date_created": "2019-03-05T08:00:00Z", "title": "TEST2", "reference_number": "12345", "date_submitted": "2019-03-05T08:00:00Z", "user_id": 2, "submitted": true, "report_pk": 5}]};
|
||||||
|
let expectedHTML = displayReportsOneViewableExpected;
|
||||||
|
displayListOfReports(parsedData);
|
||||||
|
let cardBody = document.querySelector(".card-body");
|
||||||
|
assert.deepEqual(cardBody.outerHTML.replace(/>\s+</g, "><"), expectedHTML, "card body and expectedHTML are identical");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
44
front/tests/testObjects.js
Normal file
44
front/tests/testObjects.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue