Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #2659 - Make console logs in browser configuration details easier to read #3103

Merged
merged 7 commits into from
Dec 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions grunt-tasks/cssmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ module.exports = function(grunt) {
"<%= cssPath %>/dist/webcompat.min.css": [
// input
"<%= cssPath %>/webcompat.dev.css"
],
// output
"<%= cssPath %>/dist/webcompat-logs.min.css": [
// input
"<%= cssPath %>/webcompat-logs.dev.css"
]
}
}
Expand Down
4 changes: 3 additions & 1 deletion grunt-tasks/cssnext.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ module.exports = function(grunt) {
dist: {
files: {
"<%= cssPath %>/dist/webcompat.min.css":
"<%= cssPath %>/webcompat.dev.css"
"<%= cssPath %>/webcompat.dev.css",
"<%= cssPath %>/dist/webcompat-logs.min.css":
"<%= cssPath %>/webcompat-logs.dev.css"
}
}
});
Expand Down
156 changes: 156 additions & 0 deletions tests/unit/test_console_logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

'''Tests for console logs upload.'''

import json
import os.path
import sys
import unittest
from werkzeug.datastructures import MultiDict

# Add webcompat module to import path
sys.path.append(os.path.realpath(os.pardir))

from webcompat import app # noqa

LOG = [
{
'level': 'log',
'log': [
'test log'
],
'uri': 'http://example.com/vendor.js',
'pos': '95:13'
},
{
'level': 'warn',
'log': [
'test warn'
],
'uri': 'http://example.com/test.js',
'pos': '1:28535'
}
]


def get_json_contents(filepath):
with open(filepath, 'r') as f:
json_contents = json.load(f)
return json_contents


def get_path(self, url):
return self.app.config['UPLOADS_DEFAULT_DEST'] + url + '.json'


def cleanup(filepath):
os.remove(filepath)


def form_request(data):
d = MultiDict()
d['console_logs'] = data
return d


class TestConsoleUploads(unittest.TestCase):
def setUp(self):
app.config['TESTING'] = True
self.app = app
self.test_client = self.app.test_client()

def tearDown(self):
pass

def test_get(self):
'''Test that /upload/ doesn't let you GET.'''
rv = self.test_client.get('/upload/')
self.assertEqual(rv.status_code, 404)

def test_console_log_upload(self):
rv = self.test_client.post(
'/upload/', data=form_request(json.dumps(LOG)))
self.assertEqual(rv.status_code, 201)

response = json.loads(rv.data)
self.assertTrue('url' in response)
cleanup(get_path(self, response.get('url')))

def test_console_log_bad_format(self):
rv = self.test_client.post(
'/upload/', data=form_request('{test}'))
self.assertEqual(rv.status_code, 400)

rv = self.test_client.post(
'/upload/', data=form_request(''))
self.assertEqual(rv.status_code, 501)

rv = self.test_client.post(
'/upload/', data=json.dumps(LOG))
self.assertEqual(rv.status_code, 501)

def test_console_log_file_contents(self):
rv = self.test_client.post(
'/upload/', data=form_request(json.dumps(LOG)))
response = json.loads(rv.data)
filepath = get_path(self, response.get('url'))
actual = get_json_contents(filepath)
self.assertEqual(actual, LOG)
cleanup(filepath)

def test_console_log_render(self):
test = [
{
'level': 'log',
'log': [
'test log'
],
'uri': 'http://example.com/vendor.js',
'pos': '95:13'
},
{
'level': 'warn',
'log': [
'<script> alert("hi")</script>',
'something else..'
],
'uri': 'http://example.com/test.js',
'pos': '1:28535'
},
{
'level': 'error',
'log': [
'<div style="background-image: url(javascript:alert(\'XSS\'))">', # noqa
],
'uri': 'http://example.com/test.js',
'pos': '1:28535'
}
]

rv = self.test_client.post(
'/upload/', data=form_request(json.dumps(test)))
response = json.loads(rv.data)
console_logs_url = '/console_logs/' + response.get('url')
rv = self.test_client.get(console_logs_url)
for expected in [
b'<div class="log level-log">',
b'<div class="log level-warn">',
b'<div class="log level-error">',
b'<a href="http://example.com/vendor.js">vendor.js:95:13</a>',
b'test log',
b'&lt;script&gt; alert(&#34;hi&#34;)&lt;/script&gt;',
b'&lt;div style=&#34;background-image: url(javascript:alert(&#39;XSS&#39;))&#34;&gt;' # noqa
]:
self.assertTrue(expected in rv.data)

self.assertEqual(rv.status_code, 200)
filepath = get_path(self, response.get('url'))
cleanup(filepath)


if __name__ == '__main__':
unittest.main()
26 changes: 13 additions & 13 deletions tests/unit/test_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,37 +209,37 @@ def test_build_details(self):
# Test for receiving JSON object as a string
actual_json_arg = form.build_details(json.dumps(
{'a': 'b', 'c': False}))
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
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
self.assertEqual(actual_json_arg, expected_json_arg)
# Test for receiving a JSON value which is not an object
actual_json_arg = form.build_details('null')
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>None</li>\n</ul>\n\n</details>' # noqa
expected_json_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>None</li>\n</ul>\n</details>' # noqa
self.assertEqual(actual_json_arg, expected_json_arg)
# Test for receiving a string
actual_string_arg = form.build_details('cool')
expected_string_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>cool</li>\n</ul>\n\n</details>' # noqa
expected_string_arg = '<details>\n<summary>Browser Configuration</summary>\n<ul>\n <li>cool</li>\n</ul>\n</details>' # noqa
self.assertEqual(actual_string_arg, expected_string_arg)

def test_build_details_with_console_logs(self):
"""Expected HTML is returned for a json object with console logs."""
def test_build_details_without_console_logs(self):
"""Expected HTML is returned for a json object without console logs."""
actual_json_arg = form.build_details(json.dumps(
{'a': 'b', 'c': False, 'consoleLog': ['console.log(hi)']}))
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
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
self.assertEqual(actual_json_arg, expected_json_arg)
actual_empty_log_arg = form.build_details(json.dumps(
{'a': 'b', 'c': False, 'consoleLog': ''}))
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
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
self.assertEqual(actual_empty_log_arg, expected_empty_log_arg)

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

def test_is_valid_issue_form(self):
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from webcompat.helpers import rewrite_links
from webcompat.helpers import sanitize_link
from webcompat.helpers import get_extra_labels
from webcompat.helpers import get_filename_from_url


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
Expand Down Expand Up @@ -565,6 +566,36 @@ def test_get_extra_labels_for_experiment(self):
['type-fastclick', 'form-v2-experiment']
)

def test_process_log_url(self):
self.assertEqual(get_filename_from_url(
'https://example.com/file.js'),
'file.js'
)
self.assertEqual(get_filename_from_url(
'https://example.com/vendor.min.js?201911131607%20line%202%20%3E%20#id'), # noqa
'vendor.min.js'
)
self.assertEqual(get_filename_from_url(
'https://example.com/some_path/to_page/'
),
'to_page'
)

self.assertEqual(get_filename_from_url(
'https://example.com/some_path/to_page'
),
'to_page'
)

self.assertEqual(get_filename_from_url(
'https://example.com/'),
'example.com'
)
self.assertEqual(get_filename_from_url(
'https://example.com'),
'example.com'
)


if __name__ == '__main__':
unittest.main()
Loading