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

feat: add groups to config, accessibility renderer #2057

Merged
merged 13 commits into from
May 3, 2017
18 changes: 16 additions & 2 deletions lighthouse-core/config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function validatePasses(passes, audits, rootPath) {
});
}

function validateCategories(categories, audits, auditResults) {
function validateCategories(categories, audits, auditResults, groups) {
if (!categories) {
return;
}
Expand All @@ -167,6 +167,14 @@ function validateCategories(categories, audits, auditResults) {
if (!auditIds.includes(audit.id)) {
throw new Error(`could not find ${audit.id} audit for category ${categoryId}`);
}

if (categoryId === 'accessibility' && !audit.group) {
throw new Error(`${audit.id} accessibility audit does not have a group`);
}

if (audit.group && !groups[audit.group]) {
throw new Error(`${audit.id} references unknown group ${audit.group}`);
}
});
});
}
Expand Down Expand Up @@ -321,10 +329,11 @@ class Config {
this._audits = Config.requireAudits(configJSON.audits, this._configDir);
this._artifacts = expandArtifacts(configJSON.artifacts);
this._categories = configJSON.categories;
this._groups = configJSON.groups;

// validatePasses must follow after audits are required
validatePasses(configJSON.passes, this._audits, this._configDir);
validateCategories(configJSON.categories, this._audits, this._auditResults);
validateCategories(configJSON.categories, this._audits, this._auditResults, this._groups);
}

/**
Expand Down Expand Up @@ -573,6 +582,11 @@ class Config {
get categories() {
return this._categories;
}

/** @type {Object<string, {title: string, description: string}>|undefined} */
get groups() {
return this._groups;
}
}

module.exports = Config;
104 changes: 69 additions & 35 deletions lighthouse-core/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,40 @@ module.exports = {
}
}]
}],
"groups": {
"a11y-color-contrast": {
"title": "Color Contrast Is Satisfactory",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
"a11y-describe-contents": {
"title": "Elements Describe Contents Well",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
"a11y-well-structured": {
"title": "Elements Are Well Structured",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
"a11y-aria": {
"title": "ARIA Attributes Follow Best Practices",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
"a11y-correct-attributes": {
"title": "Elements Use Attributes Correctly",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
"a11y-element-names": {
"title": "Elements Have Discernable Names",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
"a11y-language": {
"title": "Page Specifies Valid Language",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
"a11y-meta": {
"title": "Meta Tags Used Properly",
"description": "Screen readers and other assitive technologies require annotations to understand otherwise ambiguous content."
},
},
"categories": {
"pwa": {
"name": "Progressive Web App",
Expand Down Expand Up @@ -631,41 +665,41 @@ module.exports = {
"name": "Accessibility",
"description": "These checks highlight opportunities to [improve the accessibility of your app](https://developers.google.com/web/fundamentals/accessibility).",
"audits": [
{"id": "accesskeys", "weight": 1},
{"id": "aria-allowed-attr", "weight": 1},
{"id": "aria-required-attr", "weight": 1},
{"id": "aria-required-children", "weight": 1},
{"id": "aria-required-parent", "weight": 1},
{"id": "aria-roles", "weight": 1},
{"id": "aria-valid-attr-value", "weight": 1},
{"id": "aria-valid-attr", "weight": 1},
{"id": "audio-caption", "weight": 1},
{"id": "button-name", "weight": 1},
{"id": "bypass", "weight": 1},
{"id": "color-contrast", "weight": 1},
{"id": "definition-list", "weight": 1},
{"id": "dlitem", "weight": 1},
{"id": "document-title", "weight": 1},
{"id": "duplicate-id", "weight": 1},
{"id": "frame-title", "weight": 1},
{"id": "html-has-lang", "weight": 1},
{"id": "html-lang-valid", "weight": 1},
{"id": "image-alt", "weight": 1},
{"id": "input-image-alt", "weight": 1},
{"id": "label", "weight": 1},
{"id": "layout-table", "weight": 1},
{"id": "link-name", "weight": 1},
{"id": "list", "weight": 1},
{"id": "listitem", "weight": 1},
{"id": "meta-refresh", "weight": 1},
{"id": "meta-viewport", "weight": 1},
{"id": "object-alt", "weight": 1},
{"id": "tabindex", "weight": 1},
{"id": "td-headers-attr", "weight": 1},
{"id": "th-has-data-cells", "weight": 1},
{"id": "valid-lang", "weight": 1},
{"id": "video-caption", "weight": 1},
{"id": "video-description", "weight": 1},
{"id": "accesskeys", "weight": 1, "group": "a11y-correct-attributes"},
{"id": "aria-allowed-attr", "weight": 1, "group": "a11y-aria"},
{"id": "aria-required-attr", "weight": 1, "group": "a11y-aria"},
{"id": "aria-required-children", "weight": 1, "group": "a11y-aria"},
{"id": "aria-required-parent", "weight": 1, "group": "a11y-aria"},
{"id": "aria-roles", "weight": 1, "group": "a11y-aria"},
{"id": "aria-valid-attr-value", "weight": 1, "group": "a11y-aria"},
{"id": "aria-valid-attr", "weight": 1, "group": "a11y-aria"},
{"id": "audio-caption", "weight": 1, "group": "a11y-correct-attributes"},
{"id": "button-name", "weight": 1, "group": "a11y-element-names"},
{"id": "bypass", "weight": 1, "group": "a11y-describe-contents"},
{"id": "color-contrast", "weight": 1, "group": "a11y-color-contrast"},
{"id": "definition-list", "weight": 1, "group": "a11y-well-structured"},
{"id": "dlitem", "weight": 1, "group": "a11y-well-structured"},
{"id": "document-title", "weight": 1, "group": "a11y-describe-contents"},
{"id": "duplicate-id", "weight": 1, "group": "a11y-well-structured"},
{"id": "frame-title", "weight": 1, "group": "a11y-describe-contents"},
{"id": "html-has-lang", "weight": 1, "group": "a11y-language"},
{"id": "html-lang-valid", "weight": 1, "group": "a11y-language"},
{"id": "image-alt", "weight": 1, "group": "a11y-correct-attributes"},
{"id": "input-image-alt", "weight": 1, "group": "a11y-correct-attributes"},
{"id": "label", "weight": 1, "group": "a11y-describe-contents"},
{"id": "layout-table", "weight": 1, "group": "a11y-describe-contents"},
{"id": "link-name", "weight": 1, "group": "a11y-element-names"},
{"id": "list", "weight": 1, "group": "a11y-well-structured"},
{"id": "listitem", "weight": 1, "group": "a11y-well-structured"},
{"id": "meta-refresh", "weight": 1, "group": "a11y-meta"},
{"id": "meta-viewport", "weight": 1, "group": "a11y-meta"},
{"id": "object-alt", "weight": 1, "group": "a11y-describe-contents"},
{"id": "tabindex", "weight": 1, "group": "a11y-correct-attributes"},
{"id": "td-headers-attr", "weight": 1, "group": "a11y-correct-attributes"},
{"id": "th-has-data-cells", "weight": 1, "group": "a11y-correct-attributes"},
{"id": "valid-lang", "weight": 1, "group": "a11y-language"},
{"id": "video-caption", "weight": 1, "group": "a11y-describe-contents"},
{"id": "video-description", "weight": 1, "group": "a11y-describe-contents"},
]
},
"best-practices": {
Expand Down
97 changes: 96 additions & 1 deletion lighthouse-core/report/v2/renderer/category-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,23 @@ class CategoryRenderer {

/**
* @param {!ReportRenderer.CategoryJSON} category
* @param {!Object<string, !ReportRenderer.GroupJSON>} groups
* @return {!Element}
*/
render(category) {
render(category, groups) {
switch (category.id) {
case 'accessibility':
return this._renderAccessibilityCategory(category, groups);
default:
return this._renderDefaultCategory(category);
}
}

/**
* @param {!ReportRenderer.CategoryJSON} category
* @return {!Element}
*/
_renderDefaultCategory(category) {
const element = this._dom.createElement('div', 'lh-category');
element.id = category.id;
element.appendChild(this._renderCategoryScore(category));
Expand Down Expand Up @@ -174,6 +188,87 @@ class CategoryRenderer {
element.appendChild(passedElem);
return element;
}

/**
* @param {!Array<!ReportRenderer.AuditJSON>} audits
* @param {!ReportRenderer.GroupJSON} group
* @return {!Element}
*/
_renderAuditGroup(audits, group) {
const auditGroupElem = this._dom.createElement('details',
'lh-audit-group lh-expandable-details');
const auditGroupHeader = this._dom.createElement('div',
'lh-audit-group__header lh-expandable-details__header');
auditGroupHeader.textContent = group.title;

const auditGroupDescription = this._dom.createElement('div', 'lh-audit-group__description');
auditGroupDescription.textContent = group.description;

const auditGroupSummary = this._dom.createElement('summary',
'lh-audit-group__summary lh-expandable-details__summary');
const auditGroupArrow = this._dom.createElement('div', 'lh-toggle-arrow', {
title: 'See audits',
});
auditGroupSummary.appendChild(auditGroupHeader);
auditGroupSummary.appendChild(auditGroupArrow);

auditGroupElem.appendChild(auditGroupSummary);
auditGroupElem.appendChild(auditGroupDescription);
audits.forEach(audit => auditGroupElem.appendChild(this._renderAudit(audit)));
return auditGroupElem;
}

/**
* @param {!ReportRenderer.CategoryJSON} category
* @param {!Object<string, !ReportRenderer.GroupJSON>} groups
* @return {!Element}
*/
_renderAccessibilityCategory(category, groupDefinitions) {
const element = this._dom.createElement('div', 'lh-category');
element.id = category.id;
element.appendChild(this._renderCategoryScore(category));

const auditsGroupedByGroup = category.audits.reduce((indexed, audit) => {
const groupId = audit.group;
const groups = indexed[groupId] || {passed: [], failed: []};

if (audit.score === 100) {
groups.passed.push(audit);
} else {
groups.failed.push(audit);
}

indexed[groupId] = groups;
return indexed;
}, {});

const passedElements = [];
Object.keys(auditsGroupedByGroup).forEach(groupId => {
const group = groupDefinitions[groupId];
const groups = auditsGroupedByGroup[groupId];
if (groups.failed.length) {
const auditGroupElem = this._renderAuditGroup(groups.failed, group);
auditGroupElem.open = true;
element.appendChild(auditGroupElem);
}

if (groups.passed.length) {
const auditGroupElem = this._renderAuditGroup(groups.passed, group);
passedElements.push(auditGroupElem);
}
});

// don't create a passed section if there are no passed
if (!passedElements.length) return element;

const passedElem = this._dom.createElement('details', 'lh-passed-audits');
const passedSummary = this._dom.createElement('summary', 'lh-passed-audits-summary');
passedElem.appendChild(passedSummary);
passedSummary.textContent = `View ${passedElements.length} passed items`;
passedElements.forEach(elem => passedElem.appendChild(elem));
element.appendChild(passedElem);
return element;
}
}

if (typeof module !== 'undefined' && module.exports) {
Expand Down
12 changes: 11 additions & 1 deletion lighthouse-core/report/v2/renderer/report-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class ReportRenderer {
const categories = reportSection.appendChild(this._dom.createElement('div', 'lh-categories'));
for (const category of report.reportCategories) {
scoreHeader.appendChild(this._categoryRenderer.renderScoreGauge(category));
categories.appendChild(this._categoryRenderer.render(category));
categories.appendChild(this._categoryRenderer.render(category, report.reportGroups));
}

reportSection.appendChild(this._renderReportFooter(report));
Expand All @@ -169,6 +169,7 @@ if (typeof module !== 'undefined' && module.exports) {
* id: string,
* weight: number,
* score: number,
* group: string,
* result: {
* description: string,
* debugString: string,
Expand All @@ -195,13 +196,22 @@ ReportRenderer.AuditJSON; // eslint-disable-line no-unused-expressions
*/
ReportRenderer.CategoryJSON; // eslint-disable-line no-unused-expressions

/**
* @typedef {{
* title: string,
* description: string,
* }}
*/
ReportRenderer.GroupJSON; // eslint-disable-line no-unused-expressions

/**
* @typedef {{
* lighthouseVersion: string,
* generatedTime: string,
* initialUrl: string,
* url: string,
* reportCategories: !Array<!ReportRenderer.CategoryJSON>,
* reportGroups: !Object<string, !ReportRenderer.GroupJSON>,
* runtimeConfig: {
* blockedUrlPatterns: !Array<string>,
* environment: !Array<{description: string, enabled: boolean, name: string}>
Expand Down
Loading