web/test/unittest_form.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 
       
    19 import time
       
    20 
       
    21 from xml.etree.ElementTree import fromstring
       
    22 from lxml import html
       
    23 
       
    24 from six import text_type
       
    25 
       
    26 from logilab.common.testlib import unittest_main
       
    27 
       
    28 from cubicweb import Binary, ValidationError
       
    29 from cubicweb.mttransforms import HAS_TAL
       
    30 from cubicweb.devtools.testlib import CubicWebTC
       
    31 from cubicweb.web.formfields import (IntField, StringField, RichTextField,
       
    32                                      PasswordField, DateTimeField,
       
    33                                      FileField, EditableFileField)
       
    34 from cubicweb.web.formwidgets import PasswordInput, Input, DateTimePicker
       
    35 from cubicweb.web.views.forms import EntityFieldsForm, FieldsForm
       
    36 from cubicweb.web.views.workflow import ChangeStateForm
       
    37 from cubicweb.web.views.formrenderers import FormRenderer
       
    38 
       
    39 
       
    40 class FieldsFormTC(CubicWebTC):
       
    41 
       
    42     def test_form_field_format(self):
       
    43         with self.admin_access.web_request() as req:
       
    44             form = FieldsForm(req, None)
       
    45             self.assertEqual(StringField().format(form), 'text/plain')
       
    46             req.cnx.execute('INSERT CWProperty X: X pkey "ui.default-text-format", X value "text/rest", X for_user U WHERE U login "admin"')
       
    47             req.cnx.commit()
       
    48             self.assertEqual(StringField().format(form), 'text/rest')
       
    49 
       
    50 
       
    51     def test_process_posted(self):
       
    52         class AForm(FieldsForm):
       
    53             anint = IntField()
       
    54             astring = StringField()
       
    55         with self.admin_access.web_request(anint='1', astring='2', _cw_fields='anint,astring') as req:
       
    56             form = AForm(req)
       
    57             self.assertEqual(form.process_posted(), {'anint': 1, 'astring': '2'})
       
    58         with self.admin_access.web_request(anint='1a', astring='2b', _cw_fields='anint,astring') as req:
       
    59             form = AForm(req)
       
    60             self.assertRaises(ValidationError, form.process_posted)
       
    61 
       
    62 
       
    63 class EntityFieldsFormTC(CubicWebTC):
       
    64 
       
    65     def test_form_field_choices(self):
       
    66         with self.admin_access.web_request() as req:
       
    67             b = req.create_entity('BlogEntry', title=u'di mascii code', content=u'a best-seller')
       
    68             t = req.create_entity('Tag', name=u'x')
       
    69             form1 = self.vreg['forms'].select('edition', req, entity=t)
       
    70             choices = [reid for rview, reid in form1.field_by_name('tags', 'subject', t.e_schema).choices(form1)]
       
    71             self.assertIn(text_type(b.eid), choices)
       
    72             form2 = self.vreg['forms'].select('edition', req, entity=b)
       
    73             choices = [reid for rview, reid in form2.field_by_name('tags', 'object', t.e_schema).choices(form2)]
       
    74             self.assertIn(text_type(t.eid), choices)
       
    75 
       
    76             b.cw_clear_all_caches()
       
    77             t.cw_clear_all_caches()
       
    78             req.cnx.execute('SET X tags Y WHERE X is Tag, Y is BlogEntry')
       
    79 
       
    80             choices = [reid for rview, reid in form1.field_by_name('tags', 'subject', t.e_schema).choices(form1)]
       
    81             self.assertIn(text_type(b.eid), choices)
       
    82             choices = [reid for rview, reid in form2.field_by_name('tags', 'object', t.e_schema).choices(form2)]
       
    83             self.assertIn(text_type(t.eid), choices)
       
    84 
       
    85     def test_form_field_choices_new_entity(self):
       
    86         with self.admin_access.web_request() as req:
       
    87             e = self.vreg['etypes'].etype_class('CWUser')(req)
       
    88             form = self.vreg['forms'].select('edition', req, entity=e)
       
    89             unrelated = [rview for rview, reid in form.field_by_name('in_group', 'subject').choices(form)]
       
    90             # should be default groups but owners, i.e. managers, users, guests
       
    91             self.assertEqual(unrelated, [u'guests', u'managers', u'users'])
       
    92 
       
    93     def test_consider_req_form_params(self):
       
    94         with self.admin_access.web_request() as req:
       
    95             e = self.vreg['etypes'].etype_class('CWUser')(req)
       
    96             e.eid = 'A'
       
    97             with self.admin_access.web_request(login=u'toto') as toto_req:
       
    98                 form = EntityFieldsForm(toto_req, None, entity=e)
       
    99                 field = StringField(name='login', role='subject', eidparam=True)
       
   100                 form.append_field(field)
       
   101                 form.build_context({})
       
   102                 self.assertEqual(field.widget.values(form, field), (u'toto',))
       
   103 
       
   104     def test_linkto_field_duplication_inout(self):
       
   105         with self.admin_access.web_request() as req:
       
   106             e = self.vreg['etypes'].etype_class('CWUser')(req)
       
   107             e.eid = 'A'
       
   108             e._cw = req
       
   109             geid = req.cnx.execute('CWGroup X WHERE X name "users"')[0][0]
       
   110             req.form['__linkto'] = 'in_group:%s:subject' % geid
       
   111             form = self.vreg['forms'].select('edition', req, entity=e)
       
   112             form.content_type = 'text/html'
       
   113             data = []
       
   114             form.render(w=data.append)
       
   115             pageinfo = self._check_html(u'\n'.join(data), form, template=None)
       
   116             inputs = pageinfo.find_tag('select', False)
       
   117             ok = False
       
   118             for selectnode in pageinfo.matching_nodes('select', name='from_in_group-subject:A'):
       
   119                 for optionnode in selectnode:
       
   120                     self.assertEqual(optionnode.get('value'), str(geid))
       
   121                     self.assertEqual(ok, False)
       
   122                     ok = True
       
   123             inputs = pageinfo.find_tag('input', False)
       
   124             self.assertFalse(list(pageinfo.matching_nodes('input', name='__linkto')))
       
   125 
       
   126     def test_reledit_composite_field(self):
       
   127         with self.admin_access.web_request() as req:
       
   128             rset = req.execute('INSERT BlogEntry X: X title "cubicweb.org", X content "hop"')
       
   129             form = self.vreg['views'].select('reledit', req,
       
   130                                              rset=rset, row=0, rtype='content')
       
   131             data = form.render(row=0, rtype='content', formid='base', action='edit_rtype')
       
   132             self.assertIn('content_format', data)
       
   133 
       
   134 
       
   135     def test_form_generation_time(self):
       
   136         with self.admin_access.web_request() as req:
       
   137             e = req.create_entity('BlogEntry', title=u'cubicweb.org', content=u"hop")
       
   138             expected_field_name = '__form_generation_time:%d' % e.eid
       
   139 
       
   140             ts_before = time.time()
       
   141             form = self.vreg['forms'].select('edition', req, entity=e)
       
   142             ts_after = time.time()
       
   143 
       
   144             data = []
       
   145             form.render(action='edit', w=data.append)
       
   146             html_form = html.fromstring(''.join(data)).forms[0]
       
   147             fields = dict(html_form.form_values())
       
   148             self.assertIn(expected_field_name, fields)
       
   149             ts = float(fields[expected_field_name])
       
   150             self.assertTrue(ts_before < ts  < ts_after)
       
   151 
       
   152 
       
   153     # form tests ##############################################################
       
   154 
       
   155     def test_form_inheritance(self):
       
   156         with self.admin_access.web_request() as req:
       
   157             class CustomChangeStateForm(ChangeStateForm):
       
   158                 hello = IntField(name='youlou')
       
   159                 creation_date = DateTimeField(widget=DateTimePicker)
       
   160             form = CustomChangeStateForm(req, redirect_path='perdu.com',
       
   161                                          entity=req.user)
       
   162             data = []
       
   163             form.render(w=data.append,
       
   164                         formvalues=dict(state=123, trcomment=u'',
       
   165                                         trcomment_format=u'text/plain'))
       
   166 
       
   167     def test_change_state_form(self):
       
   168         with self.admin_access.web_request() as req:
       
   169             form = ChangeStateForm(req, redirect_path='perdu.com',
       
   170                                    entity=req.user)
       
   171             data = []
       
   172             form.render(w=data.append,
       
   173                         formvalues=dict(state=123, trcomment=u'',
       
   174                                         trcomment_format=u'text/plain'))
       
   175 
       
   176     # fields tests ############################################################
       
   177 
       
   178     def _render_entity_field(self, req, name, form):
       
   179         form.build_context({})
       
   180         renderer = FormRenderer(req)
       
   181         return form.field_by_name(name, 'subject').render(form, renderer)
       
   182 
       
   183     def _test_richtextfield(self, req, expected):
       
   184         class RTFForm(EntityFieldsForm):
       
   185             description = RichTextField(eidparam=True, role='subject')
       
   186         state = self.vreg['etypes'].etype_class('State')(req)
       
   187         state.eid = 'S'
       
   188         form = RTFForm(req, redirect_path='perdu.com', entity=state)
       
   189         # make it think it can use fck editor anyway
       
   190         form.field_by_name('description', 'subject').format = lambda form, field=None: 'text/html'
       
   191         self.assertMultiLineEqual(self._render_entity_field(req, 'description', form),
       
   192                               expected % {'eid': state.eid})
       
   193 
       
   194 
       
   195     def test_richtextfield_1(self):
       
   196         with self.admin_access.web_request() as req:
       
   197             req.use_fckeditor = lambda: False
       
   198             self._test_richtextfield(req, '''<select id="description_format-subject:%(eid)s" name="description_format-subject:%(eid)s" size="1" style="display: block" tabindex="1">
       
   199 ''' + ('<option value="text/cubicweb-page-template">text/cubicweb-page-template</option>\n'
       
   200 if HAS_TAL else '') +
       
   201 '''<option selected="selected" value="text/html">text/html</option>
       
   202 <option value="text/markdown">text/markdown</option>
       
   203 <option value="text/plain">text/plain</option>
       
   204 <option value="text/rest">text/rest</option>
       
   205 </select><textarea cols="80" id="description-subject:%(eid)s" name="description-subject:%(eid)s" onkeyup="autogrow(this)" rows="2" tabindex="2"></textarea>''')
       
   206 
       
   207 
       
   208     def test_richtextfield_2(self):
       
   209         with self.admin_access.web_request() as req:
       
   210             req.use_fckeditor = lambda: True
       
   211             self._test_richtextfield(req, '<input name="description_format-subject:%(eid)s" type="hidden" value="text/html" /><textarea cols="80" cubicweb:type="wysiwyg" id="description-subject:%(eid)s" name="description-subject:%(eid)s" onkeyup="autogrow(this)" rows="2" tabindex="1"></textarea>')
       
   212 
       
   213 
       
   214     def test_filefield(self):
       
   215         class FFForm(EntityFieldsForm):
       
   216             data = FileField(
       
   217                 format_field=StringField(name='data_format', max_length=50,
       
   218                                          eidparam=True, role='subject'),
       
   219                 encoding_field=StringField(name='data_encoding', max_length=20,
       
   220                                            eidparam=True, role='subject'),
       
   221                 eidparam=True, role='subject')
       
   222         with self.admin_access.web_request() as req:
       
   223             file = req.create_entity('File', data_name=u"pouet.txt", data_encoding=u'UTF-8',
       
   224                                      data=Binary(b'new widgets system'))
       
   225             form = FFForm(req, redirect_path='perdu.com', entity=file)
       
   226             self.assertMultiLineEqual(self._render_entity_field(req, 'data', form),
       
   227                               '''<input id="data-subject:%(eid)s" name="data-subject:%(eid)s" tabindex="1" type="file" value="" />
       
   228 <a href="javascript: toggleVisibility(&#39;data-subject:%(eid)s-advanced&#39;)" title="show advanced fields"><img src="http://testing.fr/cubicweb/data/puce_down.png" alt="show advanced fields"/></a>
       
   229 <div id="data-subject:%(eid)s-advanced" class="hidden">
       
   230 <label for="data_format-subject:%(eid)s">data_format</label><input id="data_format-subject:%(eid)s" maxlength="50" name="data_format-subject:%(eid)s" size="45" tabindex="2" type="text" value="text/plain" /><br/>
       
   231 <label for="data_encoding-subject:%(eid)s">data_encoding</label><input id="data_encoding-subject:%(eid)s" maxlength="20" name="data_encoding-subject:%(eid)s" size="20" tabindex="3" type="text" value="UTF-8" /><br/>
       
   232 </div>
       
   233 <br/>
       
   234 <input name="data-subject__detach:%(eid)s" type="checkbox" />
       
   235 detach attached file''' % {'eid': file.eid})
       
   236 
       
   237 
       
   238     def test_editablefilefield(self):
       
   239         class EFFForm(EntityFieldsForm):
       
   240             data = EditableFileField(
       
   241                 format_field=StringField('data_format', max_length=50,
       
   242                                          eidparam=True, role='subject'),
       
   243                 encoding_field=StringField('data_encoding', max_length=20,
       
   244                                            eidparam=True, role='subject'),
       
   245                 eidparam=True, role='subject')
       
   246         with self.admin_access.web_request() as req:
       
   247             file = req.create_entity('File', data_name=u"pouet.txt", data_encoding=u'UTF-8',
       
   248                                      data=Binary(b'new widgets system'))
       
   249             form = EFFForm(req, redirect_path='perdu.com', entity=file)
       
   250             self.assertMultiLineEqual(self._render_entity_field(req, 'data', form),
       
   251                               '''<input id="data-subject:%(eid)s" name="data-subject:%(eid)s" tabindex="1" type="file" value="" />
       
   252 <a href="javascript: toggleVisibility(&#39;data-subject:%(eid)s-advanced&#39;)" title="show advanced fields"><img src="http://testing.fr/cubicweb/data/puce_down.png" alt="show advanced fields"/></a>
       
   253 <div id="data-subject:%(eid)s-advanced" class="hidden">
       
   254 <label for="data_format-subject:%(eid)s">data_format</label><input id="data_format-subject:%(eid)s" maxlength="50" name="data_format-subject:%(eid)s" size="45" tabindex="2" type="text" value="text/plain" /><br/>
       
   255 <label for="data_encoding-subject:%(eid)s">data_encoding</label><input id="data_encoding-subject:%(eid)s" maxlength="20" name="data_encoding-subject:%(eid)s" size="20" tabindex="3" type="text" value="UTF-8" /><br/>
       
   256 </div>
       
   257 <br/>
       
   258 <input name="data-subject__detach:%(eid)s" type="checkbox" />
       
   259 detach attached file
       
   260 <p><b>You can either submit a new file using the browse button above, or choose to remove already uploaded file by checking the "detach attached file" check-box, or edit file content online with the widget below.</b></p>
       
   261 <textarea cols="80" name="data-subject:%(eid)s" onkeyup="autogrow(this)" rows="3" tabindex="4">new widgets system</textarea>''' % {'eid': file.eid})
       
   262 
       
   263 
       
   264     def test_passwordfield(self):
       
   265         class PFForm(EntityFieldsForm):
       
   266             upassword = PasswordField(eidparam=True, role='subject')
       
   267         with self.admin_access.web_request() as req:
       
   268             form = PFForm(req, redirect_path='perdu.com', entity=req.user)
       
   269             self.assertMultiLineEqual(self._render_entity_field(req, 'upassword', form),
       
   270                                   '''<input id="upassword-subject:%(eid)s" name="upassword-subject:%(eid)s" tabindex="1" type="password" value="" />
       
   271 <br/>
       
   272 <input name="upassword-subject-confirm:%(eid)s" tabindex="1" type="password" value="" />
       
   273 &#160;
       
   274 <span class="emphasis">confirm password</span>''' % {'eid': req.user.eid})
       
   275 
       
   276 
       
   277     # def test_datefield(self):
       
   278     #     class DFForm(EntityFieldsForm):
       
   279     #         creation_date = DateTimeField(widget=Input)
       
   280     #     form = DFForm(self.req, entity=self.entity)
       
   281     #     init, cur = (fromstring(self._render_entity_field(attr, form)).get('value')
       
   282     #                  for attr in ('edits-creation_date', 'creation_date'))
       
   283     #     self.assertEqual(init, cur)
       
   284 
       
   285 if __name__ == '__main__':
       
   286     unittest_main()