diff --git a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap index d1e45ec5d810..13268b7bcf6d 100644 --- a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap +++ b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap @@ -69,6 +69,9 @@ Object { Object { "path": "installable-manifest", }, + Object { + "path": "apple-touch-icon", + }, Object { "path": "splash-screen", }, @@ -923,6 +926,11 @@ Object { "id": "without-javascript", "weight": 1, }, + Object { + "group": "pwa-optimized", + "id": "apple-touch-icon", + "weight": 1, + }, Object { "id": "pwa-cross-browser", "weight": 0, diff --git a/lighthouse-cli/test/smokehouse/pwa-expectations.js b/lighthouse-cli/test/smokehouse/pwa-expectations.js index b4a91c98c0b1..85616240be77 100644 --- a/lighthouse-cli/test/smokehouse/pwa-expectations.js +++ b/lighthouse-cli/test/smokehouse/pwa-expectations.js @@ -66,6 +66,9 @@ module.exports = [ 'content-width': { score: 1, }, + 'apple-touch-icon': { + score: 1, + }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { @@ -128,6 +131,9 @@ module.exports = [ 'content-width': { score: 1, }, + 'apple-touch-icon': { + score: 1, + }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { diff --git a/lighthouse-cli/test/smokehouse/pwa2-expectations.js b/lighthouse-cli/test/smokehouse/pwa2-expectations.js index 3a56038d3e74..b8b93d09b62d 100644 --- a/lighthouse-cli/test/smokehouse/pwa2-expectations.js +++ b/lighthouse-cli/test/smokehouse/pwa2-expectations.js @@ -61,6 +61,12 @@ module.exports = [ 'content-width': { score: 1, }, + 'apple-touch-icon': { + score: 1, + warnings: [ + /apple-touch-icon-precomposed/, + ], + }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { @@ -123,6 +129,9 @@ module.exports = [ 'content-width': { score: 1, }, + 'apple-touch-icon': { + score: 0, + }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { diff --git a/lighthouse-cli/test/smokehouse/pwa3-expectations.js b/lighthouse-cli/test/smokehouse/pwa3-expectations.js index 351a34272daf..d05f37387f03 100644 --- a/lighthouse-cli/test/smokehouse/pwa3-expectations.js +++ b/lighthouse-cli/test/smokehouse/pwa3-expectations.js @@ -58,6 +58,9 @@ module.exports = [ 'content-width': { score: 1, }, + 'apple-touch-icon': { + score: 1, + }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { diff --git a/lighthouse-core/audits/apple-touch-icon.js b/lighthouse-core/audits/apple-touch-icon.js new file mode 100644 index 000000000000..46313a29e1e6 --- /dev/null +++ b/lighthouse-core/audits/apple-touch-icon.js @@ -0,0 +1,71 @@ +/** + * @license Copyright 2019 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 Audit = require('./audit.js'); +const i18n = require('../lib/i18n/i18n.js'); + +/** + * @fileoverview Audits if a page has an `apple-touch-icon` link element with a valid href. + */ + +const UIStrings = { + /** Title of a Lighthouse audit that tells the user that their site contains a vaild touch icon. This descriptive title is shown when the page contains a valid iOS touch icon. "apple-touch-icon" is an HTML attribute value and should not be translated. */ + title: 'Provides a valid `apple-touch-icon`', + /** Title of a Lighthouse audit that tells the user that their site contains a vaild touch icon. This descriptive title is shown when the page does not contain a valid iOS touch icon. "apple-touch-icon" is an HTML attribute value and should not be translated. */ + failureTitle: 'Does not provide a valid `apple-touch-icon`', + /** Description of a Lighthouse audit that tells the user what having a valid apple-touch-icon does. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. "apple-touch-icon" is an HTML attribute value and should not be translated. */ + description: 'For ideal appearance on iOS when users add to the home screen, define an ' + + 'apple-touch-icon. It must point to a non-transparent 192px (or 180px) square PNG. ' + + '[Learn More](https://developers.google.com/web/fundamentals/design-and-ux/browser-customization/).', + /** Warning that HTML attribute `apple-touch-icon-precomposed` should not be used in favor of `apple-touch-icon`. "apple-touch-icon-precomposed" and "apple-touch-icon" are HTML attribute values and should not be translated. */ + precomposedWarning: '`apple-touch-icon-precomposed` is out of date; ' + + '`apple-touch-icon` is preferred.', +}; + +const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings); + +class AppleTouchIcon extends Audit { + /** + * @return {LH.Audit.Meta} + */ + static get meta() { + return { + id: 'apple-touch-icon', + title: str_(UIStrings.title), + failureTitle: str_(UIStrings.failureTitle), + description: str_(UIStrings.description), + requiredArtifacts: ['LinkElements'], + }; + } + + /** + * @param {LH.Artifacts} artifacts + * @return {LH.Audit.Product} + */ + static audit(artifacts) { + const appleTouchIcons = artifacts.LinkElements + .filter(el => el.rel === 'apple-touch-icon' || el.rel === 'apple-touch-icon-precomposed') + .filter(el => !!el.href); + + // Audit passes if an `apple-touch-icon` exists. + const passed = appleTouchIcons.length !== 0; + + const warnings = []; + if (appleTouchIcons.filter(el => el.rel === 'apple-touch-icon-precomposed').length !== 0 + && appleTouchIcons.filter(el => el.rel === 'apple-touch-icon').length === 0) { + warnings.push(str_(UIStrings.precomposedWarning)); + } + + return { + score: passed ? 1 : 0, + warnings, + }; + } +} + +module.exports = AppleTouchIcon; +module.exports.UIStrings = UIStrings; diff --git a/lighthouse-core/config/default-config.js b/lighthouse-core/config/default-config.js index 9184e54928f1..42672983cf19 100644 --- a/lighthouse-core/config/default-config.js +++ b/lighthouse-core/config/default-config.js @@ -179,6 +179,7 @@ const defaultConfig = { 'critical-request-chains', 'redirects', 'installable-manifest', + 'apple-touch-icon', 'splash-screen', 'themed-omnibox', 'content-width', @@ -523,6 +524,7 @@ const defaultConfig = { {id: 'content-width', weight: 1, group: 'pwa-optimized'}, {id: 'viewport', weight: 2, group: 'pwa-optimized'}, {id: 'without-javascript', weight: 1, group: 'pwa-optimized'}, + {id: 'apple-touch-icon', weight: 1, group: 'pwa-optimized'}, // Manual audits {id: 'pwa-cross-browser', weight: 0}, {id: 'pwa-page-transitions', weight: 0}, diff --git a/lighthouse-core/lib/i18n/en-US.json b/lighthouse-core/lib/i18n/en-US.json index e40e4f0483bd..b2d17c82babd 100644 --- a/lighthouse-core/lib/i18n/en-US.json +++ b/lighthouse-core/lib/i18n/en-US.json @@ -423,6 +423,22 @@ "message": "`