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_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 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_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_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 test_adding_checkboxes(web_fixture, form_layout_fixture): """CheckboxInputs are added non-inlined, and by default without labels.""" class DomainObjectWithBoolean: @exposed def fields(self, fields): fields.an_attribute = BooleanField(label='Some input', required=True) fixture = form_layout_fixture fixture.domain_object = DomainObjectWithBoolean() class FormWithInputWithCheckbox(Form): def __init__(self, view): super().__init__(view, 'aform') self.use_layout(FormLayout()) self.layout.add_input( CheckboxInput(self, fixture.domain_object.fields.an_attribute)) browser = Browser( web_fixture.new_wsgi_app( child_factory=FormWithInputWithCheckbox.factory())) browser.open('/') assert not any(child.tag == 'label' for child in fixture.get_form_group_children(browser)) [div] = fixture.get_form_group_children(browser) [checkbox] = div.getchildren() checkbox_classes = checkbox.attrib['class'].split(' ') assert 'custom-control' in checkbox_classes assert 'custom-checkbox' in checkbox_classes
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_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_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, disable_csrf_check=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_remote_methods_via_ajax(web_fixture, remote_method_fixture): """A RemoteMethod can be called via AJAX with CSRF protection built-in.""" fixture = remote_method_fixture def callable_object(): return 'value returned from method' remote_method = RemoteMethod(web_fixture.view, 'amethod', callable_object, MethodResult(), disable_csrf_check=False) wsgi_app = fixture.new_wsgi_app(remote_method=remote_method, enable_js=True) web_fixture.reahl_server.set_app(wsgi_app) browser = web_fixture.driver_browser # Case: using jquery to POST to the method includes the necessary xsrf info automatically browser.open('/') browser.execute_script( '$.post("/_amethod_method", success=function(data){ $("body").attr("data-result", data) })' ) results = browser.execute_script('return $("body").attr("data-result")') assert results == 'value returned from method' # Case: POSTing without a csrf token breaks browser = Browser(wsgi_app) browser.post('/_amethod_method', {}, status=403)
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_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_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().__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_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: @exposed def fields(self, fields): fields.name = Field() class MyPanel(Div): def __init__(self, view): super().__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_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_internal_redirects(web_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 = web_fixture fixture.requests_handled = [] fixture.handling_resources = [] @stubclass(Resource) class ResourceStub: should_commit = True def cleanup_after_transaction(self): pass 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('/') assert browser.raw_html == 'response given after internal redirect' assert fixture.requests_handled[0] is fixture.requests_handled[1] assert fixture.handling_resources[0] is not fixture.handling_resources[1]
def test_missing_variable_in_regex(web_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') fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) with expected(ProgrammerError, test='The arguments contained in URL.*'): browser.open('/a_ui/test1/')
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_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_adding_basic_input(web_fixture, form_layout_fixture): """Adding an input to a FormLayout, adds it in a bootstrap form-group with Some input.""" fixture = form_layout_fixture class FormWithInputAddedUsingDefaults(Form): def __init__(self, view): super().__init__(view, 'aform') self.use_layout(FormLayout()) self.layout.add_input( TextInput(self, fixture.domain_object.fields.an_attribute)) browser = Browser( web_fixture.new_wsgi_app( child_factory=FormWithInputAddedUsingDefaults.factory())) browser.open('/') assert 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 assert label.tag == 'label' assert label.attrib['for'] == input_widget.attrib['id'] assert label.text == 'Some input' # form-group has an input, correctly set up for bootstrap assert input_widget.tag == 'input' assert input_widget.attrib['name'] == 'aform-an_attribute'
def test_addressbook1(web_fixture, addressbook1_scenario): john = addressbook1.Address(name='John', email_address='*****@*****.**') john.save() browser = Browser(addressbook1_scenario.wsgi_app) browser.open('/') assert browser.is_element_present(XPath.paragraph().including_text('John: [email protected]'))
def test_error_page_shown_on_error(web_fixture, error_fixture): """If not in debug mode and an uncaught Exception is raised, the user is redirected to an error page.""" wsgi_app = web_fixture.new_wsgi_app(site_root=error_fixture.MainUI) browser = Browser(wsgi_app) wsgi_app.config.reahlsystem.debug = False browser.open('/a_page') assert browser.current_url.path == '/error'
def test_handling_HTTPError_exceptions(web_fixture): """If an HTTPError exception is raised, it is used as response.""" @stubclass(ReahlWSGIApplication) class ReahlWSGIApplicationStub2(ReahlWSGIApplicationStub): def resource_for(self, request): raise HTTPNotFound() browser = Browser(ReahlWSGIApplicationStub2(web_fixture.config)) browser.open('/', status=404)
def test_non_writable_input_is_dealt_with_like_invalid_input(web_fixture): """If a form submits a value for an Input that is linked to Field with access rights that prohibit writing, the input is silently ignored.""" fixture = web_fixture class ModelObject: field_name = 'Original value' @exposed def events(self, events): events.an_event = Event(label='click me') @exposed def fields(self, fields): fields.field_name = Field(default='abc', writable=Allowed(False), disallowed_message='you are not allowed to write this') model_object = ModelObject() class TestPanel(Div): def __init__(self, view): super().__init__(view) form = self.add_child(Form(view, 'some_form')) form.define_event_handler(model_object.events.an_event) form.add_child(ButtonInput(form, model_object.events.an_event)) form.add_child(TextInput(form, model_object.fields.field_name)) fixture.form = form wsgi_app = web_fixture.new_wsgi_app(child_factory=TestPanel.factory()) browser = Browser(wsgi_app) browser.open('/') csrf_token = browser.get_value('//input[@name="some_form-_reahl_csrf_token"]') browser.post(fixture.form.event_channel.get_url().path, {'event.some_form-an_event?':'', 'some_form-field_name': 'illigitimate value', 'some_form-_reahl_database_concurrency_digest':'', 'some_form-_reahl_csrf_token': csrf_token}) browser.follow_response() assert model_object.field_name == 'Original value'
def test_slots(web_fixture, slot_scenarios): """A View modifies the page by populating named Slots in the page with Widgets.""" fixture = slot_scenarios wsgi_app = web_fixture.new_wsgi_app(site_root=fixture.MainUI) browser = Browser(wsgi_app) browser.open('/') assert browser.title == 'Hello' [main_p, footer_p] = browser.xpath('//p') assert main_p.text == 'Hello world' assert footer_p.text == 'I am the footer'
def test_alternative_event_trigerring(web_fixture): """Events can also be triggered by submitting a Form via Ajax. In such cases the normal redirect-after-submit behaviour of the underlying EventChannel is not desirable. This behaviour can be switched off by submitting an extra argument along with the Form in order to request the alternative behaviour. """ fixture = web_fixture class ModelObject: def handle_event(self): self.handled_event = True @exposed def events(self, events): events.an_event = Event(label='click me', action=Action(self.handle_event)) model_object = ModelObject() class MyForm(Form): def __init__(self, view, name, other_view): super().__init__(view, name) self.define_event_handler(model_object.events.an_event, target=other_view) self.add_child(ButtonInput(self, model_object.events.an_event)) class MainUI(UserInterface): def assemble(self): self.define_page(HTML5Page).use_layout(BasicPageLayout()) home = self.define_view('/', title='Home page') other_view = self.define_view('/page2', title='Page 2') home.set_slot('main', MyForm.factory('myform', other_view)) wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) # when POSTing with _noredirect, the Action is executed, but the browser is not redirected to /page2 as usual browser.open('/') csrf_token = browser.get_value('//input[@name="myform-_reahl_csrf_token"]') browser.post( '/__myform_method', { 'event.myform-an_event?': '', '_noredirect': '', 'myform-_reahl_database_concurrency_digest': '', 'myform-_reahl_csrf_token': csrf_token }) browser.follow_response( ) # Needed to make the test break should a HTTPTemporaryRedirect response be sent assert model_object.handled_event assert browser.current_url.path != '/page2' assert browser.current_url.path == '/__myform_method' # the response is a json object reporting the success of the event and a new rendition of the form json_dict = json.loads(browser.raw_html) assert json_dict['success'] expected_html = '<div id="myform_hashes">' assert json_dict['result']['myform'].startswith(expected_html)
def test_basic_error3(web_fixture): """Forgetting to define either a page of a page for a View is reported to the programmer.""" class MainUI(UserInterface): def assemble(self): self.define_view('/', title='Hello') fixture = web_fixture wsgi_app = fixture.new_wsgi_app(site_root=MainUI) browser = Browser(wsgi_app) with expected(ProgrammerError, test='there is no page defined for /'): browser.open('/')
def test_detour_to_login(web_fixture, party_account_fixture, workflow_web_fixture): fixture = workflow_web_fixture browser = Browser(fixture.wsgi_app) browser.open('/inbox/') assert browser.current_url.path == '/accounts/login' browser.type(XPath.input_labelled('Email'), party_account_fixture.system_account.email) browser.type(XPath.input_labelled('Password'), party_account_fixture.system_account.password) browser.click(XPath.button_labelled('Log in')) assert browser.current_url.path == '/inbox/'