~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# Copyright 2010-2011 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

__metaclass__ = type

import simplejson

from zope.interface import Interface
from zope.interface.interface import InterfaceClass
from zope.schema import Choice
from zope.schema.vocabulary import getVocabularyRegistry

from canonical.launchpad.webapp.servers import LaunchpadTestRequest
from canonical.testing.layers import DatabaseFunctionalLayer
from lp.app.widgets.popup import (
    PersonPickerWidget,
    VocabularyPickerWidget,
    )
from lp.testing import TestCaseWithFactory


class TestMetaClass(InterfaceClass):
# We want to force creation of a field with an invalid HTML id.
    def __init__(self, name, bases=(), attrs=None, __doc__=None,
                 __module__=None):
        attrs = {
            "test_invalid_chars+":
            Choice(vocabulary='ValidTeamOwner'),
            "test_valid.item":
            Choice(vocabulary='ValidTeamOwner')}
        super(TestMetaClass, self).__init__(
            name, bases=bases, attrs=attrs, __doc__=__doc__,
            __module__=__module__)


class ITest(Interface):
# The schema class for the widget we will test.
    __metaclass__ = TestMetaClass


class TestVocabularyPickerWidget(TestCaseWithFactory):

    layer = DatabaseFunctionalLayer

    def setUp(self):
        super(TestVocabularyPickerWidget, self).setUp()
        self.context = self.factory.makeTeam()
        vocabulary_registry = getVocabularyRegistry()
        self.vocabulary = vocabulary_registry.get(
            self.context, 'ValidTeamOwner')
        self.request = LaunchpadTestRequest()

    def test_widget_template_properties(self):
        # Check the picker widget is correctly set up for a field which has a
        # name containing only valid HTML ID characters.

        field = ITest['test_valid.item']
        bound_field = field.bind(self.context)
        picker_widget = VocabularyPickerWidget(
            bound_field, self.vocabulary, self.request)

        widget_config = simplejson.loads(picker_widget.json_config)
        self.assertEqual(
            'ValidTeamOwner', picker_widget.vocabulary_name)
        self.assertEqual(self.vocabulary.displayname, widget_config['header'])
        self.assertEqual(self.vocabulary.step_title,
            widget_config['step_title'])
        self.assertEqual(
            'show-widget-field-test_valid-item', picker_widget.show_widget_id)
        self.assertEqual(
            'field.test_valid.item', picker_widget.input_id)
        self.assertIsNone(picker_widget.extra_no_results_message)
        markup = picker_widget()
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
            .*
            var picker = Y\\.lp\\.app\\.picker\\.create\\('ValidTeamOwner',
                config,
                'field\\.test_valid.item'\\);
            .*
            """, markup)

    def test_widget_fieldname_with_invalid_html_chars(self):
        # Check the picker widget is correctly set up for a field which has a
        # name containing some invalid HTML ID characters.

        field = ITest['test_invalid_chars+']
        bound_field = field.bind(self.context)
        picker_widget = VocabularyPickerWidget(
            bound_field, self.vocabulary, self.request)

        # The widget name is encoded to get the widget's ID. It must only
        # contain valid HTML characters.
        self.assertEqual(
            'show-widget-field-test_invalid_chars-'
            'ZmllbGQudGVzdF9pbnZhbGlkX2NoYXJzKw',
            picker_widget.show_widget_id)
        self.assertEqual(
            'field.test_invalid_chars-ZmllbGQudGVzdF9pbnZhbGlkX2NoYXJzKw',
            picker_widget.input_id)

    def test_widget_suggestions(self):
        # The suggestions menu is shown when the input is invalid and there
        # are matches to suggest to the user.
        field = ITest['test_valid.item']
        bound_field = field.bind(self.context)
        request = LaunchpadTestRequest(form={'field.test_valid.item': 'foo'})
        picker_widget = VocabularyPickerWidget(
            bound_field, self.vocabulary, request)
        matches = list(picker_widget.matches)
        self.assertEqual(1, len(matches))
        self.assertEqual('Foo Bar', matches[0].title)
        markup = picker_widget()
        self.assertIn('id="field.test_valid.item-suggestions"', markup)
        self.assertIn(
            "Y.DOM.byId('field.test_valid.item-suggestions')", markup)
        self.assertTextMatchesExpressionIgnoreWhitespace(
            'Y.lp.app.picker.connect_select_menu\( '
            'select_menu, text_input\);',
            markup)

    def test_widget_extra_buttons(self):
        # The picker widgets define defaults for the display of extra buttons.
        field = ITest['test_valid.item']
        bound_field = field.bind(self.context)

        # A vocabulary widget does not show the extra buttons by default.
        picker_widget = VocabularyPickerWidget(
            bound_field, self.vocabulary, self.request)
        self.assertEqual('false',
            picker_widget.config['show_assign_me_button'])
        self.assertEqual('false',
            picker_widget.config['show_remove_button'])

        # A person picker widget does show them by default.
        person_picker_widget = PersonPickerWidget(
            bound_field, self.vocabulary, self.request)
        self.assertEqual('true',
            person_picker_widget.config['show_assign_me_button'])
        self.assertEqual('true',
            person_picker_widget.config['show_remove_button'])

    def test_widget_personvalue_meta(self):
        # The person picker has the correct meta value for a person value.
        person = self.factory.makePerson()
        bound_field = ITest['test_valid.item'].bind(person)
        person_picker_widget = PersonPickerWidget(
            bound_field, self.vocabulary, self.request)
        person_picker_widget.setRenderedValue(person)
        self.assertEqual('person',
            person_picker_widget.config['selected_value_metadata'])

    def test_widget_teamvalue_meta(self):
        # The person picker has the correct meta value for a team value.
        team = self.factory.makeTeam()
        bound_field = ITest['test_valid.item'].bind(team)
        person_picker_widget = PersonPickerWidget(
            bound_field, self.vocabulary, self.request)
        person_picker_widget.setRenderedValue(team)
        self.assertEqual('team',
            person_picker_widget.config['selected_value_metadata'])