diff --git a/addons/survey/tests/__init__.py b/addons/survey/tests/__init__.py
index 12f614f03bc..b345311e36b 100644
--- a/addons/survey/tests/__init__.py
+++ b/addons/survey/tests/__init__.py
@@ -1,5 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from . import common
from . import test_survey
+from . import test_survey_flow
+from . import test_survey_invite
from . import test_survey_ui
diff --git a/addons/survey/tests/common.py b/addons/survey/tests/common.py
new file mode 100644
index 00000000000..fbe03f3f24b
--- /dev/null
+++ b/addons/survey/tests/common.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from collections import Counter
+from contextlib import contextmanager
+from functools import partial
+
+from odoo.tests import common, new_test_user
+
+survey_new_test_user = partial(new_test_user, context={'mail_create_nolog': True, 'mail_create_nosubscribe': True, 'mail_notrack': True, 'no_reset_password': True})
+
+
+class SurveyCase(common.SavepointCase):
+
+ def setUp(self):
+ super(SurveyCase, self).setUp()
+
+ """ Some custom stuff to make the matching between questions and answers
+ :param dict _type_match: dict
+ key: question type
+ value: (answer type, answer field_name)
+ """
+ self._type_match = {
+ 'free_text': ('free_text', 'value_free_text'),
+ 'textbox': ('text', 'value_text'),
+ 'numerical_box': ('number', 'value_number'),
+ 'date': ('date', 'value_date'),
+ 'simple_choice': ('suggestion', 'value_suggested'), # TDE: still unclear
+ 'multiple_choice': ('suggestion', 'value_suggested'), # TDE: still unclear
+ 'matrix': ('suggestion', ('value_suggested', 'value_suggested_row')), # TDE: still unclear
+ }
+
+ """ Create test data: a survey with some pre-defined questions and various test users for ACL """
+ self.survey_manager = survey_new_test_user(
+ self.env, name='Gustave Doré', login='survey_manager', email='survey.manager@example.com',
+ groups='survey.group_survey_manager,base.group_user'
+ )
+
+ self.survey_user = survey_new_test_user(
+ self.env, name='Lukas Peeters', login='survey_user', email='survey.user@example.com',
+ groups='survey.group_survey_user,base.group_user'
+ )
+
+ self.user_emp = survey_new_test_user(
+ self.env, name='Eglantine Employee', login='user_emp', email='employee@example.com',
+ groups='base.group_user'
+ )
+
+ self.user_portal = survey_new_test_user(
+ self.env, name='Patrick Portal', login='user_portal', email='portal@example.com',
+ groups='base.group_portal'
+ )
+
+ self.user_public = survey_new_test_user(
+ self.env, name='Pauline Public', login='user_public', email='public@example.com',
+ groups='base.group_public'
+ )
+
+ self.customer = self.env['res.partner'].create({
+ 'name': 'Caroline Customer',
+ 'email': 'customer@example.com',
+ 'customer': True,
+ })
+
+ self.survey = self.env['survey.survey'].sudo(self.survey_manager).create({
+ 'title': 'Test Survey',
+ 'auth_required': True,
+ 'users_can_go_back': False,
+ })
+ self.page_0 = self.env['survey.page'].sudo(self.survey_manager).create({
+ 'title': 'First page',
+ 'survey_id': self.survey.id,
+ })
+ self.question_ft = self.env['survey.question'].sudo(self.survey_manager).create({
+ 'question': 'Test Free Text',
+ 'page_id': self.page_0.id,
+ 'question_type': 'free_text',
+ })
+ self.question_num = self.env['survey.question'].sudo(self.survey_manager).create({
+ 'question': 'Test NUmerical Box',
+ 'page_id': self.page_0.id,
+ 'question_type': 'numerical_box',
+ })
+
+ @contextmanager
+ def sudo(self, user):
+ """ Quick sudo environment """
+ old_uid = self.uid
+ try:
+ self.uid = user.id
+ self.env = self.env(user=self.uid)
+ yield
+ finally:
+ # back
+ self.uid = old_uid
+ self.env = self.env(user=self.uid)
+
+ def assertAnswer(self, answer, state, page):
+ self.assertEqual(answer.state, state)
+ self.assertEqual(answer.last_displayed_page_id, page)
+
+ def assertAnswerLines(self, page, answer, answer_data):
+ """ Check answer lines.
+
+ :param dict answer_data:
+ key = question ID
+ value = {'value': [user input]}
+ """
+ lines = answer.user_input_line_ids.filtered(lambda l: l.page_id == page)
+ answer_count = sum(len(user_input['value']) for user_input in answer_data.values())
+ self.assertEqual(len(lines), answer_count)
+ for qid, user_input in answer_data.items():
+ answer_lines = lines.filtered(lambda l: l.question_id.id == qid)
+ question = answer_lines[0].question_id # TDE note: might have several answers for a given question
+ if question.question_type == 'multiple_choice':
+ values = user_input['value']
+ answer_fname = self._type_match[question.question_type][1]
+ self.assertEqual(
+ Counter(getattr(line, answer_fname).id for line in answer_lines),
+ Counter(values))
+ elif question.question_type == 'simple_choice':
+ [value] = user_input['value']
+ answer_fname = self._type_match[question.question_type][1]
+ self.assertEqual(getattr(answer_lines, answer_fname).id, value)
+ elif question.question_type == 'matrix':
+ [value_col, value_row] = user_input['value']
+ answer_fname_col = self._type_match[question.question_type][1][0]
+ answer_fname_row = self._type_match[question.question_type][1][1]
+ self.assertEqual(getattr(answer_lines, answer_fname_col).id, value_col)
+ self.assertEqual(getattr(answer_lines, answer_fname_row).id, value_row)
+ else:
+ [value] = user_input['value']
+ answer_fname = self._type_match[question.question_type][1]
+ self.assertEqual(getattr(answer_lines, answer_fname), value)
+
+ def assertResponse(self, response, status_code, text_bits=None):
+ self.assertEqual(response.status_code, status_code)
+ for text in text_bits or []:
+ self.assertIn(text, response.text)
+
+ def _add_question(self, page, name, qtype, **kwargs):
+ constr_mandatory = kwargs.pop('constr_mandatory', True)
+ constr_error_msg = kwargs.pop('constr_error_msg', 'TestError')
+ base_qvalues = {
+ 'page_id': page.id,
+ 'question': name,
+ 'question_type': qtype,
+ 'constr_mandatory': constr_mandatory,
+ 'constr_error_msg': constr_error_msg,
+ }
+ if qtype in ('simple_choice', 'multiple_choice'):
+ base_qvalues['labels_ids'] = [
+ (0, 0, {'value': label['value'], 'quizz_mark': label.get('quizz_mark', 0)})
+ for label in kwargs.pop('labels')
+ ]
+ elif qtype == 'matrix':
+ base_qvalues['matrix_subtype'] = kwargs.pop('matrix_subtype', 'simple')
+ base_qvalues['labels_ids'] = [
+ (0, 0, {'value': label['value'], 'quizz_mark': label.get('quizz_mark', 0)})
+ for label in kwargs.pop('labels')
+ ]
+ base_qvalues['labels_ids_2'] = [
+ (0, 0, {'value': label['value'], 'quizz_mark': label.get('quizz_mark', 0)})
+ for label in kwargs.pop('labels_2')
+ ]
+ else:
+ pass
+ base_qvalues.update(kwargs)
+ question = self.env['survey.question'].create(base_qvalues)
+ return question
+
+ def _add_answer(self, survey, partner, **kwargs):
+ base_avals = {
+ 'survey_id': survey.id,
+ 'partner_id': partner.id if partner else False,
+ 'email': kwargs.pop('email', False),
+ 'input_type': 'manually',
+ }
+ base_avals.update(kwargs)
+ return self.env['survey.user_input'].create(base_avals)
+
+ def _add_answer_line(self, question, answer, answer_value, **kwargs):
+ qtype = self._type_match.get(question.question_type, (False, False))
+ answer_type = kwargs.pop('answer_type', qtype[0])
+ answer_fname = kwargs.pop('answer_fname', qtype[1])
+
+ base_alvals = {
+ 'user_input_id': answer.id,
+ 'question_id': question.id,
+ 'skipped': False,
+ 'answer_type': answer_type,
+ }
+ base_alvals[answer_fname] = answer_value
+ base_alvals.update(kwargs)
+ return self.env['survey.user_input_line'].create(base_alvals)
diff --git a/addons/survey/tests/test_survey.py b/addons/survey/tests/test_survey.py
index 312a566e56a..0ce7c5d612d 100644
--- a/addons/survey/tests/test_survey.py
+++ b/addons/survey/tests/test_survey.py
@@ -2,269 +2,192 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import random
-import re
+
from collections import Counter
from itertools import product
-
from werkzeug import urls
from odoo import _
from odoo.addons.http_routing.models.ir_http import slug
-from odoo.exceptions import UserError
-from odoo.tests.common import TransactionCase
+from odoo.addons.survey.tests import common
+from odoo.tests.common import users
-class TestSurvey(TransactionCase):
- def setUp(self):
- super(TestSurvey, self).setUp()
- User = self.env['res.users'].with_context({'no_reset_password': True})
- (group_survey_user, group_employee) = (self.ref('survey.group_survey_user'), self.ref('base.group_user'))
- self.survey_manager = User.create({
- 'name': 'Gustave Doré', 'login': 'Gustav','email': 'gustav.dore@example.com',
- 'groups_id': [(6, 0, [self.ref('survey.group_survey_manager'), group_survey_user, group_employee])]})
+class TestSurveyInternals(common.SurveyCase):
- self.survey_user = User.create({
- 'name': 'Lukas Peeters', 'login': 'Lukas', 'email': 'lukas.petters@example.com',
- 'groups_id': [(6, 0, [group_survey_user, group_employee])]})
-
- self.user_public = User.create({
- 'name': 'Wout Janssens', 'login': 'Wout', 'email': 'wout.janssens@example.com',
- 'groups_id': [(6, 0, [self.ref('base.group_public')])]})
-
- self.survey1 = self.env['survey.survey'].sudo(self.survey_manager).create({'title': "S0", 'page_ids': [(0, 0, {'title': "P0"})]})
- self.page1 = self.survey1.page_ids[0]
-
- def test_00_create_minimal_survey(self):
- question = self.env['survey.question'].sudo(self.survey_manager).create({'page_id': self.page1.id, 'question': 'Q0'})
- self.assertEqual(self.survey1.title, "S0", msg="Title of the survey is somehow modified.")
- self.assertEqual(len(self.survey1.page_ids), 1, msg="Additional Pages are linked with the survey after creation.")
- self.assertEqual(self.page1.title, "P0", msg="Title of the page is somehow modified.")
- self.assertEqual(len(self.page1.question_ids), 1, msg="Additional questions are linked with the page after creation.")
- self.assertEqual(question.question, "Q0", msg="Title of the Question is somehow modified.")
-
- def test_01_question_type_validation_save_line_function(self):
+ @users('survey_manager')
+ def test_answer_validation_mandatory(self):
+ """ For each type of question check that mandatory questions correctly check for complete answers """
for (question_type, text) in self.env['survey.question']._fields['question_type'].selection:
- # Each question type must have validation function.
- self.assertTrue(hasattr(self.env['survey.question'], 'validate_' + question_type), msg="Question must have a validation method in\
- the form of 'validate_' followed by the name of the type.")
-
- # Survey Input Lines must have validation function for each line.
- self.assertTrue(hasattr(self.env['survey.user_input_line'], 'save_line_' + question_type), msg="Inputline must have Save method in \
- the form of 'save_line_' followed by the name of the type.")
-
- def test_02_question_answer_required(self):
- for (question_type, text) in self.env['survey.question']._fields['question_type'].selection:
- # Blank value of field is not accepted for mandatory questions.
+ kwargs = {}
if question_type == 'multiple_choice':
- question = self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'multiple_choice',
- 'constr_mandatory': True, 'constr_error_msg': 'Error',
- 'labels_ids': [(0, 0, {'value': "MChoice0", "quizz_mark": 0}), (0, 0, {'value': "MChoice1", "quizz_mark": 0})]})
-
+ kwargs['labels'] = [{'value': 'MChoice0'}, {'value': 'MChoice1'}]
+ elif question_type == 'simple_choice':
+ kwargs['labels'] = []
elif question_type == 'matrix':
- question = self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'matrix', 'matrix_subtype': 'simple',
- 'constr_mandatory': True, 'constr_error_msg': 'Error',
- 'labels_ids': [(0, 0, {'value': "Column0", "quizz_mark": 0}), (0, 0, {'value': "Column1", "quizz_mark": 0})],
- 'labels_ids_2': [(0, 0, {'value': "Row0", "quizz_mark": 0}), (0, 0, {'value': "Row1", "quizz_mark": 0})]})
+ kwargs['labels'] = [{'value': 'Column0'}, {'value': 'Column1'}]
+ kwargs['labels_2'] = [{'value': 'Row0'}, {'value': 'Row1'}]
+ question = self._add_question(self.page_0, 'Q0', question_type, **kwargs)
- else:
- question = self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': question_type, 'constr_mandatory': True, 'constr_error_msg': 'Error'})
- answer_tag = '%s_%s_%s' % (self.survey1.id, self.page1.id, question.id)
- self.assertDictEqual({answer_tag: "Error"}, question.validate_question({answer_tag: ''}, answer_tag),
- msg=("Validation function for type %s is unable to generate error if it is mandatory and answer is blank." % question_type))
+ answer_tag = '%s_%s_%s' % (self.survey.id, self.page_0.id, question.id)
+ self.assertDictEqual(
+ question.validate_question({answer_tag: ''}, answer_tag),
+ {answer_tag: 'TestError'}
+ )
- def test_03_question_textbox(self):
- questions = [
- self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'textbox', 'validation_email': True}),
- self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q1', 'question_type': 'textbox', 'validation_required': True,
- 'validation_length_min': 2, 'validation_length_max': 8, 'validation_error_msg': "Error"})]
+ @users('survey_manager')
+ def test_answer_validation_date(self):
+ question = self._add_question(
+ self.page_0, 'Q0', 'date', validation_required=True,
+ validation_min_date='2015-03-20', validation_max_date='2015-03-25', validation_error_msg='ValidationError')
+ answer_tag = '%s_%s_%s' % (self.survey.id, self.page_0.id, question.id)
- results = [('test @ testcom', _('This answer must be an email address')), ('t', 'Error')]
- for i in range(len(questions)):
- answer_tag = '%s_%s_%s' % (self.survey1.id, self.page1.id, questions[i].id)
- self.assertEqual(questions[i].validate_question({answer_tag: results[i][0]}, answer_tag), {answer_tag: results[i][1]}, msg="\
- Validation function for textbox is unable to notify if answer is violating the validation rules")
-
- def test_04_question_numerical_box(self):
- question = self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'numerical_box', 'validation_required': True,
- 'validation_min_float_value': 2.1, 'validation_max_float_value': 3.0, 'validation_error_msg': "Error"})
- answer_tag = '%s_%s_%s' % (self.survey1.id, self.page1.id, question.id)
- results = [('aaa', _('This is not a number')), ('4.5', 'Error'), ('0.1', 'Error')]
- for i in range(len(results)):
- self.assertEqual(question.validate_question({answer_tag: results[i][0]}, answer_tag), {answer_tag: results[i][1]}, msg="\
- Validation function for type numerical_box is unable to notify if answer is violating the validation rules")
-
- def test_05_question_date(self):
- question = self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'date', 'validation_required': True,
- 'validation_min_date': '2015-03-20', 'validation_max_date': '2015-03-25', 'validation_error_msg': "Error"})
- answer_tag = '%s_%s_%s' % (self.survey1.id, self.page1.id, question.id)
- results = [('2015-55-10', _('This is not a date')), ('2015-03-19', 'Error'), ('2015-03-26', 'Error')]
- for i in range(len(results)):
- self.assertEqual(question.validate_question({answer_tag: results[i][0]}, answer_tag), {answer_tag: results[i][1]}, msg="\
- Validation function for type date is unable to notify if answer is violating the validation rules")
-
- def test_06_survey_sharing(self):
- # Case-1: Executing action with correct data.
- correct_survey = self.env['survey.survey'].sudo(self.survey_manager).create({
- 'title': "S0", 'stage_id': self.env['survey.stage'].search([('sequence', '=', 1)]).id,
- 'page_ids': [(0, 0, {'title': "P0", 'question_ids': [(0, 0, {'question': "Q0", 'question_type': 'free_text'})]})]})
- action = correct_survey.action_send_survey()
- template = self.env.ref('survey.email_template_survey', raise_if_not_found=False)
-
- ctx = dict(
- self.env.context,
- default_model='survey.survey',
- default_res_id=correct_survey.id,
- default_survey_id=correct_survey.id,
- default_use_template=bool(template),
- default_template_id=template and template.id or False,
- default_composition_mode='comment',
- notif_layout='mail.mail_notification_light',
+ self.assertEqual(
+ question.validate_question({answer_tag: 'Is Alfred an answer ?'}, answer_tag),
+ {answer_tag: _('This is not a date')}
)
- self.assertDictEqual(action, {
- 'type': 'ir.actions.act_window',
- 'view_type': 'form',
- 'view_mode': 'form',
- 'res_model': 'survey.invite',
- 'target': 'new',
- 'context': ctx,
- })
+ self.assertEqual(
+ question.validate_question({answer_tag: '2015-03-19'}, answer_tag),
+ {answer_tag: 'ValidationError'}
+ )
- # Case-2: Executing action with incorrect data.
- surveys = [
- self.env['survey.survey'].sudo(self.survey_manager).create({ # Survey without any page or question.
- 'title': "Test survey"}),
- self.env['survey.survey'].sudo(self.survey_manager).create({ # Closed Survey.
- 'title': "S0", 'stage_id': self.env['survey.stage'].search([('closed', '=', True)]).id, # Getting Closed stage id.
- 'page_ids': [(0, 0, {'title': "P0", 'question_ids': [(0, 0, {'question': "Q0", 'question_type': 'free_text'})]})]})]
- for survey in surveys:
- self.assertRaises(UserError, survey.action_send_survey)
+ self.assertEqual(
+ question.validate_question({answer_tag: '2015-03-26'}, answer_tag),
+ {answer_tag: 'ValidationError'}
+ )
- def test_07_survey_email_message(self):
- # Case-1: Executing send_mail with correct data.
- partner = self.env['res.partner'].create({'name': 'Marie De Cock', 'email': 'marie.de.cock@gmail.com'})
- survey_mail_message = self.env['survey.invite'].sudo(self.survey_manager).create({
- 'survey_id': self.survey1.id, 'public': 'email_public_link', 'body': '__URL__', 'partner_ids': [(4, partner.id)]})
- survey_mail_message.send_mail()
+ self.assertEqual(
+ question.validate_question({answer_tag: '2015-03-25'}, answer_tag),
+ {}
+ )
- # Case-2: Executing send_mail with incorrect data.
- mail_messages = [
- self.env['survey.invite'].sudo(self.survey_manager).create({ # Mail Message without __URL__ in body.
- 'survey_id': self.survey1.id, 'public': 'email_public_link'}),
- self.env['survey.invite'].sudo(self.survey_manager).create({ # Mail Message without recipents.
- 'survey_id': self.survey1.id, 'public': 'email_public_link', 'body': "__URL__"})]
- for message in mail_messages:
- self.assertRaises(UserError, message.send_mail)
+ @users('survey_manager')
+ def test_answer_validation_numerical(self):
+ question = self._add_question(
+ self.page_0, 'Q0', 'numerical_box', validation_required=True,
+ validation_min_float_value=2.2, validation_max_float_value=3.3, validation_error_msg='ValidationError')
+ answer_tag = '%s_%s_%s' % (self.survey.id, self.page_0.id, question.id)
- def test_08_survey_urls(self):
- def validate_url(url):
- """ Reference: https://github.com/django/django/blob/master/django/core/validators.py """
- url_regex = re.compile(
- r'^https?://' # http:// or https://
- r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
- r'localhost|' # localhost...
- r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
- r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
- r'(?::\d+)?' # optional port
- r'(?:/?|[/?]\S+)$', re.IGNORECASE)
- return True if url_regex.match(url) else False
+ self.assertEqual(
+ question.validate_question({answer_tag: 'Is Alfred an answer ?'}, answer_tag),
+ {answer_tag: _('This is not a number')}
+ )
- base_url = self.env['ir.config_parameter'].get_param('web.base.url')
- urltypes = {'public': 'start', 'print': 'print', 'result': 'results'}
- for urltype, urltxt in urltypes.items():
- survey_url = getattr(self.survey1, urltype + '_url')
- survey_url_relative = getattr(self.survey1.with_context({'relative_url': True}), urltype + '_url')
- self.assertTrue(validate_url(survey_url))
- url = "survey/%s/%s" % (urltxt, slug(self.survey1))
- full_url = urls.url_join(base_url, url)
- self.assertEqual(full_url, survey_url)
- self.assertEqual('/' + url, survey_url_relative)
- if urltype == 'public':
- url_html = 'Click here to start survey'
- self.assertEqual(url_html % full_url, getattr(self.survey1, urltype + '_url_html'), msg="Public URL is incorrect")
- self.assertEqual(url_html % ('/' + url), getattr(self.survey1.with_context({'relative_url': True}), urltype + '_url_html'), msg="Public URL is incorrect.")
+ self.assertEqual(
+ question.validate_question({answer_tag: '2.0'}, answer_tag),
+ {answer_tag: 'ValidationError'}
+ )
- def test_09_answer_survey(self):
- question = self.env['survey.question'].sudo(self.survey_manager).create({'page_id': self.page1.id, 'question': 'Q0'})
- input_portal = self.env['survey.user_input'].sudo(self.survey_user).create({
- 'survey_id': self.survey1.id,
- 'partner_id': self.survey_user.partner_id.id,
- 'user_input_line_ids': [(0, 0, {
- 'skipped': False, 'answer_type': 'free_text', 'value_free_text': "Test Answer",
- 'survey_id': self.survey1.id, 'question_id': question.id})]})
+ self.assertEqual(
+ question.validate_question({answer_tag: '4.0'}, answer_tag),
+ {answer_tag: 'ValidationError'}
+ )
- input_public = self.env['survey.user_input'].sudo(self.user_public).create({
- 'survey_id': self.survey1.id,
- 'partner_id': self.survey_user.partner_id.id,
- 'user_input_line_ids': [(0, 0, {
- 'skipped': False, 'answer_type': 'free_text', 'value_free_text': "Test Answer",
- 'survey_id': self.survey1.id, 'question_id': question.id})]})
+ self.assertEqual(
+ question.validate_question({answer_tag: '2.9'}, answer_tag),
+ {}
+ )
- answers = [input_portal.user_input_line_ids[0], input_public.user_input_line_ids[0]]
- expected_values = {'answer_type': 'free_text', 'value_free_text': "Test Answer"}
- for answer in answers:
- for field, value in expected_values.items():
- self.assertEqual(answer[field], value, msg="Unable to answer the survey. Expected behaviour of %s is not proper." % (field))
+ @users('survey_manager')
+ def test_answer_validation_textbox_email(self):
+ question = self._add_question(self.page_0, 'Q0', 'textbox', validation_email=True)
+ answer_tag = '%s_%s_%s' % (self.survey.id, self.page_0.id, question.id)
- def test_10_survey_result_simple_multiple_choice(self):
- question = self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'simple_choice',
- 'labels_ids': [(0, 0, {'value': "Choice0", 'quizz_mark': 0}), (0, 0, {'value': "Choice1", 'quizz_mark': 0})]})
+ self.assertEqual(
+ question.validate_question({answer_tag: 'not an email'}, answer_tag),
+ {answer_tag: _('This answer must be an email address')}
+ )
+
+ self.assertEqual(
+ question.validate_question({answer_tag: 'email@example.com'}, answer_tag),
+ {}
+ )
+
+ @users('survey_manager')
+ def test_answer_validation_textbox_length(self):
+ question = self._add_question(
+ self.page_0, 'Q0', 'textbox', validation_required=True,
+ validation_length_min=2, validation_length_max=8, validation_error_msg='ValidationError')
+ answer_tag = '%s_%s_%s' % (self.survey.id, self.page_0.id, question.id)
+
+ self.assertEqual(
+ question.validate_question({answer_tag: 'l'}, answer_tag),
+ {answer_tag: 'ValidationError'}
+ )
+
+ self.assertEqual(
+ question.validate_question({answer_tag: 'waytoomuchlonganswer'}, answer_tag),
+ {answer_tag: 'ValidationError'}
+ )
+
+ self.assertEqual(
+ question.validate_question({answer_tag: 'valid'}, answer_tag),
+ {}
+ )
+
+ @users('survey_manager')
+ def test_result_data_simple_multiple_choice(self):
+ question = self._add_question(
+ self.page_0, 'Q0', 'simple_choice',
+ labels=[{'value': 'Choice0'}, {'value': 'Choice1'}]
+ )
for i in range(3):
- self.env['survey.user_input'].sudo(self.user_public).create({'survey_id': self.survey1.id, 'user_input_line_ids': [(0, 0, {
- 'question_id': question.id,
- 'answer_type': 'suggestion',
- 'value_suggested': random.choice(question.labels_ids.ids)})]})
+ answer = self._add_answer(self.survey, False, email='public@example.com')
+ self._add_answer_line(
+ question, answer, random.choice(question.labels_ids.ids),
+ answer_type='suggestion', answer_fname='value_suggested')
lines = [line.value_suggested.id for line in question.user_input_line_ids]
answers = [{'text': label.value, 'count': lines.count(label.id), 'answer_id': label.id} for label in question.labels_ids]
prp_result = self.env['survey.survey'].prepare_result(question)['answers']
- self.assertItemsEqual(prp_result, answers, msg="Statistics of simple, multiple choice questions are different from expectation")
+ self.assertItemsEqual(prp_result, answers)
- def test_11_survey_result_matrix(self):
- question = self.env['survey.question'].sudo(self.survey_manager).create({
- 'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'matrix', 'matrix_subtype': 'simple',
- 'labels_ids': [(0, 0, {'value': "Column0", "quizz_mark": 0}), (0, 0, {'value': "Column1", "quizz_mark": 0})],
- 'labels_ids_2': [(0, 0, {'value': "Row0", "quizz_mark": 0}), (0, 0, {'value': "Row1", "quizz_mark": 0})]})
+ @users('survey_manager')
+ def test_result_data_matrix(self):
+ question = self._add_question(
+ self.page_0, 'Q0', 'matrix', matrix_subtype='simple',
+ labels=[{'value': 'Column0'}, {'value': 'Column1'}],
+ labels_2=[{'value': 'Row0'}, {'value': 'Row1'}]
+ )
for i in range(3):
- self.env['survey.user_input'].sudo(self.user_public).create({'survey_id': self.survey1.id, 'user_input_line_ids': [(0, 0, {
- 'question_id': question.id, 'answer_type': 'suggestion', 'value_suggested': random.choice(question.labels_ids.ids),
- 'value_suggested_row': random.choice(question.labels_ids_2.ids)})]})
+ answer = self._add_answer(self.survey, False, email='public@example.com')
+ self._add_answer_line(
+ question, answer, random.choice(question.labels_ids.ids),
+ answer_type='suggestion', answer_fname='value_suggested', value_suggested_row=random.choice(question.labels_ids_2.ids)
+ )
lines = [(line.value_suggested_row.id, line.value_suggested.id) for line in question.user_input_line_ids]
res = {}
for i in product(question.labels_ids_2.ids, question.labels_ids.ids):
res[i] = lines.count((i))
- self.assertEqual(self.env['survey.survey'].prepare_result(question)['result'], res, msg="Statistics of matrix type questions are different from expectations")
+ self.assertEqual(self.env['survey.survey'].prepare_result(question)['result'], res)
- def test_12_survey_result_numeric_box(self):
- question = self.env['survey.question'].sudo(self.survey_manager).create({'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'numerical_box'})
+ @users('survey_manager')
+ def test_result_data_numeric_box(self):
+ question = self._add_question(self.page_0, 'Q0', 'numerical_box')
num = [float(n) for n in random.sample(range(1, 100), 3)]
nsum = sum(num)
for i in range(3):
- self.env['survey.user_input'].sudo(self.user_public).create({'survey_id': self.survey1.id, 'user_input_line_ids': [(0, 0, {
- 'question_id': question.id, 'answer_type': 'number', 'value_number': num[i]})]})
+ answer = self._add_answer(self.survey, False, email='public@example.com')
+ self._add_answer_line(question, answer, num[i])
exresult = {
'average': round((nsum / len(num)), 2), 'max': round(max(num), 2),
'min': round(min(num), 2), 'sum': nsum, 'most_common': Counter(num).most_common(5)}
result = self.env['survey.survey'].prepare_result(question)
for key in exresult:
- self.assertEqual(result[key], exresult[key], msg="Statistics of numeric box type questions are different from expectations")
+ self.assertEqual(result[key], exresult[key])
- def test_13_survey_actions(self):
- self.env['survey.question'].sudo(self.survey_manager).create({'page_id': self.page1.id, 'question': 'Q0', 'question_type': 'numerical_box'})
-
- actions = {
- 'start': {'method': 'public', 'token': '/test', 'text': 'Start'},
- 'print': {'method': 'print', 'token': '/test', 'text': 'Print'},
- 'result': {'method': 'result', 'token': '', 'text': 'Results of the'},
- 'test': {'method': 'public', 'token': '/phantom', 'text': 'Results of the'}}
- for action, val in actions.items():
- result = getattr(self.survey1.with_context({'survey_token': val['token'][1:]}), 'action_' + action + '_survey')()
- url = getattr(self.survey1.with_context({'relative_url': True}), val['method'] + '_url') + val['token']
- self.assertEqual(result['url'], url)
+ @users('survey_manager')
+ def test_survey_urls(self):
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+ urltypes = {'public': 'start', 'print': 'print', 'result': 'results'}
+ for urltype, urltxt in urltypes.items():
+ survey_url = getattr(self.survey, urltype + '_url')
+ survey_url_relative = getattr(self.survey.with_context({'relative_url': True}), urltype + '_url')
+ url = "survey/%s/%s" % (urltxt, slug(self.survey))
+ full_url = urls.url_join(base_url, url)
+ self.assertEqual(full_url, survey_url)
+ self.assertEqual('/' + url, survey_url_relative)
+ if urltype == 'public':
+ url_html = 'Click here to start survey'
+ self.assertEqual(url_html % full_url, getattr(self.survey, urltype + '_url_html'), msg="Public URL is incorrect")
+ self.assertEqual(url_html % ('/' + url), getattr(self.survey.with_context({'relative_url': True}), urltype + '_url_html'))
diff --git a/addons/survey/tests/test_survey_flow.py b/addons/survey/tests/test_survey_flow.py
new file mode 100644
index 00000000000..12230d49194
--- /dev/null
+++ b/addons/survey/tests/test_survey_flow.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import re
+
+from odoo.addons.survey.tests import common
+from odoo.tests import tagged
+from odoo.tests.common import HttpCase
+
+
+@tagged('functional')
+class TestSurveyFlow(common.SurveyCase, HttpCase):
+
+ def _access_start(self, survey):
+ return self.url_open('/survey/start/%s' % survey.id)
+
+ def _access_page(self, survey, token):
+ return self.url_open('/survey/fill/%s/%s' % (survey.id, token))
+
+ def _access_submit(self, survey, post_data):
+ return self.url_open('/survey/submit/%s' % survey.id, data=post_data)
+
+ def _find_csrf_token(self, text):
+ csrf_token_re = re.compile("(input.+csrf_token.+value=\")([_a-zA-Z0-9]{51})", re.MULTILINE)
+ return csrf_token_re.search(text).groups()[1]
+
+ def _format_submission_data(self, page, answer_data, additional_post_data):
+ post_data = {}
+ post_data['page_id'] = page.id
+ for question_id, answer_vals in answer_data.items():
+ question = page.question_ids.filtered(lambda q: q.id == question_id)
+ if question.question_type == 'multiple_choice':
+ values = answer_vals['value']
+ for value in values:
+ key = "%s_%s_%s_%s" % (page.survey_id.id, page.id, question.id, value)
+ post_data[key] = value
+ else:
+ [value] = answer_vals['value']
+ key = "%s_%s_%s" % (page.survey_id.id, page.id, question.id)
+ post_data[key] = value
+ post_data.update(**additional_post_data)
+ return post_data
+
+ def test_flow_public(self):
+ # Step: survey manager creates the survey
+ # --------------------------------------------------
+ with self.sudo(self.survey_manager):
+ survey = self.env['survey.survey'].create({
+ 'title': 'Public Survey for Tarte Al Djotte',
+ 'auth_required': False,
+ })
+
+ # First page is about customer data
+ page_0 = self.env['survey.page'].create({
+ 'title': 'Page1: Your Data',
+ 'survey_id': survey.id,
+ })
+ page0_q0 = self._add_question(
+ page_0, 'What is your name', 'free_text',
+ comments_allowed=False,
+ constr_mandatory=True, constr_error_msg='Please enter your name')
+ page0_q1 = self._add_question(
+ page_0, 'What is your age', 'numerical_box',
+ comments_allowed=False,
+ constr_mandatory=True, constr_error_msg='Please enter your name')
+
+ # Second page is about tarte al djotte
+ page_1 = self.env['survey.page'].create({
+ 'title': 'Page2: Tarte Al Djotte',
+ 'survey_id': survey.id,
+ })
+ page1_q0 = self._add_question(
+ page_1, 'What do you like most in our tarte al djotte', 'multiple_choice',
+ labels=[{'value': 'The gras'},
+ {'value': 'The bette'},
+ {'value': 'The tout'},
+ {'value': 'The regime is fucked up'}])
+
+ # fetch starting data to check only newly created data during this flow
+ answers = self.env['survey.user_input'].search([('survey_id', '=', survey.id)])
+ answer_lines = self.env['survey.user_input_line'].search([('survey_id', '=', survey.id)])
+ self.assertEqual(answers, self.env['survey.user_input'])
+ self.assertEqual(answer_lines, self.env['survey.user_input_line'])
+
+ # Step: customer takes the survey
+ # --------------------------------------------------
+
+ # Customer opens start page
+ r = self._access_start(survey)
+ self.assertResponse(r, 200, [survey.title])
+
+ # -> this should have generated a new answer with a token
+ answers = self.env['survey.user_input'].search([('survey_id', '=', survey.id)])
+ self.assertEqual(len(answers), 1)
+ answer_token = answers.token
+ self.assertTrue(answer_token)
+ self.assertAnswer(answers, 'new', self.env['survey.page'])
+
+ # Customer begins survey with first page
+ r = self._access_page(survey, answer_token)
+ self.assertResponse(r, 200)
+ self.assertAnswer(answers, 'new', self.env['survey.page'])
+ csrf_token = self._find_csrf_token(r.text)
+
+ # Customer submit first page answers
+ answer_data = {
+ page0_q0.id: {'value': ['Alfred Poilvache']},
+ page0_q1.id: {'value': [44.0]},
+ }
+ post_data = self._format_submission_data(page_0, answer_data, {'csrf_token': csrf_token, 'token': answer_token, 'button_submit': 'next'})
+ r = self._access_submit(survey, post_data)
+ self.assertResponse(r, 200)
+ answers.invalidate_cache() # TDE note: necessary as lots of sudo in controllers messing with cache
+
+ # -> this should have generated answer lines
+ self.assertAnswer(answers, 'skip', page_0)
+ self.assertAnswerLines(page_0, answers, answer_data)
+
+ # Customer is redirected on second page and begins filling it
+ r = self._access_page(survey, answer_token)
+ self.assertResponse(r, 200)
+ csrf_token_re = re.compile("(input.+csrf_token.+value=\")([_a-zA-Z0-9]{51})", re.MULTILINE)
+ csrf_token = csrf_token_re.search(r.text).groups()[1]
+
+ # Customer submit second page answers
+ answer_data = {
+ page1_q0.id: {'value': [page1_q0.labels_ids.ids[0], page1_q0.labels_ids.ids[1]]},
+ }
+ post_data = self._format_submission_data(page_1, answer_data, {'csrf_token': csrf_token, 'token': answer_token, 'button_submit': 'next'})
+ r = self._access_submit(survey, post_data)
+ self.assertResponse(r, 200)
+ answers.invalidate_cache() # TDE note: necessary as lots of sudo in controllers messing with cache
+
+ # -> this should have generated answer lines and closed the answer
+ self.assertAnswer(answers, 'done', page_1)
+ self.assertAnswerLines(page_1, answers, answer_data)
diff --git a/addons/survey/tests/test_survey_invite.py b/addons/survey/tests/test_survey_invite.py
new file mode 100644
index 00000000000..b2f464dcf98
--- /dev/null
+++ b/addons/survey/tests/test_survey_invite.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.addons.survey.tests import common
+from odoo.exceptions import UserError
+from odoo.tests.common import users
+
+
+class TestSurveyInvite(common.SurveyCase):
+
+ @users('survey_manager')
+ def test_survey_invite_action(self):
+ # Check correctly configured survey returns an invite wizard action
+ action = self.survey.action_send_survey()
+ self.assertEqual(action['res_model'], 'survey.invite')
+
+ # Bad cases
+ surveys = [
+ # no page
+ self.env['survey.survey'].create({'title': 'Test survey'}),
+ # no questions
+ self.env['survey.survey'].create({'title': 'Test survey', 'page_ids': [(0, 0, {'title': 'P0'})]}),
+ # closed
+ self.env['survey.survey'].sudo(self.survey_manager).create({
+ 'title': 'S0',
+ 'stage_id': self.env['survey.stage'].search([('closed', '=', True)]).id,
+ 'page_ids': [(0, 0, {'title': 'P0', 'question_ids': [(0, 0, {'question': 'Q0', 'question_type': 'free_text'})]})]
+ })
+ ]
+ for survey in surveys:
+ with self.assertRaises(UserError):
+ survey.action_send_survey()