core: add TestedAsMobileDevice base artifact (#7280)
This commit is contained in:
Родитель
d3c155e98c
Коммит
299ca2b133
|
@ -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",
|
||||
|
|
|
@ -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. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче