diff --git a/lighthouse-core/audits/errors-in-console.js b/lighthouse-core/audits/errors-in-console.js index d6357e533e9e..0fa44f6e5f5f 100644 --- a/lighthouse-core/audits/errors-in-console.js +++ b/lighthouse-core/audits/errors-in-console.js @@ -61,7 +61,7 @@ class ErrorLogs extends Audit { const headings = [ {key: 'url', itemType: 'url', text: 'URL'}, - {key: 'description', itemType: 'text', text: 'Description'}, + {key: 'description', itemType: 'code', text: 'Description'}, ]; const details = Audit.makeTableDetails(headings, tableRows); diff --git a/lighthouse-core/report/v2/renderer/details-renderer.js b/lighthouse-core/report/v2/renderer/details-renderer.js index 08b8bccb0312..21f31d3c1d2d 100644 --- a/lighthouse-core/report/v2/renderer/details-renderer.js +++ b/lighthouse-core/report/v2/renderer/details-renderer.js @@ -66,28 +66,37 @@ class DetailsRenderer { _renderTextURL(text) { const url = text.text || ''; - let displayedURL; + let displayedPath; + let displayedHost; let title; try { - displayedURL = Util.parseURL(url).file; + const parsed = Util.parseURL(url); + displayedPath = parsed.file; + displayedHost = `(${parsed.hostname})`; title = url; } catch (/** @type {!Error} */ e) { if (!(e instanceof TypeError)) { throw e; } - displayedURL = url; + displayedPath = url; } - const element = this._renderText({ - type: 'url', - text: displayedURL, - }); - element.classList.add('lh-text__url'); + const element = this._dom.createElement('div', 'lh-text__url'); + element.appendChild(this._renderText({ + text: displayedPath, + type: 'text', + })); - if (title) { - element.title = url; + if (displayedHost) { + const hostElem = this._renderText({ + text: displayedHost, + type: 'text', + }); + hostElem.classList.add('lh-text__url-host'); + element.appendChild(hostElem); } + if (title) element.title = url; return element; } diff --git a/lighthouse-core/report/v2/renderer/util.js b/lighthouse-core/report/v2/renderer/util.js index 25637ab6aa26..f97925118905 100644 --- a/lighthouse-core/report/v2/renderer/util.js +++ b/lighthouse-core/report/v2/renderer/util.js @@ -147,8 +147,15 @@ class Util { } const MAX_LENGTH = 64; - // Always elide hash + // Always elide hexadecimal hash name = name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g, `$1${ELLIPSIS}`); + // Also elide other hash-like mixed-case strings + name = name.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g, + `$1${ELLIPSIS}`); + // Also elide long number sequences + name = name.replace(/(\d{3})\d{6,}/g, `$1${ELLIPSIS}`); + // Merge any adjacent ellipses + name = name.replace(/\u2026+/g, ELLIPSIS); // Elide query params first if (name.length > MAX_LENGTH && name.includes('?')) { diff --git a/lighthouse-core/report/v2/report-styles.css b/lighthouse-core/report/v2/report-styles.css index 002753b81442..706732c0c520 100644 --- a/lighthouse-core/report/v2/report-styles.css +++ b/lighthouse-core/report/v2/report-styles.css @@ -744,13 +744,12 @@ span.lh-node:hover { font-size: large; } -.lh-text__url { +.lh-text { white-space: nowrap; } .lh-code { - text-overflow: ellipsis; - white-space: pre-line; + white-space: normal; margin-top: 0; } @@ -902,8 +901,9 @@ summary.lh-passed-audits-summary { --image-preview-size: 24px; border: 1px solid var(--report-secondary-border-color); border-collapse: collapse; - table-layout: fixed; width: 100%; + + --url-col-max-width: 450px; } .lh-table thead { @@ -916,8 +916,7 @@ summary.lh-passed-audits-summary { .lh-table th, .lh-table td { - padding: 10px; - overflow: auto; + padding: 8px 6px; } .lh-table-column--text { @@ -932,6 +931,31 @@ summary.lh-passed-audits-summary { text-align: left; min-width: 250px; white-space: nowrap; + max-width: var(--url-col-max-width); +} + +.lh-table-column--code { + max-width: var(--url-col-max-width); +} + +.lh-text__url { + overflow: hidden; + text-overflow: ellipsis; +} + +.lh-text__url:hover { + text-decoration: underline dotted #999; + text-decoration-skip-ink: auto; +} + +.lh-text__url > .lh-text, .lh-text__url-host { + display: inline; +} + +.lh-text__url-host { + margin-left: calc(var(--body-font-size) / 2); + opacity: 0.6; + font-size: 90% } .lh-thumbnail { diff --git a/lighthouse-core/test/audits/errors-in-console-test.js b/lighthouse-core/test/audits/errors-in-console-test.js index 15b5d91abd2c..c41b0c2dba20 100644 --- a/lighthouse-core/test/audits/errors-in-console-test.js +++ b/lighthouse-core/test/audits/errors-in-console-test.js @@ -86,18 +86,18 @@ describe('Console error logs audit', () => { assert.equal(auditResult.details.items.length, 3); assert.equal(auditResult.details.items[0][0].type, 'url'); assert.equal(auditResult.details.items[0][0].text, 'http://www.example.com/favicon.ico'); - assert.equal(auditResult.details.items[0][1].type, 'text'); + assert.equal(auditResult.details.items[0][1].type, 'code'); assert.equal(auditResult.details.items[0][1].text, 'The server responded with a status of 404 (Not Found)'); assert.equal(auditResult.details.items[1][0].type, 'url'); assert.equal(auditResult.details.items[1][0].text, 'http://www.example.com/wsconnect.ws'); - assert.equal(auditResult.details.items[1][1].type, 'text'); + assert.equal(auditResult.details.items[1][1].type, 'code'); assert.equal(auditResult.details.items[1][1].text, 'WebSocket connection failed: Unexpected response code: 500'); assert.equal(auditResult.details.items[2][0].type, 'url'); assert.equal(auditResult.details.items[2][0].text, 'http://example.com/fancybox.js'); - assert.equal(auditResult.details.items[2][1].type, 'text'); + assert.equal(auditResult.details.items[2][1].type, 'code'); assert.equal(auditResult.details.items[2][1].text, 'TypeError: Cannot read property \'msie\' of undefined'); }); diff --git a/lighthouse-core/test/lib/url-shim-test.js b/lighthouse-core/test/lib/url-shim-test.js index b07942bd85c6..8eba0d943f0e 100644 --- a/lighthouse-core/test/lib/url-shim-test.js +++ b/lighthouse-core/test/lib/url-shim-test.js @@ -123,6 +123,19 @@ describe('URL Shim', () => { assert.equal(result, '/file-f303dec\u2026-somethingmore.css'); }); + it('Elides google-fonts hashes', () => { + const url = 'https://fonts.gstatic.com/s/droidsans/v8/s-BiyweUPV0v-yRb-cjciAzyDMXhdD8sAj6OAJTFsBI.woff2'; + const result = URL.getURLDisplayName(url); + assert.equal(result, '\u2026v8/s-BiyweUP\u2026.woff2'); + }); + + it('Elides long number sequences', () => { + const url = 'http://cdn.cnn.com/cnnnext/dam/assets/150507173438-11-week-in-photos-0508-large-169.jpg'; + const result = URL.getURLDisplayName(url); + assert.equal(result, '\u2026assets/150\u2026-11-week-in-photos-0508-large-169.jpg'); + }); + + it('Elides query strings when can first parameter', () => { const url = 'http://example.com/file.css?aQueryString=true&other_long_query_stuff=false&some_other_super_long_query'; const result = URL.getURLDisplayName(url); @@ -145,7 +158,7 @@ describe('URL Shim', () => { const url = superLongName.slice(0, -3) + '-f303dec6eec305a4fab8025577db3c2feb418148ac75ba378281399fb1ba670b.css'; const result = URL.getURLDisplayName(url); - const expected = '/thisIsASuperLongURLThatWillTriggerFilenameTruncationWhichW\u2026.css'; + const expected = '/thisIsASu\u2026.css'; assert.equal(result, expected); }); diff --git a/lighthouse-core/test/report/v2/renderer/details-renderer-test.js b/lighthouse-core/test/report/v2/renderer/details-renderer-test.js index 96075f13693b..995361a13dce 100644 --- a/lighthouse-core/test/report/v2/renderer/details-renderer-test.js +++ b/lighthouse-core/test/report/v2/renderer/details-renderer-test.js @@ -216,7 +216,7 @@ describe('DetailsRenderer', () => { it('renders text URLs', () => { const urlText = 'https://example.com/'; - const displayUrlText = '/'; + const displayUrlText = '/(example.com)'; const el = renderer.render({ type: 'url', text: urlText, @@ -224,7 +224,7 @@ describe('DetailsRenderer', () => { assert.equal(el.localName, 'div'); assert.equal(el.textContent, displayUrlText); - assert.ok(el.classList.contains('lh-text'), 'adds classes'); + assert.ok(el.classList.contains('lh-text__url'), 'adds classes'); }); }); });