From 14f2c6af49be129770751444d11197f8918211df Mon Sep 17 00:00:00 2001 From: Paul Lewis Date: Fri, 15 Jul 2016 16:44:08 +0100 Subject: [PATCH] Adds tests for checking interstitials --- lighthouse-core/audits/interstitial.js | 54 +++++++++++++++ lighthouse-core/config/default.json | 10 ++- .../driver/gatherers/interstitial.js | 66 +++++++++++++++++++ lighthouse-core/test/audits/intersitial.js | 45 +++++++++++++ .../test/driver/gatherers/interstitial.js | 56 ++++++++++++++++ 5 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 lighthouse-core/audits/interstitial.js create mode 100644 lighthouse-core/driver/gatherers/interstitial.js create mode 100644 lighthouse-core/test/audits/intersitial.js create mode 100644 lighthouse-core/test/driver/gatherers/interstitial.js diff --git a/lighthouse-core/audits/interstitial.js b/lighthouse-core/audits/interstitial.js new file mode 100644 index 000000000000..ab7cd303a7f5 --- /dev/null +++ b/lighthouse-core/audits/interstitial.js @@ -0,0 +1,54 @@ +/** + * @license + * Copyright 2016 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'); + +class Interstitial extends Audit { + /** + * @return {!AuditMeta} + */ + static get meta() { + return { + category: 'UX', + name: 'interstitial', + description: 'The page does not place interstitials over the page content', + requiredArtifacts: ['Interstitial'] + }; + } + + /** + * @param {!Artifacts} artifacts + * @return {!AuditResult} + */ + static audit(artifacts) { + if (typeof artifacts.Interstitial === 'undefined' || + !Array.isArray(artifacts.Interstitial)) { + return Interstitial.generateAuditResult({ + rawValue: false, + debugString: 'Unable to retrieve element information.' + }); + } + + return Interstitial.generateAuditResult({ + rawValue: (artifacts.Interstitial.length === 0) + }); + } +} + +module.exports = Interstitial; diff --git a/lighthouse-core/config/default.json b/lighthouse-core/config/default.json index 10f964a2ed53..d12645bdb110 100644 --- a/lighthouse-core/config/default.json +++ b/lighthouse-core/config/default.json @@ -16,7 +16,8 @@ "critical-request-chains", "speedline", "content-width", - "cache-contents" + "cache-contents", + "interstitial" ] }, { @@ -65,7 +66,8 @@ "label", "tabindex", "content-width", - "cache-start-url" + "cache-start-url", + "interstitial" ], "aggregations": [{ @@ -230,6 +232,10 @@ "content-width": { "value": true, "weight": 1 + }, + "interstitial": { + "value": true, + "weight": 1 } } }] diff --git a/lighthouse-core/driver/gatherers/interstitial.js b/lighthouse-core/driver/gatherers/interstitial.js new file mode 100644 index 000000000000..3418c2570d70 --- /dev/null +++ b/lighthouse-core/driver/gatherers/interstitial.js @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2016 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 Gather = require('./gather'); + +/* global window, document, __returnResults */ + +/* istanbul ignore next */ +function getInterstitial() { + const viewportSize = window.outerWidth * window.outerHeight; + + // Walk the tree of elements + const candidates = [...document.querySelectorAll('*')] + .filter(e => { + // Check for position fixed. + const isFixed = window.getComputedStyle(e).position === 'fixed'; + + // Check for nav elements. + const regExpNav = /menu|nav|sidebar|drawer/i; + const isNav = regExpNav.test(e.className) || regExpNav.test(e.id); + + // Get the size of the element. + const eBCR = e.getBoundingClientRect(); + const size = eBCR.width * eBCR.height; + + // Only allow through fixed, non-nav elements whose size makes them cover + // over 50% of the available viewport. + return isFixed && !isNav && (size / viewportSize > 0.5); + }); + + // __returnResults is injected by evaluateAsync for passing back the result. + __returnResults(candidates); +} + +class Interstitial extends Gather { + + afterPass(options) { + const driver = options.driver; + + return driver.evaluateAsync(`(${getInterstitial.toString()}())`) + + .then(returnedValue => { + this.artifact = returnedValue; + }, _ => { + this.artifact = -1; + return; + }); + } +} + +module.exports = Interstitial; diff --git a/lighthouse-core/test/audits/intersitial.js b/lighthouse-core/test/audits/intersitial.js new file mode 100644 index 000000000000..bcedd987e7e6 --- /dev/null +++ b/lighthouse-core/test/audits/intersitial.js @@ -0,0 +1,45 @@ +/** + * Copyright 2016 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. + */ +const Audit = require('../../audits/interstitial.js'); +const assert = require('assert'); + +/* global describe, it*/ + +describe('Mobile-friendly: interstitial audit', () => { + it('fails when no input present', () => { + return assert.equal(Audit.audit({}).rawValue, false); + }); + + it('fails when input is of incorrect type', () => { + return assert.equal(Audit.audit({ + Interstitial: 3 + }).rawValue, false); + }); + + it('fails when element array is non-empty', () => { + return assert.equal(Audit.audit({ + Interstitial: [ + 'x' + ] + }).rawValue, false); + }); + + it('passes when widths match', () => { + return assert.equal(Audit.audit({ + Interstitial: [] + }).rawValue, true); + }); +}); diff --git a/lighthouse-core/test/driver/gatherers/interstitial.js b/lighthouse-core/test/driver/gatherers/interstitial.js new file mode 100644 index 000000000000..33fa91b1aede --- /dev/null +++ b/lighthouse-core/test/driver/gatherers/interstitial.js @@ -0,0 +1,56 @@ +/** + * Copyright 2016 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'; + +/* eslint-env mocha */ + +const InterstitialGatherer = require('../../../driver/gatherers/interstitial'); +const assert = require('assert'); +let interstitialGatherer; + +describe('Interstitial gatherer', () => { + // Reset the Gatherer before each test. + beforeEach(() => { + interstitialGatherer = new InterstitialGatherer(); + }); + + it('returns an artifact', () => { + return interstitialGatherer.afterPass({ + driver: { + evaluateAsync() { + return Promise.resolve(['test']); + } + } + }).then(_ => { + assert.ok(Array.isArray(interstitialGatherer.artifact)); + assert.equal(interstitialGatherer.artifact.length, 1); + }); + }); + + it('handles driver failure', () => { + return interstitialGatherer.afterPass({ + driver: { + evaluateAsync() { + return Promise.reject('such a fail'); + } + } + }).then(_ => { + assert(false); + }).catch(_ => { + assert.equal(interstitialGatherer.artifact, -1); + }); + }); +});