Skip to content

Commit 6dda1e2

Browse files
author
Mike Taylor
authored
Merge pull request #3103 from webcompat/issue/2659/1
Fixes #2659 - Make console logs in browser configuration details easier to read
2 parents 9c9d1dd + 6055e31 commit 6dda1e2

15 files changed

+509
-114
lines changed

grunt-tasks/cssmin.js

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ module.exports = function(grunt) {
1313
"<%= cssPath %>/dist/webcompat.min.css": [
1414
// input
1515
"<%= cssPath %>/webcompat.dev.css"
16+
],
17+
// output
18+
"<%= cssPath %>/dist/webcompat-logs.min.css": [
19+
// input
20+
"<%= cssPath %>/webcompat-logs.dev.css"
1621
]
1722
}
1823
}

grunt-tasks/cssnext.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ module.exports = function(grunt) {
2424
dist: {
2525
files: {
2626
"<%= cssPath %>/dist/webcompat.min.css":
27-
"<%= cssPath %>/webcompat.dev.css"
27+
"<%= cssPath %>/webcompat.dev.css",
28+
"<%= cssPath %>/dist/webcompat-logs.min.css":
29+
"<%= cssPath %>/webcompat-logs.dev.css"
2830
}
2931
}
3032
});

tests/unit/test_console_logs.py

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# This Source Code Form is subject to the terms of the Mozilla Public
4+
# License, v. 2.0. If a copy of the MPL was not distributed with this
5+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
7+
'''Tests for console logs upload.'''
8+
9+
import json
10+
import os.path
11+
import sys
12+
import unittest
13+
from werkzeug.datastructures import MultiDict
14+
15+
# Add webcompat module to import path
16+
sys.path.append(os.path.realpath(os.pardir))
17+
18+
from webcompat import app # noqa
19+
20+
LOG = [
21+
{
22+
'level': 'log',
23+
'log': [
24+
'test log'
25+
],
26+
'uri': 'http://example.com/vendor.js',
27+
'pos': '95:13'
28+
},
29+
{
30+
'level': 'warn',
31+
'log': [
32+
'test warn'
33+
],
34+
'uri': 'http://example.com/test.js',
35+
'pos': '1:28535'
36+
}
37+
]
38+
39+
40+
def get_json_contents(filepath):
41+
with open(filepath, 'r') as f:
42+
json_contents = json.load(f)
43+
return json_contents
44+
45+
46+
def get_path(self, url):
47+
return self.app.config['UPLOADS_DEFAULT_DEST'] + url + '.json'
48+
49+
50+
def cleanup(filepath):
51+
os.remove(filepath)
52+
53+
54+
def form_request(data):
55+
d = MultiDict()
56+
d['console_logs'] = data
57+
return d
58+
59+
60+
class TestConsoleUploads(unittest.TestCase):
61+
def setUp(self):
62+
app.config['TESTING'] = True
63+
self.app = app
64+
self.test_client = self.app.test_client()
65+
66+
def tearDown(self):
67+
pass
68+
69+
def test_get(self):
70+
'''Test that /upload/ doesn't let you GET.'''
71+
rv = self.test_client.get('/upload/')
72+
self.assertEqual(rv.status_code, 404)
73+
74+
def test_console_log_upload(self):
75+
rv = self.test_client.post(
76+
'/upload/', data=form_request(json.dumps(LOG)))
77+
self.assertEqual(rv.status_code, 201)
78+
79+
response = json.loads(rv.data)
80+
self.assertTrue('url' in response)
81+
cleanup(get_path(self, response.get('url')))
82+
83+
def test_console_log_bad_format(self):
84+
rv = self.test_client.post(
85+
'/upload/', data=form_request('{test}'))
86+
self.assertEqual(rv.status_code, 400)
87+
88+
rv = self.test_client.post(
89+
'/upload/', data=form_request(''))
90+
self.assertEqual(rv.status_code, 501)
91+
92+
rv = self.test_client.post(
93+
'/upload/', data=json.dumps(LOG))
94+
self.assertEqual(rv.status_code, 501)
95+
96+
def test_console_log_file_contents(self):
97+
rv = self.test_client.post(
98+
'/upload/', data=form_request(json.dumps(LOG)))
99+
response = json.loads(rv.data)
100+
filepath = get_path(self, response.get('url'))
101+
actual = get_json_contents(filepath)
102+
self.assertEqual(actual, LOG)
103+
cleanup(filepath)
104+
105+
def test_console_log_render(self):
106+
test = [
107+
{
108+
'level': 'log',
109+
'log': [
110+
'test log'
111+
],
112+
'uri': 'http://example.com/vendor.js',
113+
'pos': '95:13'
114+
},
115+
{
116+
'level': 'warn',
117+
'log': [
118+
'<script> alert("hi")</script>',
119+
'something else..'
120+
],
121+
'uri': 'http://example.com/test.js',
122+
'pos': '1:28535'
123+
},
124+
{
125+
'level': 'error',
126+
'log': [
127+
'<div style="background-image: url(javascript:alert(\'XSS\'))">', # noqa
128+
],
129+
'uri': 'http://example.com/test.js',
130+
'pos': '1:28535'
131+
}
132+
]
133+
134+
rv = self.test_client.post(
135+
'/upload/', data=form_request(json.dumps(test)))
136+
response = json.loads(rv.data)
137+
console_logs_url = '/console_logs/' + response.get('url')
138+
rv = self.test_client.get(console_logs_url)
139+
for expected in [
140+
b'<div class="log level-log">',
141+
b'<div class="log level-warn">',
142+
b'<div class="log level-error">',
143+
b'<a href="http://example.com/vendor.js">vendor.js:95:13</a>',
144+
b'test log',
145+
b'&lt;script&gt; alert(&#34;hi&#34;)&lt;/script&gt;',
146+
b'&lt;div style=&#34;background-image: url(javascript:alert(&#39;XSS&#39;))&#34;&gt;' # noqa
147+
]:
148+
self.assertTrue(expected in rv.data)
149+
150+
self.assertEqual(rv.status_code, 200)
151+
filepath = get_path(self, response.get('url'))
152+
cleanup(filepath)
153+
154+
155+
if __name__ == '__main__':
156+
unittest.main()

tests/unit/test_form.py

+13-13
Original file line numberDiff line numberDiff line change
@@ -209,37 +209,37 @@ def test_build_details(self):
209209
# Test for receiving JSON object as a string
210210
actual_json_arg = form.build_details(json.dumps(
211211
{'a': 'b', 'c': False}))
212-
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>' # noqa
212+
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>a: b</li><li>c: false</li>\n</ul>\n</details>' # noqa
213213
self.assertEqual(actual_json_arg, expected_json_arg)
214214
# Test for receiving a JSON value which is not an object
215215
actual_json_arg = form.build_details('null')
216-
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>None</li>\n</ul>\n\n</details>' # noqa
216+
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>None</li>\n</ul>\n</details>' # noqa
217217
self.assertEqual(actual_json_arg, expected_json_arg)
218218
# Test for receiving a string
219219
actual_string_arg = form.build_details('cool')
220-
expected_string_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>cool</li>\n</ul>\n\n</details>' # noqa
220+
expected_string_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>cool</li>\n</ul>\n</details>' # noqa
221221
self.assertEqual(actual_string_arg, expected_string_arg)
222222

223-
def test_build_details_with_console_logs(self):
224-
"""Expected HTML is returned for a json object with console logs."""
223+
def test_build_details_without_console_logs(self):
224+
"""Expected HTML is returned for a json object without console logs."""
225225
actual_json_arg = form.build_details(json.dumps(
226226
{'a': 'b', 'c': False, 'consoleLog': ['console.log(hi)']}))
227-
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[\'console.log(hi)\']\n</pre>\n</details>' # noqa
227+
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>a: b</li><li>c: false</li>\n</ul>\n</details>' # noqa
228228
self.assertEqual(actual_json_arg, expected_json_arg)
229229
actual_empty_log_arg = form.build_details(json.dumps(
230230
{'a': 'b', 'c': False, 'consoleLog': ''}))
231-
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>' # noqa
231+
expected_empty_log_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>a: b</li><li>c: false</li>\n</ul>\n</details>' # noqa
232232
self.assertEqual(actual_empty_log_arg, expected_empty_log_arg)
233233

234-
def test_get_console_section(self):
235-
"""Assert we return an empty string, or a pre with console messages."""
236-
actual_empty_arg = form.get_console_section('')
234+
def test_get_console_logs_url(self):
235+
"""Assert we return an empty string, or a link to console logs page."""
236+
actual_empty_arg = form.get_console_logs_url('')
237237
expected_empty_arg = ''
238238
self.assertEqual(actual_empty_arg, expected_empty_arg)
239-
actual_none_arg = form.get_console_section(None)
239+
actual_none_arg = form.get_console_logs_url(None)
240240
self.assertEqual(actual_none_arg, expected_empty_arg)
241-
actual_stringy_arg = form.get_console_section('sup')
242-
expected_stringy_arg = '<p>Console Messages:</p>\n<pre>\nsup\n</pre>'
241+
actual_stringy_arg = form.get_console_logs_url('some url')
242+
expected_stringy_arg = '\n\n[View console log messages](some url)'
243243
self.assertEqual(actual_stringy_arg, expected_stringy_arg)
244244

245245
def test_is_valid_issue_form(self):

tests/unit/test_helpers.py

+31
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from webcompat.helpers import rewrite_links
3535
from webcompat.helpers import sanitize_link
3636
from webcompat.helpers import get_extra_labels
37+
from webcompat.helpers import get_filename_from_url
3738

3839

3940
ACCESS_TOKEN_LINK = '<https://api.github.com/repositories/17839063/issues?per_page=50&page=3&access_token=12345>; rel="next", <https://api.github.com/repositories/17839063/issues?access_token=12345&per_page=50&page=4>; rel="last", <https://api.github.com/repositories/17839063/issues?per_page=50&access_token=12345&page=1>; rel="first", <https://api.github.com/repositories/17839063/issues?per_page=50&page=1&access_token=12345>; rel="prev"' # noqa
@@ -565,6 +566,36 @@ def test_get_extra_labels_for_experiment(self):
565566
['type-fastclick', 'form-v2-experiment']
566567
)
567568

569+
def test_process_log_url(self):
570+
self.assertEqual(get_filename_from_url(
571+
'https://example.com/file.js'),
572+
'file.js'
573+
)
574+
self.assertEqual(get_filename_from_url(
575+
'https://example.com/vendor.min.js?201911131607%20line%202%20%3E%20#id'), # noqa
576+
'vendor.min.js'
577+
)
578+
self.assertEqual(get_filename_from_url(
579+
'https://example.com/some_path/to_page/'
580+
),
581+
'to_page'
582+
)
583+
584+
self.assertEqual(get_filename_from_url(
585+
'https://example.com/some_path/to_page'
586+
),
587+
'to_page'
588+
)
589+
590+
self.assertEqual(get_filename_from_url(
591+
'https://example.com/'),
592+
'example.com'
593+
)
594+
self.assertEqual(get_filename_from_url(
595+
'https://example.com'),
596+
'example.com'
597+
)
598+
568599

569600
if __name__ == '__main__':
570601
unittest.main()

0 commit comments

Comments
 (0)