def test_i18n_dhtml(web_fixture, dhtml_fixture): """Dhtml files can have i18nsed versions, which would be served up if applicable.""" class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page).use_layout(BasicPageLayout()) self.define_user_interface('/dhtml_ui', DhtmlUI, {'main_slot': 'main'}, name='test_ui', static_div_name='astatic') fixture = dhtml_fixture # Dhtml files should be located in the web.static_root web_fixture.config.web.static_root = fixture.static_dir.name wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) # request the file, but get the translated alternative for the locale def stubbed_create_context_for_request(): return LocaleContextStub(locale='af') with replaced(wsgi_app.create_context_for_request, stubbed_create_context_for_request): browser.open('/dhtml_ui/correctfile.d.html') assert browser.title == 'Afrikaans bo!'
def test_packaged_files(web_fixture): """Files can also be served straight from a python egg.""" # Create an egg with package packaged_files, containing the file packaged_file egg_dir = temp_dir() package_dir = egg_dir.sub_dir('packaged_files') init_file = package_dir.file_with('__init__.py', '') afile = package_dir.file_with('packaged_file', 'contents') easter_egg.clear() pkg_resources.working_set.add(easter_egg) easter_egg.location = egg_dir.name class MainUI(UserInterface): def assemble(self): list_of_files = [ PackagedFile(easter_egg.as_requirement_string(), 'packaged_files', 'packaged_file') ] self.define_static_files('/files', list_of_files) wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) # How the file would be accessed browser.open('/files/packaged_file') assert browser.raw_html == 'contents'
def test_ui_arguments(web_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(BasicPageLayout()) self.define_user_interface('/a_ui', UIWithArguments, {'text': 'main'}, name='myui', kwarg='the kwarg') fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/a_ui/') [p] = browser.lxml_html.xpath('//p') assert p.text == 'the kwarg'
def test_check_missing_form(web_fixture): """All forms referred to by inputs on a page have to be present on that page.""" fixture = web_fixture class ModelObject(object): @exposed def fields(self, fields): fields.name = Field() class MyPanel(Div): def __init__(self, view): super(MyPanel, self).__init__(view) model_object = ModelObject() forgotten_form = Form(view, 'myform') self.add_child(TextInput(forgotten_form, model_object.fields.name)) wsgi_app = fixture.new_wsgi_app(child_factory=MyPanel.factory()) browser = Browser(wsgi_app) expected_message = 'Could not find form for <TextInput name=myform-name>. '\ 'Its form, <Form form id="myform".*> is not present on the current page' with expected(ProgrammerError, test=expected_message): browser.open('/')
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!')
def test_i18n_urls(web_fixture): """The current locale is determined by reading the first segment of the path. If the locale is not present in the path, web.default_url_locale is used.""" _ = Catalogue('reahl-web') class I18nUI(UserInterface): def assemble(self): view = self.define_view('/aview', title=_('A View')) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page) self.define_user_interface('/a_ui', I18nUI, IdentityDictionary(), name='test_ui') wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/a_ui/aview') assert browser.title == 'A View' browser.open('/af/a_ui/aview') assert browser.title == '\'n Oogpunt' web_fixture.config.web.default_url_locale = 'af' browser.open('/a_ui/aview') assert browser.title == '\'n Oogpunt' browser.open('/en_gb/a_ui/aview') assert browser.title == 'A View'
def test_widget_factory_creates_widget_with_layout(web_fixture, widget_creation_scenarios): """A Layout can be specified to any WidgetFactory or to UserInterface.define_page""" class MyLayout(Layout): def customise_widget(self): self.widget.add_child( P(self.view, text='This widget is using Mylayout')) layout_for_widget = MyLayout() class MainUI(UserInterface): def assemble(self): self.define_view( '/', title='Hello', page=HTML5Page.factory(use_layout=layout_for_widget)) fixture = widget_creation_scenarios wsgi_app = web_fixture.new_wsgi_app(site_root=fixture.MainUI) browser = Browser(wsgi_app) browser.open('/') [p] = browser.lxml_html.xpath('//p') assert p.text == 'This widget is using Mylayout'
def missing_variable_in_regex(self, fixture): """If a variable is missing from the regex, an appropriate error is raised.""" class ParameterisedView(UrlBoundView): def assemble(self, some_key=None): self.title = 'View for: %s' % some_key class UIWithParameterisedViews(UserInterface): def assemble(self): self.define_regex_view('/(?P<incorrect_name_for_key>.*)', '/${key}', view_class=ParameterisedView, some_key=Field(required=True)) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page) self.define_user_interface('/a_ui', UIWithParameterisedViews, {}, name='test_ui') wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) def check_message(ex): return six.text_type(ex).startswith( 'The arguments contained in URL') with expected(ProgrammerError, test=check_message): browser.open('/a_ui/test1/')
def test_activating_javascript(web_fixture): """The JavaScript snippets of all Widgets are collected in a jQuery.ready() function by""" """ an automatically inserted Widget in the slot named reahl_footer. Duplicate snippets are removed.""" @stubclass(Widget) class WidgetWithJavaScript(Widget): def __init__(self, view, fake_js): super().__init__(view) self.fake_js = fake_js def get_js(self, context=None): return [self.fake_js] class MyPage(Widget): def __init__(self, view): super().__init__(view) self.add_child(WidgetWithJavaScript(view, 'js1')) self.add_child(WidgetWithJavaScript(view, 'js2')) self.add_child(WidgetWithJavaScript(view, 'js1'))#intended duplicate self.add_child(Slot(view, 'reahl_footer')) class MainUI(UserInterface): def assemble(self): self.define_page(MyPage) self.define_view('/', title='Home') fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/') rendered_js = [i.text for i in browser.lxml_html.xpath('//script[@id="reahl-jqueryready"]')][0] assert rendered_js == '\njQuery(document).ready(function($){\n$(\'body\').addClass(\'enhanced\');\njs1\njs2\n\n});\n' number_of_duplicates = rendered_js.count('js1') - 1 assert number_of_duplicates == 0
def internal_redirects(self, fixture): """During request handling, an InternalRedirect exception can be thrown. This is handled by restarting the request loop from scratch to handle the same request again, using a freshly constructed resource just as though the request was submitted again by the browser save for the browser round trip.""" fixture.requests_handled = [] fixture.handling_resources = [] @stubclass(Resource) class ResourceStub(object): def handle_request(self, request): fixture.requests_handled.append(request) fixture.handling_resources.append(self) if hasattr(request, 'internal_redirect'): return Response(body='response given after internal redirect') raise InternalRedirect(None, None) @stubclass(ReahlWSGIApplication) class ReahlWSGIApplicationStub2(ReahlWSGIApplicationStub): def resource_for(self, request): return ResourceStub() browser = Browser(ReahlWSGIApplicationStub2(fixture.config)) browser.open('/') vassert( browser.raw_html == 'response given after internal redirect' ) vassert( fixture.requests_handled[0] is fixture.requests_handled[1] ) vassert( fixture.handling_resources[0] is not fixture.handling_resources[1] )
def test_missing_variable_in_ui_regex(web_fixture): class RegexUserInterface(UserInterface): def assemble(self, ui_key=None): self.name = 'user_interface-%s' % ui_key class UIWithParameterisedUserInterfaces(UserInterface): def assemble(self): self.define_regex_user_interface('/(?P<xxx>[^/]*)', 'N/A', RegexUserInterface, {}, ui_key=Field(required=True)) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page) self.define_user_interface('/a_ui', UIWithParameterisedUserInterfaces, {}, name='test_ui') wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) with expected(RequiredConstraint): browser.open('/a_ui/test1/')
def test_immutable_remote_methods(web_fixture, remote_method_fixture, sql_alchemy_fixture): """The database is always rolled back at the end of an immutable RemoteMethod.""" class TestObject(Base): __tablename__ = 'test_remotemethods_test_object' id = Column(Integer, primary_key=True) name = Column(UnicodeText) with sql_alchemy_fixture.persistent_test_classes(TestObject): def callable_object(): Session.add(TestObject(name='new object')) assert Session.query(TestObject).count() == 1 return 'value returned from method' remote_method = RemoteMethod(web_fixture.view, 'amethod', callable_object, MethodResult(), immutable=True) assert remote_method.idempotent # Immutable methods are idempotent wsgi_app = remote_method_fixture.new_wsgi_app( remote_method=remote_method) browser = Browser(wsgi_app) browser.open('/_amethod_method') assert browser.raw_html == 'value returned from method' # The database is rolled back to ensure immutability assert Session.query(TestObject).count() == 0
def test_inline_form_layouts(web_fixture, form_layout_fixture): """An InlineFormLayout adds the Label and Input of each added input next to each other, with some space between them.""" fixture = form_layout_fixture class FormWithInlineFormLayout(Form): def __init__(self, view): super().__init__(view, 'aform') self.use_layout(InlineFormLayout()) self.layout.add_input(TextInput( self, fixture.domain_object.fields.an_attribute), help_text='some help') browser = Browser( web_fixture.new_wsgi_app( child_factory=FormWithInlineFormLayout.factory())) browser.open('/') [label, input_, help_text] = fixture.get_form_group_children(browser) #check spacing specified between label, input and help_text assert label.tag == 'label' assert 'mr-2' == label.attrib['class'] assert input_.tag == 'input' assert help_text.tag == 'span' assert 'ml-2' in help_text.attrib['class'].split(' ')
def test_grid_form_layouts(web_fixture, form_layout_fixture): """A GridFormLayout adds the Label and Input of each added input in separate columns sized like you specify""" fixture = form_layout_fixture class FormWithGridFormLayout(Form): def __init__(self, view): super().__init__(view, 'aform') self.use_layout( GridFormLayout(ResponsiveSize(lg=4), ResponsiveSize(lg=8))) self.layout.add_input(TextInput( self, fixture.domain_object.fields.an_attribute), help_text='some help') browser = Browser( web_fixture.new_wsgi_app( child_factory=FormWithGridFormLayout.factory())) browser.open('/') [label_column, input_column] = fixture.get_form_group_children(browser) assert label_column.tag == 'div' assert 'col-lg-4' in label_column.attrib['class'].split(' ') assert 'column-label' in label_column.attrib['class'].split(' ') [label] = fixture.get_label_in_form_group(browser) assert 'col-form-label' in label.attrib['class'].split(' ') assert input_column.tag == 'div' assert 'col-lg-8' in input_column.attrib['class'].split(' ') assert 'column-input' in input_column.attrib['class'].split(' ') [input_, help_text] = input_column.getchildren() assert input_.tag == 'input' assert help_text.tag == 'p' assert 'form-text' in help_text.attrib['class'].split(' ')
def test_query_string_prepopulates_form(web_fixture, value_scenarios): """Widget query string arguments can be used on forms to pre-populate inputs based on the query string.""" fixture = value_scenarios class ModelObject: @exposed def fields(self, fields): fields.arg_on_other_object = fixture.field class FormWithQueryArguments(Form): def __init__(self, view): self.model_object = ModelObject() super().__init__(view, 'name') self.use_layout(FormLayout()) self.layout.add_input(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 = web_fixture.new_wsgi_app(enable_js=True, child_factory=FormWithQueryArguments.factory()) browser = Browser(wsgi_app) browser.open('/?%s' % fixture.field_on_query_string.format(field_name='name-arg_on_other_object')) assert browser.get_value(XPath.input_labelled('field')) == fixture.field_value_as_string
def remote_field_validator_handles_GET(self, fixture): class ModelObject(object): @exposed def fields(self, fields): fields.field_name = EmailField() model_object = ModelObject() class MyForm(Form): def __init__(self, view, name): super(MyForm, self).__init__(view, name) self.add_child(TextInput(self, model_object.fields.field_name)) wsgi_app = fixture.new_wsgi_app(child_factory=MyForm.factory( name='some_form')) fixture.reahl_server.set_app(wsgi_app) browser = Browser(wsgi_app) browser.open(six.text_type(fixture.url)) response = browser.last_response vassert(response.unicode_body == fixture.expected_body) vassert(response.status == fixture.expected_status) vassert(response.content_type == fixture.expected_content_type) vassert(response.charset == fixture.expected_charset)
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')
def test_remote_field_validator_handles_GET(web_fixture, validation_scenarios): fixture = validation_scenarios class ModelObject: @exposed def fields(self, fields): fields.field_name = EmailField() model_object = ModelObject() class MyForm(Form): def __init__(self, view, name): super().__init__(view, name) self.add_child(TextInput(self, model_object.fields.field_name)) wsgi_app = web_fixture.new_wsgi_app(child_factory=MyForm.factory(name='some_form')) web_fixture.reahl_server.set_app(wsgi_app) browser = Browser(wsgi_app) browser.open(str(fixture.url)) response = browser.last_response assert response.unicode_body == fixture.expected_body assert response.status == fixture.expected_status assert response.content_type == fixture.expected_content_type assert response.charset == fixture.expected_charset
def adding_basic_input(fixture): """Adding an input to a FormLayout, adds it in a bootstrap form-group with Some input.""" class FormWithInputAddedUsingDefaults(Form): def __init__(self, view): super(FormWithInputAddedUsingDefaults, self).__init__(view, 'aform') self.use_layout(FormLayout()) self.layout.add_input( TextInput(self, fixture.domain_object.fields.an_attribute)) browser = Browser( fixture.new_wsgi_app( child_factory=FormWithInputAddedUsingDefaults.factory())) browser.open('/') vassert(fixture.form_contains_form_group(browser)) [label, input_widget] = fixture.get_form_group_children(browser) # form-group has a label, correctly set up for bootstrap vassert(label.tag == 'label') vassert(label.attrib['for'] == input_widget.attrib['id']) vassert(label.text == 'Some input') # form-group has an input, correctly set up for bootstrap vassert(input_widget.tag == 'input') vassert(input_widget.attrib['name'] == 'an_attribute')
def test_simple_sub_resources(web_fixture): """During their construction, Widgets can add SubResources to their View. The SubResource will then be available via a special URL underneath the URL of the Widget's View.""" fixture = web_fixture @stubclass(SubResource) class ASimpleSubResource(SubResource): sub_regex = 'simple_resource' sub_path_template = 'simple_resource' @exempt def handle_get(self, request): return Response() @stubclass(Widget) class WidgetWithSubResource(Widget): def __init__(self, view): super(WidgetWithSubResource, self).__init__(view) view.add_resource(ASimpleSubResource(view, 'uniquename')) wsgi_app = fixture.new_wsgi_app( child_factory=WidgetWithSubResource.factory()) browser = Browser(wsgi_app) browser.open('/_uniquename_simple_resource')
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')
def test_basic_workings(web_fixture, dhtml_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(BasicPageLayout()) self.define_user_interface('/dhtml_ui', DhtmlUI, {'main_slot': 'main'}, name='test_ui', static_div_name='astatic') fixture = dhtml_fixture # Dhtml files should be located in the web.static_root web_fixture.config.web.static_root = fixture.static_dir.name wsgi_app = web_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) assert html == fixture.div_internals # A non-dhtml file is returned verbatim browser.open('/dhtml_ui/otherfile.txt') contents = browser.raw_html assert 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)
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)
def test_ui_slots_map_to_window(web_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(BasicPageLayout()) self.define_user_interface('/a_ui', UIWithSlots, {'text': 'main'}, name='myui') fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/a_ui/') assert 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') assert p.text == 'in user_interface slot named text'
def test_files_from_database(web_fixture): """Files can also be created on the fly such as from data in a database.""" content_bytes = ('hôt stuff').encode('utf-8') class MainUI(UserInterface): def assemble(self): mime_type = 'text/html' encoding = 'utf-8' mtime = 123 size = len(content_bytes) list_of_files = [ FileFromBlob('database_file', content_bytes, mime_type, encoding, size, mtime) ] self.define_static_files('/files', list_of_files) wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) # How the file would be accessed browser.open('/files/database_file') assert browser.raw_html == 'hôt stuff' response = browser.last_response # The meta-info of the file assert response.content_type == 'text/html' assert not response.content_encoding assert response.content_length == len(content_bytes) assert response.last_modified.replace( tzinfo=None) == datetime.datetime.fromtimestamp(123) expected_etag = '123-%s-%s' % (len(content_bytes), abs(hash('database_file'))) assert response.etag == expected_etag
def test_views_from_regex(web_fixture): """Parameterised Views can also be added based on a regex over the url.""" class ParameterisedView(UrlBoundView): def assemble(self, some_key=None): self.title = 'View for: %s' % some_key class UIWithParameterisedViews(UserInterface): def assemble(self): self.define_regex_view('/someurl_(?P<some_key>.*)', '/someurl_${some_key}', view_class=ParameterisedView, some_key=Field(required=True)) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page) self.define_user_interface('/a_ui', UIWithParameterisedViews, {}, name='myui') wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) # Parameterised constructing a View from an URL browser.open('/a_ui/someurl_test1') assert browser.title == 'View for: test1'
def test_concatenated_files(web_fixture, concatenate_scenarios): """Files can also be formed by concatenating other files. Files ending in .css or .js are appropriately minified in the process.""" fixture = concatenate_scenarios # Make an egg with a package called packaged_files, and two files in there. egg_dir = temp_dir() package_dir = egg_dir.sub_dir('packaged_files') init_file = package_dir.file_with('__init__.py', '') afile = package_dir.file_with('packaged_file', fixture.file1_contents) another_file = package_dir.file_with('packaged_file2', fixture.file2_contents) pkg_resources.working_set.add(easter_egg) easter_egg.location = egg_dir.name class MainUI(UserInterface): def assemble(self): to_concatenate = [ PackagedFile('test==1.0', 'packaged_files', 'packaged_file'), PackagedFile('test==1.0', 'packaged_files', 'packaged_file2') ] list_of_files = [ ConcatenatedFile(fixture.filename, to_concatenate) ] self.define_static_files('/files', list_of_files) web_fixture.config.reahlsystem.debug = False # To enable minification wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) # How the first file would be accessed browser.open('/files/%s' % fixture.filename) assert browser.raw_html == fixture.expected_result
def test_linking_to_views_marked_as_detour(web_fixture): """A View can be marked as the start of a Detour. Where used, a Bookmark for such a View will automatically include a returnTo in the its query string. This allows an eventual return_transition (or similar) to return to where, eg, a link was clicked from. This mechanism works for returning across UserInterfaces.""" class UIWithLink(UserInterface): def assemble(self, bookmark=None): self.bookmark = bookmark self.define_view('/initial', title='View a').set_slot( 'main', A.factory_from_bookmark(self.bookmark)) class UIWithDetour(UserInterface): def assemble(self): event = Event(label='Click me') event.bind('anevent', None) step1 = self.define_view('/firstStepOfDetour', title='Step 1', detour=True) step1.set_slot('main', FormWithButton.factory(event)) step2 = self.define_view('/lastStepOfDetour', title='Step 2') step2.set_slot('main', FormWithButton.factory(event)) self.define_transition(event, step1, step2) self.define_return_transition(event, step2) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page).use_layout(BasicPageLayout()) detour_ui = self.define_user_interface('/uiWithDetour', UIWithDetour, IdentityDictionary(), name='second_ui') bookmark = detour_ui.get_bookmark( relative_path='/firstStepOfDetour') self.define_user_interface('/uiWithLink', UIWithLink, IdentityDictionary(), name='first_ui', bookmark=bookmark) wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/uiWithLink/initial') browser.click('//a') assert browser.current_url.path == '/uiWithDetour/firstStepOfDetour' browser.click('//input[@type="submit"]') assert browser.current_url.path == '/uiWithDetour/lastStepOfDetour' browser.click('//input[@type="submit"]') assert browser.current_url.path == '/uiWithLink/initial' # The query string is cleared after such a return (it is used to remember where to return to) assert browser.current_url.query == ''
def slots(fixture): """A View modifies the page by populating named Slots in the page with Widgets.""" wsgi_app = fixture.new_wsgi_app(site_root=fixture.MainUI) browser = Browser(wsgi_app) browser.open('/') vassert(browser.title == 'Hello') [main_p, footer_p] = browser.xpath('//p') vassert(main_p.text == 'Hello world') vassert(footer_p.text == 'I am the footer')
def detour_to_login(self, fixture): browser = Browser(fixture.wsgi_app) browser.open('/inbox/') vassert(browser.location_path == '/accounts/login') browser.type('//input[@name="email"]', fixture.system_account.email) browser.type('//input[@name="password"]', fixture.system_account.password) browser.click('//input[@value="Log in"]') vassert(browser.location_path == '/inbox/')