lighthouse 8.6.0-dev.20211023 → 8.6.0-dev.20211027
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/report/flow.js +10 -10
- package/dist/report/standalone.js +2 -2
- package/flow-report/assets/styles.css +57 -1
- package/flow-report/src/i18n/ui-strings.js +2 -0
- package/flow-report/src/summary/category.tsx +73 -4
- package/flow-report/src/summary/summary.tsx +1 -0
- package/flow-report/src/wrappers/markdown.tsx +27 -0
- package/flow-report/test/summary/category-test.tsx +111 -19
- package/flow-report/test/wrappers/markdown-test.tsx +29 -0
- package/jest.config.js +2 -2
- package/lighthouse-core/audits/byte-efficiency/modern-image-formats.js +4 -2
- package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +11 -10
- package/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js +5 -3
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images-snapshot.js +2 -1
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +2 -1
- package/lighthouse-core/audits/image-aspect-ratio.js +4 -3
- package/lighthouse-core/audits/image-size-responsive.js +3 -2
- package/lighthouse-core/audits/preload-lcp-image.js +7 -5
- package/lighthouse-core/audits/script-treemap-data.js +1 -1
- package/lighthouse-core/audits/unsized-images.js +1 -2
- package/package.json +6 -5
- package/report/renderer/category-renderer.js +7 -0
- package/report/renderer/pwa-category-renderer.js +0 -10
- package/report/renderer/report-renderer.js +1 -1
- package/report/test/renderer/category-renderer-test.js +41 -0
- package/report/test/renderer/pwa-category-renderer-test.js +4 -4
- package/report/test/renderer/text-encoding-test.js +1 -1
- package/shared/localization/locales/ar-XB.json +8 -8
- package/shared/localization/locales/ar.json +8 -8
- package/shared/localization/locales/bg.json +8 -8
- package/shared/localization/locales/ca.json +8 -8
- package/shared/localization/locales/cs.json +8 -8
- package/shared/localization/locales/da.json +8 -8
- package/shared/localization/locales/de.json +8 -8
- package/shared/localization/locales/el.json +8 -8
- package/shared/localization/locales/en-GB.json +8 -8
- package/shared/localization/locales/en-US.json +27 -24
- package/shared/localization/locales/en-XA.json +8 -8
- package/shared/localization/locales/en-XL.json +27 -24
- package/shared/localization/locales/es-419.json +8 -8
- package/shared/localization/locales/es.json +8 -8
- package/shared/localization/locales/fi.json +8 -8
- package/shared/localization/locales/fil.json +8 -8
- package/shared/localization/locales/fr.json +8 -8
- package/shared/localization/locales/he.json +8 -8
- package/shared/localization/locales/hi.json +8 -8
- package/shared/localization/locales/hr.json +8 -8
- package/shared/localization/locales/hu.json +8 -8
- package/shared/localization/locales/id.json +8 -8
- package/shared/localization/locales/it.json +8 -8
- package/shared/localization/locales/ja.json +8 -8
- package/shared/localization/locales/ko.json +8 -8
- package/shared/localization/locales/lt.json +8 -8
- package/shared/localization/locales/lv.json +8 -8
- package/shared/localization/locales/nl.json +8 -8
- package/shared/localization/locales/no.json +8 -8
- package/shared/localization/locales/pl.json +8 -8
- package/shared/localization/locales/pt-PT.json +8 -8
- package/shared/localization/locales/pt.json +8 -8
- package/shared/localization/locales/ro.json +8 -8
- package/shared/localization/locales/ru.json +8 -8
- package/shared/localization/locales/sk.json +8 -8
- package/shared/localization/locales/sl.json +8 -8
- package/shared/localization/locales/sr-Latn.json +8 -8
- package/shared/localization/locales/sr.json +8 -8
- package/shared/localization/locales/sv.json +8 -8
- package/shared/localization/locales/ta.json +8 -8
- package/shared/localization/locales/te.json +8 -8
- package/shared/localization/locales/th.json +8 -8
- package/shared/localization/locales/tr.json +8 -8
- package/shared/localization/locales/uk.json +8 -8
- package/shared/localization/locales/vi.json +8 -8
- package/shared/localization/locales/zh-HK.json +8 -8
- package/shared/localization/locales/zh-TW.json +8 -8
- package/shared/localization/locales/zh.json +8 -8
- package/tsconfig-all.json +2 -2
- package/types/lhr/audit-details.d.ts +5 -5
|
@@ -63,7 +63,7 @@ class s{constructor(e){this._document=e,this._lighthouseChannel="unknown",this._
|
|
|
63
63
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
64
64
|
* See the License for the specific language governing permissions and
|
|
65
65
|
* limitations under the License.
|
|
66
|
-
*/class d{constructor(e,t){this.dom=e,this.detailsRenderer=t}get _clumpTitles(){return{warning:l.i18n.strings.warningAuditsGroupTitle,manual:l.i18n.strings.manualAuditsGroupTitle,passed:l.i18n.strings.passedAuditsGroupTitle,notApplicable:l.i18n.strings.notApplicableAuditsGroupTitle}}renderAudit(e){const t=this.dom.createComponent("audit");return this.populateAuditValues(e,t)}populateAuditValues(e,t){const n=l.i18n.strings,r=this.dom.find(".lh-audit",t);r.id=e.result.id;const o=e.result.scoreDisplayMode;e.result.displayValue&&(this.dom.find(".lh-audit__display-text",r).textContent=e.result.displayValue);const i=this.dom.find(".lh-audit__title",r);i.appendChild(this.dom.convertMarkdownCodeSnippets(e.result.title));const a=this.dom.find(".lh-audit__description",r);a.appendChild(this.dom.convertMarkdownLinkSnippets(e.result.description));for(const t of e.relevantMetrics||[]){const e=this.dom.createChildOf(a,"span","lh-audit__adorn");e.title=`Relevant to ${t.result.title}`,e.textContent=t.acronym||t.id}e.stackPacks&&e.stackPacks.forEach((e=>{const t=this.dom.createElement("div");t.classList.add("lh-audit__stackpack");const n=this.dom.createElement("img");n.classList.add("lh-audit__stackpack__img"),n.src=e.iconDataURL,n.alt=e.title,t.appendChild(n),t.appendChild(this.dom.convertMarkdownLinkSnippets(e.description)),this.dom.find(".lh-audit__stackpacks",r).appendChild(t)}));const s=this.dom.find("details",r);if(e.result.details){const t=this.detailsRenderer.render(e.result.details);t&&(t.classList.add("lh-details"),s.appendChild(t))}if(this.dom.find(".lh-chevron-container",r).appendChild(this._createChevron()),this._setRatingClass(r,e.result.score,o),"error"===e.result.scoreDisplayMode){r.classList.add("lh-audit--error");const t=this.dom.find(".lh-audit__display-text",r);t.textContent=n.errorLabel,t.classList.add("lh-tooltip-boundary");this.dom.createChildOf(t,"div","lh-tooltip lh-tooltip--error").textContent=e.result.errorMessage||n.errorMissingAuditInfo}else if(e.result.explanation){this.dom.createChildOf(i,"div","lh-audit-explanation").textContent=e.result.explanation}const c=e.result.warnings;if(!c||0===c.length)return r;const d=this.dom.find("summary",s),h=this.dom.createChildOf(d,"div","lh-warnings");if(this.dom.createChildOf(h,"span").textContent=n.warningHeader,1===c.length)h.appendChild(this.dom.document().createTextNode(c.join("")));else{const e=this.dom.createChildOf(h,"ul");for(const t of c){this.dom.createChildOf(e,"li").textContent=t}}return r}injectFinalScreenshot(e,t,n){const r=t["final-screenshot"];if(!r||"error"===r.scoreDisplayMode)return null;if(!r.details||"screenshot"!==r.details.type)return null;const o=this.dom.createElement("img","lh-final-ss-image"),i=r.details.data;o.src=i,o.alt=r.title;const a=this.dom.find(".lh-category .lh-category-header",e),l=this.dom.createElement("div","lh-category-headercol"),s=this.dom.createElement("div","lh-category-headercol lh-category-headercol--separator"),c=this.dom.createElement("div","lh-category-headercol");l.append(...a.childNodes),l.append(n),c.append(o),a.append(l,s,c),a.classList.add("lh-category-header__finalscreenshot")}_createChevron(){const e=this.dom.createComponent("chevron");return this.dom.find("svg.lh-chevron",e)}_setRatingClass(e,t,n){const r=l.calculateRating(t,n);return e.classList.add(`lh-audit--${n.toLowerCase()}`),"informative"!==n&&e.classList.add(`lh-audit--${r}`),e}renderCategoryHeader(e,t,n){const r=this.dom.createComponent("categoryHeader"),o=this.dom.find(".lh-score__gauge",r),i=this.renderCategoryScore(e,t,n);if(o.appendChild(i),e.description){const t=this.dom.convertMarkdownLinkSnippets(e.description);this.dom.find(".lh-category-header__description",r).appendChild(t)}return r}renderAuditGroup(e){const t=this.dom.createElement("div","lh-audit-group"),n=this.dom.createElement("div","lh-audit-group__header");if(this.dom.createChildOf(n,"span","lh-audit-group__title").textContent=e.title,e.description){const t=this.dom.convertMarkdownLinkSnippets(e.description);t.classList.add("lh-audit-group__description"),n.appendChild(t)}return t.appendChild(n),t}_renderGroupedAudits(e,t){const n=new Map,r="NotAGroup";n.set(r,[]);for(const t of e){const e=t.group||r,o=n.get(e)||[];o.push(t),n.set(e,o)}const o=[];for(const[e,i]of n){if(e===r){for(const e of i)o.push(this.renderAudit(e));continue}const n=t[e],a=this.renderAuditGroup(n);for(const e of i)a.appendChild(this.renderAudit(e));a.classList.add(`lh-audit-group--${e}`),o.push(a)}return o}renderUnexpandableClump(e,t){const n=this.dom.createElement("div");return this._renderGroupedAudits(e,t).forEach((e=>n.appendChild(e))),n}renderClump(e,{auditRefs:t,description:n}){const r=this.dom.createComponent("clump"),o=this.dom.find(".lh-clump",r);"warning"===e&&o.setAttribute("open","");this.dom.find("div.lh-audit-group__summary",o).appendChild(this._createChevron());const i=this.dom.find(".lh-audit-group__header",o),a=this._clumpTitles[e];if(this.dom.find(".lh-audit-group__title",i).textContent=a,n){const e=this.dom.convertMarkdownLinkSnippets(n);e.classList.add("lh-audit-group__description"),i.appendChild(e)}this.dom.find(".lh-audit-group__itemcount",o).textContent=`(${t.length})`;const l=t.map(this.renderAudit.bind(this));return o.append(...l),o.classList.add(`lh-clump--${e.toLowerCase()}`),o}renderCategoryScore(e,t,n){return n&&l.shouldDisplayAsFraction(n.gatherMode)?this.renderCategoryFraction(e):this.renderScoreGauge(e,t)}renderScoreGauge(e,t){const n=this.dom.createComponent("gauge"),r=this.dom.find("a.lh-gauge__wrapper",n);l.isPluginCategory(e.id)&&r.classList.add("lh-gauge__wrapper--plugin");const o=Number(e.score),i=this.dom.find(".lh-gauge",n),a=this.dom.find("circle.lh-gauge-arc",i);a&&this._setGaugeArc(a,o);const s=Math.round(100*o),c=this.dom.find("div.lh-gauge__percentage",n);return c.textContent=s.toString(),null===e.score&&(c.textContent="?",c.title=l.i18n.strings.errorLabel),0===e.auditRefs.length||this.hasApplicableAudits(e)?r.classList.add(`lh-gauge__wrapper--${l.calculateRating(e.score)}`):(r.classList.add("lh-gauge__wrapper--not-applicable"),c.textContent="-",c.title=l.i18n.strings.notApplicableAuditsGroupTitle),this.dom.find(".lh-gauge__label",n).textContent=e.title,n}renderCategoryFraction(e){const t=this.dom.createComponent("fraction"),n=this.dom.find("a.lh-fraction__wrapper",t),{numPassed:r,numPassableAudits:o,totalWeight:i}=l.calculateCategoryFraction(e),a=r/o,s=this.dom.find(".lh-fraction__content",t),c=this.dom.createElement("span");c.textContent=`${r}/${o}`,s.appendChild(c);let d=l.calculateRating(a);return 0===i&&(d="null"),n.classList.add(`lh-fraction__wrapper--${d}`),this.dom.find(".lh-fraction__label",t).textContent=e.title,t}hasApplicableAudits(e){return e.auditRefs.some((e=>"notApplicable"!==e.result.scoreDisplayMode))}_setGaugeArc(e,t){const n=2*Math.PI*Number(e.getAttribute("r")),r=Number(e.getAttribute("stroke-width")),o=.25*r/n;e.style.transform=`rotate(${360*o-90}deg)`;let i=t*n-r/2;0===t&&(e.style.opacity="0"),1===t&&(i=n),e.style.strokeDasharray=`${Math.max(i,0)} ${n}`}_auditHasWarning(e){return Boolean(e.result.warnings&&e.result.warnings.length)}_getClumpIdForAuditRef(e){const t=e.result.scoreDisplayMode;return"manual"===t||"notApplicable"===t?t:l.showAsPassed(e.result)?this._auditHasWarning(e)?"warning":"passed":"failed"}render(e,t={},n){const r=this.dom.createElement("div","lh-category");r.id=e.id,r.appendChild(this.renderCategoryHeader(e,t,n));const o=new Map;o.set("failed",[]),o.set("warning",[]),o.set("manual",[]),o.set("passed",[]),o.set("notApplicable",[]);for(const t of e.auditRefs){const e=this._getClumpIdForAuditRef(t),n=o.get(e);n.push(t),o.set(e,n)}for(const[n,i]of o){if(0===i.length)continue;if("failed"===n){const e=this.renderUnexpandableClump(i,t);e.classList.add("lh-clump--failed"),r.appendChild(e);continue}const o="manual"===n?e.manualDescription:void 0,a=this.renderClump(n,{auditRefs:i,description:o});r.appendChild(a)}return r}}
|
|
66
|
+
*/class d{constructor(e,t){this.dom=e,this.detailsRenderer=t}get _clumpTitles(){return{warning:l.i18n.strings.warningAuditsGroupTitle,manual:l.i18n.strings.manualAuditsGroupTitle,passed:l.i18n.strings.passedAuditsGroupTitle,notApplicable:l.i18n.strings.notApplicableAuditsGroupTitle}}renderAudit(e){const t=this.dom.createComponent("audit");return this.populateAuditValues(e,t)}populateAuditValues(e,t){const n=l.i18n.strings,r=this.dom.find(".lh-audit",t);r.id=e.result.id;const o=e.result.scoreDisplayMode;e.result.displayValue&&(this.dom.find(".lh-audit__display-text",r).textContent=e.result.displayValue);const i=this.dom.find(".lh-audit__title",r);i.appendChild(this.dom.convertMarkdownCodeSnippets(e.result.title));const a=this.dom.find(".lh-audit__description",r);a.appendChild(this.dom.convertMarkdownLinkSnippets(e.result.description));for(const t of e.relevantMetrics||[]){const e=this.dom.createChildOf(a,"span","lh-audit__adorn");e.title=`Relevant to ${t.result.title}`,e.textContent=t.acronym||t.id}e.stackPacks&&e.stackPacks.forEach((e=>{const t=this.dom.createElement("div");t.classList.add("lh-audit__stackpack");const n=this.dom.createElement("img");n.classList.add("lh-audit__stackpack__img"),n.src=e.iconDataURL,n.alt=e.title,t.appendChild(n),t.appendChild(this.dom.convertMarkdownLinkSnippets(e.description)),this.dom.find(".lh-audit__stackpacks",r).appendChild(t)}));const s=this.dom.find("details",r);if(e.result.details){const t=this.detailsRenderer.render(e.result.details);t&&(t.classList.add("lh-details"),s.appendChild(t))}if(this.dom.find(".lh-chevron-container",r).appendChild(this._createChevron()),this._setRatingClass(r,e.result.score,o),"error"===e.result.scoreDisplayMode){r.classList.add("lh-audit--error");const t=this.dom.find(".lh-audit__display-text",r);t.textContent=n.errorLabel,t.classList.add("lh-tooltip-boundary");this.dom.createChildOf(t,"div","lh-tooltip lh-tooltip--error").textContent=e.result.errorMessage||n.errorMissingAuditInfo}else if(e.result.explanation){this.dom.createChildOf(i,"div","lh-audit-explanation").textContent=e.result.explanation}const c=e.result.warnings;if(!c||0===c.length)return r;const d=this.dom.find("summary",s),h=this.dom.createChildOf(d,"div","lh-warnings");if(this.dom.createChildOf(h,"span").textContent=n.warningHeader,1===c.length)h.appendChild(this.dom.document().createTextNode(c.join("")));else{const e=this.dom.createChildOf(h,"ul");for(const t of c){this.dom.createChildOf(e,"li").textContent=t}}return r}injectFinalScreenshot(e,t,n){const r=t["final-screenshot"];if(!r||"error"===r.scoreDisplayMode)return null;if(!r.details||"screenshot"!==r.details.type)return null;const o=this.dom.createElement("img","lh-final-ss-image"),i=r.details.data;o.src=i,o.alt=r.title;const a=this.dom.find(".lh-category .lh-category-header",e),l=this.dom.createElement("div","lh-category-headercol"),s=this.dom.createElement("div","lh-category-headercol lh-category-headercol--separator"),c=this.dom.createElement("div","lh-category-headercol");l.append(...a.childNodes),l.append(n),c.append(o),a.append(l,s,c),a.classList.add("lh-category-header__finalscreenshot")}_createChevron(){const e=this.dom.createComponent("chevron");return this.dom.find("svg.lh-chevron",e)}_setRatingClass(e,t,n){const r=l.calculateRating(t,n);return e.classList.add(`lh-audit--${n.toLowerCase()}`),"informative"!==n&&e.classList.add(`lh-audit--${r}`),e}renderCategoryHeader(e,t,n){const r=this.dom.createComponent("categoryHeader"),o=this.dom.find(".lh-score__gauge",r),i=this.renderCategoryScore(e,t,n);if(o.appendChild(i),e.description){const t=this.dom.convertMarkdownLinkSnippets(e.description);this.dom.find(".lh-category-header__description",r).appendChild(t)}return r}renderAuditGroup(e){const t=this.dom.createElement("div","lh-audit-group"),n=this.dom.createElement("div","lh-audit-group__header");if(this.dom.createChildOf(n,"span","lh-audit-group__title").textContent=e.title,e.description){const t=this.dom.convertMarkdownLinkSnippets(e.description);t.classList.add("lh-audit-group__description"),n.appendChild(t)}return t.appendChild(n),t}_renderGroupedAudits(e,t){const n=new Map,r="NotAGroup";n.set(r,[]);for(const t of e){const e=t.group||r,o=n.get(e)||[];o.push(t),n.set(e,o)}const o=[];for(const[e,i]of n){if(e===r){for(const e of i)o.push(this.renderAudit(e));continue}const n=t[e],a=this.renderAuditGroup(n);for(const e of i)a.appendChild(this.renderAudit(e));a.classList.add(`lh-audit-group--${e}`),o.push(a)}return o}renderUnexpandableClump(e,t){const n=this.dom.createElement("div");return this._renderGroupedAudits(e,t).forEach((e=>n.appendChild(e))),n}renderClump(e,{auditRefs:t,description:n}){const r=this.dom.createComponent("clump"),o=this.dom.find(".lh-clump",r);"warning"===e&&o.setAttribute("open","");this.dom.find("div.lh-audit-group__summary",o).appendChild(this._createChevron());const i=this.dom.find(".lh-audit-group__header",o),a=this._clumpTitles[e];if(this.dom.find(".lh-audit-group__title",i).textContent=a,n){const e=this.dom.convertMarkdownLinkSnippets(n);e.classList.add("lh-audit-group__description"),i.appendChild(e)}this.dom.find(".lh-audit-group__itemcount",o).textContent=`(${t.length})`;const l=t.map(this.renderAudit.bind(this));return o.append(...l),o.classList.add(`lh-clump--${e.toLowerCase()}`),o}renderCategoryScore(e,t,n){return n&&l.shouldDisplayAsFraction(n.gatherMode)?this.renderCategoryFraction(e):this.renderScoreGauge(e,t)}renderScoreGauge(e,t){const n=this.dom.createComponent("gauge"),r=this.dom.find("a.lh-gauge__wrapper",n);l.isPluginCategory(e.id)&&r.classList.add("lh-gauge__wrapper--plugin");const o=Number(e.score),i=this.dom.find(".lh-gauge",n),a=this.dom.find("circle.lh-gauge-arc",i);a&&this._setGaugeArc(a,o);const s=Math.round(100*o),c=this.dom.find("div.lh-gauge__percentage",n);return c.textContent=s.toString(),null===e.score&&(c.textContent="?",c.title=l.i18n.strings.errorLabel),0===e.auditRefs.length||this.hasApplicableAudits(e)?r.classList.add(`lh-gauge__wrapper--${l.calculateRating(e.score)}`):(r.classList.add("lh-gauge__wrapper--not-applicable"),c.textContent="-",c.title=l.i18n.strings.notApplicableAuditsGroupTitle),this.dom.find(".lh-gauge__label",n).textContent=e.title,n}renderCategoryFraction(e){const t=this.dom.createComponent("fraction"),n=this.dom.find("a.lh-fraction__wrapper",t),{numPassed:r,numPassableAudits:o,totalWeight:i}=l.calculateCategoryFraction(e),a=r/o,s=this.dom.find(".lh-fraction__content",t),c=this.dom.createElement("span");c.textContent=`${r}/${o}`,s.appendChild(c);let d=l.calculateRating(a);return 0===i&&(d="null"),n.classList.add(`lh-fraction__wrapper--${d}`),this.dom.find(".lh-fraction__label",t).textContent=e.title,t}hasApplicableAudits(e){return e.auditRefs.some((e=>"notApplicable"!==e.result.scoreDisplayMode))}_setGaugeArc(e,t){const n=2*Math.PI*Number(e.getAttribute("r")),r=Number(e.getAttribute("stroke-width")),o=.25*r/n;e.style.transform=`rotate(${360*o-90}deg)`;let i=t*n-r/2;0===t&&(e.style.opacity="0"),1===t&&(i=n),e.style.strokeDasharray=`${Math.max(i,0)} ${n}`}_auditHasWarning(e){return Boolean(e.result.warnings&&e.result.warnings.length)}_getClumpIdForAuditRef(e){const t=e.result.scoreDisplayMode;return"manual"===t||"notApplicable"===t?t:l.showAsPassed(e.result)?this._auditHasWarning(e)?"warning":"passed":"failed"}render(e,t={},n){const r=this.dom.createElement("div","lh-category");r.id=e.id,r.appendChild(this.renderCategoryHeader(e,t,n));const o=new Map;o.set("failed",[]),o.set("warning",[]),o.set("manual",[]),o.set("passed",[]),o.set("notApplicable",[]);for(const t of e.auditRefs){const e=this._getClumpIdForAuditRef(t),n=o.get(e);n.push(t),o.set(e,n)}for(const e of o.values())e.sort(((e,t)=>t.weight-e.weight));for(const[n,i]of o){if(0===i.length)continue;if("failed"===n){const e=this.renderUnexpandableClump(i,t);e.classList.add("lh-clump--failed"),r.appendChild(e);continue}const o="manual"===n?e.manualDescription:void 0,a=this.renderClump(n,{auditRefs:i,description:o});r.appendChild(a)}return r}}
|
|
67
67
|
/**
|
|
68
68
|
* @license
|
|
69
69
|
* Copyright 2017 The Lighthouse Authors. All Rights Reserved.
|
|
@@ -142,7 +142,7 @@ class s{constructor(e){this._document=e,this._lighthouseChannel="unknown",this._
|
|
|
142
142
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
143
143
|
* See the License for the specific language governing permissions and
|
|
144
144
|
* limitations under the License.
|
|
145
|
-
*/class N extends d{render(e,t={}){const n=this.dom.createElement("div","lh-category");n.id=e.id,n.appendChild(this.renderCategoryHeader(e,t));const r=e.auditRefs,o=r.filter((e=>"manual"!==e.result.scoreDisplayMode)),i=this._renderAudits(o,t);n.appendChild(i);const a=r.filter((e=>"manual"===e.result.scoreDisplayMode)),l=this.renderClump("manual",{auditRefs:a,description:e.manualDescription});return n.appendChild(l),n}
|
|
145
|
+
*/class N extends d{render(e,t={}){const n=this.dom.createElement("div","lh-category");n.id=e.id,n.appendChild(this.renderCategoryHeader(e,t));const r=e.auditRefs,o=r.filter((e=>"manual"!==e.result.scoreDisplayMode)),i=this._renderAudits(o,t);n.appendChild(i);const a=r.filter((e=>"manual"===e.result.scoreDisplayMode)),l=this.renderClump("manual",{auditRefs:a,description:e.manualDescription});return n.appendChild(l),n}renderCategoryScore(e,t){if(null===e.score)return super.renderScoreGauge(e,t);const n=this.dom.createComponent("gaugePwa"),r=this.dom.find("a.lh-gauge--pwa__wrapper",n),o=n.querySelector("svg");if(!o)throw new Error("no SVG element found in PWA score gauge template");N._makeSvgReferencesUnique(o);const i=this._getGroupIds(e.auditRefs),a=this._getPassingGroupIds(e.auditRefs);if(a.size===i.size)r.classList.add("lh-badged--all");else for(const e of a)r.classList.add(`lh-badged--${e}`);return this.dom.find(".lh-gauge__label",n).textContent=e.title,r.title=this._getGaugeTooltip(e.auditRefs,t),n}_getGroupIds(e){const t=e.map((e=>e.group)).filter((e=>!!e));return new Set(t)}_getPassingGroupIds(e){const t=this._getGroupIds(e);for(const n of e)!l.showAsPassed(n.result)&&n.group&&t.delete(n.group);return t}_getGaugeTooltip(e,t){const n=this._getGroupIds(e),r=[];for(const o of n){const n=e.filter((e=>e.group===o)),i=n.length,a=n.filter((e=>l.showAsPassed(e.result))).length,s=t[o].title;r.push(`${s}: ${a}/${i}`)}return r.join(", ")}_renderAudits(e,t){const n=this.renderUnexpandableClump(e,t),r=this._getPassingGroupIds(e);for(const e of r){this.dom.find(`.lh-audit-group--${e}`,n).classList.add("lh-badged")}return n}static _makeSvgReferencesUnique(e){const t=e.querySelector("defs");if(!t)return;const n=l.getUniqueSuffix(),r=t.querySelectorAll("[id]");for(const t of r){const r=t.id,o=`${r}-${n}`;t.id=o;const i=e.querySelectorAll(`use[href="#${r}"]`);for(const e of i)e.setAttribute("href",`#${o}`);const a=e.querySelectorAll(`[fill="url(#${r})"]`);for(const e of a)e.setAttribute("fill",`url(#${o})`)}}}
|
|
146
146
|
/**
|
|
147
147
|
* @license
|
|
148
148
|
* Copyright 2017 The Lighthouse Authors. All Rights Reserved.
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
--summary-subtitle-font-size: 12px;
|
|
32
32
|
--summary-title-font-size: 20px;
|
|
33
33
|
--summary-tooltip-box-shadow-color: rgba(0, 0, 0, 0.25);
|
|
34
|
+
--summary-tooltip-line-height: 16px;
|
|
34
35
|
--topbar-button-font-size: 14px;
|
|
35
36
|
--topbar-button-size: 45px;
|
|
36
37
|
--topbar-title-font-size: 14px;
|
|
@@ -394,22 +395,33 @@
|
|
|
394
395
|
border-radius: 3px;
|
|
395
396
|
padding: var(--base-spacing);
|
|
396
397
|
right: 0;
|
|
398
|
+
line-height: var(--summary-tooltip-line-height);
|
|
397
399
|
box-shadow: 0px 4px 4px var(--summary-tooltip-box-shadow-color);
|
|
398
400
|
z-index: 1;
|
|
399
401
|
}
|
|
400
402
|
|
|
401
403
|
.SummaryTooltip__title {
|
|
402
404
|
font-weight: var(--bold-weight);
|
|
403
|
-
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.SummaryTooltip__url {
|
|
408
|
+
overflow-x: hidden;
|
|
409
|
+
text-overflow: ellipsis;
|
|
410
|
+
white-space: nowrap;
|
|
411
|
+
margin-top: calc(0.25 * var(--base-spacing));
|
|
412
|
+
margin-bottom: calc(0.75 * var(--base-spacing));
|
|
413
|
+
color: var(--color-gray-700);
|
|
404
414
|
}
|
|
405
415
|
|
|
406
416
|
.SummaryTooltip__category {
|
|
407
417
|
font-weight: var(--bold-weight);
|
|
408
418
|
display: flex;
|
|
419
|
+
align-items: center;
|
|
409
420
|
margin-top: var(--half-base-spacing);
|
|
410
421
|
}
|
|
411
422
|
|
|
412
423
|
.SummaryTooltip__category-title {
|
|
424
|
+
line-height: 24px;
|
|
413
425
|
flex-grow: 1;
|
|
414
426
|
}
|
|
415
427
|
|
|
@@ -424,6 +436,50 @@
|
|
|
424
436
|
color: var(--color-fail);
|
|
425
437
|
}
|
|
426
438
|
|
|
439
|
+
.SummaryTooltip__fraction {
|
|
440
|
+
color: var(--color-gray-700);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.SummaryTooltip__informative {
|
|
444
|
+
margin-top: calc(0.25 * var(--base-spacing));
|
|
445
|
+
color: var(--color-gray-700);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.SummaryTooltipAudits__title {
|
|
449
|
+
line-height: 24px;
|
|
450
|
+
margin-top: calc(0.75 * var(--base-spacing));
|
|
451
|
+
font-weight: var(--bold-weight);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.SummaryTooltipAudit {
|
|
455
|
+
display: flex;
|
|
456
|
+
margin: calc(0.25 * var(--base-spacing)) 0px;
|
|
457
|
+
color: var(--color-gray-700);
|
|
458
|
+
--score-icon-size: 10px;
|
|
459
|
+
}
|
|
460
|
+
.SummaryTooltipAudit code {
|
|
461
|
+
color: var(--snippet-color);
|
|
462
|
+
}
|
|
463
|
+
.SummaryTooltipAudit::before {
|
|
464
|
+
content: '';
|
|
465
|
+
height: var(--score-icon-size);
|
|
466
|
+
width: var(--score-icon-size);
|
|
467
|
+
margin-top: calc((var(--summary-tooltip-line-height) - var(--score-icon-size)) / 2);
|
|
468
|
+
margin-right: var(--half-base-spacing);
|
|
469
|
+
}
|
|
470
|
+
.SummaryTooltipAudit--pass::before {
|
|
471
|
+
background-color: var(--color-pass);
|
|
472
|
+
border-radius: 50%;
|
|
473
|
+
}
|
|
474
|
+
.SummaryTooltipAudit--average::before {
|
|
475
|
+
background-color: var(--color-average);
|
|
476
|
+
}
|
|
477
|
+
.SummaryTooltipAudit--fail::before {
|
|
478
|
+
border-left: calc(var(--score-icon-size) / 2) solid transparent;
|
|
479
|
+
border-right: calc(var(--score-icon-size) / 2) solid transparent;
|
|
480
|
+
border-bottom: var(--score-icon-size) solid var(--color-fail);
|
|
481
|
+
}
|
|
482
|
+
|
|
427
483
|
.SummaryNavigationHeader {
|
|
428
484
|
font-size: var(--summary-navigation-header-font-size);
|
|
429
485
|
line-height: 16px;
|
|
@@ -10,9 +10,14 @@ import {Util} from '../../../report/renderer/util';
|
|
|
10
10
|
import {Separator} from '../common';
|
|
11
11
|
import {CategoryScore} from '../wrappers/category-score';
|
|
12
12
|
import {useI18n, useStringFormatter, useLocalizedStrings} from '../i18n/i18n';
|
|
13
|
+
import {Markdown} from '../wrappers/markdown';
|
|
13
14
|
|
|
14
15
|
import type {UIStringsType} from '../i18n/ui-strings';
|
|
15
16
|
|
|
17
|
+
const MAX_TOOLTIP_AUDITS = 2;
|
|
18
|
+
|
|
19
|
+
type ScoredAuditRef = LH.ReportResult.AuditRef & {result: {score: number}};
|
|
20
|
+
|
|
16
21
|
function getGatherModeLabel(gatherMode: LH.Result.GatherMode, strings: UIStringsType) {
|
|
17
22
|
switch (gatherMode) {
|
|
18
23
|
case 'navigation': return strings.navigationReport;
|
|
@@ -30,10 +35,71 @@ function getCategoryRating(rating: string, strings: UIStringsType) {
|
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
function getScoreToBeGained(audit: ScoredAuditRef): number {
|
|
39
|
+
return audit.weight * (1 - audit.result.score);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getOverallSavings(audit: LH.ReportResult.AuditRef): number {
|
|
43
|
+
return (
|
|
44
|
+
audit.result.details &&
|
|
45
|
+
audit.result.details.type === 'opportunity' &&
|
|
46
|
+
audit.result.details.overallSavingsMs
|
|
47
|
+
) || 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const SummaryTooltipAudit: FunctionComponent<{audit: LH.ReportResult.AuditRef}> = ({audit}) => {
|
|
51
|
+
const rating = Util.calculateRating(audit.result.score, audit.result.scoreDisplayMode);
|
|
52
|
+
return (
|
|
53
|
+
<div className={`SummaryTooltipAudit SummaryTooltipAudit--${rating}`}>
|
|
54
|
+
<Markdown text={audit.result.title}/>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const SummaryTooltipAudits: FunctionComponent<{category: LH.ReportResult.Category}> =
|
|
60
|
+
({category}) => {
|
|
61
|
+
const strings = useLocalizedStrings();
|
|
62
|
+
|
|
63
|
+
function isRelevantAudit(audit: LH.ReportResult.AuditRef): audit is ScoredAuditRef {
|
|
64
|
+
return audit.result.score !== null &&
|
|
65
|
+
// Metrics should not be displayed in this group.
|
|
66
|
+
audit.group !== 'metrics' &&
|
|
67
|
+
// Audits in performance without a group are hidden.
|
|
68
|
+
(audit.group !== undefined || category.id !== 'performance') &&
|
|
69
|
+
// We don't want unweighted audits except for opportunities with potential savings.
|
|
70
|
+
(audit.weight > 0 || getOverallSavings(audit) > 0) &&
|
|
71
|
+
// Passing audits should never be high impact.
|
|
72
|
+
!Util.showAsPassed(audit.result);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const audits = category.auditRefs
|
|
76
|
+
.filter(isRelevantAudit)
|
|
77
|
+
.sort((a, b) => {
|
|
78
|
+
// Remaining score should always be 0 for perf opportunities because weight is 0.
|
|
79
|
+
// In that case, we want to sort by `overallSavingsMs`.
|
|
80
|
+
const remainingScoreA = getScoreToBeGained(a);
|
|
81
|
+
const remainingScoreB = getScoreToBeGained(b);
|
|
82
|
+
if (remainingScoreA !== remainingScoreB) return remainingScoreB - remainingScoreA;
|
|
83
|
+
return getOverallSavings(b) - getOverallSavings(a);
|
|
84
|
+
})
|
|
85
|
+
.splice(0, MAX_TOOLTIP_AUDITS);
|
|
86
|
+
if (!audits.length) return null;
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div className="SummaryTooltipAudits">
|
|
90
|
+
<div className="SummaryTooltipAudits__title">{strings.highestImpact}</div>
|
|
91
|
+
{
|
|
92
|
+
audits.map(audit => <SummaryTooltipAudit key={audit.id} audit={audit}/>)
|
|
93
|
+
}
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
33
98
|
export const SummaryTooltip: FunctionComponent<{
|
|
34
99
|
category: LH.ReportResult.Category,
|
|
35
|
-
gatherMode: LH.Result.GatherMode
|
|
36
|
-
|
|
100
|
+
gatherMode: LH.Result.GatherMode,
|
|
101
|
+
url: string,
|
|
102
|
+
}> = ({category, gatherMode, url}) => {
|
|
37
103
|
const strings = useLocalizedStrings();
|
|
38
104
|
const str_ = useStringFormatter();
|
|
39
105
|
const {
|
|
@@ -53,6 +119,7 @@ export const SummaryTooltip: FunctionComponent<{
|
|
|
53
119
|
return (
|
|
54
120
|
<div className="SummaryTooltip">
|
|
55
121
|
<div className="SummaryTooltip__title">{getGatherModeLabel(gatherMode, strings)}</div>
|
|
122
|
+
<div className="SummaryTooltip__url">{url}</div>
|
|
56
123
|
<Separator/>
|
|
57
124
|
<div className="SummaryTooltip__category">
|
|
58
125
|
<div className="SummaryTooltip__category-title">
|
|
@@ -81,6 +148,7 @@ export const SummaryTooltip: FunctionComponent<{
|
|
|
81
148
|
{str_(strings.informativeAuditCount, {numInformative})}
|
|
82
149
|
</div>
|
|
83
150
|
}
|
|
151
|
+
<SummaryTooltipAudits category={category}/>
|
|
84
152
|
</div>
|
|
85
153
|
);
|
|
86
154
|
};
|
|
@@ -89,7 +157,8 @@ export const SummaryCategory: FunctionComponent<{
|
|
|
89
157
|
category: LH.ReportResult.Category|undefined,
|
|
90
158
|
href: string,
|
|
91
159
|
gatherMode: LH.Result.GatherMode,
|
|
92
|
-
|
|
160
|
+
finalUrl: string,
|
|
161
|
+
}> = ({category, href, gatherMode, finalUrl}) => {
|
|
93
162
|
return (
|
|
94
163
|
<div className="SummaryCategory">
|
|
95
164
|
{
|
|
@@ -100,7 +169,7 @@ export const SummaryCategory: FunctionComponent<{
|
|
|
100
169
|
href={href}
|
|
101
170
|
gatherMode={gatherMode}
|
|
102
171
|
/>
|
|
103
|
-
<SummaryTooltip category={category} gatherMode={gatherMode}/>
|
|
172
|
+
<SummaryTooltip category={category} gatherMode={gatherMode} url={finalUrl}/>
|
|
104
173
|
</div> :
|
|
105
174
|
<div className="SummaryCategory__null" data-testid="SummaryCategory__null"/>
|
|
106
175
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
4
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {FunctionComponent} from 'preact';
|
|
8
|
+
import {useLayoutEffect, useRef} from 'preact/hooks';
|
|
9
|
+
|
|
10
|
+
import {useReportRenderer} from '../wrappers/report-renderer';
|
|
11
|
+
|
|
12
|
+
export const Markdown: FunctionComponent<{text: string}> = ({text}) => {
|
|
13
|
+
const {dom} = useReportRenderer();
|
|
14
|
+
const ref = useRef<HTMLSpanElement>(null);
|
|
15
|
+
|
|
16
|
+
useLayoutEffect(() => {
|
|
17
|
+
if (ref.current) {
|
|
18
|
+
const md = dom.convertMarkdownCodeSnippets(text);
|
|
19
|
+
ref.current.appendChild(md);
|
|
20
|
+
}
|
|
21
|
+
return () => {
|
|
22
|
+
if (ref.current) ref.current.innerHTML = '';
|
|
23
|
+
};
|
|
24
|
+
}, [text]);
|
|
25
|
+
|
|
26
|
+
return <span ref={ref}/>;
|
|
27
|
+
};
|
|
@@ -11,6 +11,7 @@ import {SummaryTooltip} from '../../src/summary/category';
|
|
|
11
11
|
import {flowResult} from '../sample-flow';
|
|
12
12
|
import {I18nProvider} from '../../src/i18n/i18n';
|
|
13
13
|
import {FlowResultContext} from '../../src/util';
|
|
14
|
+
import {ReportRendererProvider} from '../../src/wrappers/report-renderer';
|
|
14
15
|
|
|
15
16
|
let wrapper: FunctionComponent;
|
|
16
17
|
|
|
@@ -18,9 +19,11 @@ beforeEach(() => {
|
|
|
18
19
|
// Include sample flowResult for locale in I18nProvider.
|
|
19
20
|
wrapper = ({children}) => (
|
|
20
21
|
<FlowResultContext.Provider value={flowResult}>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
<ReportRendererProvider>
|
|
23
|
+
<I18nProvider>
|
|
24
|
+
{children}
|
|
25
|
+
</I18nProvider>
|
|
26
|
+
</ReportRendererProvider>
|
|
24
27
|
</FlowResultContext.Provider>
|
|
25
28
|
);
|
|
26
29
|
});
|
|
@@ -31,14 +34,16 @@ describe('SummaryTooltip', () => {
|
|
|
31
34
|
id: 'performance',
|
|
32
35
|
score: 1,
|
|
33
36
|
auditRefs: [
|
|
34
|
-
|
|
35
|
-
{result: {score: 1, scoreDisplayMode: 'binary'}, weight: 1, group: 'diagnostics'},
|
|
36
|
-
{result: {score:
|
|
37
|
+
/* eslint-disable max-len */
|
|
38
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 1'}, weight: 1, group: 'diagnostics'},
|
|
39
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 2'}, weight: 1, group: 'diagnostics'},
|
|
40
|
+
{result: {score: 0, scoreDisplayMode: 'binary', title: 'Audit 3'}, weight: 1, group: 'diagnostics'},
|
|
41
|
+
/* eslint-enable max-len */
|
|
37
42
|
],
|
|
38
43
|
};
|
|
39
44
|
|
|
40
45
|
const root = render(
|
|
41
|
-
<SummaryTooltip category={category} gatherMode="snapshot"/>,
|
|
46
|
+
<SummaryTooltip category={category} gatherMode="snapshot" url="https://example.com"/>,
|
|
42
47
|
{wrapper}
|
|
43
48
|
);
|
|
44
49
|
|
|
@@ -46,6 +51,7 @@ describe('SummaryTooltip', () => {
|
|
|
46
51
|
expect(() => root.getByText(/^[0-9]+$/)).toThrow();
|
|
47
52
|
expect(root.getByText('2 audits passed')).toBeTruthy();
|
|
48
53
|
expect(root.getByText('3 passable audits')).toBeTruthy();
|
|
54
|
+
expect(root.getByText('https://example.com'));
|
|
49
55
|
});
|
|
50
56
|
|
|
51
57
|
it('renders tooltip without rating', async () => {
|
|
@@ -53,14 +59,16 @@ describe('SummaryTooltip', () => {
|
|
|
53
59
|
id: 'performance',
|
|
54
60
|
score: 1,
|
|
55
61
|
auditRefs: [
|
|
56
|
-
|
|
57
|
-
{result: {score: 1, scoreDisplayMode: 'binary'}, weight: 0, group: 'diagnostics'},
|
|
58
|
-
{result: {score:
|
|
62
|
+
/* eslint-disable max-len */
|
|
63
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 1'}, weight: 0, group: 'diagnostics'},
|
|
64
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 2'}, weight: 0, group: 'diagnostics'},
|
|
65
|
+
{result: {score: 0, scoreDisplayMode: 'binary', title: 'Audit 3'}, weight: 0, group: 'diagnostics'},
|
|
66
|
+
/* eslint-enable max-len */
|
|
59
67
|
],
|
|
60
68
|
};
|
|
61
69
|
|
|
62
70
|
const root = render(
|
|
63
|
-
<SummaryTooltip category={category} gatherMode="snapshot"/>,
|
|
71
|
+
<SummaryTooltip category={category} gatherMode="snapshot" url="https://example.com"/>,
|
|
64
72
|
{wrapper}
|
|
65
73
|
);
|
|
66
74
|
|
|
@@ -68,6 +76,7 @@ describe('SummaryTooltip', () => {
|
|
|
68
76
|
expect(() => root.getByText(/^[0-9]+$/)).toThrow();
|
|
69
77
|
expect(root.getByText('2 audits passed')).toBeTruthy();
|
|
70
78
|
expect(root.getByText('3 passable audits')).toBeTruthy();
|
|
79
|
+
expect(root.getByText('https://example.com'));
|
|
71
80
|
});
|
|
72
81
|
|
|
73
82
|
it('renders scored category tooltip with score', async () => {
|
|
@@ -75,14 +84,16 @@ describe('SummaryTooltip', () => {
|
|
|
75
84
|
id: 'performance',
|
|
76
85
|
score: 1,
|
|
77
86
|
auditRefs: [
|
|
78
|
-
|
|
79
|
-
{result: {score: 1, scoreDisplayMode: 'binary'}, weight: 1, group: 'diagnostics'},
|
|
80
|
-
{result: {score:
|
|
87
|
+
/* eslint-disable max-len */
|
|
88
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 1'}, weight: 1, group: 'diagnostics'},
|
|
89
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 2'}, weight: 1, group: 'diagnostics'},
|
|
90
|
+
{result: {score: 0, scoreDisplayMode: 'binary', title: 'Audit 3'}, weight: 1, group: 'diagnostics'},
|
|
91
|
+
/* eslint-enable max-len */
|
|
81
92
|
],
|
|
82
93
|
};
|
|
83
94
|
|
|
84
95
|
const root = render(
|
|
85
|
-
<SummaryTooltip category={category} gatherMode="navigation"/>,
|
|
96
|
+
<SummaryTooltip category={category} gatherMode="navigation" url="https://example.com"/>,
|
|
86
97
|
{wrapper}
|
|
87
98
|
);
|
|
88
99
|
|
|
@@ -90,6 +101,7 @@ describe('SummaryTooltip', () => {
|
|
|
90
101
|
expect(root.getByText('100')).toBeTruthy();
|
|
91
102
|
expect(root.getByText('2 audits passed')).toBeTruthy();
|
|
92
103
|
expect(root.getByText('3 passable audits')).toBeTruthy();
|
|
104
|
+
expect(root.getByText('https://example.com'));
|
|
93
105
|
});
|
|
94
106
|
|
|
95
107
|
it('renders informative audit count if any', async () => {
|
|
@@ -97,14 +109,16 @@ describe('SummaryTooltip', () => {
|
|
|
97
109
|
id: 'performance',
|
|
98
110
|
score: 1,
|
|
99
111
|
auditRefs: [
|
|
100
|
-
|
|
101
|
-
{result: {score: 1, scoreDisplayMode: 'binary'}, weight: 1, group: 'diagnostics'},
|
|
102
|
-
{result: {score:
|
|
112
|
+
/* eslint-disable max-len */
|
|
113
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 1'}, weight: 1, group: 'diagnostics'},
|
|
114
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 2'}, weight: 1, group: 'diagnostics'},
|
|
115
|
+
{result: {score: null, scoreDisplayMode: 'informative', title: 'Audit 3'}, weight: 1, group: 'diagnostics'},
|
|
116
|
+
/* eslint-enable max-len */
|
|
103
117
|
],
|
|
104
118
|
};
|
|
105
119
|
|
|
106
120
|
const root = render(
|
|
107
|
-
<SummaryTooltip category={category} gatherMode="navigation"/>,
|
|
121
|
+
<SummaryTooltip category={category} gatherMode="navigation" url="https://example.com"/>,
|
|
108
122
|
{wrapper}
|
|
109
123
|
);
|
|
110
124
|
|
|
@@ -113,5 +127,83 @@ describe('SummaryTooltip', () => {
|
|
|
113
127
|
expect(root.getByText('2 audits passed')).toBeTruthy();
|
|
114
128
|
expect(root.getByText('2 passable audits')).toBeTruthy();
|
|
115
129
|
expect(root.getByText('1 informative audit')).toBeTruthy();
|
|
130
|
+
expect(root.getByText('https://example.com'));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('renders highest impact audits', async () => {
|
|
134
|
+
const category: any = {
|
|
135
|
+
id: 'seo',
|
|
136
|
+
score: 1,
|
|
137
|
+
auditRefs: [
|
|
138
|
+
/* eslint-disable max-len */
|
|
139
|
+
{result: {score: 0, scoreDisplayMode: 'binary', title: 'Audit 1'}, weight: 1, group: 'group'},
|
|
140
|
+
{result: {score: 0, scoreDisplayMode: 'binary', title: 'Audit 2'}, weight: 2, group: 'group'},
|
|
141
|
+
{result: {score: 0, scoreDisplayMode: 'binary', title: 'Audit 3'}, weight: 3, group: 'group'},
|
|
142
|
+
/* eslint-enable max-len */
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const root = render(
|
|
147
|
+
<SummaryTooltip category={category} gatherMode="navigation" url="https://example.com"/>,
|
|
148
|
+
{wrapper}
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const audits = root.getAllByText(/^Audit [0-9]$/);
|
|
152
|
+
|
|
153
|
+
expect(root.getByText('Highest impact')).toBeTruthy();
|
|
154
|
+
expect(audits.map(a => a.textContent)).toEqual([
|
|
155
|
+
'Audit 3',
|
|
156
|
+
'Audit 2',
|
|
157
|
+
]);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('renders highest impact audits in performance', async () => {
|
|
161
|
+
const category: any = {
|
|
162
|
+
id: 'performance',
|
|
163
|
+
score: 0.75,
|
|
164
|
+
auditRefs: [
|
|
165
|
+
/* eslint-disable max-len */
|
|
166
|
+
{result: {score: 0.75, scoreDisplayMode: 'numeric', title: 'Metric 1'}, weight: 1, group: 'metrics'},
|
|
167
|
+
{result: {score: 0, scoreDisplayMode: 'numeric', title: 'Audit 1', details: {type: 'opportunity', overallSavingsMs: 500}}, weight: 0, group: 'opportunities'},
|
|
168
|
+
{result: {score: 0, scoreDisplayMode: 'numeric', title: 'Audit 2', details: {type: 'opportunity', overallSavingsMs: 1000}}, weight: 0, group: 'opportunities'},
|
|
169
|
+
{result: {score: 0, scoreDisplayMode: 'numeric', title: 'Audit 3', details: {type: 'opportunity', overallSavingsMs: 100}}, weight: 0, group: 'opportunities'},
|
|
170
|
+
/* eslint-enable max-len */
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const root = render(
|
|
175
|
+
<SummaryTooltip category={category} gatherMode="navigation" url="https://example.com"/>,
|
|
176
|
+
{wrapper}
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const audits = root.getAllByText(/^(Audit|Metric) [0-9]$/);
|
|
180
|
+
|
|
181
|
+
expect(root.getByText('Highest impact')).toBeTruthy();
|
|
182
|
+
expect(audits.map(a => a.textContent)).toEqual([
|
|
183
|
+
'Audit 2',
|
|
184
|
+
'Audit 1',
|
|
185
|
+
]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('hides highest impact if nothing to show', async () => {
|
|
189
|
+
const category: any = {
|
|
190
|
+
id: 'performance',
|
|
191
|
+
score: 1,
|
|
192
|
+
auditRefs: [
|
|
193
|
+
/* eslint-disable max-len */
|
|
194
|
+
{result: {score: 1, scoreDisplayMode: 'binary', title: 'Audit 1'}, weight: 1, group: 'diagnostics'},
|
|
195
|
+
{result: {score: 0, scoreDisplayMode: 'binary', title: 'Audit 2'}, weight: 1},
|
|
196
|
+
{result: {score: null, scoreDisplayMode: 'informative', title: 'Audit 3'}, weight: 1, group: 'diagnostics'},
|
|
197
|
+
/* eslint-enable max-len */
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const root = render(
|
|
202
|
+
<SummaryTooltip category={category} gatherMode="navigation" url="https://example.com"/>,
|
|
203
|
+
{wrapper}
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
expect(() => root.getByText('Highest impact')).toThrow();
|
|
207
|
+
expect(() => root.getByText(/^Audit [0-9]$/)).toThrow();
|
|
116
208
|
});
|
|
117
209
|
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
4
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {render} from '@testing-library/preact';
|
|
8
|
+
import {FunctionComponent} from 'preact';
|
|
9
|
+
|
|
10
|
+
import {Markdown} from '../../src/wrappers/markdown';
|
|
11
|
+
import {ReportRendererProvider} from '../../src/wrappers/report-renderer';
|
|
12
|
+
|
|
13
|
+
let wrapper: FunctionComponent;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
wrapper = ({children}) => (
|
|
17
|
+
<ReportRendererProvider>
|
|
18
|
+
{children}
|
|
19
|
+
</ReportRendererProvider>
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('Markdown', () => {
|
|
24
|
+
it('renders markdown text', () => {
|
|
25
|
+
const root = render(<Markdown text="Some `fancy` text"/>, {wrapper});
|
|
26
|
+
const text = root.getByText(/^Some.*text$/);
|
|
27
|
+
expect(text.innerHTML).toEqual('Some <code>fancy</code> text');
|
|
28
|
+
});
|
|
29
|
+
});
|
package/jest.config.js
CHANGED
|
@@ -13,8 +13,8 @@ module.exports = {
|
|
|
13
13
|
'**/lighthouse-cli/**/*-test.js',
|
|
14
14
|
'**/report/**/*-test.js',
|
|
15
15
|
'**/lighthouse-core/test/fraggle-rock/**/*-test-pptr.js',
|
|
16
|
-
'**/
|
|
17
|
-
'**/
|
|
16
|
+
'**/treemap/**/*-test.js',
|
|
17
|
+
'**/viewer/**/*-test.js',
|
|
18
18
|
'**/third-party/**/*-test.js',
|
|
19
19
|
'**/clients/test/**/*-test.js',
|
|
20
20
|
'**/shared/**/*-test.js',
|
|
@@ -103,6 +103,8 @@ class ModernImageFormats extends ByteEfficiencyAudit {
|
|
|
103
103
|
const items = [];
|
|
104
104
|
const warnings = [];
|
|
105
105
|
for (const image of images) {
|
|
106
|
+
const imageElement = imageElementsByURL.get(image.url);
|
|
107
|
+
|
|
106
108
|
if (image.failed) {
|
|
107
109
|
warnings.push(`Unable to decode ${URL.getURLDisplayName(image.url)}`);
|
|
108
110
|
continue;
|
|
@@ -120,7 +122,6 @@ class ModernImageFormats extends ByteEfficiencyAudit {
|
|
|
120
122
|
let fromProtocol = true;
|
|
121
123
|
|
|
122
124
|
if (typeof webpSize === 'undefined') {
|
|
123
|
-
const imageElement = imageElementsByURL.get(image.url);
|
|
124
125
|
if (!imageElement) {
|
|
125
126
|
warnings.push(`Unable to locate resource ${URL.getURLDisplayName(image.url)}`);
|
|
126
127
|
continue;
|
|
@@ -155,6 +156,7 @@ class ModernImageFormats extends ByteEfficiencyAudit {
|
|
|
155
156
|
const isCrossOrigin = !URL.originsMatch(pageURL, image.url);
|
|
156
157
|
|
|
157
158
|
items.push({
|
|
159
|
+
node: imageElement ? ByteEfficiencyAudit.makeNodeItem(imageElement.node) : undefined,
|
|
158
160
|
url,
|
|
159
161
|
fromProtocol,
|
|
160
162
|
isCrossOrigin,
|
|
@@ -166,7 +168,7 @@ class ModernImageFormats extends ByteEfficiencyAudit {
|
|
|
166
168
|
|
|
167
169
|
/** @type {LH.Audit.Details.Opportunity['headings']} */
|
|
168
170
|
const headings = [
|
|
169
|
-
{key: '
|
|
171
|
+
{key: 'node', valueType: 'node', label: ''},
|
|
170
172
|
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
171
173
|
{key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnResourceSize)},
|
|
172
174
|
{key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnWastedBytes)},
|