diff --git a/lighthouse-cli/test/fixtures/byte-efficiency/tester.html b/lighthouse-cli/test/fixtures/byte-efficiency/tester.html index a206f546f92d..3b207c03e692 100644 --- a/lighthouse-cli/test/fixtures/byte-efficiency/tester.html +++ b/lighthouse-cli/test/fixtures/byte-efficiency/tester.html @@ -40,6 +40,12 @@ style.appendChild(document.createTextNode(textContent)); document.head.appendChild(style); } + +// Lazily load the image +setTimeout(() => { + const template = document.getElementById('lazily-loaded-image'); + document.body.appendChild(template.content.cloneNode(true)); +}, 3000); @@ -53,7 +59,8 @@

Byte efficiency tester page

- + + @@ -61,33 +68,47 @@

Byte efficiency tester page

+ + + - + + + + - + +
+ + + + diff --git a/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js b/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js index 374e1189cf41..914be1820ffd 100644 --- a/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js +++ b/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js @@ -34,6 +34,16 @@ module.exports = [ } } }, + 'offscreen-images': { + score: false, + extendedInfo: { + value: { + results: { + length: 3 + } + } + } + }, 'uses-optimized-images': { score: false, extendedInfo: { diff --git a/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js b/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js index 04ecad76c3a7..33e4764c8c28 100644 --- a/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +++ b/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js @@ -62,8 +62,9 @@ class UnusedBytes extends Audit { static audit(artifacts) { const networkRecords = artifacts.networkRecords[Audit.DEFAULT_PASS]; return artifacts.requestNetworkThroughput(networkRecords).then(networkThroughput => { - const result = this.audit_(artifacts, networkRecords); - return this.createAuditResult(result, networkThroughput); + return Promise.resolve(this.audit_(artifacts, networkRecords)).then(result => { + return this.createAuditResult(result, networkThroughput); + }); }); } diff --git a/lighthouse-core/audits/byte-efficiency/offscreen-images.js b/lighthouse-core/audits/byte-efficiency/offscreen-images.js new file mode 100644 index 000000000000..f3449a2bf905 --- /dev/null +++ b/lighthouse-core/audits/byte-efficiency/offscreen-images.js @@ -0,0 +1,147 @@ +/** + * @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. + */ + /** + * @fileoverview Checks to see if images are displayed only outside of the viewport. + * Images requested after TTI are not flagged as violations. + */ +'use strict'; + +const Audit = require('./byte-efficiency-audit'); +const TTIAudit = require('../time-to-interactive'); +const URL = require('../../lib/url-shim'); + +const ALLOWABLE_OFFSCREEN_X = 100; +const ALLOWABLE_OFFSCREEN_Y = 200; + +const IGNORE_THRESHOLD_IN_BYTES = 2048; +const IGNORE_THRESHOLD_IN_PERCENT = 75; + +class OffscreenImages extends Audit { + /** + * @return {!AuditMeta} + */ + static get meta() { + return { + category: 'Images', + name: 'offscreen-images', + description: 'Offscreen images', + helpText: 'Images that are not above the fold should be lazily loaded after the page is ' + + 'interactive. Consider using the [IntersectionObserver](https://developers.google.com/web/updates/2016/04/intersectionobserver) API.', + requiredArtifacts: ['ImageUsage', 'ViewportDimensions', 'traces', 'networkRecords'] + }; + } + + /** + * @param {!ClientRect} imageRect + * @param {{innerWidth: number, innerHeight: number}} viewportDimensions + * @return {number} + */ + static computeVisiblePixels(imageRect, viewportDimensions) { + const innerWidth = viewportDimensions.innerWidth; + const innerHeight = viewportDimensions.innerHeight; + + const top = Math.max(imageRect.top, -1 * ALLOWABLE_OFFSCREEN_Y); + const right = Math.min(imageRect.right, innerWidth + ALLOWABLE_OFFSCREEN_X); + const bottom = Math.min(imageRect.bottom, innerHeight + ALLOWABLE_OFFSCREEN_Y); + const left = Math.max(imageRect.left, -1 * ALLOWABLE_OFFSCREEN_X); + + return Math.max(right - left, 0) * Math.max(bottom - top, 0); + } + + /** + * @param {!Object} image + * @param {{innerWidth: number, innerHeight: number}} viewportDimensions + * @return {?Object} + */ + static computeWaste(image, viewportDimensions) { + const url = URL.getDisplayName(image.src, {preserveQuery: true}); + const totalPixels = image.clientWidth * image.clientHeight; + const visiblePixels = this.computeVisiblePixels(image.clientRect, viewportDimensions); + const wastedRatio = 1 - visiblePixels / totalPixels; + const totalBytes = image.networkRecord.resourceSize; + const wastedBytes = Math.round(totalBytes * wastedRatio); + + if (!Number.isFinite(wastedRatio)) { + return new Error(`Invalid image sizing information ${url}`); + } + + return { + url, + preview: { + url: image.networkRecord.url, + mimeType: image.networkRecord.mimeType + }, + requestStartTime: image.networkRecord.startTime, + totalBytes, + wastedBytes, + wastedPercent: 100 * wastedRatio, + }; + } + + /** + * @param {!Artifacts} artifacts + * @return {{results: !Array, tableHeadings: Object, + * passes: boolean=, debugString: string=}} + */ + static audit_(artifacts) { + const images = artifacts.ImageUsage; + const viewportDimensions = artifacts.ViewportDimensions; + + let debugString; + const resultsMap = images.reduce((results, image) => { + if (!image.networkRecord) { + return results; + } + + const processed = OffscreenImages.computeWaste(image, viewportDimensions); + if (processed instanceof Error) { + debugString = processed.message; + return results; + } + + // If an image was used more than once, warn only about its least wasteful usage + const existing = results.get(processed.preview.url); + if (!existing || existing.wastedBytes > processed.wastedBytes) { + results.set(processed.preview.url, processed); + } + + return results; + }, new Map()); + + return TTIAudit.audit(artifacts).then(ttiResult => { + const ttiTimestamp = ttiResult.extendedInfo.value.timestamps.timeToInteractive / 1000000; + const results = Array.from(resultsMap.values()).filter(item => { + const isWasteful = item.wastedBytes > IGNORE_THRESHOLD_IN_BYTES && + item.wastedPercent > IGNORE_THRESHOLD_IN_PERCENT; + const loadedEarly = item.requestStartTime < ttiTimestamp; + return isWasteful && loadedEarly; + }); + return { + debugString, + results, + tableHeadings: { + preview: '', + url: 'URL', + totalKb: 'Original', + potentialSavings: 'Potential Savings', + } + }; + }); + } +} + +module.exports = OffscreenImages; diff --git a/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js b/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js index 4316d1677ed5..afa91d8b65f8 100644 --- a/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +++ b/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js @@ -44,7 +44,7 @@ class UsesResponsiveImages extends Audit { 'Image sizes served should be based on the device display size to save network bytes. ' + 'Learn more about [responsive images](https://developers.google.com/web/fundamentals/design-and-ui/media/images) ' + 'and [client hints](https://developers.google.com/web/updates/2015/09/automating-resource-selection-with-client-hints).', - requiredArtifacts: ['ImageUsage', 'ContentWidth', 'networkRecords'] + requiredArtifacts: ['ImageUsage', 'ViewportDimensions', 'networkRecords'] }; } @@ -85,10 +85,9 @@ class UsesResponsiveImages extends Audit { */ static audit_(artifacts) { const images = artifacts.ImageUsage; - const contentWidth = artifacts.ContentWidth; + const DPR = artifacts.ViewportDimensions.devicePixelRatio; let debugString; - const DPR = contentWidth.devicePixelRatio; const resultsMap = images.reduce((results, image) => { // TODO: give SVG a free pass until a detail per pixel metric is available if (!image.networkRecord || image.networkRecord.mimeType === 'image/svg+xml') { diff --git a/lighthouse-core/audits/content-width.js b/lighthouse-core/audits/content-width.js index 946c5d4c63f3..6d42b8335cfc 100644 --- a/lighthouse-core/audits/content-width.js +++ b/lighthouse-core/audits/content-width.js @@ -31,7 +31,7 @@ class ContentWidth extends Audit { helpText: 'If the width of your app\'s content doesn\'t match the width ' + 'of the viewport, your app might not be optimized for mobile screens. ' + '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/content-sized-correctly-for-viewport).', - requiredArtifacts: ['ContentWidth'] + requiredArtifacts: ['ViewportDimensions'] }; } @@ -40,13 +40,13 @@ class ContentWidth extends Audit { * @return {!AuditResult} */ static audit(artifacts) { - const scrollWidth = artifacts.ContentWidth.scrollWidth; - const viewportWidth = artifacts.ContentWidth.viewportWidth; - const widthsMatch = scrollWidth === viewportWidth; + const viewportWidth = artifacts.ViewportDimensions.innerWidth; + const windowWidth = artifacts.ViewportDimensions.outerWidth; + const widthsMatch = viewportWidth === windowWidth; return { rawValue: widthsMatch, - debugString: this.createDebugString(widthsMatch, artifacts.ContentWidth) + debugString: this.createDebugString(widthsMatch, artifacts.ViewportDimensions) }; } @@ -55,8 +55,8 @@ class ContentWidth extends Audit { return ''; } - return 'The content scroll size is ' + artifact.scrollWidth + 'px, ' + - 'whereas the viewport size is ' + artifact.viewportWidth + 'px.'; + return 'The viewport size is ' + artifact.innerWidth + 'px, ' + + 'whereas the window size is ' + artifact.outerWidth + 'px.'; } } diff --git a/lighthouse-core/closure/typedefs/Artifacts.js b/lighthouse-core/closure/typedefs/Artifacts.js index 9e30c384c1e1..402b8930a243 100644 --- a/lighthouse-core/closure/typedefs/Artifacts.js +++ b/lighthouse-core/closure/typedefs/Artifacts.js @@ -74,8 +74,8 @@ Artifacts.prototype.CriticalRequestChains; /** @type {{first: number, complete: number, duration: number, frames: !Array, debugString: (string|undefined)}} */ Artifacts.prototype.Speedline; -/** @type {{scrollWidth: number, viewportWidth: number}} */ -Artifacts.prototype.ContentWidth; +/** @type {{innerWidth: number, outerWidth: number}} */ +Artifacts.prototype.ViewportDimensions; /** @type {!Array} */ Artifacts.prototype.CacheContents; diff --git a/lighthouse-core/config/default.json b/lighthouse-core/config/default.json index 1d223553ee7e..006c06f0698b 100644 --- a/lighthouse-core/config/default.json +++ b/lighthouse-core/config/default.json @@ -9,11 +9,11 @@ "url", "https", "viewport", + "viewport-dimensions", "theme-color", "manifest", - "accessibility", "image-usage", - "content-width" + "accessibility" ] }, { @@ -120,6 +120,7 @@ "accessibility/video-description", "byte-efficiency/total-byte-weight", "byte-efficiency/unused-css-rules", + "byte-efficiency/offscreen-images", "byte-efficiency/uses-optimized-images", "byte-efficiency/uses-responsive-images", "dobetterweb/appcache-manifest", @@ -579,6 +580,10 @@ "expectedValue": true, "weight": 1 }, + "offscreen-images": { + "expectedValue": true, + "weight": 1 + }, "uses-optimized-images": { "expectedValue": true, "weight": 1 diff --git a/lighthouse-core/gather/gatherers/image-usage.js b/lighthouse-core/gather/gatherers/image-usage.js index 1dd18fbaf460..8c5e10d4b6b2 100644 --- a/lighthouse-core/gather/gatherers/image-usage.js +++ b/lighthouse-core/gather/gatherers/image-usage.js @@ -28,12 +28,20 @@ const Gatherer = require('./gatherer'); /* istanbul ignore next */ function collectImageElementInfo() { return [...document.querySelectorAll('img')].map(element => { + const clientRect = element.getBoundingClientRect(); return { // currentSrc used over src to get the url as determined by the browser // after taking into account srcset/media/sizes/etc. src: element.currentSrc, clientWidth: element.clientWidth, clientHeight: element.clientHeight, + clientRect: { + // manually copy the properties because ClientRect does not JSONify + top: clientRect.top, + bottom: clientRect.bottom, + left: clientRect.left, + right: clientRect.right, + }, naturalWidth: element.naturalWidth, naturalHeight: element.naturalHeight, isPicture: element.parentElement.tagName === 'PICTURE', diff --git a/lighthouse-core/gather/gatherers/content-width.js b/lighthouse-core/gather/gatherers/viewport-dimensions.js similarity index 61% rename from lighthouse-core/gather/gatherers/content-width.js rename to lighthouse-core/gather/gatherers/viewport-dimensions.js index 2e1686a5feb1..4be3231e85a1 100644 --- a/lighthouse-core/gather/gatherers/content-width.js +++ b/lighthouse-core/gather/gatherers/viewport-dimensions.js @@ -21,38 +21,40 @@ const Gatherer = require('./gatherer'); /* global window */ /* istanbul ignore next */ -function getContentWidth() { +function getViewportDimensions() { // window.innerWidth to get the scrollable size of the window (irrespective of zoom) // window.outerWidth to get the size of the visible area // window.devicePixelRatio to get ratio of logical pixels to physical pixels return Promise.resolve({ - scrollWidth: window.innerWidth, - viewportWidth: window.outerWidth, + innerWidth: window.innerWidth, + innerHeight: window.innerHeight, + outerWidth: window.outerWidth, + outerHeight: window.outerHeight, devicePixelRatio: window.devicePixelRatio, }); } -class ContentWidth extends Gatherer { +class ViewportDimensions extends Gatherer { /** * @param {!Object} options - * @return {!Promise<{scrollWidth: number, viewportWidth: number, devicePixelRatio: number}>} + * @return {!Promise<{innerWidth: number, outerWidth: number, devicePixelRatio: number}>} */ afterPass(options) { const driver = options.driver; - return driver.evaluateAsync(`(${getContentWidth.toString()}())`) + return driver.evaluateAsync(`(${getViewportDimensions.toString()}())`) - .then(returnedValue => { - if (!Number.isFinite(returnedValue.scrollWidth) || - !Number.isFinite(returnedValue.viewportWidth) || - !Number.isFinite(returnedValue.devicePixelRatio)) { - throw new Error(`ContentWidth results were not numeric: ${JSON.stringify(returnedValue)}`); + .then(dimensions => { + const allNumeric = Object.keys(dimensions).every(key => Number.isFinite(dimensions[key])); + if (!allNumeric) { + const results = JSON.stringify(dimensions); + throw new Error(`ViewportDimensions results were not numeric: ${results}`); } - return returnedValue; + return dimensions; }); } } -module.exports = ContentWidth; +module.exports = ViewportDimensions; diff --git a/lighthouse-core/test/audits/byte-efficiency/offscreen-images-test.js b/lighthouse-core/test/audits/byte-efficiency/offscreen-images-test.js new file mode 100644 index 000000000000..2e53504cb288 --- /dev/null +++ b/lighthouse-core/test/audits/byte-efficiency/offscreen-images-test.js @@ -0,0 +1,144 @@ +/** + * 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 UnusedImages = + require('../../../audits/byte-efficiency/offscreen-images.js'); +const TTIAudit = require('../../../audits/time-to-interactive.js'); +const assert = require('assert'); + +/* eslint-env mocha */ +function generateRecord(resourceSizeInKb, startTime = 0, mimeType = 'image/png') { + return { + mimeType, + startTime, // DevTools timestamp which is in seconds + resourceSize: resourceSizeInKb * 1024, + }; +} + +function generateSize(width, height, prefix = 'client') { + const size = {}; + size[`${prefix}Width`] = width; + size[`${prefix}Height`] = height; + return size; +} + +function generateImage(size, coords, networkRecord, src = 'https://google.com/logo.png') { + Object.assign(networkRecord || {}, {url: src}); + + const x = coords[0]; + const y = coords[1]; + + const clientRect = { + top: y, + bottom: y + size.clientHeight, + left: x, + right: x + size.clientWidth, + }; + const image = {src, networkRecord, clientRect}; + Object.assign(image, size); + return image; +} + +describe('OffscreenImages audit', () => { + const _ttiAuditOriginal = TTIAudit.audit; + before(() => { + const desiredTTIInSeconds = 2; + const timeToInteractive = desiredTTIInSeconds * 1000000; // trace timestamps are in microseconds + const extendedInfo = {value: {timestamps: {timeToInteractive}}}; + TTIAudit.audit = () => Promise.resolve({extendedInfo}); + }); + + after(() => { + TTIAudit.audit = _ttiAuditOriginal; + }); + + const DEFAULT_DIMENSIONS = {innerWidth: 1920, innerHeight: 1080}; + + it('handles images without network record', () => { + return UnusedImages.audit_({ + ViewportDimensions: DEFAULT_DIMENSIONS, + ImageUsage: [ + generateImage(generateSize(100, 100), [0, 0]), + ], + }).then(auditResult => { + assert.equal(auditResult.results.length, 0); + }); + }); + + it('does not find used images', () => { + const urlB = 'https://google.com/logo2.png'; + const urlC = 'data:image/jpeg;base64,foobar'; + return UnusedImages.audit_({ + ViewportDimensions: DEFAULT_DIMENSIONS, + ImageUsage: [ + generateImage(generateSize(200, 200), [0, 0], generateRecord(100)), + generateImage(generateSize(100, 100), [0, 1080], generateRecord(100), urlB), + generateImage(generateSize(400, 400), [1720, 1080], generateRecord(3), urlC), + ], + }).then(auditResult => { + assert.equal(auditResult.results.length, 0); + }); + }); + + it('finds unused images', () => { + const url = s => `https://google.com/logo${s}.png`; + return UnusedImages.audit_({ + ViewportDimensions: DEFAULT_DIMENSIONS, + ImageUsage: [ + // offscreen to the right + generateImage(generateSize(200, 200), [3000, 0], generateRecord(100)), + // offscreen to the bottom + generateImage(generateSize(100, 100), [0, 2000], generateRecord(100), url('B')), + // offscreen to the top-left + generateImage(generateSize(100, 100), [-2000, -1000], generateRecord(100), url('C')), + // offscreen to the bottom-right + generateImage(generateSize(100, 100), [3000, 2000], generateRecord(100), url('D')), + // half offscreen to the top, should not warn + generateImage(generateSize(1000, 1000), [0, -500], generateRecord(100), url('E')), + ], + }).then(auditResult => { + assert.equal(auditResult.results.length, 4); + }); + }); + + it('de-dupes images', () => { + const urlB = 'https://google.com/logo2.png'; + return UnusedImages.audit_({ + ViewportDimensions: DEFAULT_DIMENSIONS, + ImageUsage: [ + generateImage(generateSize(50, 50), [0, 0], generateRecord(50)), + generateImage(generateSize(1000, 1000), [1000, 1000], generateRecord(50)), + generateImage(generateSize(50, 50), [0, 1500], generateRecord(200), urlB), + generateImage(generateSize(400, 400), [0, 1500], generateRecord(90), urlB), + ], + }).then(auditResult => { + assert.equal(auditResult.results.length, 1); + }); + }); + + it('disregards images loaded after TTI', () => { + return UnusedImages.audit_({ + ViewportDimensions: DEFAULT_DIMENSIONS, + ImageUsage: [ + // offscreen to the right + generateImage(generateSize(200, 200), [3000, 0], generateRecord(100, 3)), + ], + }).then(auditResult => { + assert.equal(auditResult.results.length, 0); + }); + }); +}); diff --git a/lighthouse-core/test/audits/byte-efficiency/uses-responsive-images-test.js b/lighthouse-core/test/audits/byte-efficiency/uses-responsive-images-test.js index b45ff3633746..f8b34d42a7f6 100644 --- a/lighthouse-core/test/audits/byte-efficiency/uses-responsive-images-test.js +++ b/lighthouse-core/test/audits/byte-efficiency/uses-responsive-images-test.js @@ -48,7 +48,7 @@ describe('Page uses responsive images', () => { const description = `${data.passes ? 'passes' : 'fails'} when an image is ${condition}`; it(description, () => { const result = UsesResponsiveImagesAudit.audit_({ - ContentWidth: {devicePixelRatio: data.devicePixelRatio || 1}, + ViewportDimensions: {devicePixelRatio: data.devicePixelRatio || 1}, ImageUsage: [ generateImage( generateSize(...data.clientSize), @@ -101,7 +101,7 @@ describe('Page uses responsive images', () => { it('handles images without network record', () => { const auditResult = UsesResponsiveImagesAudit.audit_({ - ContentWidth: {devicePixelRatio: 2}, + ViewportDimensions: {devicePixelRatio: 2}, ImageUsage: [ generateImage( generateSize(100, 100), @@ -117,7 +117,7 @@ describe('Page uses responsive images', () => { it('passes when all images are not wasteful', () => { const auditResult = UsesResponsiveImagesAudit.audit_({ - ContentWidth: {devicePixelRatio: 2}, + ViewportDimensions: {devicePixelRatio: 2}, ImageUsage: [ generateImage( generateSize(200, 200), @@ -150,7 +150,7 @@ describe('Page uses responsive images', () => { const recordA = generateRecord(100, 300, 'image/svg+xml'); const auditResult = UsesResponsiveImagesAudit.audit_({ - ContentWidth: {devicePixelRatio: 1}, + ViewportDimensions: {devicePixelRatio: 1}, ImageUsage: [ generateImage(generateSize(10, 10), naturalSizeA, recordA, urlA), ], @@ -169,7 +169,7 @@ describe('Page uses responsive images', () => { const recordB = generateRecord(10, 20); // make it small to still test passing const auditResult = UsesResponsiveImagesAudit.audit_({ - ContentWidth: {devicePixelRatio: 1}, + ViewportDimensions: {devicePixelRatio: 1}, ImageUsage: [ generateImage(generateSize(10, 10), naturalSizeA, recordA, urlA), generateImage(generateSize(450, 450), naturalSizeA, recordA, urlA), diff --git a/lighthouse-core/test/audits/content-width-test.js b/lighthouse-core/test/audits/content-width-test.js index 7298d5cdcf9b..d63c2f9f7e83 100644 --- a/lighthouse-core/test/audits/content-width-test.js +++ b/lighthouse-core/test/audits/content-width-test.js @@ -23,9 +23,9 @@ const assert = require('assert'); describe('Mobile-friendly: content-width audit', () => { it('fails when scroll width differs from viewport width', () => { const result = Audit.audit({ - ContentWidth: { - scrollWidth: 100, - viewportWidth: 300 + ViewportDimensions: { + innerWidth: 100, + outerWidth: 300 } }); @@ -35,9 +35,9 @@ describe('Mobile-friendly: content-width audit', () => { it('passes when widths match', () => { return assert.equal(Audit.audit({ - ContentWidth: { - scrollWidth: 300, - viewportWidth: 300 + ViewportDimensions: { + innerWidth: 300, + outerWidth: 300 } }).rawValue, true); }); diff --git a/lighthouse-core/test/gather/gatherers/content-width-test.js b/lighthouse-core/test/gather/gatherers/viewport-dimensions-test.js similarity index 69% rename from lighthouse-core/test/gather/gatherers/content-width-test.js rename to lighthouse-core/test/gather/gatherers/viewport-dimensions-test.js index 2d7de7479993..bf1b326f9037 100644 --- a/lighthouse-core/test/gather/gatherers/content-width-test.js +++ b/lighthouse-core/test/gather/gatherers/viewport-dimensions-test.js @@ -17,30 +17,33 @@ /* eslint-env mocha */ -const ContentWidthGatherer = require('../../../gather/gatherers/content-width'); +const ViewportDimensionsGatherer = require('../../../gather/gatherers/viewport-dimensions'); const assert = require('assert'); -let contentWidthGatherer; +let gatherer; -describe('Content Width gatherer', () => { +describe('ViewportDimensions gatherer', () => { // Reset the Gatherer before each test. beforeEach(() => { - contentWidthGatherer = new ContentWidthGatherer(); + gatherer = new ViewportDimensionsGatherer(); }); it('returns an artifact', () => { - return contentWidthGatherer.afterPass({ + return gatherer.afterPass({ driver: { evaluateAsync() { return Promise.resolve({ - scrollWidth: 400, - viewportWidth: 400, + innerWidth: 400, + outerWidth: 400, + innerHeight: 600, + outerHeight: 600, devicePixelRatio: 2, }); } } }).then(artifact => { assert.ok(typeof artifact === 'object'); - assert.ok(artifact.viewportWidth === 400); + assert.ok(artifact.outerWidth === 400); + assert.ok(artifact.innerHeight === 600); }); }); });