From 6556ef5ddf0e11bccb4ff3a4e8ec5f8a1458b115 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 7 Aug 2018 16:20:16 -0700 Subject: [PATCH 1/9] add PSI.prepareLabData() --- lighthouse-core/report/html/renderer/psi.js | 66 +++++++++++++++++ lighthouse-core/report/html/renderer/util.js | 8 +-- .../test/report/html/renderer/psi-test.js | 70 +++++++++++++++++++ 3 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 lighthouse-core/report/html/renderer/psi.js create mode 100644 lighthouse-core/test/report/html/renderer/psi-test.js diff --git a/lighthouse-core/report/html/renderer/psi.js b/lighthouse-core/report/html/renderer/psi.js new file mode 100644 index 000000000000..b0bb40397512 --- /dev/null +++ b/lighthouse-core/report/html/renderer/psi.js @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2018 Google Inc. All Rights Reserved. + * + * 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 + * + * 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. + */ +'use strict'; + +/* globals self DOM PerformanceCategoryRenderer Util DetailsRenderer */ + +class PSI { + /** + * Returns all the elements that PSI needs to render the report + * We keep expose this helper method to minimize the 'public' API surface of the renderer + * and allow us to refactor without two-sided patches. + * + * const {scoreGaugeEl, perfCategoryEl, finalScreenshotDataUri} = PSI.prepareLabData( + * LHresponseJsonString, + * document + * ); + * + * @param {string} LHresponseJsonString + * @param {Document} document + * @return {{scoreGaugeEl: Element, perfCategoryEl: Element, finalScreenshotDataUri: string|null}} + */ + static prepareLabData(LHresponseJsonString, document) { + const lhResult = /** @type {LH.Result} */ JSON.parse(LHresponseJsonString); + const dom = new DOM(document); + + const reportLHR = Util.prepareReportResult(lhResult); + const perfCategory = reportLHR.reportCategories.find(cat => cat.id === 'performance'); + if (!perfCategory) throw new Error(`No performance category. Can't make lab data section`); + if (!reportLHR.categoryGroups) throw new Error(`No category groups found.`); + + const perfRenderer = new PerformanceCategoryRenderer(dom, new DetailsRenderer(dom)); + const perfCategoryEl = perfRenderer.render(perfCategory, reportLHR.categoryGroups); + + const scoreGaugeEl = dom.find('.lh-score__gauge', perfCategoryEl); + const scoreGaugeWrapper = dom.find('.lh-gauge__wrapper', scoreGaugeEl); + scoreGaugeWrapper.classList.add('lh-gauge__wrapper--huge'); + // Remove Performance category title/description + dom.find('.lh-category-header', perfCategoryEl).remove(); + // Remove navigation links + scoreGaugeWrapper.removeAttribute('href'); + dom.find('.lh-permalink', perfCategoryEl).remove(); + + const finalScreenshotDataUri = Util.getFinalScreenshot(perfCategory); + return {scoreGaugeEl, perfCategoryEl, finalScreenshotDataUri}; + } +} + +if (typeof module !== 'undefined' && module.exports) { + module.exports = PSI; +} else { + self.PSI = PSI; +} diff --git a/lighthouse-core/report/html/renderer/util.js b/lighthouse-core/report/html/renderer/util.js index 922b90517fbb..47577020eefb 100644 --- a/lighthouse-core/report/html/renderer/util.js +++ b/lighthouse-core/report/html/renderer/util.js @@ -378,13 +378,11 @@ class Util { } /** - * @param {LH.ReportResult} result + * @param {LH.ReportResult.Category} perfCategory * @return {null|string} */ - static getFinalScreenshot(result) { - const category = result.reportCategories.find(cat => cat.id === 'performance'); - if (!category) return null; - const auditRef = category.auditRefs.find(audit => audit.id === 'final-screenshot'); + static getFinalScreenshot(perfCategory) { + const auditRef = perfCategory.auditRefs.find(audit => audit.id === 'final-screenshot'); if (!auditRef || !auditRef.result || auditRef.result.scoreDisplayMode === 'error') return null; return auditRef.result.details.data; } diff --git a/lighthouse-core/test/report/html/renderer/psi-test.js b/lighthouse-core/test/report/html/renderer/psi-test.js new file mode 100644 index 000000000000..494f8b56833e --- /dev/null +++ b/lighthouse-core/test/report/html/renderer/psi-test.js @@ -0,0 +1,70 @@ +/** + * @license Copyright 2017 Google Inc. All Rights Reserved. + * 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 + * 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. + */ +'use strict'; + +const assert = require('assert'); +const fs = require('fs'); + +const jsdom = require('jsdom'); + +const URL = require('../../../../lib/url-shim'); +const PSI = require('../../../../report/html/renderer/psi.js'); +const Util = require('../../../../report/html/renderer/util.js'); +const DOM = require('../../../../report/html/renderer/dom.js'); +const CategoryRenderer = + require('../../../../report/html/renderer/category-renderer'); +const DetailsRenderer = require('../../../../report/html/renderer/details-renderer'); +const CriticalRequestChainRenderer = + require('../../../../report/html/renderer/crc-details-renderer'); + +const sampleResultsStr = fs.readFileSync(__dirname + '/../../../results/sample_v2.json', 'utf-8'); +const TEMPLATE_FILE = fs.readFileSync(__dirname + + '/../../../../report/html/templates.html', 'utf8'); + +/* eslint-env jest */ + +describe('DOM', () => { + let document; + beforeAll(() => { + global.URL = URL; // do i need to do this? + global.Util = Util; + global.DOM = DOM; + global.CategoryRenderer = CategoryRenderer; + global.DetailsRenderer = DetailsRenderer; + + // Delayed so that CategoryRenderer is in global scope + const PerformanceCategoryRenderer = + require('../../../../report/html/renderer/performance-category-renderer'); + global.PerformanceCategoryRenderer = PerformanceCategoryRenderer; + global.CriticalRequestChainRenderer = CriticalRequestChainRenderer; + + document = jsdom.jsdom(TEMPLATE_FILE); + }); + + afterAll(() => { + global.URL = undefined; + global.Util = undefined; + global.DOM = undefined; + global.CategoryRenderer = undefined; + global.DetailsRenderer = undefined; + global.PerformanceCategoryRenderer = undefined; + global.CriticalRequestChainRenderer = undefined; + }); + + describe('psi prepareLabData helper', () => { + it('reports expected data', () => { + const result = PSI.prepareLabData(sampleResultsStr, document); + assert.ok(result.scoreGaugeEl instanceof document.defaultView.Element); + assert.ok(result.perfCategoryEl instanceof document.defaultView.Element); + assert.equal(typeof result.finalScreenshotDataUri, 'string'); + + assert.ok(result.finalScreenshotDataUri.startsWith('data:image/jpeg;base64,')); + assert.ok(result.scoreGaugeEl.outerHTML.includes('