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_library_files(web_fixture, library_fixture): """The files part of configured frontend libraries are (a) added to /static and also (b) included on any page.""" config = web_fixture.config config.web.frontend_libraries.clear() config.web.frontend_libraries.add(library_fixture.MyLibrary()) browser = Browser(ReahlWSGIApplication(config)) browser.open('/static/somefile.js') assert browser.raw_html == 'contents - js' browser.open('/static/somefile.css') assert browser.raw_html == 'contents - css' browser.open('/') script_added = browser.get_html_for('//script[@src]') assert script_added == '<script type="text/javascript" src="/static/somefile.js"></script>' link_added = browser.get_html_for('//link') assert link_added == '<link rel="stylesheet" href="/static/somefile.css" type="text/css">'
def widgets_for_tasks(self, fixture): """The widget to use for displaying a particular type of task can be set via an entry point.""" pkg_resources.working_set.add(easter_egg) line = 'MyTaskWidget = reahl.domainui_dev.bootstrap.test_workflow:MyTaskWidget' easter_egg.add_entry_point_from_line('reahl.workflowui.task_widgets', line) with fixture.persistent_test_classes(MyTask): task = MyTask(queue=fixture.queue, title='a task') browser = Browser(fixture.wsgi_app) fixture.log_in(browser=browser) browser.open('/inbox/task/%s' % task.id) html = browser.get_html_for('//div/p') vassert(html == '<p>my task widget</p>')
def test_form_input_validation(web_fixture): """Validation of input happens in JS on the client, but also on the server if JS is bypassed.""" error_xpath = '//form[contains(@class, "reahl-form")]/label[contains(@class, "error")]' fixture = web_fixture class ModelObject(object): def handle_event(self): pass @exposed def events(self, events): events.an_event = Event(label='click me', action=Action(self.handle_event)) @exposed def fields(self, fields): fields.field_name = EmailField() model_object = ModelObject() class MyForm(Form): def __init__(self, view, name, other_view): super(MyForm, self).__init__(view, name) if self.exception: self.add_child( P(view, ','.join(self.exception.detail_messages))) self.define_event_handler(model_object.events.an_event, target=other_view) self.add_child(ButtonInput(self, model_object.events.an_event)) text_input = self.add_child( TextInput(self, model_object.fields.field_name)) if text_input.validation_error: self.add_child(self.create_error_label(text_input)) 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, enable_js=True) # Case: form validation fails in JS on the client # - Form submission is blocked # - Error message is displayed fixture.reahl_server.set_app(wsgi_app) fixture.driver_browser.open('/') fixture.driver_browser.wait_for_element_not_visible(error_xpath) fixture.driver_browser.type('//input[@type="text"]', 'not@notvalid', trigger_blur=False, wait_for_ajax=False) fixture.driver_browser.press_tab() fixture.driver_browser.wait_for_element_visible(error_xpath) with fixture.driver_browser.no_page_load_expected(): fixture.driver_browser.click("//input[@value='click me']") error_text = fixture.driver_browser.get_text(error_xpath) assert error_text == 'field_name should be a valid email address' # .. but the error is removed again upon valid input fixture.driver_browser.type('//input[@type="text"]', '*****@*****.**') fixture.driver_browser.wait_for_element_not_visible(error_xpath) # Case: form validation fails on the server (assuming no JS on the client to block submission) # - ValidationException is raised (which is dealt with as any DomainException) browser = Browser(wsgi_app) browser.open('/') browser.type('//input[@type="text"]', 'not@notvalid') browser.click('//input[@type="submit"]') assert not hasattr(model_object, 'field_name') label = browser.get_html_for('//label') input_id = browser.get_id_of('//input[@type="text"]') assert label == '<label for="%s" class="error">field_name should be a valid email address</label>' % input_id assert Session.query(UserInput).filter_by(key='myform-field_name').count( ) == 1 # The invalid input was persisted exception = Session.query(PersistedException).one().exception assert isinstance(exception, ValidationException) # Is was persisted assert not exception.commit # Case: form validation passes (no-js) # - no ValidationException # - all input is translated to python and set as values on the model objects # - any saved input on the form is cleared browser.type('//input[@type="text"]', '*****@*****.**') browser.click("//input[@value='click me']") assert model_object.field_name == '*****@*****.**' assert Session.query(UserInput).filter_by( key='myform-field_name').count() == 0 # The invalid input was removed assert Session.query( PersistedException).count() == 0 # The exception was removed assert browser.current_url.path == '/page2' # Case: form validation passes (js) # - no ValidationException # - all input is translated to python and set as values on the model objects fixture.driver_browser.open('/') fixture.driver_browser.type('//input[@type="text"]', '*****@*****.**') fixture.driver_browser.wait_for_element_not_visible(error_xpath) fixture.driver_browser.click("//input[@value='click me']") assert model_object.field_name == '*****@*****.**' assert fixture.driver_browser.current_url.path == '/page2'
def test_form_preserves_user_input_after_validation_exceptions_multichoice( web_fixture): """When a form is submitted and validation fails on the server, the user is presented with the values that were originally entered (even if they were invalid).""" fixture = web_fixture class ModelObject(object): @exposed def events(self, events): events.an_event = Event(label='click me') @exposed def fields(self, fields): choices = [ Choice(1, IntegerField(label='One')), Choice(2, IntegerField(label='Two')), Choice(3, IntegerField(label='Three')) ] fields.no_validation_exception_field = MultiChoiceField( choices, label='Make your invalid choice', default=[]) fields.validation_exception_field = MultiChoiceField( choices, label='Make your choice', default=[], required=True) model_object = ModelObject() class MyForm(Form): def __init__(self, view): super(MyForm, self).__init__(view, 'my_form') self.define_event_handler(model_object.events.an_event) self.add_child(ButtonInput(self, model_object.events.an_event)) input = self.add_child( SelectInput(self, model_object.fields.no_validation_exception_field)) if input.validation_error: self.add_child(self.create_error_label(input)) input = self.add_child( SelectInput(self, model_object.fields.validation_exception_field)) if input.validation_error: self.add_child(self.create_error_label(input)) wsgi_app = web_fixture.new_wsgi_app(child_factory=MyForm.factory()) browser = Browser(wsgi_app) browser.open('/') no_validation_exception_input = '//select[@name="my_form-no_validation_exception_field[]"]' validation_exception_input = '//select[@name="my_form-validation_exception_field[]"]' browser.select_many(no_validation_exception_input, ['One', 'Two']) browser.select_none(validation_exception_input ) # select none to trigger the RequiredConstraint browser.click(XPath.button_labelled('click me')) assert browser.get_value(no_validation_exception_input) == ['1', '2'] assert not browser.get_value(validation_exception_input) label = browser.get_html_for('//label') input_id = browser.get_id_of(validation_exception_input) assert label == '<label for="%s" class="error">Make your choice is required</label>' % input_id #2. Submit again ths time not expecting validation exceptions, also expecting the validation error to be cleared and the domain should have all input browser.select_many(validation_exception_input, ['Two', 'Three']) browser.click(XPath.button_labelled('click me')) assert not browser.is_element_present('//label[@class="error"]') assert browser.get_value(no_validation_exception_input) == ['1', '2'] assert browser.get_value(validation_exception_input) == ['2', '3']