def test_render_display(self): # Render in display mode form = factory( 'form', name='myform', props={ 'action': 'myaction' }) form['image'] = factory( 'image', value={ 'file': StringIO(self.dummy_png), 'mimetype': 'image/png' }, props={ 'src': 'http://www.example.com/someimage.png', 'alt': 'Alternative text' }, mode='display') self.check_output(""" <form action="myaction" enctype="multipart/form-data" id="form-myform" method="post" novalidate="novalidate"> <img alt="Alternative text" src="http://www.example.com/someimage.png"/> </form> """, fxml(form())) # Rendering is skipped if no source form['image'].attrs['src'] = None self.check_output(""" <form action="myaction" enctype="multipart/form-data" id="form-myform" method="post" novalidate="novalidate"/> """, fxml(form()))
def test_fieldset_blueprint(self): compound = factory('fieldset', 'COMPOUND', props={'legend': 'Some Test'}) compound['inner'] = factory('text', 'inner', 'value') compound['inner2'] = factory('text', 'inner2', 'value2') self.check_output( """ <fieldset id="fieldset-COMPOUND"> <legend>Some Test</legend> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="value"/> <input class="text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" type="text" value="value2"/> </fieldset> """, fxml(compound())) # Structural fieldset renders without id attribute compound = factory('fieldset', 'COMPOUND', props={'structural': True}) self.assertEqual(compound(), '<fieldset></fieldset>') # Fieldset display renderers are the same as fieldset edit renderers compound = factory('fieldset', 'COMPOUND', props={'legend': 'Some Test'}, mode='display') self.check_output( """ <fieldset id="fieldset-COMPOUND"> <legend>Some Test</legend> </fieldset> """, fxml(compound()))
def test_div_blueprint_as_leaf(self): # Div blueprint as leaf input = factory( 'div:text', name='DIV', value='1') self.check_output(""" <div> <input class="text" id="input-DIV" name="DIV" type="text" value="1"/> </div> """, fxml(input())) data = input.extract({ 'DIV': '2', }) self.assertEqual(data.name, 'DIV') self.assertEqual(data.value, '1') self.assertEqual(data.extracted, '2') self.assertEqual(data.errors, []) # Empty div input = factory( 'div', name='DIV') self.assertEqual(input(), '<div></div>') # Div with data attributes input = factory( 'div', name='DIV', props={ 'data': { 'foo': 'bar' } }) self.assertEqual(input(), "<div data-foo='bar'></div>") # Display mode div = factory( 'div', name='DIV', props={ 'class': 'foo' }, mode='display') self.assertEqual(div(), '<div class="foo"></div>') input = factory( 'div:text', name='DIV', value='1', mode='display') self.check_output(""" <div> <div class="display-text" id="display-DIV">1</div> </div> """, fxml(input()))
def test_render_with_preset_value_src_property_callable(self): # Src property can be callable form = factory( 'form', name='myform', props={ 'action': 'myaction' }) form['image'] = factory( 'image', value={ 'file': StringIO(self.dummy_png), 'mimetype': 'image/png' }, props={ 'src': lambda w, d: 'http://www.example.com/otherimage.png', 'alt': 'Alternative text' }) self.check_output(""" <form action="myaction" enctype="multipart/form-data" id="form-myform" method="post" novalidate="novalidate"> <img alt="Alternative text" class="image-preview" id="image-preview-myform-image" src="http://www.example.com/otherimage.png?nocache=..."/> <input accept="image/*" class="image" id="input-myform-image" name="myform.image" type="file"/> ... </form> """, fxml(form()))
def test_render_with_preset_value_src_property(self): # If file URL of existing image is known, ``src`` property can be set # do display image above controls form = factory( 'form', name='myform', props={ 'action': 'myaction' }) form['image'] = factory( 'image', value={ 'file': StringIO(self.dummy_png), 'mimetype': 'image/png' }, props={ 'src': 'http://www.example.com/someimage.png', 'alt': 'Alternative text' }) self.check_output(""" <form action="myaction" enctype="multipart/form-data" id="form-myform" method="post" novalidate="novalidate"> <img alt="Alternative text" class="image-preview" id="image-preview-myform-image" src="http://www.example.com/someimage.png?nocache=..."/> <input accept="image/*" class="image" id="input-myform-image" name="myform.image" type="file"/> ... </form> """, fxml(form()))
def test_plain_widget_source_is_tree(self): # Render plain widget, source is tree widget = factory( 'dynatree', name='root', props={ 'source': self.mock_tree }) self.check_output(""" <div class="yafowil-widget-dynatree"> <input id="input-root" name="root" type="hidden"/> <ul class="hiddenStructure" id="dynatree-source-root"> <li id="animal">Animals<ul> <li id="mammal">Mammals<ul> <li id="horse">Horse </li><li id="ape">Ape </li><li id="elephant">Elephant </li></ul> </li><li id="bird">Birds<ul> <li id="turkey">Turkey </li><li id="swan">Swan </li><li id="hummingbird">Hummingbird </li><li id="duck">Duck </li></ul> </li></ul> </li></ul> <div class="dynatree-params hiddenStructure">selectMode,1|minExpandLevel,1|rootVisible,False|autoCollapse,False|checkbox,True|imagePath,skin-bootstrap|type,local|initId,dynatree-source-root</div> <div class="yafowil-widget-dynatree-tree"/> </div> """, fxml(widget()))
def test_extraction(self): widget = factory('ace', 'acefield', props={'required': True}) request = {'acefield': ''} data = widget.extract(request) self.assertEqual(data.name, 'acefield') self.assertEqual(data.value, UNSET) self.assertEqual(data.extracted, '') self.assertEqual(data.errors, [ ExtractionError('Mandatory field was empty') ]) request = {'acefield': 'class Foo(object): pass'} data = widget.extract(request) self.assertEqual(data.name, 'acefield') self.assertEqual(data.value, UNSET) self.assertEqual(data.extracted, 'class Foo(object): pass') self.assertEqual(data.errors, []) self.check_output(""" <div class="ace-editor-wrapper ace-option-theme-github ace-option-mode-python"> <textarea class="ace-editor-value" id="ace-acefield-value" name="acefield" style="display:none;">class Foo(object): pass</textarea> <div class="ace-editor" id="ace-acefield">class Foo(object): pass</div> </div> """, fxml(widget(data)))
def test_compound_blueprint_extraction(self): compound = factory('compound', name='COMPOUND') compound['inner'] = factory('text', value='value1') compound['inner2'] = factory('error:text', value='value2', props={'required': True}) # Extract Compound with empty request data = compound.extract({}) self.assertEqual(data.name, 'COMPOUND') self.assertEqual(data.value, UNSET) expected = odict() expected['inner'] = UNSET expected['inner2'] = UNSET self.assertEqual(data.extracted, expected) self.assertEqual(data.errors, []) inner_data = data['inner'] self.assertEqual(inner_data.name, 'inner') self.assertEqual(inner_data.value, 'value1') self.assertEqual(inner_data.extracted, UNSET) self.assertEqual(inner_data.errors, []) # Extract with a value in request request = { 'COMPOUND.inner': 'newvalue', 'COMPOUND.inner2': '', } data = compound.extract(request) data_inner = data['inner'] self.assertEqual(data_inner.name, 'inner') self.assertEqual(data_inner.value, 'value1') self.assertEqual(data_inner.extracted, 'newvalue') self.assertEqual(data_inner.errors, []) data_inner2 = data['inner2'] self.assertEqual(data_inner2.name, 'inner2') self.assertEqual(data_inner2.value, 'value2') self.assertEqual(data_inner2.extracted, '') self.assertEqual(data_inner2.errors, [ExtractionError('Mandatory field was empty')]) expected = odict() expected['inner'] = 'newvalue' expected['inner2'] = '' self.assertEqual(data.extracted, expected) self.check_output( """ <div> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="newvalue"/> <div class="error"> <div class="errormessage">Mandatory field was empty</div> <input class="required text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" required="required" type="text" value=""/> </div> </div> """, fxml('<div>' + compound(data=data) + '</div>'))
def test_render_table(self): form = factory( 'form', name='myform', props={ 'action': 'myaction', }) form['table'] = factory('table') form['table']['row1'] = factory('tr') form['table']['row1']['field1'] = factory( 'td:text', name='field1') self.check_output(""" <form action="myaction" enctype="multipart/form-data" id="form-myform" method="post" novalidate="novalidate"> <table> <tr> <td> <input class="text" id="input-myform-table-row1-field1" name="myform.table.row1.field1" type="text" value=""/> </td> </tr> </table> </form> """, fxml(form()))
def test_nested_form_structural_compound(self): # Create nested form, case structural compound main_path = os.path.join(self.tempdir, 'main.yaml') with open(main_path, 'w') as file: file.write(self.yaml_main_tmpl) nested_raw = """ factory: compound props: structural: True widgets: - subfieldname: factory: text value: subfieldvalue """ nested_path = os.path.join(self.tempdir, 'sub.yaml') with open(nested_path, 'w') as file: file.write(nested_raw) context = DummyContext() form = YAMLParser(main_path, context=context)() self.check_output(""" <form action="mainformaction" enctype="multipart/form-data" id="form-mainform" method="post" novalidate="novalidate"> <input class="text" id="input-mainform-subfieldname" name="mainform.subfieldname" type="text" value="subfieldvalue"/> </form> """, fxml(form()))
def test_yaml_form_flat(self): raw = """ factory: form name: demoform props: action: demoaction widgets: - firstfield: factory: text value: context.some_attr """ template_path = os.path.join(self.tempdir, 'tmpl.yaml') with open(template_path, 'w') as file: file.write(raw) context = DummyContext() form = YAMLParser(template_path, context=context)() self.check_output( """ <form action="demoaction" enctype="multipart/form-data" id="form-demoform" method="post" novalidate="novalidate"> <input class="text" id="input-demoform-firstfield" name="demoform.firstfield" type="text" value="context.some_attr"/> </form> """, fxml(form()))
def test_nested_form_structural_compound(self): # Create nested form, case structural compound main_path = os.path.join(self.tempdir, 'main.yaml') with open(main_path, 'w') as file: file.write(self.yaml_main_tmpl) nested_raw = """ factory: compound props: structural: True widgets: - subfieldname: factory: text value: subfieldvalue """ nested_path = os.path.join(self.tempdir, 'sub.yaml') with open(nested_path, 'w') as file: file.write(nested_raw) context = DummyContext() form = YAMLParser(main_path, context=context)() self.check_output( """ <form action="mainformaction" enctype="multipart/form-data" id="form-mainform" method="post" novalidate="novalidate"> <input class="text" id="input-mainform-subfieldname" name="mainform.subfieldname" type="text" value="subfieldvalue"/> </form> """, fxml(form()))
def test_edit_renderer(self): # Render map widget with defaults widget = factory( 'recaptcha', name='recaptcha', props={ 'public_key': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'private_key': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'lang': 'de', 'theme': 'clean', }) self.check_output(""" <div> <div class="recaptcha" data-lang="de" data-public_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" data-theme="clean" id="recaptcha-recaptcha"> </div> <noscript> <iframe src="http://www.google.com/recaptcha/api/noscript?k=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" height="300" width="500" frameborder="0"> </iframe> <br/> <textarea name="recaptcha_challenge_field" rows="3" cols="40"/> <input type="hidden" name="recaptcha_response_field" value="manual_challenge"/> </noscript> </div> """, fxml('<div>\n' + widget() + '</div>'))
def test_compound_blueprint_value_via_compound(self): # Render Compound with values set via compound widget value = { 'inner': 'Value 1 from parent', 'inner2': 'Value 2 from parent', } compound = factory( 'compound', name='COMPOUND', value=value) compound['inner'] = factory('text') compound['inner2'] = factory( 'text', props={ 'required': True }) self.check_output(""" <div> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="Value 1 from parent"/> <input class="required text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" required="required" type="text" value="Value 2 from parent"/> </div> """, fxml(tag('div', compound())))
def test_skip_labels(self): widget = factory('dict', name='mydict') rendered = fxml('<div>{}</div>'.format(widget())) # search for empty th index = rendered.find('<th> </th>') self.assertTrue(index > -1) # search for second empty th self.assertTrue(rendered.find('<th> </th>', index + 1) > index)
def test_edit_renderer(self): # Render widget widget = factory('cron', name='cronwidget') self.check_output( """ <div class="crontab widget" id="input-cronwidget"> <div class="cron-value minute"> <input class="hidden" id="input-cronwidget-minute" name="cronwidget.minute" type="hidden" value=""/> <button class="btn btn-sm edit">Minute</button> </div> <div class="cron-value hour"> <input class="hidden" id="input-cronwidget-hour" name="cronwidget.hour" type="hidden" value=""/> <button class="btn btn-sm edit">Hour</button> </div> <div class="cron-value dom"> <input class="hidden" id="input-cronwidget-dom" name="cronwidget.dom" type="hidden" value=""/> <button class="btn btn-sm edit">Day of Month</button> </div> <div class="cron-value month"> <input class="hidden" id="input-cronwidget-month" name="cronwidget.month" type="hidden" value=""/> <button class="btn btn-sm edit">Month</button> </div> <div class="cron-value dow"> <input class="hidden" id="input-cronwidget-dow" name="cronwidget.dow" type="hidden" value=""/> <button class="btn btn-sm edit">Day of Week</button> </div> <div class="cron-value year"> <input class="hidden" id="input-cronwidget-year" name="cronwidget.year" type="hidden" value=""/> <button class="btn btn-sm edit">Year</button> </div> <div class="editarea"/> </div> """, fxml(widget())) # Render with JS config properties widget = factory('cron', name='cronwidget', props={ 'lang': 'de', 'start_year': 2010, 'end_year': 2020 }) self.check_output( """ <div class="crontab widget" data-end_year='2020' data-lang='de' data-start_year='2010' id="input-cronwidget">...</div> """, widget())
def test_compound_blueprint_structural_children(self): # Compound with structural compound as child value = { 'inner': 'Value 1 from parent', 'inner2': 'Value 2 from parent', } compound = factory('compound', name='COMPOUND', value=value) structural = compound['STRUCTURAL'] = factory( 'compound', props={'structural': True}) structural['inner'] = factory('text') structural['inner2'] = factory('text', props={'required': True}) self.check_output( """ <div> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="Value 1 from parent"/> <input class="required text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" required="required" type="text" value="Value 2 from parent"/> </div> """, fxml(tag('div', compound()))) self.assertEqual(compound.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: COMPOUND", " <class 'yafowil.base.Widget'>: STRUCTURAL", " <class 'yafowil.base.Widget'>: inner", " <class 'yafowil.base.Widget'>: inner2", "" ]) data = compound.extract({ 'COMPOUND.inner': 'newvalue', 'COMPOUND.inner2': '', }) self.assertEqual(data.name, 'COMPOUND') self.assertEqual(data.value, { 'inner2': 'Value 2 from parent', 'inner': 'Value 1 from parent' }) expected = odict() expected['inner'] = 'newvalue' expected['inner2'] = '' self.assertEqual(data.extracted, expected) data_inner = data['inner'] self.assertEqual(data_inner.name, 'inner') self.assertEqual(data_inner.value, 'Value 1 from parent') self.assertEqual(data_inner.extracted, 'newvalue') self.assertEqual(data_inner.errors, []) data_inner2 = data['inner2'] self.assertEqual(data_inner2.name, 'inner2') self.assertEqual(data_inner2.value, 'Value 2 from parent') self.assertEqual(data_inner2.extracted, '') self.assertEqual(data_inner2.errors, [ExtractionError('Mandatory field was empty')])
def test_static_dict(self): widget = factory( 'error:dict', name='mydict', value=odict([('k1', 'v1')]), props={ 'static': True, 'key_label': 'Key', 'value_label': 'Value' }) rendered = widget() self.assertEqual(widget.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: mydict", " <class 'yafowil.base.Widget'>: exists", " <class 'yafowil.base.Widget'>: table", " <class 'yafowil.base.Widget'>: head", " <class 'yafowil.base.Widget'>: row", " <class 'yafowil.base.Widget'>: key", " <class 'yafowil.base.Widget'>: value", " <class 'yafowil.base.Widget'>: body", " <class 'yafowil.base.Widget'>: entry0", " <class 'yafowil.base.Widget'>: key", " <class 'yafowil.base.Widget'>: value", "" ]) self.check_output(""" <div> <input class="hidden" id="input-mydict-exists" name="mydict.exists" type="hidden" value="1"/> <table class="dictwidget key-keyfield value-valuefield" id="dictwidget_mydict.entry"> <thead> <tr> <th>Key</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td class="key"> <input class="keyfield" disabled="disabled" id="input-mydict-entry0-key" name="mydict.entry0.key" type="text" value="k1"/> </td> <td class="value"> <input class="valuefield" id="input-mydict-entry0-value" name="mydict.entry0.value" type="text" value="v1"/> </td> </tr> </tbody> </table> </div> """, fxml('<div>{}</div>'.format(rendered)))
def test_edit_renderer(self): widget = factory('ace', 'acefield', props={'required': True}) self.check_output(""" <div class="ace-editor-wrapper ace-option-theme-github ace-option-mode-python"> <textarea class="ace-editor-value" id="ace-acefield-value" name="acefield" style="display:none;"/> <div class="ace-editor" id="ace-acefield"/> </div> """, fxml(widget()))
def test_display_renderer_no_labels(self): widget = factory( 'dict', name='display_dict', mode='display' ) self.check_output(""" <div> <dl/> </div> """, fxml('<div>{}</div>'.format(widget())))
def app(environ, start_response): url = 'http://%s/' % environ['HTTP_HOST'] if environ['PATH_INFO'] == '/ywd.js': return javascript_response(environ, start_response) elif environ['PATH_INFO'] == '/ywd.json': return json_response(environ, start_response) elif environ['PATH_INFO'] == '/jquery.dynatree.js': return javascript_response2(environ, start_response) elif environ['PATH_INFO'].startswith('/skin/'): return skin_response(environ, start_response) elif environ['PATH_INFO'] != '/': response = Response(status=404) return response(environ, start_response) form = factory(u'form', name='yqaexample', props={ 'action': url}) form['local'] = factory('field:label:error:dynatree', props={ 'label': 'Select single value', 'value': '', 'source': sample_tree}) form['remote'] = factory('field:label:error:dynatree', props={ 'label': 'Select multiple', 'value': '', 'source': '%sywd.json' % url, 'selectMode': 2}) form['submit'] = factory('field:submit', props={ 'label': 'submit', 'action': 'save', 'handler': lambda widget, data: None, 'next': lambda request: url}) controller = Controller(form, Request(environ)) tag = controller.data.tag jq = tag('script', ' ', src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js', type='text/javascript') jqui = tag('script', ' ', src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.js', type='text/javascript') jqdy = tag('script', ' ', src='%sjquery.dynatree.js' % url, type='text/javascript') ywd = tag('script', ' ', src='%sywd.js' % url, type='text/javascript') css = tag("style", "@import url(%sskin/ui.dynatree.css)" % url, type='text/css') css += tag('style', '.hiddenStructure { display: none; }', type='text/css') head = tag('head', jq, jqui, jqdy, ywd, css) h1 = tag('h1', 'YAFOWIL Widget Dynatree Example') body = tag('body', h1, controller.rendered) response = Response(body=fxml(tag('html', head, body))) return response(environ, start_response)
def test_display_renderer(self): widget = factory('cron', name='cronwidget', value='* * * * *', mode='display') self.check_output( """ <div class="display-crontab widget" id="display-cronwidget"> <code>* * * * *</code> </div> """, fxml(widget()))
def test_div_blueprint_as_leaf(self): # Div blueprint as leaf input = factory('div:text', name='DIV', value='1') self.check_output( """ <div> <input class="text" id="input-DIV" name="DIV" type="text" value="1"/> </div> """, fxml(input())) data = input.extract({ 'DIV': '2', }) self.assertEqual(data.name, 'DIV') self.assertEqual(data.value, '1') self.assertEqual(data.extracted, '2') self.assertEqual(data.errors, []) # Empty div input = factory('div', name='DIV') self.assertEqual(input(), '<div></div>') # Div with data attributes input = factory('div', name='DIV', props={'data': {'foo': 'bar'}}) self.assertEqual(input(), "<div data-foo='bar'></div>") # Display mode div = factory('div', name='DIV', props={'class': 'foo'}, mode='display') self.assertEqual(div(), '<div class="foo"></div>') input = factory('div:text', name='DIV', value='1', mode='display') self.check_output( """ <div> <div class="display-text" id="display-DIV">1</div> </div> """, fxml(input()))
def test_fieldset_blueprint(self): compound = factory( 'fieldset', 'COMPOUND', props={ 'legend': 'Some Test' }) compound['inner'] = factory('text', 'inner', 'value') compound['inner2'] = factory('text', 'inner2', 'value2') self.check_output(""" <fieldset id="fieldset-COMPOUND"> <legend>Some Test</legend> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="value"/> <input class="text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" type="text" value="value2"/> </fieldset> """, fxml(compound())) # Structural fieldset renders without id attribute compound = factory( 'fieldset', 'COMPOUND', props={ 'structural': True }) self.assertEqual(compound(), '<fieldset></fieldset>') # Fieldset display renderers are the same as fieldset edit renderers compound = factory( 'fieldset', 'COMPOUND', props={ 'legend': 'Some Test' }, mode='display') self.check_output(""" <fieldset id="fieldset-COMPOUND"> <legend>Some Test</legend> </fieldset> """, fxml(compound()))
def test_key_label_and_value_label_bc_callables(self): # test B/C callable signature widget = factory( 'dict', name='mydict', props={ 'key_label': lambda: 'B/C Computed Key', 'value_label': lambda: 'B/C Computed Value' }) rendered = fxml('<div>{}</div>'.format(widget())) self.assertTrue(rendered.find('B/C Computed Key') > -1) self.assertTrue(rendered.find('B/C Computed Value') > -1)
def test_key_label_and_value_label_callables(self): # ``key_label`` and ``value_label`` may be callables widget = factory( 'dict', name='mydict', props={ 'key_label': lambda w, d: 'Computed Key', 'value_label': lambda w, d: 'Computed Value' }) rendered = fxml('<div>{}</div>'.format(widget())) self.assertTrue(rendered.find('Computed Key') > -1) self.assertTrue(rendered.find('Computed Value') > -1)
def test_render_no_range(self): # Render no range widget = factory( 'slider', name='sliderfield') self.check_output(""" <div class="yafowil_slider"> <input class="slider_value" id="input-sliderfield" name="sliderfield" style="display:none;" type="text" value=""/> <div class="slider"> </div> </div> """, fxml(widget()))
def test_bc_head_property_bc_callables(self): widget = factory( 'dict', name='mydict', props={ 'head': { 'key': lambda: 'B/C Computed B/C Key', 'value': lambda: 'B/C Computed B/C Value', } }) rendered = fxml('<div>{}</div>'.format(widget())) self.assertTrue(rendered.find('B/C Computed B/C Key') > -1) self.assertTrue(rendered.find('B/C Computed B/C Value') > -1)
def test_bc_head_property(self): # Test B/C ``head`` property widget = factory( 'dict', name='mydict', props={ 'head': { 'key': 'B/C Key', 'value': 'B/C Value', } }) rendered = fxml('<div>{}</div>'.format(widget())) self.assertTrue(rendered.find('B/C Key') > -1) self.assertTrue(rendered.find('B/C Value') > -1)
def test_display_empty_value(self): widget = factory( 'dict', name='display_dict', props={ 'key_label': 'Key', 'value_label': 'Value' }, mode='display') self.check_output(""" <div> <h5>Key: Value</h5> <dl/> </div> """, fxml('<div>{}</div>'.format(widget())))
def test_display_bc_callable_labels(self): widget = factory( 'dict', name='display_dict', props={ 'key_label': lambda: 'B/C Computed Key', 'value_label': lambda: 'B/C Computed Value' }, mode='display') self.check_output(""" <div> <h5>B/C Computed Key: B/C Computed Value</h5> <dl/> </div> """, fxml('<div>{}</div>'.format(widget())))
def test_render_empty(self): form = factory( 'form', name='myform', props={ 'action': 'myaction' }) form['image'] = factory('image') self.check_output(""" <form action="myaction" enctype="multipart/form-data" id="form-myform" method="post" novalidate="novalidate"> <input accept="image/*" class="image" id="input-myform-image" name="myform.image" type="file"/> </form> """, fxml(form()))
def test_plain_widget_source_is_string(self): # Render plain widget, source is string widget = factory( 'dynatree', name='root', props={ 'source': 'http://www.foo.bar/baz.json' }) self.check_output(""" <div class="yafowil-widget-dynatree"> <input id="input-root" name="root" type="hidden"/> <div class="dynatree-source hiddenStructure">http://www.foo.bar/baz.json</div> <div class="dynatree-params hiddenStructure">selectMode,1|minExpandLevel,1|rootVisible,False|autoCollapse,False|checkbox,True|imagePath,skin-bootstrap|type,remote</div> <div class="yafowil-widget-dynatree-tree"/> </div> """, fxml(widget()))
def test_div_blueprint_compound(self): # Div blueprint as compound div = factory( 'div', name='DIV_COMPOUND') div['inner'] = factory( 'text', value='value1') div['inner2'] = factory( 'text', value='value2', props={ 'required': True }) self.check_output(""" <div> <input class="text" id="input-DIV_COMPOUND-inner" name="DIV_COMPOUND.inner" type="text" value="value1"/> <input class="required text" id="input-DIV_COMPOUND-inner2" name="DIV_COMPOUND.inner2" required="required" type="text" value="value2"/> </div> """, fxml(div())) data = div.extract({ 'DIV_COMPOUND.inner': '1', 'DIV_COMPOUND.inner2': '2', }) self.assertEqual(data.name, 'DIV_COMPOUND') self.assertEqual(data.value, UNSET) expected = odict() expected['inner'] = '1' expected['inner2'] = '2' self.assertEqual(data.extracted, expected) self.assertEqual(data.errors, []) data_inner = data['inner'] self.assertEqual(data_inner.name, 'inner') self.assertEqual(data_inner.value, 'value1') self.assertEqual(data_inner.extracted, '1') self.assertEqual(data_inner.errors, []) data_inner2 = data['inner2'] self.assertEqual(data_inner2.name, 'inner2') self.assertEqual(data_inner2.value, 'value2') self.assertEqual(data_inner2.extracted, '2') self.assertEqual(data_inner2.errors, [])
def test_compound_blueprint_value_via_members(self): # Render Compound with values set via compound members compound = factory('compound', name='COMPOUND') compound['inner'] = factory('text', value='value1') compound['inner2'] = factory('error:text', value='value2', props={'required': True}) self.check_output( """ <div> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="value1"/> <input class="required text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" required="required" type="text" value="value2"/> </div> """, fxml(tag('div', compound())))
def test_display_computed_bc_labels(self): widget = factory( 'dict', name='display_dict', props={ 'head': { 'key': lambda w, d: 'Computed B/C Key', 'value': lambda w, d: 'Computed B/C Value', } }, mode='display') self.check_output(""" <div> <h5>Computed B/C Key: Computed B/C Value</h5> <dl/> </div> """, fxml('<div>{}</div>'.format(widget())))
def test_datetime_with_preset_value(self): # Test widget with given datetime value widget = factory( 'datetime', name='dt', value=datetime.datetime(2011, 5, 1), props={ 'time': True, }) self.check_output(""" <div> <input class="dateinput datetime" id="input-dt" name="dt" size="10" type="text" value="2011.5.1"/> <input class="timeinput" id="input-dt-time" name="dt.time" size="5" type="text" value="00:00"/> </div> """, fxml('<div>{}</div>'.format(widget())))
def test_empty_dict(self): # Create empty Dict widget widget = factory( 'dict', name='mydict', props={ 'key_label': 'Key', 'value_label': 'Value', }) result = widget() self.assertEqual(widget.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: mydict", " <class 'yafowil.base.Widget'>: exists", " <class 'yafowil.base.Widget'>: table", " <class 'yafowil.base.Widget'>: head", " <class 'yafowil.base.Widget'>: row", " <class 'yafowil.base.Widget'>: key", " <class 'yafowil.base.Widget'>: value", " <class 'yafowil.base.Widget'>: actions", " <class 'yafowil.base.Widget'>: body", "" ]) self.check_output(""" <div> <input class="hidden" id="input-mydict-exists" name="mydict.exists" type="hidden" value="1"/> <table class="dictwidget key-keyfield value-valuefield" id="dictwidget_mydict.entry"> <thead> <tr> <th>Key</th> <th>Value</th> <th class="actions"> <div class="dict_actions"> <a class="dict_row_add" href="#"> <span class="icon-plus-sign"> </span> </a> </div> </th> </tr> </thead> <tbody/> </table> </div> """, fxml('<div>' + result + '</div>'))
def test_compound_blueprint_value_via_compound(self): # Render Compound with values set via compound widget value = { 'inner': 'Value 1 from parent', 'inner2': 'Value 2 from parent', } compound = factory('compound', name='COMPOUND', value=value) compound['inner'] = factory('text') compound['inner2'] = factory('text', props={'required': True}) self.check_output( """ <div> <input class="text" id="input-COMPOUND-inner" name="COMPOUND.inner" type="text" value="Value 1 from parent"/> <input class="required text" id="input-COMPOUND-inner2" name="COMPOUND.inner2" required="required" type="text" value="Value 2 from parent"/> </div> """, fxml(tag('div', compound())))
def test_render_no_range_display_value(self): # Render no range, display value widget = factory( 'slider', name='sliderfield', value=20, props={ 'show_value': True, 'unit': 'Unit' }) self.check_output(""" <div class="yafowil_slider"> <input class="slider_value" id="input-sliderfield" name="sliderfield" style="display:none;" type="text" value="20"/> <span class="unit">Unit: </span> <span class="slider_value">20</span> <div class="slider"> </div> </div> """, fxml(widget()))
def test_parse_from_yaml(self): template_path = os.path.join(self.tempdir, 'tmpl.yaml') with open(template_path, 'w') as file: file.write(self.yaml_tmpl) context = DummyContext() _ = lambda x, default=None: default and default or x form = parse_from_YAML(template_path, context, _) self.assertEqual(form.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: demoform", " <class 'yafowil.base.Widget'>: firstfield", " <class 'yafowil.base.Widget'>: secondfield", "" ]) self.assertEqual(sorted(form.attrs.items()), [('action', 'demoaction')]) self.check_output( """ <form action="demoaction" enctype="multipart/form-data" id="form-demoform" method="post" novalidate="novalidate"> <div class="field" id="field-demoform-firstfield"> <label for="input-demoform-firstfield">First Field</label> <input class="required text" id="input-demoform-firstfield" name="demoform.firstfield" required="required" type="text" value="First value"/> </div> <div class="field" id="field-demoform-secondfield"> <label for="input-demoform-secondfield" title="Second Field">secondfield</label> <input id="exists-demoform-secondfield" name="demoform.secondfield-exists" type="hidden" value="exists"/> <select class="select" id="input-demoform-secondfield" multiple="multiple" name="demoform.secondfield"> <option id="input-demoform-secondfield-a" selected="selected" value="a">a</option> <option id="input-demoform-secondfield-b" selected="selected" value="b">b</option> <option id="input-demoform-secondfield-c" value="c">c</option> </select> </div> </form> """, fxml(form()))
def test_yaml_form_compounds(self): raw = """ factory: form name: demoform props: action: demoaction widgets: - sometable: factory: table props: structural: True widgets: - row_1: factory: tr props: structural: True widgets: - somefield: factory: td:field:text """ template_path = os.path.join(self.tempdir, 'tmpl.yaml') with open(template_path, 'w') as file: file.write(raw) context = DummyContext() form = YAMLParser(template_path, context=context)() self.check_output( """ <form action="demoaction" enctype="multipart/form-data" id="form-demoform" method="post" novalidate="novalidate"> <table> <tr> <td> <div class="field" id="field-demoform-somefield"> <input class="text" id="input-demoform-somefield" name="demoform.somefield" type="text" value=""/> </div> </td> </tr> </table> </form> """, fxml(form()))
def test_div_blueprint_compound(self): # Div blueprint as compound div = factory('div', name='DIV_COMPOUND') div['inner'] = factory('text', value='value1') div['inner2'] = factory('text', value='value2', props={'required': True}) self.check_output( """ <div> <input class="text" id="input-DIV_COMPOUND-inner" name="DIV_COMPOUND.inner" type="text" value="value1"/> <input class="required text" id="input-DIV_COMPOUND-inner2" name="DIV_COMPOUND.inner2" required="required" type="text" value="value2"/> </div> """, fxml(div())) data = div.extract({ 'DIV_COMPOUND.inner': '1', 'DIV_COMPOUND.inner2': '2', }) self.assertEqual(data.name, 'DIV_COMPOUND') self.assertEqual(data.value, UNSET) expected = odict() expected['inner'] = '1' expected['inner2'] = '2' self.assertEqual(data.extracted, expected) self.assertEqual(data.errors, []) data_inner = data['inner'] self.assertEqual(data_inner.name, 'inner') self.assertEqual(data_inner.value, 'value1') self.assertEqual(data_inner.extracted, '1') self.assertEqual(data_inner.errors, []) data_inner2 = data['inner2'] self.assertEqual(data_inner2.name, 'inner2') self.assertEqual(data_inner2.value, 'value2') self.assertEqual(data_inner2.extracted, '2') self.assertEqual(data_inner2.errors, [])
def test_nested_form_single_field(self): # Create nested form, case single field main_path = os.path.join(self.tempdir, 'main.yaml') with open(main_path, 'w') as file: file.write(self.yaml_main_tmpl) nested_raw = """ factory: text value: context.some_attr props: class_add: nested_input """ nested_path = os.path.join(self.tempdir, 'sub.yaml') with open(nested_path, 'w') as file: file.write(nested_raw) context = DummyContext() form = YAMLParser(main_path, context=context)() self.check_output( """ <form action="mainformaction" enctype="multipart/form-data" id="form-mainform" method="post" novalidate="novalidate"> <input class="nested_input text" id="input-mainform-sub" name="mainform.sub" type="text" value="context.some_attr"/> </form> """, fxml(form()))
def test_controller(self): # Dummy context class Context(object): value = 'hello world' context = Context() # Dummy getter def getter(widget, data): return data.request.context.value # Create Widget tree form = factory(u'form', name='testform', props={'action': 'http://fubar.com'}) form['field1'] = factory('text', value=getter) form['field2'] = factory('text', value='', props={'required': True}) # Define action ``handler`` def handler(widget, data): self.handler_result = 'handler called "%s"' % '.'.join(widget.path) # Define action ``next`` def next(request): return 'next return value' # Indicate widget to be an ``action`` definition by setting ``action`` # attribute to widget properties. ``expression``, ``handler`` and # ``next`` are action referring properties props = { 'action': 'save', 'expression': True, 'handler': handler, 'next': next, 'label': 'Save', 'skip': False, } # Add save action form['save'] = factory('submit', props=props) # Add cancel action. In this case we want the form processing to be # skipped and just the next action to be performed props = { 'action': 'cancel', 'expression': True, 'handler': None, 'next': next, 'label': 'Cancel', 'skip': True, } form['cancel'] = factory('submit', props=props) # Check widget tree self.assertEqual(form.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: testform", " <class 'yafowil.base.Widget'>: field1", " <class 'yafowil.base.Widget'>: field2", " <class 'yafowil.base.Widget'>: save", " <class 'yafowil.base.Widget'>: cancel", "" ]) # Dummy request class Request(dict): context = None Request.context = context request = Request() # Render form with empty request data = form.extract(request) self.check_output( """ <form action="http://fubar.com" enctype="multipart/form-data" id="form-testform" method="post" novalidate="novalidate"> <input class="text" id="input-testform-field1" name="testform.field1" type="text" value="hello world"/> <input class="required text" id="input-testform-field2" name="testform.field2" required="required" type="text" value=""/> <input id="input-testform-save" name="action.testform.save" type="submit" value="Save"/> <input id="input-testform-cancel" name="action.testform.cancel" type="submit" value="Cancel"/> </form> """, fxml(form(data))) # Create controller for form controller = Controller(form, request) # If action is not triggered, or ``action['next']`` is not set, # ``Controller.next`` is ``None`` self.assertEqual(controller.next, None) # An empty request does not trigger validation failures self.assertFalse(controller.error) # Provide empty required field and it fails! request['testform.field2'] = '' controller = Controller(form, request) self.assertTrue(controller.error) # Provide required field and all is fine request['testform.field2'] = '1' controller = Controller(form, request) self.assertFalse(controller.error) # Trigger save action without required field request['testform.field2'] = '' request['action.testform.save'] = '1' controller = Controller(form, request) self.assertTrue(controller.error, True) self.assertTrue(controller.performed, True) # Trigger save action with valid input request['testform.field2'] = '1' controller = Controller(form, request) self.assertEqual(self.handler_result, 'handler called "testform"') self.handler_result = None self.assertEqual(controller.next, 'next return value') self.assertFalse(controller.error) self.assertTrue(controller.performed) # Render the form performed self.check_output( """ <form action="http://fubar.com" enctype="multipart/form-data" id="form-testform" method="post" novalidate="novalidate"> <input class="text" id="input-testform-field1" name="testform.field1" type="text" value="hello world"/> <input class="required text" id="input-testform-field2" name="testform.field2" required="required" type="text" value="1"/> <input id="input-testform-save" name="action.testform.save" type="submit" value="Save"/> <input id="input-testform-cancel" name="action.testform.cancel" type="submit" value="Cancel"/> </form> """, fxml(controller.rendered)) # Trigger cancel action. performing is skipped del request['action.testform.save'] request['action.testform.cancel'] = '1' controller = Controller(form, request) self.assertEqual(controller.next, 'next return value') self.assertFalse(controller.performed) # Render form not performed self.check_output( """ <form action="http://fubar.com" enctype="multipart/form-data" id="form-testform" method="post" novalidate="novalidate"> <input class="text" id="input-testform-field1" name="testform.field1" type="text" value="hello world"/> <input class="required text" id="input-testform-field2" name="testform.field2" required="required" type="text" value=""/> <input id="input-testform-save" name="action.testform.save" type="submit" value="Save"/> <input id="input-testform-cancel" name="action.testform.cancel" type="submit" value="Cancel"/> </form> """, fxml(controller.rendered)) # Try recursive lookup of actions form = factory(u'form', name='testform', props={'action': 'http://fubar.com'}) form['level1'] = factory('submit', props={'action': 'l1action'}) form['fieldset'] = factory('fieldset') form['fieldset']['level2'] = factory('submit', props={'action': 'l2action'}) form['fieldset']['subset'] = factory('fieldset') form['fieldset']['subset']['level3'] = factory( 'submit', props={'action': 'l3action'}) controller = Controller(form, {}) self.assertEqual(len(controller.actions), 3) self.assertEqual(controller.actions[0].name, 'level1') self.assertEqual(controller.actions[1].name, 'level2') self.assertEqual(controller.actions[2].name, 'level3')
def test_form_blueprint(self): # Test Form form = factory('form', name='FORM', props={'action': 'http://fubar.com'}) self.assertEqual( form(), ('<form action="http://fubar.com" enctype="multipart/form-data" ' 'id="form-FORM" method="post" novalidate="novalidate"></form>')) # Form action as callable def action(widget, data): return 'http://fubar.com' form = factory('form', name='FORM', props={'action': action}) self.assertEqual( form(), ('<form action="http://fubar.com" enctype="multipart/form-data" ' 'id="form-FORM" method="post" novalidate="novalidate"></form>')) # Form display renderer form = factory('form', name='FORM', props={'action': 'http://fubar.com'}, mode='display') self.assertEqual(form(), '<div></div>') # Create a form with some children form = factory('form', name='myform', props={'action': 'http://www.domain.tld/someform'}) form['someinput'] = factory('label:text', props={'label': 'Your Text'}) self.form_data = None def formaction(widget, data): self.form_data = data def formnext(request): return 'http://www.domain.tld/result' form['submit'] = factory('submit', props={ 'handler': formaction, 'next': formnext, 'action': True }) # Render an empty form self.check_output( """ <form action="http://www.domain.tld/someform" enctype="multipart/form-data" id="form-myform" method="post" novalidate="novalidate"> <label for="input-myform-someinput">Your Text</label> <input class="text" id="input-myform-someinput" name="myform.someinput" type="text" value=""/> <input id="input-myform-submit" name="action.myform.submit" type="submit" value="submit"/> </form> """, fxml(form())) # Get form data out of request (request is expected dict-like) request = { 'myform.someinput': 'Hello World', 'action.myform.submit': 'submit' } Controller(form, request) form_data = self.form_data self.assertEqual(form_data.name, 'myform') self.assertEqual(form_data.value, UNSET) expected = odict() expected['someinput'] = 'Hello World' expected['submit'] = UNSET self.assertEqual(form_data.extracted, expected) self.assertEqual(form_data.errors, []) input_data = form_data['someinput'] self.assertEqual(input_data.name, 'someinput') self.assertEqual(input_data.value, UNSET) self.assertEqual(input_data.extracted, 'Hello World') self.assertEqual(input_data.errors, []) # submit blueprint gets a runtime data as well, but it's never needed # or used so far submit_data = form_data['submit'] self.assertEqual(submit_data.name, 'submit') self.assertEqual(submit_data.value, UNSET) self.assertEqual(submit_data.extracted, UNSET) self.assertEqual(submit_data.errors, []) del self.form_data # Form action property can be callable def action(widget, data): return 'actionfromcall' form = factory('form', name='form', props={ 'action': action, }) self.assertEqual( form(), ('<form action="actionfromcall" enctype="multipart/form-data" ' 'id="form-form" method="post" novalidate="novalidate"></form>')) # Create label for field in other compound form = factory('form', name='form', props={'action': 'action'}) form['label'] = factory('label', props={ 'label': 'Foo', 'for': 'field' }) form['field'] = factory('text') self.check_output( """ <form action="action" enctype="multipart/form-data" id="form-form" method="post" novalidate="novalidate"> <label for="input-form-field">Foo</label> <input class="text" id="input-form-field" name="form.field" type="text" value=""/> </form> """, fxml(form()))
def test_datetime_advanced(self): # Widget with more advanced configuration. Widget now renders time # input and input converting is locale aware. You can pass ``tzinfo`` # property as well if you want the conversion to consider timezones widget = factory( 'datetime', name='dt', props={ 'datepicker': True, 'required': 'No date given', 'delimiter': '.', 'locale': 'de', 'time': True, 'timepicker': True, 'tzinfo': None, }) self.check_output(""" <div> <input class="dateinput datepicker datetime required" id="input-dt" name="dt" size="10" type="text" value=""/> <input class="timeinput timepicker" id="input-dt-time" name="dt.time" size="5" type="text" value=""/> </div> """, fxml('<div>{}</div>'.format(widget()))) # Widget extraction, no date input was given request = {'dt': '', 'dt.time': ''} data = widget.extract(request) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['dt', UNSET, '', [ExtractionError('No date given')]] ) # Widget renders empty value self.check_output(""" <div> <input class="dateinput datepicker datetime required" id="input-dt" name="dt" size="10" type="text" value=""/> <input class="timeinput timepicker" id="input-dt-time" name="dt.time" size="5" type="text" value=""/> </div> """, fxml('<div>{}</div>'.format(widget(data)))) # Widget extraction with non-datetime input request = {'dt': 'xyz', 'dt.time': 'x'} data = widget.extract(request) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['dt', UNSET, 'xyz', [ExtractionError('Not a valid date input.')]] ) self.check_output(""" <div> <input class="dateinput datepicker datetime required" id="input-dt" name="dt" size="10" type="text" value="xyz"/> <input class="timeinput timepicker" id="input-dt-time" name="dt.time" size="5" type="text" value="x"/> </div> """, fxml('<div>{}</div>'.format(widget(data)))) # Valid widget extraction. Returns datetime instance request = {'dt': '1.1.2010', 'dt.time': '10:15'} data = widget.extract(request) self.assertEqual( [data.name, data.value, data.extracted, data.errors], ['dt', UNSET, datetime.datetime(2010, 1, 1, 10, 15), []] ) self.check_output(""" <div> <input class="dateinput datepicker datetime required" id="input-dt" name="dt" size="10" type="text" value="1.1.2010"/> <input class="timeinput timepicker" id="input-dt-time" name="dt.time" size="5" type="text" value="10:15"/> </div> """, fxml('<div>{}</div>'.format(widget(data))))
def test_table_with_structural(self): # Build same table again but set some nodes structural. This is # considered in ``Widget.dottedpath`` form = factory( 'form', name='mytableform', props={ 'action': 'mytableaction', }) form['table'] = factory( 'table', props={ 'structural': True }) form['table']['row1'] = factory( 'tr', props={ 'structural': True }) # note: td is used in a blueprint chain here form['table']['row1']['field1'] = factory( 'td:error:text', props={ 'required': 'Field 1 is required', } ) self.check_output(""" <form action="mytableaction" enctype="multipart/form-data" id="form-mytableform" method="post" novalidate="novalidate"> <table> <tr> <td> <input class="required text" id="input-mytableform-field1" name="mytableform.field1" required="required" type="text" value=""/> </td> </tr> </table> </form> """, fxml(form())) data = form.extract({}) self.assertEqual(data.name, 'mytableform') self.assertEqual(data.value, UNSET) self.assertEqual(data.extracted, odict([('field1', UNSET)])) self.assertEqual(data.errors, []) field_data = data['field1'] self.assertEqual(field_data.name, 'field1') self.assertEqual(field_data.value, UNSET) self.assertEqual(field_data.extracted, UNSET) self.assertEqual(field_data.errors, []) data = form.extract({'mytableform.field1': ''}) self.assertEqual(data.name, 'mytableform') self.assertEqual(data.value, UNSET) self.assertEqual(data.extracted, odict([('field1', '')])) self.assertEqual(data.errors, []) self.assertTrue(data.has_errors) field_data = data['field1'] self.assertEqual(field_data.name, 'field1') self.assertEqual(field_data.value, UNSET) self.assertEqual(field_data.extracted, '') self.assertEqual(field_data.errors, [ ExtractionError('Field 1 is required') ]) self.check_output(""" <form action="mytableaction" enctype="multipart/form-data" id="form-mytableform" method="post" novalidate="novalidate"> <table> <tr> <td> <div class="error"> <div class="errormessage">Field 1 is required</div> <input class="required text" id="input-mytableform-field1" name="mytableform.field1" required="required" type="text" value=""/> </div> </td> </tr> </table> </form> """, fxml(form(data)))
def test_compound_blueprint_address_compound_value_parent(self): # Address different compounds with value on parent value = { 'c1': { 'f1': 'Foo', }, 'c2': { 'f2': 'Bar', 'f3': 'Baz', }, } compound = factory('compound', 'comp', value=value) compound['c1'] = factory('compound') compound['c1']['f1'] = factory('text') compound['c2'] = factory('compound') compound['c2']['f2'] = factory('text') compound['c2']['f3'] = factory('text') compound['c3'] = factory('compound') compound['c3']['f4'] = factory('text') self.check_output( """ <div> <input class="text" id="input-comp-c1-f1" name="comp.c1.f1" type="text" value="Foo"/> <input class="text" id="input-comp-c2-f2" name="comp.c2.f2" type="text" value="Bar"/> <input class="text" id="input-comp-c2-f3" name="comp.c2.f3" type="text" value="Baz"/> <input class="text" id="input-comp-c3-f4" name="comp.c3.f4" type="text" value=""/> </div> """, fxml(tag('div', compound()))) self.assertEqual(compound.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: comp", " <class 'yafowil.base.Widget'>: c1", " <class 'yafowil.base.Widget'>: f1", " <class 'yafowil.base.Widget'>: c2", " <class 'yafowil.base.Widget'>: f2", " <class 'yafowil.base.Widget'>: f3", " <class 'yafowil.base.Widget'>: c3", " <class 'yafowil.base.Widget'>: f4", "" ]) data = compound.extract({ 'comp.c1.f1': 'Foo 1', 'comp.c2.f2': 'Bar 2', 'comp.c2.f3': 'Baz 1', }) self.assertEqual(data.name, 'comp') self.assertEqual(data.value, { 'c2': { 'f2': 'Bar', 'f3': 'Baz' }, 'c1': { 'f1': 'Foo' } }) expected = odict() expected['c1'] = odict() expected['c1']['f1'] = 'Foo 1' expected['c2'] = odict() expected['c2']['f2'] = 'Bar 2' expected['c2']['f3'] = 'Baz 1' expected['c3'] = odict() expected['c3']['f4'] = UNSET self.assertEqual(data.extracted, expected) self.assertEqual(data.errors, []) # c1 data_c1 = data['c1'] self.assertEqual(data_c1.name, 'c1') self.assertEqual(data_c1.value, {'f1': 'Foo'}) expected = odict() expected['f1'] = 'Foo 1' self.assertEqual(data_c1.extracted, expected) self.assertEqual(data_c1.errors, []) data_f1 = data['c1']['f1'] self.assertEqual(data_f1.name, 'f1') self.assertEqual(data_f1.value, 'Foo') self.assertEqual(data_f1.extracted, 'Foo 1') self.assertEqual(data_f1.errors, []) # c2 data_c2 = data['c2'] self.assertEqual(data_c2.name, 'c2') self.assertEqual(data_c2.value, {'f2': 'Bar', 'f3': 'Baz'}) expected = odict() expected['f2'] = 'Bar 2' expected['f3'] = 'Baz 1' self.assertEqual(data_c2.extracted, expected) self.assertEqual(data_c2.errors, []) data_f2 = data['c2']['f2'] self.assertEqual(data_f2.name, 'f2') self.assertEqual(data_f2.value, 'Bar') self.assertEqual(data_f2.extracted, 'Bar 2') self.assertEqual(data_f2.errors, []) data_f3 = data['c2']['f3'] self.assertEqual(data_f3.name, 'f3') self.assertEqual(data_f3.value, 'Baz') self.assertEqual(data_f3.extracted, 'Baz 1') self.assertEqual(data_f3.errors, []) # c3 data_c3 = data['c3'] self.assertEqual(data_c3.name, 'c3') self.assertEqual(data_c3.value, UNSET) expected = odict() expected['f4'] = UNSET self.assertEqual(data_c3.extracted, expected) self.assertEqual(data_c3.errors, []) data_f4 = data['c3']['f4'] self.assertEqual(data_f4.name, 'f4') self.assertEqual(data_f4.value, UNSET) self.assertEqual(data_f4.extracted, UNSET) self.assertEqual(data_f4.errors, [])
def test_table_with_compound_td(self): # Create table with 'td' as compound form = factory( 'form', name='mytableform', props={ 'action': 'mytableaction', }) form['table'] = factory( 'table', props={ 'structural': True }) form['table']['row1'] = factory( 'tr', props={ 'structural': True }) form['table']['row1']['td1'] = factory( 'td', props={ 'structural': True }) form['table']['row1']['td1']['field1'] = factory( 'error:text', props={ 'required': 'Field 1 is required', } ) self.check_output(""" <form action="mytableaction" enctype="multipart/form-data" id="form-mytableform" method="post" novalidate="novalidate"> <table> <tr> <td> <input class="required text" id="input-mytableform-field1" name="mytableform.field1" required="required" type="text" value=""/> </td> </tr> </table> </form> """, fxml(form())) data = form.extract({}) self.assertEqual(data.name, 'mytableform') self.assertEqual(data.value, UNSET) self.assertEqual(data.extracted, odict([('field1', UNSET)])) self.assertEqual(data.errors, []) field_data = data['field1'] self.assertEqual(field_data.name, 'field1') self.assertEqual(field_data.value, UNSET) self.assertEqual(field_data.extracted, UNSET) self.assertEqual(field_data.errors, []) data = form.extract({'mytableform.field1': ''}) self.assertEqual(data.name, 'mytableform') self.assertEqual(data.value, UNSET) self.assertEqual(data.extracted, odict([('field1', '')])) self.assertEqual(data.errors, []) self.assertTrue(data.has_errors) field_data = data['field1'] self.assertEqual(field_data.name, 'field1') self.assertEqual(field_data.value, UNSET) self.assertEqual(field_data.extracted, '') self.assertEqual(field_data.errors, [ ExtractionError('Field 1 is required') ]) self.check_output(""" <form action="mytableaction" enctype="multipart/form-data" id="form-mytableform" method="post" novalidate="novalidate"> <table> <tr> <td> <div class="error"> <div class="errormessage">Field 1 is required</div> <input class="required text" id="input-mytableform-field1" name="mytableform.field1" required="required" type="text" value=""/> </div> </td> </tr> </table> </form> """, fxml(form(data)))
def test_compound_blueprint_compound_children(self): # Compound with compound as child value = { 'CHILD_COMPOUND': { 'inner': 'Value 1 from parent', 'inner2': 'Value 2 from parent', } } compound = factory('compound', name='COMPOUND', value=value) child_compound = compound['CHILD_COMPOUND'] = factory('compound') child_compound['inner'] = factory('text') child_compound['inner2'] = factory('text', props={'required': True}) self.check_output(""" <div> <input class="text" id="input-COMPOUND-CHILD_COMPOUND-inner" name="COMPOUND.CHILD_COMPOUND.inner" type="text" value="Value 1 from parent"/> <input class="required text" id="input-COMPOUND-CHILD_COMPOUND-inner2" name="COMPOUND.CHILD_COMPOUND.inner2" required="required" type="text" value="Value 2 from parent"/> </div> """, fxml(tag('div', compound()))) # noqa self.assertEqual(compound.treerepr().split('\n'), [ "<class 'yafowil.base.Widget'>: COMPOUND", " <class 'yafowil.base.Widget'>: CHILD_COMPOUND", " <class 'yafowil.base.Widget'>: inner", " <class 'yafowil.base.Widget'>: inner2", "" ]) data = compound.extract({ 'COMPOUND.CHILD_COMPOUND.inner': 'newvalue', 'COMPOUND.CHILD_COMPOUND.inner2': 'newvalue2', }) self.assertEqual(data.name, 'COMPOUND') self.assertEqual( data.value, { 'CHILD_COMPOUND': { 'inner2': 'Value 2 from parent', 'inner': 'Value 1 from parent' } }) expected = odict() expected['CHILD_COMPOUND'] = odict() expected['CHILD_COMPOUND']['inner'] = 'newvalue' expected['CHILD_COMPOUND']['inner2'] = 'newvalue2' self.assertEqual(data.extracted, expected) self.assertEqual(data.errors, []) data_compound = data['CHILD_COMPOUND'] self.assertEqual(data_compound.name, 'CHILD_COMPOUND') self.assertEqual(data_compound.value, { 'inner2': 'Value 2 from parent', 'inner': 'Value 1 from parent' }) expected = odict() expected['inner'] = 'newvalue' expected['inner2'] = 'newvalue2' self.assertEqual(data_compound.extracted, expected) self.assertEqual(data_compound.errors, []) data_inner = data['CHILD_COMPOUND']['inner'] self.assertEqual(data_inner.name, 'inner') self.assertEqual(data_inner.value, 'Value 1 from parent') self.assertEqual(data_inner.extracted, 'newvalue') self.assertEqual(data_inner.errors, []) data_inner2 = data['CHILD_COMPOUND']['inner2'] self.assertEqual(data_inner2.name, 'inner2') self.assertEqual(data_inner2.value, 'Value 2 from parent') self.assertEqual(data_inner2.extracted, 'newvalue2') self.assertEqual(data_inner2.errors, [])