source: main/waeup.kofa/trunk/src/waeup/kofa/widgets/tests/test_phonewidget.py @ 7843

Last change on this file since 7843 was 7840, checked in by uli, 13 years ago

Some better suited phone widget. Yet not finished (validation missing).

  • Property svn:keywords set to Id
File size: 22.8 KB
Line 
1## $Id: test_phonewidget.py 7840 2012-03-11 18:47:20Z uli $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Tests for PhoneWidget.
20
21Tests in here are an extended reformulation of the tests done in
22z3.widget as doctests for the usphone widget.
23"""
24import unittest
25from zope import schema
26# XXX: could we possibly get rid of zope.app.testing?
27from zope.app.testing.setup import placefulSetUp, placefulTearDown
28from zope.component import provideAdapter, getGlobalSiteManager
29from zope.formlib import form
30from zope.formlib.exception import WidgetInputErrorView
31from zope.formlib.interfaces import (
32    WidgetInputError, IInputWidget, IBrowserWidget, IWidgetInputError,
33    IWidgetInputErrorView)
34from zope.formlib.textwidgets import TextWidget
35from zope.interface import verify, Interface, implements
36from zope.publisher.browser import TestRequest
37from zope.publisher.interfaces.browser import IDefaultBrowserLayer
38from zope.schema.interfaces import ITextLine
39from waeup.kofa.widgets.phonewidget import PhoneWidget
40
41# Dummy content
42class ISampleContent(Interface):
43    foo = schema.TextLine(
44        title = u'Phone',
45        description = u'Phone number',
46        required = True)
47
48    bar = schema.TextLine(
49        title = u'Phone',
50        description = u'Phone number (not required)',
51        required = False,
52        missing_value = u'')
53
54    baz = schema.TextLine(
55        title = u'Phone',
56        description = u'Required phone with a default',
57        required = True,
58        #default=u'234--'
59        )
60
61class SampleContent:
62    implements(ISampleContent)
63
64    foo = None
65    bar = 'bar'
66    baz = None
67
68class PhoneWidgetTests(unittest.TestCase):
69    # Tests for phone widget
70
71    def setUp(self):
72        placefulSetUp()
73
74        # register TextLine views (so that subwidgets can be rendered)
75        provideAdapter(
76            TextWidget, (ITextLine, IDefaultBrowserLayer), IInputWidget)
77        # errors in forms
78        provideAdapter(
79            WidgetInputErrorView, (IWidgetInputError, IDefaultBrowserLayer),
80            IWidgetInputErrorView)
81
82        # setup some sample content to bind to (only neccessary for
83        # some of the tests)
84        self.content = SampleContent()
85        self.field = ISampleContent['foo']
86        self.field = self.field.bind(self.content)
87        self.field_nonreq = ISampleContent['bar']
88        self.field_nonreq = self.field_nonreq.bind(self.content)
89        self.field_w_default = ISampleContent['baz']
90        self.field_w_default = self.field_w_default.bind(self.content)
91
92        # create an empty request. We need one to create a widget
93        self.request = TestRequest()
94        self.widget = PhoneWidget(self.field, self.request)
95        self.widget_nonreq = PhoneWidget(self.field_nonreq, self.request)
96        return
97
98    def tearDown(self):
99        placefulTearDown()
100        return
101
102    def test_ifaces(self):
103        # make sure we fullfill interface contracts
104        verify.verifyClass(IBrowserWidget, PhoneWidget)
105        verify.verifyClass(IInputWidget, PhoneWidget)
106        verify.verifyObject(IBrowserWidget, self.widget)
107        verify.verifyObject(IInputWidget, self.widget)
108        return
109
110    def test_attribs_set(self):
111        # make sure the public attributes are set correctly
112        self.assertEqual(self.widget.name, 'field.foo')
113        self.assertEqual(self.widget.label, u'Phone')
114        self.assertEqual(self.widget.hint, u'Phone number')
115        self.assertEqual(self.widget.visible, True)
116        self.assertEqual(self.widget.required, True)
117        self.assertEqual(self.widget_nonreq.required, False)
118        return
119
120    def test_subwidgets_exist(self):
121        # make sure we have three sub widgets
122        sub_widget1 = self.widget.widgets['country']
123        sub_widget2 = self.widget.widgets['area']
124        sub_widget3 = self.widget.widgets['extension']
125        self.assertTrue(isinstance(sub_widget1, TextWidget))
126        self.assertTrue(isinstance(sub_widget2, TextWidget))
127        self.assertTrue(isinstance(sub_widget3, TextWidget))
128        return
129
130    def test_set_rendered_value(self):
131        # make sure we render values correctly
132        self.widget.setRenderedValue(u'123-456-1234567')
133        self.assertEqual(
134            self.widget(),
135            (u'+&nbsp;<input class="span2 textType" id="field.foo.country"'
136             u' name="field.foo.country" size="20" type="text" value="123" '
137             u' />'
138             u'&nbsp;-\n'
139             u'<input class="span2 textType" id="field.foo.area"'
140             u' name="field.foo.area" size="20" type="text" value="456" '
141             u' />'
142             u'&nbsp;-\n'
143             u'<input class="span3 textType" id="field.foo.extension"'
144             u' name="field.foo.extension" size="20" type="text"'
145             u' value="1234567"  />\n'))
146        return
147
148    def test_set_prefix_default(self):
149        # prefix determines the name of widget and its subwidgets.
150        self.assertEqual(self.widget.name, 'field.foo')
151        self.assertEqual(self.widget.widgets['country'].name,
152                         'field.foo.country')
153        self.assertEqual(self.widget.widgets['area'].name,
154                         'field.foo.area')
155        self.assertEqual(self.widget.widgets['extension'].name,
156                         'field.foo.extension')
157        return
158
159    def test_set_prefix_changed(self):
160        # when we set the prefix, widget names change
161        self.widget.setPrefix('test.')
162        self.assertEqual(self.widget.name, 'test.foo')
163        self.assertEqual(self.widget.widgets['country'].name,
164                         'test.foo.country')
165        self.assertEqual(self.widget.widgets['area'].name,
166                         'test.foo.area')
167        self.assertEqual(self.widget.widgets['extension'].name,
168                         'test.foo.extension')
169        return
170
171    def test_set_prefix_changed_no_dot(self):
172        # when we try to set a name without trailing dot, one will be
173        # inserted automatically
174        self.widget.setPrefix('test')
175        self.assertEqual(self.widget.name, 'test.foo')
176        self.assertEqual(self.widget.widgets['country'].name,
177                         'test.foo.country')
178        self.assertEqual(self.widget.widgets['area'].name,
179                         'test.foo.area')
180        self.assertEqual(self.widget.widgets['extension'].name,
181                         'test.foo.extension')
182        return
183
184    def test_get_input_value(self):
185        # we get a string when we want the input value
186        request = TestRequest(
187            form={
188                'field.foo.country': '123',
189                'field.foo.area': '456',
190                'field.foo.extension': '12345'
191                })
192        widget = PhoneWidget(self.field, request)
193        value = widget.getInputValue()
194        self.assertEqual(value, '123-456-12345')
195        return
196
197    def test_get_input_value_invalid(self):
198        # we get errors when valid data is sent
199        request = TestRequest(
200            form={
201                'field.foo.country': 'not-a-number',
202                'field.foo.area': '456',
203                'field.foo.extension': '12345',
204                })
205        widget = PhoneWidget(self.field, request)
206        self.assertRaises(
207            WidgetInputError,
208            widget.getInputValue)
209        return
210
211    def test_apply_changes(self):
212        # we can apply passed-in numbers to content objects. The
213        # widget is smart enough to detect whether the values really
214        # changed.
215        class Content(object):
216            field = None
217        content = Content()
218        request = TestRequest(form={
219                'field.foo.country': '123',
220                'field.foo.area': '456',
221                'field.foo.extension': '7890'})
222        widget = PhoneWidget(self.field, request)
223        result1 = widget.applyChanges(content)
224        result2 = widget.applyChanges(content)
225        self.assertEqual(result1, True)
226        self.assertEqual(content.foo, u'123-456-7890')
227        self.assertEqual(result2, False)
228        return
229
230    def test_has_input(self):
231        # we can check whether there is input without actually validating.
232        request = TestRequest(form={
233                'field.foo.country': '123'})
234        widget = PhoneWidget(self.field, request)
235        result = widget.hasInput()
236        self.assertEqual(result, False)
237
238        request = TestRequest(form={
239                'field.foo.area': '123'})
240        widget = PhoneWidget(self.field, request)
241        result = widget.hasInput()
242        self.assertEqual(result, False)
243
244        request = TestRequest(form={
245                'field.foo.extension': '123567'})
246        widget = PhoneWidget(self.field, request)
247        result = widget.hasInput()
248        self.assertEqual(result, False)
249
250        request = TestRequest(form={
251                'field.foo.country': '123',
252                'field.foo.area': '456',
253                'field.foo.extension': '7890'})
254        widget = PhoneWidget(self.field, request)
255        result = widget.hasInput()
256        self.assertEqual(result, True)
257
258        self.assertEqual(self.widget.hasInput(), False)
259        return
260
261    def test_has_valid_input(self):
262        # we can check for input also including validation
263        request = TestRequest(form={
264                'field.foo.country': '123'})
265        widget = PhoneWidget(self.field, request)
266        result = widget.hasValidInput()
267        self.assertEqual(result, False)
268
269        request = TestRequest(form={
270                'field.foo.area': '123'})
271        widget = PhoneWidget(self.field, request)
272        result = widget.hasValidInput()
273        self.assertEqual(result, False)
274
275        request = TestRequest(form={
276                'field.foo.extension': '123567'})
277        widget = PhoneWidget(self.field, request)
278        result = widget.hasValidInput()
279        self.assertEqual(result, False)
280
281        request = TestRequest(form={
282                'field.foo.country': '123',
283                'field.foo.area': '456',
284                'field.foo.extension': '7890'})
285        widget = PhoneWidget(self.field, request)
286        result = widget.hasValidInput()
287        self.assertEqual(result, True)
288
289        self.assertEqual(self.widget.hasValidInput(), False)
290        return
291
292    def test_hidden(self):
293        # we can render output as hidden field(s)
294        self.widget.setRenderedValue(u'123-456-1234567')
295        self.assertEqual(
296            self.widget.hidden(),
297            (u'<input class="span2 hiddenType" id="field.foo.country"'
298             u' name="field.foo.country" type="hidden" value="123" '
299             u' />'
300             u'\n'
301             u'<input class="span2 hiddenType" id="field.foo.area"'
302             u' name="field.foo.area" type="hidden" value="456" '
303             u' />'
304             u'\n'
305             u'<input class="span3 hiddenType" id="field.foo.extension"'
306             u' name="field.foo.extension" type="hidden"'
307             u' value="1234567"  />'))
308        return
309
310    def test_error_extension(self):
311        # the widget can handle input errors in extension subwidget
312
313        # extension field too short
314        request = TestRequest(form={
315                'field.foo.country': '123',
316                'field.foo.area': '456',
317                'field.foo.extension': '0'})
318        widget = PhoneWidget(self.field, request)
319        try:
320            widget.getInputValue()
321            self.fail('No error raised')
322        except WidgetInputError, e:
323            pass
324        self.assertEqual(
325            e.__repr__(),
326            ("WidgetInputError("
327             "'extension', u'Direct Line', ConstraintNotSatisfied(u'0'))"))
328        self.assertEqual(
329            widget.error(),
330            u'<span class="error">Constraint not satisfied</span>')
331        return
332
333
334    def test_error_area(self):
335        # the widget can handle input errors in area code subwidget
336
337        # area code contains illegal chars
338        request = TestRequest(form={
339                'field.foo.country': '123',
340                'field.foo.area': 'no-number',
341                'field.foo.extension': '12345'})
342        widget = PhoneWidget(self.field, request)
343        try:
344            widget.getInputValue()
345            self.fail('No error raised')
346        except WidgetInputError, e:
347            pass
348        self.assertEqual(
349            e.__repr__(),
350            ("WidgetInputError("
351             "'area', u'Area Code', ConstraintNotSatisfied(u'no-number'))"))
352        self.assertEqual(
353            widget.error(),
354            u'<span class="error">Constraint not satisfied</span>')
355        return
356
357    def test_error_country(self):
358        # the widget can handle input errors in country code subwidget
359
360        # invalid country code
361        request = TestRequest(form={
362                'field.foo.country': 'XXX',
363                'field.foo.area': '456',
364                'field.foo.extension': '12345'})
365        widget = PhoneWidget(self.field, request)
366        try:
367            widget.getInputValue()
368            self.fail('No error raised')
369        except WidgetInputError, e:
370            pass
371        self.assertEqual(
372            e.__repr__(),
373            ("WidgetInputError("
374             "'country', u'Country Code', ConstraintNotSatisfied(u'XXX'))"))
375        self.assertEqual(
376            widget.error(),
377            u'<span class="error">Constraint not satisfied</span>')
378        return
379
380    def test_render_wo_data(self):
381        # when no data was submitted, the content data will be displayed
382        request = TestRequest(form={})
383        self.content.foo = u'11-222-3333'
384        widget = PhoneWidget(self.field, request)
385        self.assertEqual(
386            widget(),
387            (u'+&nbsp;<input class="span2 textType" id="field.foo.country"'
388             u' name="field.foo.country" size="20" type="text" value="11" '
389             u' />'
390             u'&nbsp;-\n'
391             u'<input class="span2 textType" id="field.foo.area"'
392             u' name="field.foo.area" size="20" type="text" value="222" '
393             u' />'
394             u'&nbsp;-\n'
395             u'<input class="span3 textType" id="field.foo.extension"'
396             u' name="field.foo.extension" size="20" type="text"'
397             u' value="3333"  />\n'))
398        return
399
400    def test_render_with_data(self):
401        # when data was in the request, it will override any content value
402        request = TestRequest(form={
403                'field.foo.country': '11',
404                'field.foo.area': '222',
405                'field.foo.extension': '3333'})
406        self.content.foo = u'22-333-4444'
407        widget = PhoneWidget(self.field, request)
408        self.assertEqual(
409            widget(),
410            (u'+&nbsp;<input class="span2 textType" id="field.foo.country"'
411             u' name="field.foo.country" size="20" type="text" value="11" '
412             u' />'
413             u'&nbsp;-\n'
414             u'<input class="span2 textType" id="field.foo.area"'
415             u' name="field.foo.area" size="20" type="text" value="222" '
416             u' />'
417             u'&nbsp;-\n'
418             u'<input class="span3 textType" id="field.foo.extension"'
419             u' name="field.foo.extension" size="20" type="text"'
420             u' value="3333"  />\n'))
421        return
422
423    def test_render_changed_prefix(self):
424        # when the prefix is changed, the subwidgets will reflect that
425        # properly. This tests a regression: if setPrefix was called
426        # on the phone widget, the subwidgets were already assuming
427        # that there is no data in the request
428        request = TestRequest(form={
429                'field.foo.country': '11',
430                'field.foo.area': '222',
431                'field.foo.extension': '3333'})
432        self.content.foo = u'22-333-4444'
433        widget = PhoneWidget(self.field, request)
434        # when setting a wrong prefix (not in the form), subwidgets
435        # will display the content values assuming (correctly) there
436        # is no data sent for them in the request.
437        widget.setPrefix('not-existent.')
438        self.assertTrue('value="4444"' in widget())
439        # when setting the right prefix, subwidgets will display the
440        # sent form values and not the content values.
441        widget.setPrefix('field.')
442        self.assertTrue('value="3333"' in widget())
443        return
444
445    def test_render_changed_prefix(self):
446        # when the prefix is changed, the subwidgets will reflect that
447        # properly. This tests a regression: if setPrefix was called
448        # on the phone widget, the subwidgets were already assuming
449        # that there is no data in the request
450        request = TestRequest(form={
451                'field.foo.country': '11',
452                'field.foo.area': '222',
453                'field.foo.extension': '3333'})
454        self.content.foo = u'22-333-4444'
455        widget = PhoneWidget(self.field, request)
456        # when setting a wrong prefix (not in the form), subwidgets
457        # will display the content values assuming (correctly) there
458        # is no data sent for them in the request.
459        widget.setPrefix('not-existent.')
460        self.assertTrue('value="4444"' in widget())
461        # when setting the right prefix, subwidgets will display the
462        # sent form values and not the content values.
463        widget.setPrefix('field.')
464        self.assertTrue('value="3333"' in widget())
465        return
466
467    def test_non_required_no_input(self):
468        # if the bound field requires no input phone widget will cope
469        # with that.
470        class Content(object):
471            field = None
472
473        content = Content()
474        request = TestRequest(form={
475                'field.bar.country': '',
476                'field.bar.area': '',
477                'field.bar.extension': '',
478                })
479        widget = PhoneWidget(self.field_nonreq, request)
480        result1 = widget.applyChanges(content)
481        result2 = widget.getInputValue()
482        self.assertEqual(result1, True)
483        # without input we get None
484        self.assertTrue(content.bar is None)
485        self.assertTrue(result2 is None)
486        return
487
488    def test_set_rendered_with_empty_context_value(self):
489        # if we set empty string as rendered value, empty fields are
490        # displayed.
491        self.widget.setRenderedValue(u'')
492        self.assertEqual(
493            self.widget(),
494            (u'+&nbsp;<input class="span2 textType" id="field.foo.country"'
495             u' name="field.foo.country" size="20" type="text" value="" '
496             u' />'
497             u'&nbsp;-\n'
498             u'<input class="span2 textType" id="field.foo.area"'
499             u' name="field.foo.area" size="20" type="text" value="" '
500             u' />'
501             u'&nbsp;-\n'
502             u'<input class="span3 textType" id="field.foo.extension"'
503             u' name="field.foo.extension" size="20" type="text"'
504             u' value=""  />\n'))
505        return
506
507import zope.formlib
508from zope import schema
509from zope.formlib.tests.test_functional_objectwidget import (
510    Test, PlacelessSetup, VerifyResults, traversingSetUp, xmlconfig,
511    PageTemplate, os, DefaultTraversable
512    )
513from zope.formlib.tests.test_functional_textwidget import(
514    FunctionalWidgetTestCase, patternExists)
515from zope.formlib.widgets import TextWidget
516from zope.component import adapts
517from zope.interface import implements
518from zope.traversing.interfaces import ITraversable
519from waeup.kofa.widgets.phonewidget import PhoneWidget2, PhonePrefixes
520
521class SampleForm(form.EditForm):
522    form_fields = form.fields(ISampleContent)
523    form_fields['foo'].custom_widget = PhoneWidget2
524    form_fields['bar'].custom_widget = PhoneWidget2
525    form_fields['baz'].custom_widget = PhoneWidget2
526
527class PhoneWidget2Tests(FunctionalWidgetTestCase):
528
529    widgets = [
530        (ITextLine, TextWidget),
531        ]
532
533    def setUp(self):
534        super(PhoneWidget2Tests, self).setUp()
535        self.gsm = getGlobalSiteManager()
536        self.reg_prefixes = PhonePrefixes()
537        self.gsm.registerUtility(self.reg_prefixes)
538        return
539
540    def tearDown(self):
541        self.gsm.unregisterUtility(self.reg_prefixes)
542        return
543
544    def test_display_editform(self):
545        content = SampleContent()
546        request = TestRequest()
547        html = SampleForm(content, request)()
548        # foo.country, foo.area and foo.ext exist
549        self.assert_(patternExists(
550            '<select .* name="form.foo.country".*>', html))
551        self.assert_(patternExists(
552            '<input .* name="form.foo.area".* value="".*>', html))
553        self.assert_(patternExists(
554            '<input .* name="form.foo.ext".* value="".*>', html))
555        return
556
557    def test_submit_editform(self):
558        # we can submit an edit form
559        content = SampleContent()
560        request = TestRequest()
561
562        # submit edit view
563        request.form['form.foo.country'] = u'123'
564        request.form['form.foo.area'] = u'456'
565        request.form['form.foo.ext'] = u'7890'
566        request.form['form.actions.apply'] = u''
567        SampleForm(content, request)()
568
569        # check new values in object
570        self.assertEqual(content.foo, u'123-456-7890')
571        return
572
573    def test_invalid_type(self):
574        # there is no invalid type for textline-based input
575        content = SampleContent()
576        request = TestRequest()
577
578        # submit invalid type for text line
579        request.form['form.foo.country'] = '123'
580        request.form['form.foo.area'] = '456'
581        request.form['form.foo.ext'] = '7890'
582        request.form['form.actions.apply'] = u''
583        html = SampleForm(content, request)()
584
585        # We don't have a invalid field value
586        # since we convert the value to unicode
587        self.assert_('Object is of wrong type.' not in html)
588        return
589
590    def test_missing_value(self):
591        content = SampleContent()
592        request = TestRequest()
593
594        request.form['form.foo.country'] = u'123'
595        request.form['form.foo.area'] = u'456'
596        request.form['form.foo.ext'] = u'7890'
597        request.form['form.bar.country'] = u''
598        request.form['form.bar.area'] = u''
599        request.form['form.bar.ext'] = u''
600        request.form['form.baz.country'] = u''
601        request.form['form.baz.area'] = u''
602        request.form['form.baz.ext'] = u''
603        request.form['form.actions.apply'] = u''
604        SampleForm(content, request)()
605
606        # check new values in object
607        self.assertEqual(content.foo, u'123-456-7890')
608        self.assertEqual(content.bar, u'--') # default missing value
609        self.assertEqual(content.baz, u'--')
610        return
Note: See TracBrowser for help on using the repository browser.