def posting_to_view(self, fixture): """ONLY If a View is writable, may it be POSTed to""" def disallowed(): return False class MyForm(Form): def __init__(self, view): super(MyForm, self).__init__(view, 'myform') self.define_event_handler(self.events.an_event) self.add_child(ButtonInput(self, self.events.an_event)) @exposed def events(self, events): events.an_event = Event(label='Click me') class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page).use_layout( PageLayout( contents_layout=ColumnLayout('main').with_slots())) home = self.define_view('/a_view', 'Title', write_check=disallowed) home.set_slot('main', MyForm.factory()) wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/a_view') browser.click(XPath.button_labelled('Click me'), status=403)
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_out_of_bound_widgets(web_fixture): """When you need to add a widget to the page, but not as a child/descendant.""" class MyPanel(Div): def __init__(self, view): super().__init__(view, css_id='main_panel') child_widget = self.add_child(P(view, text='Child Widget')) out_of_bound_widget = view.add_out_of_bound_widget(P(view, text='Out Of Bound Widget')) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page).use_layout(BasicPageLayout()) home = self.define_view('/', title='Hello') home.set_slot('main', MyPanel.factory()) fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/') main_panel = XPath.div().with_id('main_panel') assert browser.is_element_present(XPath.paragraph().with_text('Out Of Bound Widget')) assert not browser.is_element_present(XPath.paragraph().with_text('Out Of Bound Widget').inside_of(main_panel)) assert browser.is_element_present(XPath.paragraph().with_text('Child Widget').inside_of(main_panel))
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 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_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_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_slot_defaults(web_fixture): """If a View does not specify contents for a Slot, the Slot will be populated by the window's default widget for that slot if specified, else it will be left empty. """ class MainUI(UserInterface): def assemble(self): main = self.define_page(HTML5Page).use_layout(BasicPageLayout()) main.add_default_slot('main', P.factory(text='defaulted slot contents')) self.define_view('/', title='Hello') fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/') # The default widget for the main slot is used [p] = browser.xpath('//p') assert p.text == 'defaulted slot contents' # The header slot has no default, and is thus left empty header_contents = browser.xpath('//header/*') assert not header_contents
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_files_from_list(web_fixture): """An explicit list of files can also be added on an URL as if they were in a single directory. """ files_dir = temp_dir() one_file = files_dir.file_with('any_name_will_do_here', 'one') class MainUI(UserInterface): def assemble(self): list_of_files = [FileOnDisk(one_file.name, 'one_file')] self.define_static_files('/morestaticfiles', list_of_files) wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) # How the first file would be accessed browser.open('/morestaticfiles/one_file') assert browser.raw_html == 'one' # The meta-info of the file response = browser.last_response assert response.content_type == 'application/octet-stream' assert response.content_encoding is None assert response.content_length == 3 expected_mtime = datetime.datetime.fromtimestamp( int(os.path.getmtime(one_file.name))) assert response.last_modified.replace(tzinfo=None) == expected_mtime expected_tag = '%s-%s-%s' % (os.path.getmtime( one_file.name), 3, abs(hash(one_file.name))) assert response.etag == expected_tag # When a file does not exist browser.open('/morestaticfiles/one_that_does_not_exist', status=404)
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 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_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_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_bookmarks_from_other_sources(web_fixture): """Bookmarks can also be made from ViewFactories, UserInterfaces or UserInterfaceFactories. """ fixture = web_fixture class UIWithRelativeView(UserInterface): def assemble(self): view_factory = self.define_view('/aview', title='A View title') # How you could get a bookmark from a UserInterface or ViewFactory fixture.bookmark_from_view_factory = view_factory.as_bookmark(self) fixture.bookmark_from_ui = self.get_bookmark(relative_path='/aview') class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page) fixture.ui_factory = self.define_user_interface('/a_ui', UIWithRelativeView, {}, name='myui') # How you could get a bookmark from a UserInterfaceFactory fixture.bookmark_from_ui_factory = fixture.ui_factory.get_bookmark(relative_path='/aview') wsgi_app = fixture.new_wsgi_app(site_root=MainUI) Browser(wsgi_app).open('/a_ui/aview') # To execute the above once for bookmark in [fixture.bookmark_from_view_factory, fixture.bookmark_from_ui, fixture.bookmark_from_ui_factory]: # What the bookmark knows assert bookmark.href.path == '/a_ui/aview' assert bookmark.description == 'A View title' assert bookmark.base_path == '/a_ui' assert bookmark.relative_path == '/aview'
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 language_menu(fixture): """A Nav can also be constructed to let a user choose to view the same page in another of the supported languages.""" class PanelWithMenu(Div): def __init__(self, view): super(PanelWithMenu, self).__init__(view) self.add_child(Menu(view).with_languages()) self.add_child(P(view, text=_('This is an English sentence.'))) wsgi_app = fixture.new_wsgi_app(child_factory=PanelWithMenu.factory()) browser = Browser(wsgi_app) browser.open('/') vassert( browser.is_element_present( XPath.paragraph_containing('This is an English sentence.'))) browser.click(XPath.link_with_text('Afrikaans')) vassert( browser.is_element_present( XPath.paragraph_containing('Hierdie is \'n sin in Afrikaans.'))) browser.click(XPath.link_with_text('English (United Kingdom)')) vassert( browser.is_element_present( XPath.paragraph_containing('This is an English sentence.')))
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_basic_ui(web_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') 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' browser.open('/a_ui/other') assert browser.title == 'UserInterface other view'
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 test_remote_field_formatting(web_fixture): """A Form contains a RemoteMethod that can be used to reformat any of its fields via HTTP. """ fixture = web_fixture class ModelObject(object): @exposed def fields(self, fields): fields.a_field = DateField() 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.a_field)) wsgi_app = fixture.new_wsgi_app(child_factory=MyForm.factory('myform')) browser = Browser(wsgi_app) browser.open('/_myform_format_method?myform-a_field=13 November 2012') assert browser.raw_html == '13 Nov 2012' browser.open('/_myform_format_method?myform-a_field=invaliddate') assert browser.raw_html == ''
def test_take_and_release_task(web_fixture, task_queue_fixture, workflow_web_fixture): fixture = workflow_web_fixture browser = Browser(fixture.wsgi_app) task = task_queue_fixture.task take_task_button = XPath.button_labelled('Take') defer_task_button = XPath.button_labelled('Defer') release_task_button = XPath.button_labelled('Release') go_to_task_button = XPath.button_labelled('Go to') web_fixture.log_in(browser=browser) browser.open('/inbox/') browser.click(take_task_button) assert browser.current_url.path == '/inbox/task/%s' % task.id browser.click(defer_task_button) assert browser.current_url.path == '/inbox/' browser.click(go_to_task_button) assert browser.current_url.path == '/inbox/task/%s' % task.id browser.click(release_task_button) assert browser.current_url.path == '/inbox/'
def test_remote_field_validation(web_fixture): """A Form contains a RemoteMethod that can be used to validate any of its fields via HTTP. """ fixture = web_fixture class ModelObject(object): @exposed def fields(self, fields): fields.a_field = 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.a_field)) wsgi_app = fixture.new_wsgi_app(child_factory=MyForm.factory('myform')) browser = Browser(wsgi_app) browser.open( '/_myform_validate_method?myform-a_field=invalid email address') assert browser.raw_html == '"a_field should be a valid email address"' browser.open('/[email protected]') assert browser.raw_html == 'true'
def test_take_and_release_task(web_fixture, task_queue_fixture, workflow_web_fixture): fixture = workflow_web_fixture browser = Browser(fixture.wsgi_app) task = task_queue_fixture.task take_task_button = '//input[@value="Take"]' defer_task_button = '//input[@value="Defer"]' release_task_button = '//input[@value="Release"]' go_to_task_button = '//input[@value="Go to"]' web_fixture.log_in(browser=browser) browser.open('/inbox/') browser.click(take_task_button) assert browser.current_url.path == '/inbox/task/%s' % task.id browser.click(defer_task_button) assert browser.current_url.path == '/inbox/' browser.click(go_to_task_button) assert browser.current_url.path == '/inbox/task/%s' % task.id browser.click(release_task_button) assert browser.current_url.path == '/inbox/'
def test_views_with_parameters(web_fixture, parameterised_scenarios): """Views can have arguments that originate from code, or are parsed from the URL.""" class UIWithParameterisedViews(UserInterface): def assemble(self): self.define_view('/aview', view_class=fixture.ParameterisedView, some_arg=fixture.argument) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page).use_layout(BasicPageLayout()) self.define_user_interface('/a_ui', UIWithParameterisedViews, {'main': 'main'}, name='myui') fixture = parameterised_scenarios wsgi_app = web_fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) if fixture.should_exist: browser.open(fixture.url) assert browser.title == 'View for: %s' % fixture.expected_value assert browser.is_element_present(XPath.paragraph().including_text( 'content for %s' % fixture.expected_value)) else: browser.open(fixture.url, status=404)
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_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 test_basic_working_of_slots(web_fixture): """Slots are special Widgets that can be added to the page. The contents of a Slot are then supplied (differently) by different Views.""" class MyPage(Widget): def __init__(self, view): super(MyPage, self).__init__(view) self.add_child(Slot(view, 'slot1')) self.add_child(Slot(view, 'slot2')) class MainUI(UserInterface): def assemble(self): self.define_page(MyPage) home = self.define_view('/', title='Home') home.set_slot('slot1', P.factory(text='a')) home.set_slot('slot2', P.factory(text='b')) other = self.define_view('/other', title='Other') other.set_slot('slot1', P.factory(text='other')) fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) browser.open('/') [slot1_p, slot2_p] = browser.lxml_html.xpath('//p') assert slot1_p.text == 'a' assert slot2_p.text == 'b' browser.open('/other') [slot1_p] = browser.lxml_html.xpath('//p') assert slot1_p.text == 'other'
def basic_assembly(fixture): """An application is built by extending UserInterface, and defining this UserInterface in an .assemble() method. To define the UserInterface, several Views are defined. Views are mapped to URLs. When a user GETs the URL of a View, a page is rendered back to the user. How that page is created can happen in different ways, as illustrated by each scenario of this test. """ wsgi_app = fixture.new_wsgi_app(site_root=fixture.MainUI) browser = Browser(wsgi_app) # GETting the URL results in the HTML for that View with warnings.catch_warnings(record=True) as caught_warnings: warnings.simplefilter('always') browser.open('/') vassert(browser.title == 'Hello') warning_messages = [six.text_type(i.message) for i in caught_warnings] vassert(len(warning_messages) == len(fixture.expected_warnings)) for caught, expected_message in zip_longest(warning_messages, fixture.expected_warnings): vassert(expected_message in caught) if fixture.content_includes_p: [message] = browser.xpath('//p') vassert(message.text == 'Hello world!') # The headers are set correctly response = browser.last_response vassert(response.content_length == fixture.expected_content_length) vassert(response.content_type == 'text/html') vassert(response.charset == 'utf-8') # Invalid URLs do not exist with warnings.catch_warnings(record=True): browser.open('/nonexistantview/', 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)