Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new_audit(dobetterweb): add new audit for doctype #5274

Merged
merged 4 commits into from
Jul 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions lighthouse-core/audits/dobetterweb/doctype.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* @license Copyright 2018 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 Doctype extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'doctype',
title: 'Page has the HTML doctype',
failureTitle: 'Page is missing the HTML doctype',
description: 'Specifying a doctype prevents the browser from switching to quirks-mode.' +
'Read more on the ' +
'[MDN Web Docs page](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)',
requiredArtifacts: ['Doctype'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @return {LH.Audit.Product}
*/
static audit(artifacts) {
if (!artifacts.Doctype) {
return {
rawValue: false,
explanation: 'Document must contain a doctype',
};
}

// only set constants once we know there is a doctype
const doctypeName = artifacts.Doctype.name.trim();
const doctypePublicId = artifacts.Doctype.publicId;
const doctypeSystemId = artifacts.Doctype.systemId;

if (doctypePublicId !== '') {
return {
rawValue: false,
explanation: 'Expected publicId to be an empty string',
};
}

if (doctypeSystemId !== '') {
return {
rawValue: false,
explanation: 'Expected systemId to be an empty string',
};
}

/* Note that the value for name is case sensitive,
and must be the string `html`. For details see:
https://html.spec.whatwg.org/multipage/parsing.html#the-initial-insertion-mode */
if (doctypeName === 'html') {
return {
rawValue: true,
};
} else {
return {
rawValue: false,
explanation: 'Doctype name must be the lowercase string `html`',
};
}
}
}

module.exports = Doctype;
5 changes: 4 additions & 1 deletion lighthouse-core/config/default-config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @license Copyright 2017 Google Inc. All Rights Reserved.
* @license Copyright 2018 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.
*/
Expand Down Expand Up @@ -31,6 +31,7 @@ module.exports = {
'accessibility',
'dobetterweb/anchors-with-no-rel-noopener',
'dobetterweb/appcache',
'dobetterweb/doctype',
'dobetterweb/domstats',
'dobetterweb/js-libraries',
'dobetterweb/optimized-images',
Expand Down Expand Up @@ -161,6 +162,7 @@ module.exports = {
'byte-efficiency/uses-responsive-images',
'byte-efficiency/efficient-animated-content',
'dobetterweb/appcache-manifest',
'dobetterweb/doctype',
'dobetterweb/dom-size',
'dobetterweb/external-anchors-use-rel-noopener',
'dobetterweb/geolocation-on-start',
Expand Down Expand Up @@ -373,6 +375,7 @@ module.exports = {
{id: 'no-document-write', weight: 1},
{id: 'external-anchors-use-rel-noopener', weight: 1},
{id: 'geolocation-on-start', weight: 1},
{id: 'doctype', weight: 1},
{id: 'no-vulnerable-libraries', weight: 1},
{id: 'notification-on-start', weight: 1},
{id: 'deprecations', weight: 1},
Expand Down
36 changes: 36 additions & 0 deletions lighthouse-core/gather/gatherers/dobetterweb/doctype.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @license Copyright 2018 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 Gatherer = require('../gatherer');

/**
* Get and return `name`, `publicId`, `systemId` from
* `document.doctype`
* @return {{name: string, publicId: string, systemId: string} | null}
*/
function getDoctype() {
// An example of this is warnerbros.com/archive/spacejam/movie/jam.htm
if (!document.doctype) { // eslint-disable-line no-undef
return null;
}

const {name, publicId, systemId} = document.doctype; // eslint-disable-line no-undef
return {name, publicId, systemId};
}

class Doctype extends Gatherer {
/**
* @param {LH.Gatherer.PassContext} passContext
* @return {Promise<LH.Artifacts['Doctype']>}
*/
afterPass(passContext) {
const driver = passContext.driver;
return driver.evaluateAsync(`(${getDoctype.toString()}())`);
}
}

module.exports = Doctype;
80 changes: 80 additions & 0 deletions lighthouse-core/test/audits/dobetterweb/doctype-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @license Copyright 2018 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('../../../audits/dobetterweb/doctype.js');
const assert = require('assert');

/* eslint-env mocha */

describe('DOBETTERWEB: doctype audit', () => {
it('fails when document does not contain a doctype', () => {
const auditResult = Audit.audit({
Doctype: null,
});
assert.equal(auditResult.rawValue, false);
assert.equal(auditResult.explanation, 'Document must contain a doctype');
});

it('fails when the value of the name attribute is a value other then lowercase "html"', () => {
const auditResult = Audit.audit({
Doctype: {
name: 'xml',
publicId: '',
systemId: '',
},
});
assert.equal(auditResult.rawValue, false);
assert.equal(auditResult.explanation, 'Doctype name must be the lowercase string `html`');
});

it('fails when the value of the name attribute is not the lowercase string "html"', () => {
const auditResult = Audit.audit({
Doctype: {
name: 'HTML',
publicId: '',
systemId: '',
},
});
assert.equal(auditResult.rawValue, false);
assert.equal(auditResult.explanation, 'Doctype name must be the lowercase string `html`');
});

it('fails when the publicId attribute is not an empty string', () => {
const auditResult = Audit.audit({
Doctype: {
name: 'html',
publicId: '189655',
systemId: '',
},
});
assert.equal(auditResult.rawValue, false);
assert.equal(auditResult.explanation, 'Expected publicId to be an empty string');
});

it('fails when the systemId attribute is not an empty string', () => {
const auditResult = Audit.audit({
Doctype: {
name: 'html',
publicId: '',
systemId: '189655',
},
});
assert.equal(auditResult.rawValue, false);
assert.equal(auditResult.explanation, 'Expected systemId to be an empty string');
});

it('succeeds when document contains a doctype, and the name value is "html"', () => {
const auditResult = Audit.audit({
Doctype: {
name: 'html',
publicId: '',
systemId: '',
},
});
assert.equal(auditResult.rawValue, true);
});
});
5 changes: 5 additions & 0 deletions lighthouse-core/test/results/artifacts/artifacts.json
Original file line number Diff line number Diff line change
Expand Up @@ -2521,5 +2521,10 @@
},
"HTMLWithoutJavaScript": {
"bodyText": "Do better web tester page\nHi there!\ntouchmove section\n "
},
"Doctype": {
"name": "html",
"systemId": "",
"publicId": ""
}
}
14 changes: 13 additions & 1 deletion lighthouse-core/test/results/sample_v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -2202,6 +2202,14 @@
"rawValue": false,
"displayValue": "Found \"clock.appcache\""
},
"doctype": {
"id": "doctype",
"title": "Page has the HTML doctype",
"description": "Specifying a doctype prevents the browser from switching to quirks-mode.Read more on the [MDN Web Docs page](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)",
"score": 1,
"scoreDisplayMode": "binary",
"rawValue": true
},
"dom-size": {
"id": "dom-size",
"title": "Avoids an excessive DOM size",
Expand Down Expand Up @@ -3261,6 +3269,10 @@
"id": "geolocation-on-start",
"weight": 1
},
{
"id": "doctype",
"weight": 1
},
{
"id": "no-vulnerable-libraries",
"weight": 1
Expand All @@ -3287,7 +3299,7 @@
}
],
"id": "best-practices",
"score": 0
"score": 0.07
},
"seo": {
"title": "SEO",
Expand Down
9 changes: 9 additions & 0 deletions typings/artifacts.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ declare global {
CrawlableLinks: {href: string, text: string}[];
/** CSS coverage information for styles used by page's final state. */
CSSUsage: {rules: Crdp.CSS.RuleUsage[], stylesheets: Artifacts.CSSStyleSheetInfo[]};
/** Information on the document's doctype(or null if not present), specifically the name, publicId, and systemId.
All properties default to an empty string if not present */
Doctype: Artifacts.Doctype | null;
/** Information on the size of all DOM nodes in the page and the most extreme members. */
DOMStats: Artifacts.DOMStats;
/** Relevant attributes and child properties of all <object>s, <embed>s and <applet>s in the page. */
Expand Down Expand Up @@ -173,6 +176,12 @@ declare global {
content: string;
}

export interface Doctype {
name: string;
publicId: string;
systemId: string;
}

export interface DOMStats {
totalDOMNodes: number;
width: {max: number, pathToElement: Array<string>, snippet: string};
Expand Down