Skip to content

Commit 467632d

Browse files
committed
Issue #2653. Add console logs to details section, and update tests
This changes the way we build details, and updates tests accordingly. In build_details, we first attempt to parse the details argument as JSON. If successful, we pull out the `consoleLog` key and store it to be used to build the console logs section. If JSON parsing failed, we assume we received a (legacy) string, and pass that into get_details. Inside of get_details, if we're able to access the items() member of the details dict, we return the formatted string as a group of <li>s, otherwise if we get an AttributeError (which happens for a string, or other non-dict type), we just return the string as-is. When building the console section of details, if there are not any logs, it will just render as an empty string. But if there are logs, we return a new section with the content inside a <pre> tag. This is handled by the new get_console_section method.
1 parent 16e389b commit 467632d

File tree

2 files changed

+66
-14
lines changed

2 files changed

+66
-14
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: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,31 +117,61 @@ def get_form(form_data):
117117
return bug_form
118118

119119

120-
def get_details(details_string):
120+
def get_details(details):
121121
"""Return details content.
122122
123-
* If JSON as a formatted string
123+
* If a dict, as a formatted string
124124
* Otherwise as a string as-is.
125125
"""
126-
content = details_string
126+
content = details
127127
rv = ''
128128
try:
129-
details = json.loads(content)
130129
rv = ''.join(['<li>{k}: {v}</li>'.format(k=k, v=get_str_value(v))
131130
for k, v in details.items()])
132-
except ValueError:
131+
except AttributeError:
133132
return content
134133
return rv
135134

136135

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+
137150
def build_details(details):
138-
"""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+
139167
return """<details>
140168
<summary>Browser Configuration</summary>
141169
<ul>
142170
{details_list_items}
143171
</ul>
144-
</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))
145175

146176

147177
def get_radio_button_label(field_value, label_list):

0 commit comments

Comments
 (0)