combo/tests/test_calendar.py

336 lines
11 KiB
Python

import json
import urlparse
import datetime
import pytest
import mock
from django.contrib.auth.models import User
from combo.data.models import Page
from combo.apps.calendar.models import BookingCalendar
from combo.apps.calendar.utils import get_calendar, get_chrono_service
pytestmark = pytest.mark.django_db
CHRONO_EVENTS = {
"data": [
{
"disabled": False,
"text": "13 juin 2017 08:00",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/86/"
},
"id": 86,
"datetime": "2017-06-13 08:00:00"
},
{
"disabled": False,
"text": "13 juin 2017 08:30",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/87/"
},
"id": 87,
"datetime": "2017-06-13 08:30:00"
},
{
"disabled": False,
"text": "13 juin 2017 09:00",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/88/"
},
"id": 88,
"datetime": "2017-06-13 09:00:00"
},
{
"disabled": False,
"text": "13 juin 2017 09:30",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/89/"
},
"id": 89,
"datetime": "2017-06-13 09:30:00"
},
{
"disabled": False,
"text": "14 juin 2017 09:30",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/89/"
},
"id": 90,
"datetime": "2017-06-14 09:30:00"
},
{
"disabled": False,
"text": "14 juin 2017 10:00",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/89/"
},
"id": 91,
"datetime": "2017-06-14 10:00:00"
},
{
"disabled": True,
"text": "14 juin 2017 15:00",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/89/"
},
"id": 91,
"datetime": "2017-06-14 15:00:00"
},
{
"disabled": True,
"text": "15 juin 2017 10:00",
"api": {
"fillslot_url": "http://example.net/api/agenda/whatever/fillslot/89/"
},
"id": 92,
"datetime": "2017-06-15 10:00:00"
}
]
}
WCS_FORMDEFS = [
{
"count": 12,
"category": "common",
"functions": {
"_receiver": {
"label": "Recipient"
},
},
"authentication_required": False,
"description": "",
"title": "Demande de place en creche",
"url": "http://example.net/demande-de-place-en-creche/",
"category_slug": "common",
"redirection": False,
"keywords": [],
"slug": "demande-de-place-en-creche"
}
]
def login(app, username='admin', password='admin'):
login_page = app.get('/login/')
login_form = login_page.forms[0]
login_form['username'] = username
login_form['password'] = password
resp = login_form.submit()
assert resp.status_int == 302
return app
def str2datetime(sdt):
return datetime.datetime.strptime(sdt, '%Y-%m-%dT%H:%M:%S')
class MockedRequestResponse(mock.Mock):
def json(self):
return json.loads(self.content)
def mocked_requests_get(*args, **kwargs):
remote_service = kwargs.get('remote_service')
if 'chrono' in remote_service['url']:
return MockedRequestResponse(
content=json.dumps(CHRONO_EVENTS))
else:
return MockedRequestResponse(
content=json.dumps(WCS_FORMDEFS))
@pytest.fixture
def admin(db):
return User.objects.create_superuser(username='admin', password='admin', email=None)
@pytest.fixture
def anonymous(app):
return app
@pytest.fixture
def connected(app, admin):
return login(app)
@pytest.fixture(params=['anonymous', 'connected'])
def client(request, anonymous, connected):
return locals().get(request.param)
@pytest.fixture
def cell(db):
page = Page.objects.create(title='whatever', slug='booking', template_name='standard')
cell = BookingCalendar(
page=page, title='Example Of Calendar',
agenda_reference='default:test',
formdef_reference='default:test',
slot_duration=datetime.timedelta(minutes=30),
minimal_booking_duration=datetime.timedelta(hours=1),
placeholder='content', order=0
)
cell.save()
return cell
def test_get_chrono_service(settings):
service = get_chrono_service()
assert service['title'] == 'test'
assert service['url'] == 'http://chrono.example.org'
assert service['secondary'] is False
@mock.patch('combo.apps.calendar.utils.requests.get', side_effect=mocked_requests_get)
def test_cell_rendering(mocked_get, client, cell):
page = client.get('/booking/')
# test without selecting slots
resp = page.form.submit().follow()
assert 'Please select slots' in resp.content
# test with slots from different day
resp.form.set('slots', True, 0)
resp.form.set('slots', True, 1)
resp.form.set('slots', True, 4)
resp = resp.form.submit().follow()
# test with non contiguous slots
assert 'Please select slots of the same day' in resp.content
resp.form.set('slots', True, 0)
resp.form.set('slots', True, 2)
resp = resp.form.submit().follow()
assert 'Please select contiguous slots' in resp.content
# test with invalid booking duration
resp.form.set('slots', True, 0)
resp = resp.form.submit().follow()
assert 'Minimal booking duration is 01:00' in resp.content
# test with valid selected slots
resp.form.set('slots', True, 0)
resp.form.set('slots', True, 1)
resp.form.set('slots', True, 2)
resp = resp.form.submit()
parsed = urlparse.urlparse(resp.url)
assert parsed.path == '/test/'
qs = urlparse.parse_qs(parsed.query)
assert qs['session_var_booking_agenda_slug'] == ['test']
assert qs['session_var_booking_start'] == ['2017-06-13T08:00:00+00:00']
assert qs['session_var_booking_end'] == ['2017-06-13T09:30:00+00:00']
@mock.patch('combo.apps.calendar.utils.requests.get', side_effect=mocked_requests_get)
def test_calendar(mocked_get, cell):
cal = get_calendar('default:whatever', cell.slot_duration, 7, cell.minimal_booking_duration)
assert len(cal.days) == 3
for day in cal.get_computed_days():
assert day in [
str2datetime('2017-06-13T08:00:00').date() + datetime.timedelta(days=i)
for i in range(0, 7)]
min_slot = str2datetime('2017-06-13T08:00:00')
max_slot = str2datetime('2017-06-14T15:00:00')
for slot in cal.get_slots():
assert (min_slot.time() <= slot <= max_slot.time()) is True
assert cal.has_day(min_slot.date()) is True
assert cal.get_availability(str2datetime('2017-06-14T15:00:00')).available is False
assert cal.get_minimum_slot() == min_slot.time()
assert cal.get_maximum_slot() == max_slot.time()
assert cal.get_day(max_slot.date()).slots[-1].available is False
@mock.patch('combo.apps.calendar.utils.requests.get', side_effect=mocked_requests_get)
def test_cell_pagination(mocked_get, client, cell):
cell.days_displayed = 2
cell.save()
page = client.get('/booking/')
# first page
table = page.html.find('table')
thead_th = table.thead.findChildren('th')
assert len(thead_th) == 3
for th in thead_th:
if th.text:
assert th.text in ('06/13/2017', '06/14/2017')
links = page.html.findAll('a')
assert len(links) == 2
next_page_link = links[1]
assert next_page_link.text == 'next'
assert next_page_link.attrs['href'] == '?chunk_%d=2' % cell.pk
assert next_page_link.attrs['data-content-url'] == '/ajax/calendar/content/%d/?chunk_%d=2' % (cell.pk, cell.pk)
# second page without ajax call
page2 = client.get('/booking/?chunk_%d=2' % cell.pk)
table = page2.html.find('table')
thead_th = table.thead.findChildren('th')
assert len(thead_th) == 3
for th in thead_th:
if th.text:
assert th.text in ('06/15/2017', '06/16/2017')
links = page2.html.findAll('a')
assert len(links) == 2
previous_page_link = links[1]
assert previous_page_link.text == 'previous'
assert previous_page_link.attrs['href'] == '?chunk_%d=1' % cell.pk
assert previous_page_link.attrs['data-content-url'] == '/ajax/calendar/content/%d/?chunk_%d=1' % (cell.pk, cell.pk)
# second page through ajax call
page = client.get('/booking/?chunk_%d=1')
page2 = client.get(next_page_link.attrs['data-content-url'])
table = page2.html.find('table')
thead_th = table.thead.findChildren('th')
assert len(thead_th) == 3
for th in thead_th:
if th.text:
assert th.text in ('06/15/2017', '06/16/2017')
links = page2.html.findAll('a')
assert len(links) == 1
previous_page_link = links[0]
assert previous_page_link.text == 'previous'
assert previous_page_link.attrs['data-content-url'] == '/ajax/calendar/content/%d/?chunk_%d=1' % (cell.pk, cell.pk)
@mock.patch('combo.apps.calendar.utils.requests.get', side_effect=mocked_requests_get)
def test_cell_rendering_cal_info(mocked_get, client, cell):
page = client.get('/booking/')
title_info = page.html.h2.find('span', {'class': 'calinfo'})
assert title_info.text.strip() == '(Next available slot: June 13, 2017, 8 a.m.)'
def test_cell_rendering_cal_info_when_available_slots_next_day(client, cell):
with mock.patch('combo.utils.requests.get') as request_get:
events = CHRONO_EVENTS['data'][::]
for idx in range(2):
events[idx]['disabled'] = True
def side_effect(*args, **kwargs):
if 'chrono' in kwargs['remote_service']['url']:
return MockedRequestResponse(content=json.dumps({"data": events}))
return MockedRequestResponse(content=json.dumps(WCS_FORMDEFS))
request_get.side_effect = side_effect
page = client.get('/booking/')
title_info = page.html.h2.find('span', {'class': 'calinfo'})
assert title_info.text.strip() == '(Next available slot: June 14, 2017, 9:30 a.m.)'
def test_cell_rendering_cal_info_when_no_available_slots(client, cell):
with mock.patch('combo.utils.requests.get') as request_get:
def side_effect(*args, **kwargs):
if 'chrono' in kwargs['remote_service']['url']:
return MockedRequestResponse(content=json.dumps({"data": []}))
return MockedRequestResponse(content=json.dumps(WCS_FORMDEFS))
request_get.side_effect = side_effect
page = client.get('/booking/')
title_info = page.html.h2.find('span', {'class': 'calinfo'})
assert title_info.text.strip() == '(No available slots.)'
def test_booking_calendar_indexing(cell):
with mock.patch('combo.utils.requests.get') as request_get:
def side_effect(*args, **kwargs):
if 'chrono' in kwargs['remote_service']['url']:
return MockedRequestResponse(content=json.dumps({"data": []}))
return MockedRequestResponse(content=json.dumps(WCS_FORMDEFS))
request_get.side_effect = side_effect
search_text = cell.render_for_search()
assert 'Example Of Calendar' in search_text