Skip to content

Commit

Permalink
core: add TestedAsMobileDevice base artifact (#7280)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattzeunert authored and brendankenny committed Mar 5, 2019
1 parent d3c155e commit 299ca2b
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 97 deletions.
13 changes: 4 additions & 9 deletions lighthouse-core/audits/content-width.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,21 @@ class ContentWidth extends Audit {
description: '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: ['ViewportDimensions', 'HostUserAgent'],
requiredArtifacts: ['ViewportDimensions', 'TestedAsMobileDevice'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {LH.Audit.Product}
*/
static audit(artifacts, context) {
const userAgent = artifacts.HostUserAgent;
static audit(artifacts) {
const IsMobile = artifacts.TestedAsMobileDevice;
const viewportWidth = artifacts.ViewportDimensions.innerWidth;
const windowWidth = artifacts.ViewportDimensions.outerWidth;
const widthsMatch = viewportWidth === windowWidth;

const isMobileHost = userAgent.includes('Android') || userAgent.includes('Mobile');
const isMobile = context.settings.emulatedFormFactor === 'mobile' ||
(context.settings.emulatedFormFactor !== 'desktop' && isMobileHost);

if (isMobile) {
if (IsMobile) {
return {
rawValue: widthsMatch,
explanation: this.createExplanation(widthsMatch, artifacts.ViewportDimensions),
Expand Down
11 changes: 10 additions & 1 deletion lighthouse-core/gather/gather-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,19 @@ class GatherRunner {
* @return {Promise<LH.BaseArtifacts>}
*/
static async getBaseArtifacts(options) {
const hostUserAgent = (await options.driver.getBrowserVersion()).userAgent;

const {emulatedFormFactor} = options.settings;
// Whether Lighthouse was run on a mobile device (i.e. not on a desktop machine).
const IsMobileHost = hostUserAgent.includes('Android') || hostUserAgent.includes('Mobile');
const TestedAsMobileDevice = emulatedFormFactor === 'mobile' ||
(emulatedFormFactor !== 'desktop' && IsMobileHost);

return {
fetchTime: (new Date()).toJSON(),
LighthouseRunWarnings: [],
HostUserAgent: (await options.driver.getBrowserVersion()).userAgent,
TestedAsMobileDevice,
HostUserAgent: hostUserAgent,
NetworkUserAgent: '', // updated later
BenchmarkIndex: 0, // updated later
WebAppManifest: null, // updated later
Expand Down
23 changes: 5 additions & 18 deletions lighthouse-core/test/audits/content-width-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,12 @@ const assert = require('assert');
describe('Mobile-friendly: content-width audit', () => {
it('fails when scroll width differs from viewport width', () => {
const result = Audit.audit({
HostUserAgent: 'Desktop',
TestedAsMobileDevice: true,
ViewportDimensions: {
innerWidth: 100,
outerWidth: 300,
},
}, {settings: {emulatedFormFactor: 'mobile'}});

assert.equal(result.rawValue, false);
assert.ok(result.explanation);
});

it('fails when host user agent is a phone', () => {
const result = Audit.audit({
HostUserAgent: 'Mobile Android',
ViewportDimensions: {
innerWidth: 100,
outerWidth: 300,
},
}, {settings: {emulatedFormFactor: 'none'}});
});

assert.equal(result.rawValue, false);
assert.ok(result.explanation);
Expand All @@ -47,13 +34,13 @@ describe('Mobile-friendly: content-width audit', () => {
}, {settings: {emulatedFormFactor: 'mobile'}}).rawValue, true);
});

it('not applicable when device emulation is turned off', () => {
it('not applicable when run on desktop', () => {
return assert.equal(Audit.audit({
HostUserAgent: 'Mobile Android Chrome',
TestedAsMobileDevice: false,
ViewportDimensions: {
innerWidth: 300,
outerWidth: 450,
},
}, {settings: {emulatedFormFactor: 'desktop'}}).notApplicable, true);
}).notApplicable, true);
});
});
150 changes: 81 additions & 69 deletions lighthouse-core/test/gather/fake-driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,79 @@
*/
'use strict';

function makeFakeDriver({protocolGetVersionResponse}) {
return {
getBrowserVersion() {
return Promise.resolve(Object.assign({}, protocolGetVersionResponse, {milestone: 71}));
},
getBenchmarkIndex() {
return Promise.resolve(125.2);
},
getAppManifest() {
return Promise.resolve(null);
},
connect() {
return Promise.resolve();
},
disconnect() {
return Promise.resolve();
},
gotoURL() {
return Promise.resolve('https://www.reddit.com/r/nba');
},
beginEmulation() {
return Promise.resolve();
},
setThrottling() {
return Promise.resolve();
},
dismissJavaScriptDialogs() {
return Promise.resolve();
},
assertNoSameOriginServiceWorkerClients() {
return Promise.resolve();
},
reloadForCleanStateIfNeeded() {
return Promise.resolve();
},
enableRuntimeEvents() {
return Promise.resolve();
},
evaluateScriptOnLoad() {
return Promise.resolve();
},
cleanBrowserCaches() {},
clearDataForOrigin() {},
cacheNatives() {
return Promise.resolve();
},
evaluateAsync() {
return Promise.resolve({});
},
registerPerformanceObserver() {
return Promise.resolve();
},
beginTrace() {
return Promise.resolve();
},
endTrace() {
return Promise.resolve(
require('../fixtures/traces/progressive-app.json')
);
},
beginDevtoolsLog() {},
endDevtoolsLog() {
return require('../fixtures/artifacts/perflog/defaultPass.devtoolslog.json');
},
blockUrlPatterns() {
return Promise.resolve();
},
setExtraHTTPHeaders() {
return Promise.resolve();
},
};
}

// https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-getVersion
const protocolGetVersionResponse = {
protocolVersion: '1.3',
Expand All @@ -14,77 +87,16 @@ const protocolGetVersionResponse = {
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3577.0 Safari/537.36',
jsVersion: '7.1.314',
};
const fakeDriver = makeFakeDriver({protocolGetVersionResponse});

const fakeDriver = {
getBrowserVersion() {
return Promise.resolve(Object.assign({}, protocolGetVersionResponse, {milestone: 71}));
},
getBenchmarkIndex() {
return Promise.resolve(125.2);
},
getAppManifest() {
return Promise.resolve(null);
},
connect() {
return Promise.resolve();
},
disconnect() {
return Promise.resolve();
},
gotoURL() {
return Promise.resolve('https://www.reddit.com/r/nba');
},
beginEmulation() {
return Promise.resolve();
},
setThrottling() {
return Promise.resolve();
},
dismissJavaScriptDialogs() {
return Promise.resolve();
},
assertNoSameOriginServiceWorkerClients() {
return Promise.resolve();
},
reloadForCleanStateIfNeeded() {
return Promise.resolve();
const fakeDriverUsingRealMobileDevice = makeFakeDriver({
protocolGetVersionResponse: {
...protocolGetVersionResponse,
// eslint-disable-next-line max-len
userAgent: 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36(KHTML, like Gecko) Chrome/69.0.3464.0 Mobile Safari/537.36',
},
enableRuntimeEvents() {
return Promise.resolve();
},
evaluateScriptOnLoad() {
return Promise.resolve();
},
cleanBrowserCaches() {},
clearDataForOrigin() {},
cacheNatives() {
return Promise.resolve();
},
evaluateAsync() {
return Promise.resolve({});
},
registerPerformanceObserver() {
return Promise.resolve();
},
beginTrace() {
return Promise.resolve();
},
endTrace() {
return Promise.resolve(
require('../fixtures/traces/progressive-app.json')
);
},
beginDevtoolsLog() {},
endDevtoolsLog() {
return require('../fixtures/artifacts/perflog/defaultPass.devtoolslog.json');
},
blockUrlPatterns() {
return Promise.resolve();
},
setExtraHTTPHeaders() {
return Promise.resolve();
},
};
});

module.exports = fakeDriver;
module.exports.fakeDriverUsingRealMobileDevice = fakeDriverUsingRealMobileDevice;
module.exports.protocolGetVersionResponse = protocolGetVersionResponse;
45 changes: 45 additions & 0 deletions lighthouse-core/test/gather/gather-runner-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class TestGathererNoArtifact extends Gatherer {
}

const fakeDriver = require('./fake-driver');
const fakeDriverUsingRealMobileDevice = fakeDriver.fakeDriverUsingRealMobileDevice;

function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn,
blockUrlFn, extraHeadersFn) {
Expand Down Expand Up @@ -156,6 +157,50 @@ describe('GatherRunner', function() {
});
});

describe('collects TestedAsMobileDevice as an artifact', () => {
const url = 'https://example.com';

it('works when running on desktop device without emulation', async () => {
const driver = fakeDriver;
const config = new Config({passes: [{}]});
const settings = {};
const options = {url, driver, config, settings};

const results = await GatherRunner.run(config.passes, options);
expect(results.TestedAsMobileDevice).toBe(false);
});

it('works when running on desktop device with mobile emulation', async () => {
const driver = fakeDriver;
const config = new Config({passes: [{}]});
const settings = {emulatedFormFactor: 'mobile'};
const options = {url, driver, config, settings};

const results = await GatherRunner.run(config.passes, options);
expect(results.TestedAsMobileDevice).toBe(true);
});

it('works when running on mobile device without emulation', async () => {
const driver = fakeDriverUsingRealMobileDevice;
const config = new Config({passes: [{}]});
const settings = {};
const options = {url, driver, config, settings};

const results = await GatherRunner.run(config.passes, options);
expect(results.TestedAsMobileDevice).toBe(true);
});

it('works when running on mobile device with desktop emulation', async () => {
const driver = fakeDriverUsingRealMobileDevice;
const config = new Config({passes: [{}]});
const settings = {emulatedFormFactor: 'desktop'};
const options = {url, driver, config, settings};

const results = await GatherRunner.run(config.passes, options);
expect(results.TestedAsMobileDevice).toBe(false);
});
});

it('sets up the driver to begin emulation when all emulation flags are undefined', () => {
const tests = {
calledDeviceEmulation: false,
Expand Down
1 change: 1 addition & 0 deletions lighthouse-core/test/results/artifacts/artifacts.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"LighthouseRunWarnings": [],
"BenchmarkIndex": 1000,
"TestedAsMobileDevice": true,
"HostUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3358.0 Safari/537.36",
"NetworkUserAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36(KHTML, like Gecko) Chrome/66.0.3359.30 Mobile Safari/537.36",
"fetchTime": "2018-03-13T00:55:45.840Z",
Expand Down
2 changes: 2 additions & 0 deletions types/artifacts.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ declare global {
fetchTime: string;
/** A set of warnings about unexpected things encountered while loading and testing the page. */
LighthouseRunWarnings: string[];
/** Whether the page was loaded on either a real or emulated mobile device. */
TestedAsMobileDevice: boolean;
/** The user agent string of the version of Chrome used. */
HostUserAgent: string;
/** The user agent string that Lighthouse used to load the page. */
Expand Down

0 comments on commit 299ca2b

Please sign in to comment.