124 lines
7.0 KiB
Python
124 lines
7.0 KiB
Python
from django.contrib.auth import get_user_model
|
|
from rest_framework.test import APITestCase
|
|
|
|
from .models import Note, Poll, PollVote
|
|
|
|
|
|
class PollAPITests(APITestCase):
|
|
def setUp(self):
|
|
self.author = get_user_model().objects.create_user(username='author')
|
|
self.voter = get_user_model().objects.create_user(username='voter')
|
|
self.other = get_user_model().objects.create_user(username='other')
|
|
self.admin = get_user_model().objects.create_user(username='admin', is_staff=True)
|
|
self.client.force_authenticate(self.author)
|
|
|
|
def create_poll(self, **settings):
|
|
payload = dict(title='Question ?', content='', kind='poll', is_public=True, recipient_ids=[],
|
|
poll_settings=dict(vote_mode='single', exact_choices=1, is_anonymous=True, closes_at=None, options=['A', 'B', 'C']))
|
|
payload['poll_settings'].update(settings)
|
|
response = self.client.post('/api/notes/', payload, format='json')
|
|
self.assertEqual(response.status_code, 201, response.data)
|
|
return response.data
|
|
|
|
def vote(self, note, choices, user=None):
|
|
self.client.force_authenticate(user or self.voter)
|
|
return self.client.put(f"/api/notes/{note['id']}/vote/", {'option_ids': [note['poll']['options'][i]['id'] for i in choices]}, format='json')
|
|
|
|
def test_single_vote_is_replaced_and_results_stay_anonymous(self):
|
|
note = self.create_poll()
|
|
self.assertEqual(self.vote(note, [0, 1]).status_code, 400)
|
|
result = self.vote(note, [0])
|
|
self.assertEqual(result.status_code, 200, result.data)
|
|
result = self.vote(note, [1])
|
|
self.assertEqual(result.data['poll']['total_voters'], 1)
|
|
self.assertEqual([o['count'] for o in result.data['poll']['options']], [0, 1, 0])
|
|
for viewer in [self.author, self.admin, self.other]:
|
|
self.client.force_authenticate(viewer)
|
|
data = self.client.get(f"/api/notes/{note['id']}/").data['poll']
|
|
self.assertEqual(data['total_voters'], 1)
|
|
self.assertFalse(any('voters' in option for option in data['options']))
|
|
|
|
def test_anonymous_api_never_contains_voter_identity(self):
|
|
note = self.create_poll()
|
|
self.vote(note, [0])
|
|
for viewer in [self.author, self.admin, self.other]:
|
|
self.client.force_authenticate(viewer)
|
|
poll = self.client.get(f"/api/notes/{note['id']}/").data['poll']
|
|
self.assertEqual(poll['my_option_ids'], [])
|
|
for option in poll['options']:
|
|
self.assertNotIn('voters', option)
|
|
self.assertNotIn('user', option)
|
|
self.assertNotIn('username', str(poll))
|
|
|
|
def test_named_multiple_votes(self):
|
|
note = self.create_poll(vote_mode='multiple', is_anonymous=False)
|
|
result = self.vote(note, [0, 2])
|
|
self.assertEqual(result.status_code, 200, result.data)
|
|
self.assertEqual(result.data['poll']['options'][0]['voters'][0]['id'], self.voter.pk)
|
|
self.assertEqual(result.data['poll']['options'][0]['percent'], 100)
|
|
self.assertEqual(result.data['poll']['total_voters'], 1)
|
|
|
|
def test_exact_count_and_cross_poll_option_validation(self):
|
|
note = self.create_poll(vote_mode='exact', exact_choices=2)
|
|
self.assertEqual(self.vote(note, [0]).status_code, 400)
|
|
self.assertEqual(self.vote(note, [0, 1, 2]).status_code, 400)
|
|
self.assertEqual(self.vote(note, [0, 1]).status_code, 200)
|
|
self.client.force_authenticate(self.author)
|
|
other = self.create_poll()
|
|
self.client.force_authenticate(self.voter)
|
|
result = self.client.put(f"/api/notes/{note['id']}/vote/", {'option_ids': [note['poll']['options'][0]['id'], other['poll']['options'][0]['id']]}, format='json')
|
|
self.assertEqual(result.status_code, 400)
|
|
|
|
def test_rules_question_and_visibility_lock_after_first_vote(self):
|
|
note = self.create_poll()
|
|
self.vote(note, [0])
|
|
self.client.force_authenticate(self.author)
|
|
for payload in [dict(kind='info'), dict(title='Autre question'),
|
|
dict(poll_settings=dict(vote_mode='single', exact_choices=1, is_anonymous=False, closes_at=None, options=['A', 'B', 'C']))]:
|
|
result = self.client.patch(f"/api/notes/{note['id']}/", payload, format='json')
|
|
self.assertEqual(result.status_code, 400, result.data)
|
|
self.assertTrue(Poll.objects.get().is_anonymous)
|
|
self.assertEqual(Note.objects.get().kind, 'poll')
|
|
self.assertEqual(self.client.patch(f"/api/notes/{note['id']}/", {'content': 'Précision'}, format='json').status_code, 200)
|
|
|
|
def test_closed_and_deadline_polls_reject_votes(self):
|
|
note = self.create_poll()
|
|
self.client.force_authenticate(self.other)
|
|
self.assertEqual(self.client.post(f"/api/notes/{note['id']}/close/").status_code, 403)
|
|
self.client.force_authenticate(self.author)
|
|
self.assertEqual(self.client.post(f"/api/notes/{note['id']}/close/").status_code, 200)
|
|
self.assertEqual(self.vote(note, [0]).status_code, 400)
|
|
self.client.force_authenticate(self.author)
|
|
expired = self.create_poll(closes_at='2020-01-01T00:00:00Z')
|
|
self.assertEqual(self.vote(expired, [0]).status_code, 200)
|
|
|
|
def test_poll_scope_and_recipients_are_always_public_for_everyone(self):
|
|
note = self.create_poll()
|
|
response = self.client.patch(f"/api/notes/{note['id']}/", {'is_public': False, 'recipient_ids': [self.voter.pk]}, format='json')
|
|
self.assertEqual(response.status_code, 200, response.data)
|
|
self.assertTrue(response.data['is_public'])
|
|
self.assertEqual(response.data['recipients'], [])
|
|
self.client.force_authenticate(self.other)
|
|
self.assertEqual(self.client.get(f"/api/notes/{note['id']}/").status_code, 200)
|
|
self.assertEqual(self.vote(note, [0], self.other).status_code, 200)
|
|
|
|
def test_new_user_can_participate_in_public_poll_for_everyone(self):
|
|
note = self.create_poll()
|
|
new_user = get_user_model().objects.create_user(username='new')
|
|
self.assertEqual(self.vote(note, [1], new_user).status_code, 200)
|
|
|
|
def test_convert_existing_memo_to_poll_and_back_before_votes(self):
|
|
note = Note.objects.create(author=self.author, title='Mémo')
|
|
result = self.client.patch(f'/api/notes/{note.pk}/', dict(kind='poll', poll_settings=dict(options=['Oui', 'Non'])), format='json')
|
|
self.assertEqual(result.status_code, 200, result.data)
|
|
self.assertEqual(len(result.data['poll']['options']), 2)
|
|
result = self.client.patch(f'/api/notes/{note.pk}/', dict(kind='memo'), format='json')
|
|
self.assertEqual(result.status_code, 200)
|
|
self.assertIsNone(result.data['poll'])
|
|
self.assertFalse(Poll.objects.exists())
|
|
|
|
def test_invalid_poll_does_not_leave_note_behind(self):
|
|
result = self.client.post('/api/notes/', dict(kind='poll', title='Test', poll_settings=dict(options=['A', 'A'])), format='json')
|
|
self.assertEqual(result.status_code, 400)
|
|
self.assertFalse(Note.objects.exists())
|