core: add TestedAsMobileDevice base artifact (#7280)

This commit is contained in:
Matt Zeunert 2019-03-05 20:01:26 +00:00 коммит произвёл Brendan Kenny
Родитель d3c155e98c
Коммит 299ca2b133
7 изменённых файлов: 148 добавлений и 97 удалений

Просмотреть файл

@ -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),

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
@ -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);
});
});

Просмотреть файл

@ -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',
@ -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}));
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',
},
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();
},
};
});
module.exports = fakeDriver;
module.exports.fakeDriverUsingRealMobileDevice = fakeDriverUsingRealMobileDevice;
module.exports.protocolGetVersionResponse = protocolGetVersionResponse;

Просмотреть файл

@ -33,6 +33,7 @@ class TestGathererNoArtifact extends Gatherer {
}
const fakeDriver = require('./fake-driver');
const fakeDriverUsingRealMobileDevice = fakeDriver.fakeDriverUsingRealMobileDevice;
function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn,
blockUrlFn, extraHeadersFn) {
@ -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,

Просмотреть файл

@ -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",

2
types/artifacts.d.ts поставляемый
Просмотреть файл

@ -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. */