Skip to content

Commit 6d0f92b

Browse files
authored
Merge pull request #2658 from /issues/2653/1
Fixes #2653. Encode details as JSON before filling input
2 parents 0974eef + 467632d commit 6d0f92b

File tree

2 files changed

+72
-15
lines changed

2 files changed

+72
-15
lines changed

tests/unit/test_form.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,24 +196,46 @@ def test_build_formdata(self):
196196
self.assertEqual(actual, expected)
197197

198198
def test_get_details(self):
199-
"""Assert we handle valid JSON and other values."""
199+
"""Assert we handle valid dict and other values."""
200200
actual_string_arg = form.get_details('cool')
201201
expected_string_arg = 'cool'
202202
self.assertEqual(actual_string_arg, expected_string_arg)
203-
actual_json_arg = form.get_details(json.dumps({'a': 'b', 'c': False}))
204-
expected_json_arg = '<li>a: b</li><li>c: false</li>'
205-
self.assertEqual(actual_json_arg, expected_json_arg)
203+
actual_dict_arg = form.get_details({'a': 'b', 'c': False})
204+
expected_dict_arg = '<li>a: b</li><li>c: false</li>'
205+
self.assertEqual(actual_dict_arg, expected_dict_arg)
206206

207207
def test_build_details(self):
208208
"""Expected HTML is returned for a json object or a string."""
209209
actual_json_arg = form.build_details(json.dumps(
210210
{'a': 'b', 'c': False}))
211-
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>a: b</li><li>c: false</li>\n</ul>\n</details>' # nopep8
211+
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>a: b</li><li>c: false</li>\n</ul>\n\n</details>' # nopep8
212212
self.assertEqual(actual_json_arg, expected_json_arg)
213-
actual_string_arg = form.build_details("cool")
214-
expected_string_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n cool\n</ul>\n</details>' # nopep8
213+
actual_string_arg = form.build_details('cool')
214+
expected_string_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n cool\n</ul>\n\n</details>' # nopep8
215215
self.assertEqual(actual_string_arg, expected_string_arg)
216216

217+
def test_build_details_with_console_logs(self):
218+
"""Expected HTML is returned for a json object with console logs."""
219+
actual_json_arg = form.build_details(json.dumps(
220+
{'a': 'b', 'c': False, 'consoleLog': ['console.log(hi)']}))
221+
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>a: b</li><li>c: false</li>\n</ul>\n<p>Console Messages:</p>\n<pre>\n[u\'console.log(hi)\']\n</pre>\n</details>' # nopep8
222+
self.assertEqual(actual_json_arg, expected_json_arg)
223+
actual_empty_log_arg = form.build_details(json.dumps(
224+
{'a': 'b', 'c': False, 'consoleLog': ''}))
225+
expected_empty_log_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>a: b</li><li>c: false</li>\n</ul>\n\n</details>' # nopep8
226+
self.assertEqual(actual_empty_log_arg, expected_empty_log_arg)
227+
228+
def test_get_console_section(self):
229+
"""Assert we return an empty string, or a pre with console messages."""
230+
actual_empty_arg = form.get_console_section('')
231+
expected_empty_arg = ''
232+
self.assertEqual(actual_empty_arg, expected_empty_arg)
233+
actual_none_arg = form.get_console_section(None)
234+
self.assertEqual(actual_none_arg, expected_empty_arg)
235+
actual_stringy_arg = form.get_console_section('sup')
236+
expected_stringy_arg = '<p>Console Messages:</p>\n<pre>\nsup\n</pre>'
237+
self.assertEqual(actual_stringy_arg, expected_stringy_arg)
238+
217239
def test_is_valid_issue_form(self):
218240
"""Assert that we get the form parameters we want."""
219241
incomplete_form = MultiDict([('problem_category', u'unknown_bug')])

webcompat/form.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ def get_form(form_data):
103103
ua_header = form_data['user_agent']
104104
# Populate the form
105105
bug_form.browser.data = get_browser(ua_header)
106+
# Note: The details JSON that was POSTed to the new issue endpoint is at
107+
# this point a Python dict. We need to re-serialize to JSON when we store
108+
# its value in the hidden details form element, otherwise when we attempt
109+
# to decode it as JSON on form submission, it will throw (because Python
110+
# dicts are not valid JSON)
111+
bug_form.details.data = json.dumps(form_data.get('details'), indent=2)
106112
bug_form.extra_labels = form_data.get('extra_labels', None)
107113
bug_form.os.data = get_os(ua_header)
108114
bug_form.reported_with.data = form_data.get('src', 'web')
@@ -111,32 +117,61 @@ def get_form(form_data):
111117
return bug_form
112118

113119

114-
def get_details(details_string):
120+
def get_details(details):
115121
"""Return details content.
116122
117-
* If JSON as a formatted string
123+
* If a dict, as a formatted string
118124
* Otherwise as a string as-is.
119125
"""
120-
content = details_string
126+
content = details
121127
rv = ''
122-
123128
try:
124-
details = json.loads(content)
125129
rv = ''.join(['<li>{k}: {v}</li>'.format(k=k, v=get_str_value(v))
126130
for k, v in details.items()])
127-
except ValueError:
131+
except AttributeError:
128132
return content
129133
return rv
130134

131135

136+
def get_console_section(console_logs):
137+
"""Return a section for console logs, or the empty string.
138+
139+
This populates the named argument `{console_section}`
140+
inside the formatted string that `build_details` returns.
141+
"""
142+
if not console_logs:
143+
return ''
144+
return """<p>Console Messages:</p>
145+
<pre>
146+
{console_logs}
147+
</pre>""".format(console_logs=console_logs)
148+
149+
132150
def build_details(details):
133-
"""Populate and return the Browser Configuration section template."""
151+
"""Populate and return the Browser Configuration section template.
152+
153+
If we get JSON, we try to pull out the console logs before building the
154+
rest of the details.
155+
"""
156+
157+
console_logs = None
158+
content = details
159+
try:
160+
content = json.loads(details)
161+
console_logs = content.pop('consoleLog', None)
162+
except ValueError:
163+
# if we got a ValueError, details was a string, so just pass it
164+
# into get_details below
165+
pass
166+
134167
return """<details>
135168
<summary>Browser Configuration</summary>
136169
<ul>
137170
{details_list_items}
138171
</ul>
139-
</details>""".format(details_list_items=get_details(details))
172+
{console_section}
173+
</details>""".format(details_list_items=get_details(content),
174+
console_section=get_console_section(console_logs))
140175

141176

142177
def get_radio_button_label(field_value, label_list):

0 commit comments

Comments
 (0)