[MERGE][REF] survey: refactor tests
Purpose of this merge is to clean survey tests and add some more. This merge holds several commits that * create a common file holding test data and tools methods to create questions, answers and answerlines as well as implemented some custom assertions; * clean exiting tests by removing tests about implementation details and unnecessary code; * expand tests by adding a functional test using survey routes and controllers; This merge is linked to task ID 1911238 and PR #28831 .
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
+143
-220
@@ -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 = '<a href="%s">Click here to start survey</a>'
|
||||
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 = '<a href="%s">Click here to start survey</a>'
|
||||
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'))
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user