lighthouse 8.6.0-dev.20211024 → 8.6.0-dev.20211028
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 +11 -11
- package/dist/report/standalone.js +2 -2
- package/flow-report/assets/styles.css +57 -1
- package/flow-report/src/common.tsx +8 -8
- package/flow-report/src/header.tsx +7 -8
- 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 +2 -1
- package/flow-report/src/util.ts +4 -4
- package/flow-report/src/wrappers/markdown.tsx +27 -0
- package/flow-report/src/wrappers/report.tsx +12 -0
- package/flow-report/test/common-test.tsx +6 -6
- 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 +7 -7
- package/report/README.md +1 -1
- package/report/generator/README.md +1 -1
- 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/format.js +5 -9
- 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;
|
|
@@ -8,7 +8,7 @@ import {FunctionComponent} from 'preact';
|
|
|
8
8
|
import {useEffect, useState} from 'preact/hooks';
|
|
9
9
|
|
|
10
10
|
import {NavigationIcon, SnapshotIcon, TimespanIcon} from './icons';
|
|
11
|
-
import {getFilmstripFrames, getScreenDimensions,
|
|
11
|
+
import {getFilmstripFrames, getScreenDimensions, getFullPageScreenshot} from './util';
|
|
12
12
|
|
|
13
13
|
const ANIMATION_FRAME_DURATION_MS = 500;
|
|
14
14
|
|
|
@@ -72,15 +72,15 @@ const FlowStepAnimatedThumbnail: FunctionComponent<{
|
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
export const FlowStepThumbnail: FunctionComponent<{
|
|
75
|
-
|
|
75
|
+
lhr: LH.Result,
|
|
76
76
|
width?: number,
|
|
77
77
|
height?: number,
|
|
78
|
-
}> = ({
|
|
79
|
-
const screenshot =
|
|
80
|
-
const frames = getFilmstripFrames(
|
|
78
|
+
}> = ({lhr, width, height}) => {
|
|
79
|
+
const screenshot = getFullPageScreenshot(lhr);
|
|
80
|
+
const frames = getFilmstripFrames(lhr);
|
|
81
81
|
|
|
82
82
|
// Resize the image to fit the viewport aspect ratio.
|
|
83
|
-
const dimensions = getScreenDimensions(
|
|
83
|
+
const dimensions = getScreenDimensions(lhr);
|
|
84
84
|
if (width && height === undefined) {
|
|
85
85
|
height = dimensions.height * width / dimensions.width;
|
|
86
86
|
} else if (height && width === undefined) {
|
|
@@ -92,7 +92,7 @@ export const FlowStepThumbnail: FunctionComponent<{
|
|
|
92
92
|
return <></>;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
if (
|
|
95
|
+
if (lhr.gatherMode === 'timespan' && frames && frames.length) {
|
|
96
96
|
return <FlowStepAnimatedThumbnail frames={frames} width={width} height={height} />;
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -101,7 +101,7 @@ export const FlowStepThumbnail: FunctionComponent<{
|
|
|
101
101
|
screenshot &&
|
|
102
102
|
<img
|
|
103
103
|
className="FlowStepThumbnail"
|
|
104
|
-
src={screenshot}
|
|
104
|
+
src={screenshot.screenshot.data}
|
|
105
105
|
style={{width, height}}
|
|
106
106
|
alt="Screenshot of a page tested by Lighthouse"
|
|
107
107
|
/>
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import {FunctionComponent} from 'preact';
|
|
8
8
|
|
|
9
|
-
import {Util} from '../../report/renderer/util';
|
|
10
9
|
import {FlowStepIcon, FlowStepThumbnail} from './common';
|
|
11
10
|
import {useLocalizedStrings} from './i18n/i18n';
|
|
12
11
|
import {getModeDescription, useFlowResult} from './util';
|
|
@@ -15,16 +14,16 @@ const SIDE_THUMBNAIL_HEIGHT = 80;
|
|
|
15
14
|
const MAIN_THUMBNAIL_HEIGHT = 120;
|
|
16
15
|
|
|
17
16
|
const HeaderThumbnail: FunctionComponent<{
|
|
18
|
-
|
|
17
|
+
lhr: LH.Result,
|
|
19
18
|
position: 'prev'|'next'|'main'
|
|
20
19
|
}> =
|
|
21
|
-
({
|
|
20
|
+
({lhr, position}) => {
|
|
22
21
|
const height = position === 'main' ? MAIN_THUMBNAIL_HEIGHT : SIDE_THUMBNAIL_HEIGHT;
|
|
23
22
|
return (
|
|
24
23
|
<div className={`HeaderThumbnail HeaderThumbnail--${position}`}>
|
|
25
|
-
<FlowStepThumbnail
|
|
24
|
+
<FlowStepThumbnail lhr={lhr} height={height}/>
|
|
26
25
|
<div className="HeaderThumbnail__icon">
|
|
27
|
-
<FlowStepIcon mode={
|
|
26
|
+
<FlowStepIcon mode={lhr.gatherMode}/>
|
|
28
27
|
</div>
|
|
29
28
|
</div>
|
|
30
29
|
);
|
|
@@ -50,7 +49,7 @@ export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
|
|
|
50
49
|
flowResult.steps[index - 2] && <div className="Header__segment"/>
|
|
51
50
|
}
|
|
52
51
|
<div className="Header__prev-thumbnail">
|
|
53
|
-
<HeaderThumbnail
|
|
52
|
+
<HeaderThumbnail lhr={prevStep.lhr} position="prev"/>
|
|
54
53
|
<div className="Header__segment"/>
|
|
55
54
|
</div>
|
|
56
55
|
<a
|
|
@@ -60,7 +59,7 @@ export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
|
|
|
60
59
|
</>
|
|
61
60
|
}
|
|
62
61
|
<div className="Header__current-thumbnail">
|
|
63
|
-
<HeaderThumbnail
|
|
62
|
+
<HeaderThumbnail lhr={step.lhr} position="main"/>
|
|
64
63
|
</div>
|
|
65
64
|
<div className="Header__current-title">
|
|
66
65
|
{step.name}
|
|
@@ -72,7 +71,7 @@ export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
|
|
|
72
71
|
nextStep && <>
|
|
73
72
|
<div className="Header__next-thumbnail">
|
|
74
73
|
<div className="Header__segment"/>
|
|
75
|
-
<HeaderThumbnail
|
|
74
|
+
<HeaderThumbnail lhr={nextStep.lhr} position="next"/>
|
|
76
75
|
</div>
|
|
77
76
|
<a
|
|
78
77
|
className="Header__next-title"
|
|
@@ -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
|
}
|
|
@@ -63,7 +63,7 @@ export const SummaryFlowStep: FunctionComponent<{
|
|
|
63
63
|
<Separator/>
|
|
64
64
|
</div>
|
|
65
65
|
}
|
|
66
|
-
<FlowStepThumbnail
|
|
66
|
+
<FlowStepThumbnail lhr={lhr} width={THUMBNAIL_WIDTH}/>
|
|
67
67
|
<FlowSegment mode={lhr.gatherMode}/>
|
|
68
68
|
<div className="SummaryFlowStep__label">
|
|
69
69
|
<div className="SummaryFlowStep__mode">{modeDescription}</div>
|
|
@@ -76,6 +76,7 @@ export const SummaryFlowStep: FunctionComponent<{
|
|
|
76
76
|
category={reportResult.categories[c]}
|
|
77
77
|
href={`#index=${hashIndex}&anchor=${c}`}
|
|
78
78
|
gatherMode={lhr.gatherMode}
|
|
79
|
+
finalUrl={lhr.finalUrl}
|
|
79
80
|
/>
|
|
80
81
|
))
|
|
81
82
|
}
|
package/flow-report/src/util.ts
CHANGED
|
@@ -35,24 +35,24 @@ export function classNames(...args: Array<string|undefined|Record<string, boolea
|
|
|
35
35
|
return classes.join(' ');
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export function getScreenDimensions(reportResult: LH.
|
|
38
|
+
export function getScreenDimensions(reportResult: LH.Result) {
|
|
39
39
|
const {width, height} = reportResult.configSettings.screenEmulation;
|
|
40
40
|
return {width, height};
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
export function
|
|
43
|
+
export function getFullPageScreenshot(reportResult: LH.Result) {
|
|
44
44
|
const fullPageScreenshotAudit = reportResult.audits['full-page-screenshot'];
|
|
45
45
|
const fullPageScreenshot =
|
|
46
46
|
fullPageScreenshotAudit &&
|
|
47
47
|
fullPageScreenshotAudit.details &&
|
|
48
48
|
fullPageScreenshotAudit.details.type === 'full-page-screenshot' &&
|
|
49
|
-
fullPageScreenshotAudit.details
|
|
49
|
+
fullPageScreenshotAudit.details;
|
|
50
50
|
|
|
51
51
|
return fullPageScreenshot || null;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export function getFilmstripFrames(
|
|
55
|
-
reportResult: LH.
|
|
55
|
+
reportResult: LH.Result
|
|
56
56
|
): Array<{data: string}> | undefined {
|
|
57
57
|
const filmstripAudit = reportResult.audits['screenshot-thumbnails'];
|
|
58
58
|
if (!filmstripAudit) return undefined;
|
|
@@ -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
|
+
};
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import {FunctionComponent} from 'preact';
|
|
8
8
|
import {useLayoutEffect, useRef} from 'preact/hooks';
|
|
9
9
|
|
|
10
|
+
import {ElementScreenshotRenderer} from '../../../report/renderer/element-screenshot-renderer';
|
|
11
|
+
import {getFullPageScreenshot} from '../util';
|
|
10
12
|
import {useReportRenderer} from './report-renderer';
|
|
11
13
|
|
|
12
14
|
/**
|
|
@@ -41,6 +43,16 @@ export const Report: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
|
|
|
41
43
|
dom.clearComponentCache();
|
|
42
44
|
reportRenderer.renderReport(currentLhr.value, ref.current);
|
|
43
45
|
convertChildAnchors(ref.current, currentLhr.index);
|
|
46
|
+
const fullPageScreenshot = getFullPageScreenshot(currentLhr.value);
|
|
47
|
+
if (fullPageScreenshot) {
|
|
48
|
+
const container = dom.find('.lh-container', ref.current);
|
|
49
|
+
ElementScreenshotRenderer.installOverlayFeature({
|
|
50
|
+
dom,
|
|
51
|
+
reportEl: container,
|
|
52
|
+
overlayContainerEl: container,
|
|
53
|
+
fullPageScreenshot,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
44
56
|
const topbar = ref.current.querySelector('.lh-topbar');
|
|
45
57
|
if (topbar) topbar.remove();
|
|
46
58
|
}
|
|
@@ -9,7 +9,7 @@ import {act, render} from '@testing-library/preact';
|
|
|
9
9
|
|
|
10
10
|
import {FlowStepThumbnail} from '../src/common';
|
|
11
11
|
|
|
12
|
-
let lhr: LH.
|
|
12
|
+
let lhr: LH.Result;
|
|
13
13
|
|
|
14
14
|
jest.useFakeTimers();
|
|
15
15
|
|
|
@@ -33,7 +33,7 @@ describe('FlowStepThumbnail', () => {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
it('renders a thumbnail', () => {
|
|
36
|
-
const root = render(<FlowStepThumbnail
|
|
36
|
+
const root = render(<FlowStepThumbnail lhr={lhr} width={200} height={200} />);
|
|
37
37
|
|
|
38
38
|
const thumbnail = root.getByAltText(/Screenshot/);
|
|
39
39
|
expect(thumbnail.style.width).toEqual('200px');
|
|
@@ -41,14 +41,14 @@ describe('FlowStepThumbnail', () => {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
it('renders nothing without dimensions', () => {
|
|
44
|
-
const root = render(<FlowStepThumbnail
|
|
44
|
+
const root = render(<FlowStepThumbnail lhr={lhr} />);
|
|
45
45
|
|
|
46
46
|
expect(() => root.getByAltText(/Screenshot/)).toThrow();
|
|
47
47
|
expect(global.console.warn).toHaveBeenCalled();
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
it('interpolates height', () => {
|
|
51
|
-
const root = render(<FlowStepThumbnail
|
|
51
|
+
const root = render(<FlowStepThumbnail lhr={lhr} width={200} />);
|
|
52
52
|
|
|
53
53
|
const thumbnail = root.getByAltText(/Screenshot/);
|
|
54
54
|
expect(thumbnail.style.width).toEqual('200px');
|
|
@@ -56,7 +56,7 @@ describe('FlowStepThumbnail', () => {
|
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
it('interpolates width', () => {
|
|
59
|
-
const root = render(<FlowStepThumbnail
|
|
59
|
+
const root = render(<FlowStepThumbnail lhr={lhr} height={150} />);
|
|
60
60
|
|
|
61
61
|
const thumbnail = root.getByAltText(/Screenshot/);
|
|
62
62
|
expect(thumbnail.style.width).toEqual('100px');
|
|
@@ -74,7 +74,7 @@ describe('FlowStepThumbnail', () => {
|
|
|
74
74
|
],
|
|
75
75
|
},
|
|
76
76
|
} as any;
|
|
77
|
-
const root = render(<FlowStepThumbnail
|
|
77
|
+
const root = render(<FlowStepThumbnail lhr={lhr} height={150} />);
|
|
78
78
|
|
|
79
79
|
const thumbnail = root.getByAltText(/Animated/) as HTMLImageElement;
|
|
80
80
|
expect(thumbnail.style.width).toEqual('100px');
|