diff --git a/lighthouse-cli/test/fixtures/dobetterweb/domtester.html b/lighthouse-cli/test/fixtures/dobetterweb/domtester.html deleted file mode 100644 index dbbf2694e0d4..000000000000 --- a/lighthouse-cli/test/fixtures/dobetterweb/domtester.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - DoBetterWeb - DOM size tester - - - - -
-
-
-
6
-
-
-
-
7
-
-
-
- -
-
-
- - - - \ No newline at end of file diff --git a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js index 69c346a7e828..897cdabfe772 100644 --- a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js +++ b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js @@ -186,94 +186,6 @@ module.exports = [ }, }, }, - }, { - initialUrl: 'http://localhost:10200/dobetterweb/domtester.html?smallDOM', - url: 'http://localhost:10200/dobetterweb/domtester.html?smallDOM', - audits: { - 'dom-size': { - score: 1, - extendedInfo: { - value: { - 0: {value: '1,324'}, - 1: {value: '7'}, - 2: {value: '1,303'}, - }, - }, - details: { - items: { - 0: {value: '1,324'}, - 1: {value: '7'}, - 2: {value: '1,303'}, - }, - }, - }, - }, - }, { - initialUrl: 'http://localhost:10200/dobetterweb/domtester.html?largeDOM&withShadowDOM', - url: 'http://localhost:10200/dobetterweb/domtester.html?largeDOM&withShadowDOM', - audits: { - 'dom-size': { - score: 0, - extendedInfo: { - value: { - 0: {value: '6,037'}, - 1: {value: '9'}, - 2: {value: '6,003'}, - }, - }, - details: { - items: { - 0: {value: '6,037'}, - 1: {value: '9'}, - 2: {value: '6,003'}, - }, - }, - }, - }, - }, { - initialUrl: 'http://localhost:10200/dobetterweb/domtester.html?withShadowDOM', - url: 'http://localhost:10200/dobetterweb/domtester.html?withShadowDOM', - audits: { - 'dom-size': { - score: 1, - extendedInfo: { - value: { - 0: {value: '37'}, - 1: {value: '9'}, - 2: {value: '9'}, - }, - }, - details: { - items: { - 0: {value: '37'}, - 1: {value: '9'}, - 2: {value: '9'}, - }, - }, - }, - }, - }, { - initialUrl: 'http://localhost:10200/dobetterweb/domtester.html?ShadowRootWithManyChildren', - url: 'http://localhost:10200/dobetterweb/domtester.html?ShadowRootWithManyChildren', - audits: { - 'dom-size': { - score: 1, - extendedInfo: { - value: { - 0: {value: '33'}, - 1: {value: '7'}, - 2: {value: '9'}, - }, - }, - details: { - items: { - 0: {value: '33'}, - 1: {value: '7'}, - 2: {value: '9'}, - }, - }, - }, - }, }, { initialUrl: 'http://localhost:10200/online-only.html', url: 'http://localhost:10200/online-only.html', diff --git a/lighthouse-core/audits/accessibility/axe-audit.js b/lighthouse-core/audits/accessibility/axe-audit.js index 14182df4c3b1..8718dcd44907 100644 --- a/lighthouse-core/audits/accessibility/axe-audit.js +++ b/lighthouse-core/audits/accessibility/axe-audit.js @@ -34,29 +34,28 @@ class AxeAudit extends Audit { const violations = artifacts.Accessibility.violations || []; const rule = violations.find(result => result.id === this.meta.name); - let nodeDetails = []; + let items = []; if (rule && rule.nodes) { - nodeDetails = rule.nodes.map(node => ({ - type: 'node', - selector: Array.isArray(node.target) ? node.target.join(' ') : '', - path: node.path, - snippet: node.snippet, + items = rule.nodes.map(node => ({ + node: { + type: 'node', + selector: Array.isArray(node.target) ? node.target.join(' ') : '', + path: node.path, + snippet: node.snippet, + }, })); } + const headings = [ + {key: 'node', itemType: 'node', text: 'Failing Elements'}, + ]; + return { rawValue: typeof rule === 'undefined', extendedInfo: { value: rule, }, - details: { - type: 'list', - header: { - type: 'text', - text: 'View failing elements', - }, - items: nodeDetails, - }, + details: Audit.makeTableDetails(headings, items), }; } } diff --git a/lighthouse-core/audits/dobetterweb/dom-size.js b/lighthouse-core/audits/dobetterweb/dom-size.js index 5e7dcaa0a9a8..6499ee118c43 100644 --- a/lighthouse-core/audits/dobetterweb/dom-size.js +++ b/lighthouse-core/audits/dobetterweb/dom-size.js @@ -47,6 +47,7 @@ class DOMSize extends Audit { }; } + /** * @param {!Artifacts} artifacts * @return {!AuditResult} @@ -54,18 +55,6 @@ class DOMSize extends Audit { static audit(artifacts) { const stats = artifacts.DOMStats; - /** - * html > - * body > - * div > - * span - */ - const depthSnippet = stats.depth.pathToElement.reduce((str, curr, i) => { - return `${str}\n` + ' '.repeat(i) + `${curr} >`; - }, '').replace(/>$/g, '').trim(); - const widthSnippet = 'Element with most children:\n' + - stats.width.pathToElement[stats.width.pathToElement.length - 1]; - // Use the CDF of a log-normal distribution for scoring. // <= 1500: score≈1 // 3000: score=0.5 @@ -76,34 +65,33 @@ class DOMSize extends Audit { SCORING_MEDIAN ); - const cards = [{ - title: 'Total DOM Nodes', - value: Util.formatNumber(stats.totalDOMNodes), - target: `< ${Util.formatNumber(MAX_DOM_NODES)} nodes`, - }, { - title: 'DOM Depth', - value: Util.formatNumber(stats.depth.max), - snippet: depthSnippet, - target: `< ${Util.formatNumber(MAX_DOM_TREE_DEPTH)}`, - }, { - title: 'Maximum Children', - value: Util.formatNumber(stats.width.max), - snippet: widthSnippet, - target: `< ${Util.formatNumber(MAX_DOM_TREE_WIDTH)} nodes`, - }]; + const headings = [ + {key: 'totalNodes', itemType: 'text', text: 'Total DOM Nodes'}, + {key: 'depth', itemType: 'text', text: 'Maximum DOM Depth'}, + {key: 'width', itemType: 'text', text: 'Maximum Children'}, + ]; + + const items = [ + { + totalNodes: Util.formatNumber(stats.totalDOMNodes), + depth: Util.formatNumber(stats.depth.max), + width: Util.formatNumber(stats.width.max), + }, + { + totalNodes: '', + depth: stats.depth.snippet, + width: stats.width.snippet, + }, + ]; return { score, rawValue: stats.totalDOMNodes, displayValue: `${Util.formatNumber(stats.totalDOMNodes)} nodes`, extendedInfo: { - value: cards, - }, - details: { - type: 'cards', - header: {type: 'text', text: 'View details'}, - items: cards, + value: items, }, + details: Audit.makeTableDetails(headings, items), }; } } diff --git a/lighthouse-core/audits/dobetterweb/password-inputs-can-be-pasted-into.js b/lighthouse-core/audits/dobetterweb/password-inputs-can-be-pasted-into.js index 1affd909acc7..e4d1ded4e348 100644 --- a/lighthouse-core/audits/dobetterweb/password-inputs-can-be-pasted-into.js +++ b/lighthouse-core/audits/dobetterweb/password-inputs-can-be-pasted-into.js @@ -29,22 +29,20 @@ class PasswordInputsCanBePastedIntoAudit extends Audit { static audit(artifacts) { const passwordInputsWithPreventedPaste = artifacts.PasswordInputsWithPreventedPaste; + const items = passwordInputsWithPreventedPaste.map(input => ({ + node: {type: 'node', snippet: input.snippet}, + })); + + const headings = [ + {key: 'node', itemType: 'node', text: 'Failing Elements'}, + ]; + return { rawValue: passwordInputsWithPreventedPaste.length === 0, extendedInfo: { value: passwordInputsWithPreventedPaste, }, - details: { - type: 'list', - header: { - type: 'text', - value: 'Password inputs that prevent pasting into', - }, - items: passwordInputsWithPreventedPaste.map(input => ({ - type: 'text', - value: input.snippet, - })), - }, + details: Audit.makeTableDetails(headings, items), }; } } diff --git a/lighthouse-core/audits/is-on-https.js b/lighthouse-core/audits/is-on-https.js index 58abc2f2fdb2..4221ac99351f 100644 --- a/lighthouse-core/audits/is-on-https.js +++ b/lighthouse-core/audits/is-on-https.js @@ -58,17 +58,21 @@ class HTTPS extends Audit { displayValue = `${insecureRecords.length} insecure request found`; } + const items = insecureRecords.map(record => ({ + url: record.url, + })); + + const headings = [ + {key: 'url', itemType: 'url', text: 'Insecure URL'}, + ]; + return { rawValue: insecureRecords.length === 0, displayValue, extendedInfo: { value: insecureRecords, }, - details: { - type: 'list', - header: {type: 'text', text: 'Insecure URLs:'}, - items: insecureRecords.map(record => ({type: 'url', value: record.url})), - }, + details: Audit.makeTableDetails(headings, items), }; }); } diff --git a/lighthouse-core/gather/gatherers/dobetterweb/domstats.js b/lighthouse-core/gather/gatherers/dobetterweb/domstats.js index 7692a305dab4..36a45c030387 100644 --- a/lighthouse-core/gather/gatherers/dobetterweb/domstats.js +++ b/lighthouse-core/gather/gatherers/dobetterweb/domstats.js @@ -15,6 +15,17 @@ const Gatherer = require('../gatherer'); +/** + * Gets the opening tag text of the given node. + * @param {!Node} + * @return {string} + */ +function getOuterHTMLSnippet(node) { + const reOpeningTag = /^.*?>/; + const match = node.outerHTML.match(reOpeningTag); + return match && match[0]; +} + /** * Constructs a pretty label from element's selectors. For example, given *
, returns 'div#myid.myclass'. @@ -118,10 +129,12 @@ function getDOMStats(element, deep=true) { depth: { max: result.maxDepth, pathToElement: elementPathInDOM(deepestNode), + snippet: getOuterHTMLSnippet(deepestNode), }, width: { max: result.maxWidth, pathToElement: elementPathInDOM(parentWithMostChildren), + snippet: getOuterHTMLSnippet(parentWithMostChildren), }, }; } @@ -133,6 +146,7 @@ class DOMStats extends Gatherer { */ afterPass(options) { const expression = `(function() { + ${getOuterHTMLSnippet.toString()}; ${createSelectorsLabel.toString()}; ${elementPathInDOM.toString()}; return (${getDOMStats.toString()}(document.documentElement)); diff --git a/lighthouse-core/report/v2/renderer/details-renderer.js b/lighthouse-core/report/v2/renderer/details-renderer.js index bbc714102136..98a476191346 100644 --- a/lighthouse-core/report/v2/renderer/details-renderer.js +++ b/lighthouse-core/report/v2/renderer/details-renderer.js @@ -46,8 +46,6 @@ class DetailsRenderer { return this._renderThumbnail(/** @type {!DetailsRenderer.ThumbnailDetails} */ (details)); case 'filmstrip': return this._renderFilmstrip(/** @type {!DetailsRenderer.FilmstripDetails} */ (details)); - case 'cards': - return this._renderCards(/** @type {!DetailsRenderer.CardsDetailsJSON} */ (details)); case 'table': return this._renderTable(/** @type {!DetailsRenderer.TableDetailsJSON} */ (details)); case 'code': @@ -57,8 +55,6 @@ class DetailsRenderer { case 'criticalrequestchain': return CriticalRequestChainRenderer.render(this._dom, this._templateContext, /** @type {!CriticalRequestChainRenderer.CRCDetailsJSON} */ (details)); - case 'list': - return this._renderList(/** @type {!DetailsRenderer.ListDetailsJSON} */ (details)); default: { throw new Error(`Unknown type: ${details.type}`); } @@ -177,24 +173,6 @@ class DetailsRenderer { return element; } - /** - * @param {!DetailsRenderer.ListDetailsJSON} list - * @return {!Element} - */ - _renderList(list) { - if (!list.items.length) return this._dom.createElement('span'); - - const element = this._dom.createElement('details', 'lh-details'); - element.open = true; - - const itemsElem = this._dom.createChildOf(element, 'div', 'lh-list__items'); - for (const item of list.items) { - const itemElem = this._dom.createChildOf(itemsElem, 'span', 'lh-list__item'); - itemElem.appendChild(this.render(item)); - } - return element; - } - /** * @param {!DetailsRenderer.TableDetailsJSON} details * @return {!Element} @@ -266,37 +244,6 @@ class DetailsRenderer { return element; } - /** - * @param {!DetailsRenderer.CardsDetailsJSON} details - * @return {!Element} - */ - _renderCards(details) { - const element = this._dom.createElement('details', 'lh-details'); - element.open = true; - if (details.header) { - element.appendChild(this._dom.createElement('summary')).textContent = details.header.text; - } - - const cardsParent = this._dom.createElement('div', 'lh-scorecards'); - for (const item of details.items) { - const card = cardsParent.appendChild( - this._dom.createElement('div', 'lh-scorecard', {title: item.snippet})); - const titleEl = this._dom.createElement('div', 'lh-scorecard__title'); - const valueEl = this._dom.createElement('div', 'lh-scorecard__value'); - const targetEl = this._dom.createElement('div', 'lh-scorecard__target'); - - card.appendChild(titleEl).textContent = item.title; - card.appendChild(valueEl).textContent = item.value; - - if (item.target) { - card.appendChild(targetEl).textContent = `target: ${item.target}`; - } - } - - element.appendChild(cardsParent); - return element; - } - /** * @param {!DetailsRenderer.FilmstripDetails} details * @return {!Element} @@ -354,16 +301,6 @@ if (typeof module !== 'undefined' && module.exports) { */ DetailsRenderer.DetailsJSON; // eslint-disable-line no-unused-expressions -/** - * @typedef {{ - * type: string, - * header: ({text: string}|undefined), - * items: !Array - * }} - */ -DetailsRenderer.ListDetailsJSON; // eslint-disable-line no-unused-expressions - - /** * @typedef {{ * type: string, @@ -395,14 +332,6 @@ DetailsRenderer.NumericUnitDetailsJSON; // eslint-disable-line no-unused-express */ DetailsRenderer.NodeDetailsJSON; // eslint-disable-line no-unused-expressions -/** @typedef {{ - * type: string, - * header: ({text: string}|undefined), - * items: !Array<{title: string, value: string, snippet: (string|undefined), target: string}> - * }} - */ -DetailsRenderer.CardsDetailsJSON; // eslint-disable-line no-unused-expressions - /** * @typedef {{ * itemType: string, diff --git a/lighthouse-core/report/v2/report-styles.css b/lighthouse-core/report/v2/report-styles.css index bdb85b941fc6..cde7b628d4a0 100644 --- a/lighthouse-core/report/v2/report-styles.css +++ b/lighthouse-core/report/v2/report-styles.css @@ -167,20 +167,6 @@ summary { background-image: url('data:image/svg+xml;utf8,'); } -/* List */ -.lh-list { - font-size: smaller; - margin-top: var(--default-padding); -} - -.lh-list__items { - padding-left: var(--default-padding); -} - -.lh-list__item { - margin-bottom: 2px; -} - /* Node */ .lh-node { display: block; @@ -193,43 +179,6 @@ span.lh-node:hover { border-radius: 2px; } -/* Card */ -.lh-scorecards { - display: flex; - flex-wrap: wrap; -} -.lh-scorecard { - display: flex; - align-items: center; - justify-content: center; - flex: 0 0 calc(12 * var(--body-font-size)); - flex-direction: column; - padding: var(--default-padding); - padding-top: calc(32px + var(--default-padding)); - border-radius: 3px; - margin-right: var(--default-padding); - position: relative; - line-height: inherit; - border: 1px solid #ebebeb; -} -.lh-scorecard__title { - background-color: #eee; - position: absolute; - top: 0; - right: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - padding: calc(var(--default-padding) / 2); -} -.lh-scorecard__value { - font-size: calc(1.6 * var(--body-font-size)); -} -.lh-scorecard__target { - margin-top: calc(var(--default-padding) / 2); -} - /* Score */ .lh-score { diff --git a/lighthouse-core/test/audits/dobetterweb/dom-size-test.js b/lighthouse-core/test/audits/dobetterweb/dom-size-test.js index bc7e4b2c0a2c..a0eb9572c889 100644 --- a/lighthouse-core/test/audits/dobetterweb/dom-size-test.js +++ b/lighthouse-core/test/audits/dobetterweb/dom-size-test.js @@ -20,23 +20,14 @@ describe('Num DOM nodes audit', () => { }, }; - const snippet = 'html >\n' + - ' body >\n' + - ' div >\n' + - ' span'; - it('calculates score hitting top of distribution', () => { const auditResult = DOMSize.audit(artifact); assert.equal(auditResult.score, 1); assert.equal(auditResult.rawValue, numNodes); assert.equal(auditResult.displayValue, `${numNodes.toLocaleString()} nodes`); - assert.equal(auditResult.details.items[0].title, 'Total DOM Nodes'); - assert.equal(auditResult.details.items[0].value, numNodes.toLocaleString()); - assert.equal(auditResult.details.items[1].title, 'DOM Depth'); - assert.equal(auditResult.details.items[1].value, 1); - assert.equal(auditResult.details.items[1].snippet, snippet, 'generates snippet'); - assert.equal(auditResult.details.items[2].title, 'Maximum Children'); - assert.equal(auditResult.details.items[2].value, 2); + assert.equal(auditResult.details.items[0].totalNodes, numNodes.toLocaleString()); + assert.equal(auditResult.details.items[0].depth, '1'); + assert.equal(auditResult.details.items[0].width, '2'); }); it('calculates score hitting mid distribution', () => { 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 732127cd5bbe..167b266cc2de 100644 --- a/lighthouse-core/test/report/v2/renderer/details-renderer-test.js +++ b/lighthouse-core/test/report/v2/renderer/details-renderer-test.js @@ -40,49 +40,6 @@ describe('DetailsRenderer', () => { assert.ok(el.classList.contains('lh-text'), 'adds classes'); }); - it('renders lists without headers', () => { - const el = renderer.render({ - type: 'list', - items: [ - {type: 'text', value: 'content 1'}, - {type: 'text', value: 'content 2'}, - {type: 'text', value: 'content 3'}, - ], - }); - - const header = el.querySelector('.lh-list__header'); - assert.ok(!header, 'rendered header'); - - const items = el.querySelector('.lh-list__items'); - assert.equal(items.children.length, 3, 'did not render children'); - }); - - it('renders cards', () => { - const list = { - header: {type: 'text', value: 'View details'}, - items: [ - {title: 'Total DOM Nodes', value: 3500, target: '1,500 nodes'}, - {title: 'DOM Depth', value: 10, snippet: 'snippet'}, - {title: 'Maximum Children', value: 20, snippet: 'snippet2', target: 20}, - ], - }; - - const details = renderer._renderCards(list); - - const cards = details.querySelectorAll('.lh-scorecards > .lh-scorecard'); - assert.ok(cards.length, list.items.length, `renders ${list.items.length} cards`); - assert.equal(cards[0].hasAttribute('title'), false, - 'does not add title attr if snippet is missing'); - assert.equal(cards[0].querySelector('.lh-scorecard__title').textContent, - 'Total DOM Nodes', 'fills title'); - assert.equal(cards[0].querySelector('.lh-scorecard__value').textContent, - '3500', 'fills value'); - assert.equal(cards[0].querySelector('.lh-scorecard__target').textContent, - 'target: 1,500 nodes', 'fills target'); - assert.equal(cards[1].getAttribute('title'), 'snippet', 'adds title attribute for snippet'); - assert.ok(!cards[1].querySelector('.lh-scorecard__target'), 'handles missing target'); - }); - it('renders code', () => { const el = renderer.render({ type: 'code', diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json index 65124d657ac0..e9268ecb279b 100644 --- a/lighthouse-core/test/results/sample_v2.json +++ b/lighthouse-core/test/results/sample_v2.json @@ -23,15 +23,17 @@ "description": "Does not use HTTPS", "helpText": "All sites should be protected with HTTPS, even ones that don't handle sensitive data. HTTPS prevents intruders from tampering with or passively listening in on the communications between your app and your users, and is a prerequisite for HTTP/2 and many new web platform APIs. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/https).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "Insecure URLs:" - }, + "type": "table", + "headings": [ + { + "key": "url", + "itemType": "url", + "text": "Insecure URL" + } + ], "items": [ { - "type": "url", - "value": "http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js" + "url": "http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js" } ] } @@ -1746,11 +1748,8 @@ "description": "The page contains a heading, skip link, or landmark region", "helpText": "Adding ways to bypass repetitive content lets keyboard users navigate the page more efficiently. [Learn more](https://dequeuniversity.com/rules/axe/2.2/bypass?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [], "items": [] } }, @@ -1799,23 +1798,30 @@ "description": "Background and foreground colors do not have a sufficient contrast ratio.", "helpText": "Low-contrast text is difficult or impossible for many users to read. [Learn more](https://dequeuniversity.com/rules/axe/2.2/color-contrast?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [ + { + "key": "node", + "itemType": "node", + "text": "Failing Elements" + } + ], "items": [ { - "type": "node", - "selector": "div > h2", - "path": "3,HTML,1,BODY,0,DIV,0,H2", - "snippet": "

" + "node": { + "type": "node", + "selector": "div > h2", + "path": "3,HTML,1,BODY,0,DIV,0,H2", + "snippet": "

" + } }, { - "type": "node", - "selector": "div > span", - "path": "3,HTML,1,BODY,0,DIV,1,SPAN", - "snippet": "" + "node": { + "type": "node", + "selector": "div > span", + "path": "3,HTML,1,BODY,0,DIV,1,SPAN", + "snippet": "" + } } ] } @@ -1852,11 +1858,8 @@ "description": "Document has a `` element", "helpText": "The title gives screen reader users an overview of the page, and search engine users rely on it heavily to determine if a page is relevant to their search. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/title).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [], "items": [] } }, @@ -1870,11 +1873,8 @@ "description": "`[id]` attributes on the page are unique", "helpText": "The value of an id attribute must be unique to prevent other instances from being overlooked by assistive technologies. [Learn more](https://dequeuniversity.com/rules/axe/2.2/duplicate-id?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [], "items": [] } }, @@ -1924,17 +1924,22 @@ "description": "`<html>` element does not have a `[lang]` attribute", "helpText": "If a page doesn't specify a lang attribute, a screen reader assumes that the page is in the default language that the user chose when setting up the screen reader. If the page isn't actually in the default language, then the screen reader might not announce the page's text correctly. [Learn more](https://dequeuniversity.com/rules/axe/2.2/html-lang?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [ + { + "key": "node", + "itemType": "node", + "text": "Failing Elements" + } + ], "items": [ { - "type": "node", - "selector": "html", - "path": "3,HTML", - "snippet": "<html manifest=\"clock.appcache\">" + "node": { + "type": "node", + "selector": "html", + "path": "3,HTML", + "snippet": "<html manifest=\"clock.appcache\">" + } } ] } @@ -2007,29 +2012,38 @@ "description": "Image elements do not have `[alt]` attributes", "helpText": "Informative elements should aim for short, descriptive alternate text. Decorative elements can be ignored with an empty alt attribute.[Learn more](https://dequeuniversity.com/rules/axe/2.2/image-alt?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [ + { + "key": "node", + "itemType": "node", + "text": "Failing Elements" + } + ], "items": [ { - "type": "node", - "selector": "body > img[src$=\"lighthouse-480x318.jpg\"]:nth-child(5)", - "path": "3,HTML,1,BODY,5,IMG", - "snippet": "<img src=\"lighthouse-480x318.jpg\" width=\"480\" height=\"57\">" + "node": { + "type": "node", + "selector": "body > img[src$=\"lighthouse-480x318.jpg\"]:nth-child(5)", + "path": "3,HTML,1,BODY,5,IMG", + "snippet": "<img src=\"lighthouse-480x318.jpg\" width=\"480\" height=\"57\">" + } }, { - "type": "node", - "selector": "body > img[src$=\"lighthouse-480x318.jpg\"]:nth-child(6)", - "path": "3,HTML,1,BODY,7,IMG", - "snippet": "<img src=\"lighthouse-480x318.jpg\" width=\"480\" height=\"318\">" + "node": { + "type": "node", + "selector": "body > img[src$=\"lighthouse-480x318.jpg\"]:nth-child(6)", + "path": "3,HTML,1,BODY,7,IMG", + "snippet": "<img src=\"lighthouse-480x318.jpg\" width=\"480\" height=\"318\">" + } }, { - "type": "node", - "selector": "body > img:nth-child(20)", - "path": "3,HTML,1,BODY,36,IMG", - "snippet": "<img src=\"blob:http://localhost:10200/ae0eac03-ab9b-4a6a-b299-f5212153e277\">" + "node": { + "type": "node", + "selector": "body > img:nth-child(20)", + "path": "3,HTML,1,BODY,36,IMG", + "snippet": "<img src=\"blob:http://localhost:10200/ae0eac03-ab9b-4a6a-b299-f5212153e277\">" + } } ] } @@ -2103,29 +2117,38 @@ "description": "Form elements do not have associated labels", "helpText": "Labels ensure that form controls are announced properly by assistive technologies, like screen readers. [Learn more](https://dequeuniversity.com/rules/axe/2.2/label?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [ + { + "key": "node", + "itemType": "node", + "text": "Failing Elements" + } + ], "items": [ { - "type": "node", - "selector": "body > input[type=\"password\"]:nth-child(17)", - "path": "3,HTML,1,BODY,31,INPUT", - "snippet": "<input type=\"password\" onpaste=\"event.preventDefault();\">" + "node": { + "type": "node", + "selector": "body > input[type=\"password\"]:nth-child(17)", + "path": "3,HTML,1,BODY,31,INPUT", + "snippet": "<input type=\"password\" onpaste=\"event.preventDefault();\">" + } }, { - "type": "node", - "selector": "body > input[type=\"password\"]:nth-child(18)", - "path": "3,HTML,1,BODY,33,INPUT", - "snippet": "<input type=\"password\">" + "node": { + "type": "node", + "selector": "body > input[type=\"password\"]:nth-child(18)", + "path": "3,HTML,1,BODY,33,INPUT", + "snippet": "<input type=\"password\">" + } }, { - "type": "node", - "selector": "body > input[type=\"password\"]:nth-child(19)", - "path": "3,HTML,1,BODY,35,INPUT", - "snippet": "<input type=\"password\" onpaste=\"return false;\">" + "node": { + "type": "node", + "selector": "body > input[type=\"password\"]:nth-child(19)", + "path": "3,HTML,1,BODY,35,INPUT", + "snippet": "<input type=\"password\" onpaste=\"return false;\">" + } } ] } @@ -2190,23 +2213,30 @@ "description": "Links do not have a discernible name", "helpText": "Link text (and alternate text for images, when used as links) that is discernible, unique, and focusable improves the navigation experience for screen reader users. [Learn more](https://dequeuniversity.com/rules/axe/2.2/link-name?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [ + { + "key": "node", + "itemType": "node", + "text": "Failing Elements" + } + ], "items": [ { - "type": "node", - "selector": "body > a:nth-child(15)", - "path": "3,HTML,1,BODY,27,A", - "snippet": "<a href=\"javascript:void(0)\" target=\"_blank\">" + "node": { + "type": "node", + "selector": "body > a:nth-child(15)", + "path": "3,HTML,1,BODY,27,A", + "snippet": "<a href=\"javascript:void(0)\" target=\"_blank\">" + } }, { - "type": "node", - "selector": "body > a[href$=\"mailto:inbox@email.com\"]", - "path": "3,HTML,1,BODY,29,A", - "snippet": "<a href=\"mailto:inbox@email.com\" target=\"_blank\">" + "node": { + "type": "node", + "selector": "body > a[href$=\"mailto:inbox@email.com\"]", + "path": "3,HTML,1,BODY,29,A", + "snippet": "<a href=\"mailto:inbox@email.com\" target=\"_blank\">" + } } ] } @@ -2254,11 +2284,8 @@ "description": "`[user-scalable=\"no\"]` is not used in the `<meta name=\"viewport\">` element and the `[maximum-scale]` attribute is not less than 5.", "helpText": "Disabling zooming is problematic for users with low vision who rely on screen magnification to properly see the contents of a web page. [Learn more](https://dequeuniversity.com/rules/axe/2.2/meta-viewport?application=lighthouse).", "details": { - "type": "list", - "header": { - "type": "text", - "text": "View failing elements" - }, + "type": "table", + "headings": [], "items": [] } }, @@ -3151,21 +3178,12 @@ "extendedInfo": { "value": [ { - "title": "Total DOM Nodes", - "value": "53", - "target": "< 1,500 nodes" + "totalNodes": "53", + "depth": "4", + "width": "22" }, { - "title": "DOM Depth", - "value": "4", - "snippet": "html >\n body >\n div >\n h2", - "target": "< 32" - }, - { - "title": "Maximum Children", - "value": "22", - "snippet": "Element with most children:\nbody", - "target": "< 60 nodes" + "totalNodes": "" } ] }, @@ -3174,28 +3192,32 @@ "description": "Avoids an excessive DOM size", "helpText": "Browser engineers recommend pages contain fewer than ~1,500 DOM nodes. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory usage, cause longer [style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/fundamentals/performance/rendering/).", "details": { - "type": "cards", - "header": { - "type": "text", - "text": "View details" - }, - "items": [ + "type": "table", + "headings": [ { - "title": "Total DOM Nodes", - "value": "53", - "target": "< 1,500 nodes" + "key": "totalNodes", + "itemType": "text", + "text": "Total DOM Nodes" }, { - "title": "DOM Depth", - "value": "4", - "snippet": "html >\n body >\n div >\n h2", - "target": "< 32" + "key": "depth", + "itemType": "text", + "text": "Maximum DOM Depth" }, { - "title": "Maximum Children", - "value": "22", - "snippet": "Element with most children:\nbody", - "target": "< 60 nodes" + "key": "width", + "itemType": "text", + "text": "Maximum Children" + } + ], + "items": [ + { + "totalNodes": "53", + "depth": "4", + "width": "22" + }, + { + "totalNodes": "" } ] } @@ -4061,19 +4083,26 @@ "description": "Prevents users to paste into password fields", "helpText": "Preventing password pasting undermines good security policy. [Learn more](https://www.ncsc.gov.uk/blog-post/let-them-paste-passwords)", "details": { - "type": "list", - "header": { - "type": "text", - "value": "Password inputs that prevent pasting into" - }, + "type": "table", + "headings": [ + { + "key": "node", + "itemType": "node", + "text": "Failing Elements" + } + ], "items": [ { - "type": "text", - "value": "<input type=\"password\" onpaste=\"event.preventDefault();\">" + "node": { + "type": "node", + "snippet": "<input type=\"password\" onpaste=\"event.preventDefault();\">" + } }, { - "type": "text", - "value": "<input type=\"password\" onpaste=\"return false;\">" + "node": { + "type": "node", + "snippet": "<input type=\"password\" onpaste=\"return false;\">" + } } ] } @@ -4509,7 +4538,7 @@ "scoreDisplayMode": "binary", "name": "font-size", "description": "Document uses legible font sizes", - "helpText": "Font sizes less than 12px are too small to be legible and require mobile visitors to “pinch to zoom” in order to read. Strive to have >60% of page text ≥12px. [Learn more](https://developers.google.com/web/fundamentals/design-and-ux/responsive/#optimize_text_for_reading).", + "helpText": "Font sizes less than 12px are too small to be legible and require mobile visitors to “pinch to zoom” in order to read. Strive to have >60% of page text ≥12px. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/font-sizes).", "details": { "type": "table", "headings": [ @@ -4551,7 +4580,7 @@ "scoreDisplayMode": "binary", "name": "link-text", "description": "Links have descriptive text", - "helpText": "Descriptive link text helps search engines understand your content. [Learn more](https://webmasters.googleblog.com/2008/10/importance-of-link-architecture.html).", + "helpText": "Descriptive link text helps search engines understand your content. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/descriptive-link-text).", "details": { "type": "table", "headings": [], @@ -5312,6 +5341,6 @@ } }, "timing": { - "total": 1098 + "total": 1227 } } \ No newline at end of file