Beispiel #1
0
def view_rights_propagate_to_a(fixture):
    """The access rights specified for a View are propagated to an A, made from a Bookmark to that View."""
    fixture.view.write_check = EmptyStub()
    fixture.view.read_check = EmptyStub()
    a = A.from_bookmark(fixture.view, fixture.view.as_bookmark())
    vassert( a.read_check is fixture.view.read_check )
    vassert( a.write_check is fixture.view.write_check )
Beispiel #2
0
    def resources(self, fixture):
        """A Resource has the responsibility to handle an HTTP Request. A Resource indicates that it can
           handle a particular HTTP method by having a method named for it. Such method should return
           a Response."""
        @stubclass(Resource)
        class ResourceStub(Resource):
            called = None

            @exempt
            def handle_something(self, request):
                self.called = True
                return 'something'

            @exempt
            def handle_anotherthing(self, request):
                pass

        resource = ResourceStub()

        # Case where the HTTP method is not supported
        fixture.request.method = 'koos'
        response = resource.handle_request(fixture.request)
        vassert(isinstance(response, HTTPMethodNotAllowed))
        vassert(not resource.called)
        vassert(response.headers['allow'] == 'anotherthing, something')

        # Case where the HTTP method is supported
        fixture.request.method = 'SOMEthing'
        response = resource.handle_request(fixture.request)
        vassert(resource.called)
        vassert(response == 'something')
Beispiel #3
0
def persistence(fixture):
    fixture.start_example_app()
    fixture.driver_browser.open('/')

    vassert(not fixture.driver_browser.is_element_present('//h1'))
    vassert(fixture.driver_browser.is_element_present('//form'))

    fixture.driver_browser.type(XPath.input_labelled('Email address'),
                                '*****@*****.**')
    fixture.driver_browser.type(XPath.input_labelled('Comment'),
                                'some comment text')
    fixture.driver_browser.capture_cropped_screenshot(
        fixture.new_screenshot_path('persistence1.png'))

    fixture.driver_browser.click(XPath.button_labelled('Submit'))

    vassert(fixture.driver_browser.is_element_present('//form'))
    vassert(
        fixture.driver_browser.is_element_present(
            '//form/following-sibling::div/p'))
    comment_text = fixture.driver_browser.get_text(
        '//form/following-sibling::div/p')
    vassert(comment_text == 'By [email protected]: some comment text')

    fixture.driver_browser.capture_cropped_screenshot(
        fixture.new_screenshot_path('persistence2.png'))
Beispiel #4
0
    def ui_slots_map_to_window(self, fixture):
        """The UserInterface uses its own names for Slots. When attaching a UserInterface, you have to specify 
            which of the UserInterface's Slots plug into which of the page's Slots.
        """
        class UIWithSlots(UserInterface):
            def assemble(self):
                root = self.define_view('/', title='UserInterface root view')
                root.set_slot(
                    'text',
                    P.factory(text='in user_interface slot named text'))

        class MainUI(UserInterface):
            def assemble(self):
                self.define_page(HTML5Page).use_layout(
                    PageLayout(
                        contents_layout=ColumnLayout('main').with_slots()))
                self.define_user_interface('/a_ui',
                                           UIWithSlots, {'text': 'main'},
                                           name='myui')

        wsgi_app = fixture.new_wsgi_app(site_root=MainUI)
        browser = Browser(wsgi_app)

        browser.open('/a_ui/')
        vassert(browser.title == 'UserInterface root view')

        # The widget in the UserInterface's slot named 'text' end up in the HTML5Page slot called main
        [p
         ] = browser.lxml_html.xpath('//div[contains(@class,"column-main")]/p')
        vassert(p.text == 'in user_interface slot named text')
Beispiel #5
0
    def basic_workings(self, fixture):
        """A DhtmlUI provides a UserInterface which maps to the filesystem where there may be
           a combination of .d.html and other files. When a d.html file is requested from
           it, the contents of the specified div from inside the d.html file is inserted 
           into the specified Slot. When a normal file is requested, the file is sent verbatim."""
        class MainUI(UserInterface):
            def assemble(self):
                self.define_page(HTML5Page).use_layout(
                    PageLayout(
                        contents_layout=ColumnLayout('main').with_slots()))
                self.define_user_interface('/dhtml_ui',
                                           DhtmlUI, {'main_slot': 'main'},
                                           name='test_ui',
                                           static_div_name='astatic')

        # Djhtml files should be located in the web.static_root
        fixture.config.web.static_root = fixture.static_dir.name

        wsgi_app = fixture.new_wsgi_app(site_root=MainUI, enable_js=True)
        browser = Browser(wsgi_app)

        # A dhtml file: HTML5Page's main_slot now contains the insides of the div in the dhtml file
        browser.open('/dhtml_ui/correctfile.d.html')
        html = fixture.get_inserted_html(browser)
        vassert(html == fixture.div_internals)

        # A non-dhtml file is returned verbatim
        browser.open('/dhtml_ui/otherfile.txt')
        contents = browser.raw_html
        vassert(contents == 'other')

        # Files that do not exist are reported as such
        browser.open('/dhtml_ui/idonotexist.txt', status=404)
        browser.open('/dhtml_ui/idonotexist.d.html', status=404)
Beispiel #6
0
def version_dictates_execution_of_migration_(fixture):
    """Each Migration should have a class attribute `version` that states which version of the component
       it upgrades the database schema to. Only the Migrations with versions greater than the current 
       schema version are included in a MigrationRun for a given egg.
    """
    class PreviousVersionMigration(Migration):
        version = '1.0'

    class MatchingCurrentVersionMigration(Migration):
        version = '2.0'

    class NewerVersionMigration(Migration):
        version = '3.0'

    class EvenNewerVersionMigration(Migration):
        version = '4.0'

    egg = ReahlEggStub('my_egg', '4.0', [
        PreviousVersionMigration, MatchingCurrentVersionMigration,
        NewerVersionMigration, EvenNewerVersionMigration
    ])
    fixture.orm_control.set_currently_installed_version_for(egg, '2.0')

    migration_run = MigrationRun(fixture.orm_control, [egg])
    migrations_to_run = migration_run.migrations_to_run_for(egg)
    classes_to_run = [m.__class__ for m in migrations_to_run]
    vassert(
        classes_to_run == [NewerVersionMigration, EvenNewerVersionMigration])
Beispiel #7
0
    def ui_arguments(self, fixture):
        """UserInterfaces can take exta args and kwargs."""
        class UIWithArguments(UserInterface):
            def assemble(self, kwarg=None):
                self.kwarg = kwarg
                text = self.kwarg
                root = self.define_view('/', title='A view')
                root.set_slot('text', P.factory(text=text))

        class MainUI(UserInterface):
            def assemble(self):
                self.define_page(HTML5Page).use_layout(
                    PageLayout(
                        contents_layout=ColumnLayout('main').with_slots()))
                self.define_user_interface('/a_ui',
                                           UIWithArguments, {'text': 'main'},
                                           name='myui',
                                           kwarg='the kwarg')

        wsgi_app = fixture.new_wsgi_app(site_root=MainUI)
        browser = Browser(wsgi_app)

        browser.open('/a_ui/')
        [p] = browser.lxml_html.xpath('//p')
        vassert(p.text == 'the kwarg')
Beispiel #8
0
def adding_checkboxes(fixture):
    """CheckboxInputs are added non-inlined, and by default without labels."""
    class DomainObjectWithBoolean(object):
        @exposed
        def fields(self, fields):
            fields.an_attribute = BooleanField(label='Some input',
                                               required=True)

    fixture.domain_object = DomainObjectWithBoolean()

    class FormWithInputWithCheckbox(Form):
        def __init__(self, view):
            super(FormWithInputWithCheckbox, self).__init__(view, 'aform')
            self.use_layout(FormLayout())
            self.layout.add_input(
                CheckboxInput(self, fixture.domain_object.fields.an_attribute))

    browser = Browser(
        fixture.new_wsgi_app(
            child_factory=FormWithInputWithCheckbox.factory()))
    browser.open('/')

    vassert(not any(child.tag == 'label'
                    for child in fixture.get_form_group_children(browser)))
    [div] = fixture.get_form_group_children(browser)
    [checkbox] = div.getchildren()
    vassert(checkbox.attrib['class'] == 'checkbox')
Beispiel #9
0
    def interface_with_meta_info(self, fixture):
        """A Reahl component can publish a ReahlEgg instance to supply extra meta information about itself.
           Such interfaces with extra information are also often used from a flattened list in dependency order."""

        easter_egg.clear()
        easter_egg.add_dependency('reahl-component')

        # The interface for a component is published via the reahl.eggs entry point
        line = 'Egg = reahl.component.eggs:ReahlEgg'
        easter_egg.add_entry_point_from_line('reahl.eggs', line)

        # Interfaces can be queried in dependency order too
        interfaces_in_order = ReahlEgg.compute_all_relevant_interfaces(
            easter_egg.as_requirement_string())
        vassert(len(interfaces_in_order) ==
                2)  # That of reahl-component itself, and of the easteregg
        [interface
         ] = [i for i in interfaces_in_order if i.distribution is easter_egg]

        # The meta-info that can be obtained via such an interface
        vassert(interface.configuration_spec is None)

        orm_control = EmptyStub()
        vassert(interface.get_persisted_classes_in_order(orm_control) == [])
        vassert(interface.migrations_in_order == [])
        vassert(interface.get_roles_to_add() == [])

        # Hooks for allowing a component to do its own housekeeping
        with expected(NoException):
            interface.do_daily_maintenance()
Beispiel #10
0
    def checked_arguments(self, fixture):
        """A CheckedRemoteMethod checks and marshalls its parameters using Fields."""
        def callable_object(anint=None, astring=None):
            fixture.method_kwargs = {'anint': anint, 'astring': astring}
            return ''

        remote_method = CheckedRemoteMethod('amethod',
                                            callable_object,
                                            MethodResult(),
                                            immutable=fixture.immutable,
                                            anint=IntegerField(),
                                            astring=Field())

        wsgi_app = fixture.new_wsgi_app(remote_method=remote_method)
        browser = Browser(wsgi_app)

        if fixture.immutable:
            browser.open(
                '/_amethod_method?anint=5&astring=SupercalifraGilisticexpialidocious'
            )
        else:
            browser.post('/_amethod_method', {
                'anint': '5',
                'astring': 'SupercalifraGilisticexpialidocious'
            })
        vassert(fixture.method_kwargs == {
            'anint': 5,
            'astring': 'SupercalifraGilisticexpialidocious'
        })
Beispiel #11
0
    def query_string_prepopulates_form(self, fixture):
        """Widget query string arguments can be used on forms to pre-populate inputs based on the query string."""
        class ModelObject(object):
            @exposed
            def fields(self, fields):
                fields.arg_on_other_object = Field()

        class FormWithQueryArguments(Form):
            def __init__(self, view):
                self.model_object = ModelObject()
                super(FormWithQueryArguments, self).__init__(view, 'name')
                self.add_child(
                    TextInput(self,
                              self.model_object.fields.arg_on_other_object))

            @exposed
            def query_fields(self, fields):
                fields.arg_on_other_object = self.model_object.fields.arg_on_other_object

        wsgi_app = fixture.new_wsgi_app(
            widget_factory=FormWithQueryArguments.factory())
        browser = Browser(wsgi_app)

        browser.open('/?arg_on_other_object=metoo')
        vassert(browser.lxml_html.xpath('//input')[0].value == 'metoo')
Beispiel #12
0
    def entry_point_class_list(self, fixture):
        """EntryPointClassList is a special ConfigSetting which reads its value from a pkg_resources
           entry point which contains a list of classes published by any (possibly other) egg."""
        # Because we cannot remove EasterEggs from pkg_resources, the next test must happen after
        # this one. The next check just ensures that we know when that does not happen:
        with expected(pkg_resources.DistributionNotFound):
            pkg_resources.require('test-inject')

        fixture.set_config_spec(
            easter_egg,
            'reahl.component_dev.test_config:ConfigWithEntryPointClassList')

        # Publish some classes on the entry point being tested
        line = 'ListedClass1 = reahl.component_dev.test_config:ListedClass1'
        easter_egg.add_entry_point_from_line('some.test.entrypoint', line)
        line = 'ListedClass2 = reahl.component_dev.test_config:ListedClass2'
        easter_egg.add_entry_point_from_line('some.test.entrypoint', line)

        # Usually this happens inside other infrastructure, such as the implementation of reahl serve (see reahl-dev)
        config = StoredConfiguration(fixture.config_dir.name)
        config.configure()

        # The classes are found from the entry point
        vassert(
            set(config.some_key.some_setting) == {ListedClass1, ListedClass2})
Beispiel #13
0
    def is_version_controlled(self, fixture):
        non_initialised_directory = fixture.new_bzr_directory(initialised=False)
        bzr = Bzr(non_initialised_directory.name)
        vassert( not bzr.is_version_controlled() )

        bzr = Bzr(fixture.bzr_directory.name)
        vassert( bzr.is_version_controlled() )
Beispiel #14
0
def dynamically_determining_attributes(fixture):
    """A Widget can determine its attribute values at the latest possible stage, based on changing data."""

    class WidgetWithDynamicAttributes(HTMLElement):
        state = '1'
        @property
        def attributes(self):
            attributes = super(WidgetWithDynamicAttributes, self).attributes
            attributes.set_to('dynamic', self.state)
            attributes.add_to('dynamiclist', [self.state])
            attributes.add_to('not-there', ['a value'])
            attributes.remove_from('not-there', ['a value'])
            return attributes

    widget = WidgetWithDynamicAttributes(fixture.view, 'x')
    widget.set_attribute('fixed', 'value1')
    tester = WidgetTester(widget)

    widget.state = '1'
    rendered = tester.render_html()
    vassert( rendered == '<x dynamic="1" dynamiclist="1" fixed="value1">' )

    widget.state = '2'
    rendered = tester.render_html()
    vassert( rendered == '<x dynamic="2" dynamiclist="2" fixed="value1">' )
Beispiel #15
0
def egg_schema_version_init(fixture):
    orm_control = SqlAlchemyControl()

    egg = ReahlEggStub('initegg', '0.0', [])
    orm_control.create_db_tables(None, [egg])
    current_version = orm_control.schema_version_for(egg)
    vassert(current_version == egg.version)
Beispiel #16
0
    def rendering_inputs(self, fixture):
        """How Inputs render, depending on the rights."""

        tester = WidgetTester(fixture.input_widget)

        actual = tester.render_html()
        vassert(actual == fixture.expected_html)
Beispiel #17
0
def schedule_executes_in_order(fixture):
    """A MigrationSchedule is used internally to schedule calls in different phases. The calls 
       scheduled in each phase are executed in the order the phases have been set up on the MigrationSchedule.
       Within a phase, the calls are executed in the order they were registered in that phase.
    """

    schedule_names = ['a', 'b', 'c']
    migration_schedule = MigrationSchedule(*schedule_names)

    class SomeObject(object):
        def do_something(self, arg):
            pass

    some_object = SomeObject()

    #schedule calls not in registered order
    with CallMonitor(some_object.do_something) as monitor:
        migration_schedule.schedule('c', some_object.do_something, 'c1')
        migration_schedule.schedule('a', some_object.do_something, 'a1')
        migration_schedule.schedule('b', some_object.do_something, 'b')
        migration_schedule.schedule('a', some_object.do_something, 'a2')
        migration_schedule.schedule('c', some_object.do_something, 'c2')

    migration_schedule.execute_all()

    actual_order = [call.args[0] for call in monitor.calls]
    expected_order = ['a1', 'a2', 'b', 'c1', 'c2']
    vassert(actual_order == expected_order)
Beispiel #18
0
    def non_writable_events_are_dealt_with_like_invalid_input(self, fixture):
        """If a form submits an Event with access rights that prohibit writing, a ValidationException is raised."""
        class ModelObject(object):
            @exposed
            def events(self, events):
                events.an_event = Event(
                    label='click me',
                    writable=Allowed(False),
                    disallowed_message='you cannot do this')

        model_object = ModelObject()

        class TestPanel(Div):
            def __init__(self, view):
                super(TestPanel, self).__init__(view)
                form = self.add_child(Form(view, 'some_form'))
                form.define_event_handler(model_object.events.an_event)
                button = form.add_child(
                    ButtonInput(form, model_object.events.an_event))
                if button.validation_error:
                    form.add_child(form.create_error_label(button))
                fixture.form = form

        wsgi_app = fixture.new_wsgi_app(child_factory=TestPanel.factory())
        browser = Browser(wsgi_app)
        browser.open('/')

        browser.post(fixture.form.event_channel.get_url().path,
                     {'event.an_event?': ''})
        browser.follow_response()
        input_id = browser.get_id_of('//input[@name="event.an_event?"]')
        error_label = browser.get_html_for('//label')
        vassert(error_label ==
                '<label for="%s" class="error">you cannot do this</label>' %
                input_id)
Beispiel #19
0
def how_migration_works(fixture):
    """Calls that will modify the database are scheduled in the schedule_upgrades() method of all
       the applicable Migrations for a single migration run. `shedule_upgrades()` is called on each
       migration in order of their versions. Once all calls are scheduled,
       they are executed as scheduled.
    """
    class SomeObject(object):
        calls_made = []

        def do_something(self, arg):
            self.calls_made.append(arg)

    some_object = SomeObject()

    class Migration1(Migration):
        version = '2.0'

        def schedule_upgrades(self):
            self.schedule('drop_fk', some_object.do_something, 'drop_fk_1')
            self.schedule('data', some_object.do_something, 'data_1')
            self.schedule('drop_fk', some_object.do_something, 'drop_fk_2')

    class Migration2(Migration):
        version = '3.0'

        def schedule_upgrades(self):
            self.schedule('drop_fk', some_object.do_something, 'drop_fk_3')

    egg = ReahlEggStub('my_egg', '4.0', [Migration1, Migration2])
    fixture.orm_control.set_currently_installed_version_for(egg, '1.0')

    fixture.orm_control.migrate_db([egg])

    expected_order = ['drop_fk_1', 'drop_fk_2', 'drop_fk_3', 'data_1']
    vassert(some_object.calls_made == expected_order)
Beispiel #20
0
def table_thead(fixture):
    """Table can find its Thead element"""

    table = Table(fixture.view)
    thead = table.add_child(Thead(fixture.view))

    vassert(table.thead is thead)
Beispiel #21
0
    def basic_ui(self, fixture):
        """A UserInterface is a chunk of web app that can be grafted onto the URL hierarchy of any app.
        
           A UserInterface has its own views. Its Views are relative to the UserInterface itself.
        """
        class UIWithTwoViews(UserInterface):
            def assemble(self):
                self.define_view('/', title='UserInterface root view')
                self.define_view('/other', title='UserInterface other view')

        class MainUI(UserInterface):
            def assemble(self):
                self.define_page(HTML5Page)
                self.define_user_interface('/a_ui',
                                           UIWithTwoViews, {},
                                           name='myui')

        wsgi_app = fixture.new_wsgi_app(site_root=MainUI)
        browser = Browser(wsgi_app)

        browser.open('/a_ui/')
        vassert(browser.title == 'UserInterface root view')

        browser.open('/a_ui/other')
        vassert(browser.title == 'UserInterface other view')
Beispiel #22
0
def input_wrapped_widgets(fixture):
    """An Input is an empty Widget; its contents are supplied by overriding its 
       .create_html_widget() method. Several methods for setting HTML-things, like 
       css id are delegated to this Widget which represents the Input in HTML.
    """
    class MyInput(PrimitiveInput):
        def create_html_widget(self):
            return HTMLElement(self.view, 'x')

    test_input = MyInput(fixture.form, fixture.field)
    tester = WidgetTester(test_input)

    rendered = tester.render_html()
    vassert(rendered == '<x>')

    test_input.set_id('myid')
    test_input.set_title('mytitle')
    test_input.add_to_attribute('list-attribute', ['one', 'two'])
    test_input.set_attribute('an-attribute', 'a value')

    rendered = tester.render_html()
    vassert(
        rendered ==
        '<x id="myid" an-attribute="a value" list-attribute="one two" title="mytitle">'
    )
Beispiel #23
0
    def i18n_dhtml(self, fixture):
        """Djhtml files can have i18nsed versions, which would be served up if applicable."""
        @stubclass(WebExecutionContext)
        class AfrikaansContext(WebExecutionContext):
            @property
            def interface_locale(self):
                return 'af'

        class MainUI(UserInterface):
            def assemble(self):
                self.define_page(HTML5Page).use_layout(
                    PageLayout(
                        contents_layout=ColumnLayout('main').with_slots()))
                self.define_user_interface('/dhtml_ui',
                                           DhtmlUI, {'main_slot': 'main'},
                                           name='test_ui',
                                           static_div_name='astatic')

        # Djhtml files should be located in the web.static_root
        fixture.config.web.static_root = fixture.static_dir.name

        wsgi_app = fixture.new_wsgi_app(site_root=MainUI)

        browser = Browser(wsgi_app)

        # request the file, but get the transalated alternative for the locale
        def stubbed_create_context_for_request():
            return AfrikaansContext()

        with replaced(wsgi_app.create_context_for_request,
                      stubbed_create_context_for_request):
            browser.open('/dhtml_ui/correctfile.d.html')

        vassert(browser.title == 'Afrikaans bo!')
Beispiel #24
0
    def visibility(self, fixture):
        """Widgets are rendered only if their .visible property is True."""
        class MyMessage(Widget):
            is_visible = True

            def __init__(self, view):
                super(MyMessage, self).__init__(view)
                self.add_child(P(view, text='你好世界!'))

            @property
            def visible(self):
                return self.is_visible

        message = MyMessage(fixture.view)

        widget_tester = WidgetTester(message)

        # Case: when visible
        message.is_visible = True
        actual = widget_tester.render_html()
        vassert(actual == '<p>你好世界!</p>')

        # Case: when not visible
        message.is_visible = False
        actual = widget_tester.render_html()
        vassert(actual == '')
Beispiel #25
0
def prevent_duplicate_upload_js(fixture):
    """The user is prevented from uploading more than one file with the same name on the client side.
    """

    error_locator = XPath.span_containing(
        'uploaded files should all have different names')

    def error_is_visible():
        return browser.is_visible(error_locator)

    fixture.reahl_server.set_app(fixture.new_wsgi_app(enable_js=True))
    browser = fixture.driver_browser
    browser.open('/')

    browser.type(XPath.input_labelled('Choose file(s)'),
                 fixture.file_to_upload1.name)
    browser.wait_for_not(error_is_visible)

    browser.type(XPath.input_labelled('Choose file(s)'),
                 fixture.file_to_upload2.name)
    browser.wait_for_not(error_is_visible)

    with fixture.reahl_server.paused():
        browser.type(XPath.input_labelled('Choose file(s)'),
                     fixture.file_to_upload1.name)
        vassert(
            not fixture.upload_file_is_queued(fixture.file_to_upload1.name))
        browser.wait_for(error_is_visible)

    browser.click(
        XPath.button_labelled('Remove', filename=fixture.file_to_upload2_name))
    browser.wait_for_not(error_is_visible)
Beispiel #26
0
    def rendering_of_constraints(self, fixture):
        """The constraints of the Field of an PrimitiveInput are rendered in html as html attributes of an Input
           which corresponds with the name of each validation_constraint and has value the parameters of the validation_constraint.
           The error message of each validation_constraint is also put in a json object inside the class attribute.
           These measures make it possible to write constraints that are checked on the browser either by
           browser support or by a jquery validate add-on, and in case of failure to display the exact
           corresponding error message."""

        fixture.field.bind('an_attribute', fixture.model_object)
        fixture.model_object.an_attribute = 'field value'

        constraint1 = ValidationConstraint('validation_constraint 1 message')
        constraint1.name = 'one'

        @stubclass(ValidationConstraint)
        class ConstraintWithParams(ValidationConstraint):
            @property
            def parameters(self):
                return 'a parameter'

        constraint2 = ConstraintWithParams(
            'validation_constraint 2 message with apostrophe\'s')
        constraint2.name = 'two'

        fixture.field.add_validation_constraint(constraint1)
        fixture.field.add_validation_constraint(constraint2)

        tester = WidgetTester(fixture.input)

        actual = tester.render_html()
        escaped_json = html_escape(
            '{"validate": {"messages": {"data-one": "validation_constraint 1 message", "data-two": "validation_constraint 2 message with apostrophe\\\\\'s"}}}'
        )
        expected_html = '''<input name="an_attribute" data-one="true" data-two="a parameter" form="test" type="inputtype" value="field value" class="%s">''' % escaped_json
        vassert(actual == expected_html)
Beispiel #27
0
 def read_text_object(self, fixture):
     fixture.reader.register(fixture.tag_name, fixture.test_class)
     read_object = fixture.reader.read_file(fixture.file, None)
     if fixture.text:
         vassert(read_object.text == fixture.text)
     else:
         vassert(not hasattr(read_object, 'text'))
Beispiel #28
0
def placeholder_with_text(fixture):

    placeholder = PlaceholderImage(fixture.view, 20, 30, text='My banner')

    expected_value = 'holder.js/20x30?text=My banner'
    actual_value = placeholder.get_attribute('data-src')
    vassert(actual_value == expected_value)
Beispiel #29
0
def tabs_with_sub_options(fixture):
    """A TabbedPanel can have Tabs that are each composed of multiple sub-options."""
    fixture.request.query_string = 'tab=mult2'
    tabbed_panel = TabbedPanel(fixture.view)
    multi_tab = MultiTab(fixture.view, 'tab 1 name', 'multitab-main')
    multi_tab.add_tab(
        Tab(fixture.view, 'multi tab 1', 'mult1',
            P.factory(text='tab 1/1 content')))
    multi_tab.add_tab(
        Tab(fixture.view, 'multi tab 2', 'mult2',
            P.factory(text='tab 1/2 content')))
    tabbed_panel.add_tab(multi_tab)

    tester = WidgetTester(tabbed_panel)

    expected_html = \
     '''<ul class="nav nav-tabs reahl-menu">'''\
     '''<li class="dropdown nav-item">'''\
      '''<a data-target="-" data-toggle="dropdown" href="/?open_item=tab+1+name&amp;tab=mult2" class="active dropdown-toggle nav-link reahl-ajaxlink">tab 1 name<span class="caret"></span></a>'''\
      '''<div class="dropdown-menu">'''\
       '''<a data-target="#tab_mult1" data-toggle="tab" href="/?tab=mult1" class="dropdown-item">multi tab 1</a>'''\
       '''<a data-target="#tab_mult2" data-toggle="tab" href="/?tab=mult2" class="active dropdown-item">multi tab 2</a>'''\
      '''</div>'''\
     '''</li>'''\
    '''</ul>'''\
    '''<div class="tab-content">'''\
     '''<div id="tab_mult1" class="tab-pane"><p>tab 1/1 content</p></div>'''\
     '''<div id="tab_mult2" class="active tab-pane"><p>tab 1/2 content</p></div>'''\
    '''</div>'''

    actual = tester.render_html()
    vassert(actual == expected_html)
Beispiel #30
0
def distinguishing_identical_field_names(fixture):
    """A programmer can add different Inputs on the same Form even if their respective Fields are bound
       to identically named attributes of different objects."""
    class ModelObject(object):
        @exposed
        def fields(self, fields):
            fields.field_name = IntegerField()

    model_object1 = ModelObject()
    model_object2 = ModelObject()

    class MyForm(Form):
        @exposed
        def events(self, events):
            events.an_event = Event(label='click me')

        def __init__(self, view, name):
            super(MyForm, self).__init__(view, name)
            self.define_event_handler(self.events.an_event)
            self.add_child(ButtonInput(self, self.events.an_event))

            self.add_child(TextInput(self, model_object1.fields.field_name))
            self.add_child(TextInput(self, model_object2.fields.field_name))

    wsgi_app = fixture.new_wsgi_app(child_factory=MyForm.factory('form'))
    fixture.reahl_server.set_app(wsgi_app)
    fixture.driver_browser.open('/')

    # the correct input value gets to the correct object despite referencing identically named attributes
    fixture.driver_browser.type('//input[@type="text"][1]', '0')
    fixture.driver_browser.type('//input[@type="text"][2]', '1')
    fixture.driver_browser.click(XPath.button_labelled('click me'))
    vassert(model_object1.field_name == 0)
    vassert(model_object2.field_name == 1)