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

add explicit result error property for erroneous audit results #1591

Merged
merged 1 commit into from
Feb 3, 2017
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
4 changes: 3 additions & 1 deletion lighthouse-cli/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ function createOutput(results: Results, outputMode: OutputMode): string {
if (auditResult.comingSoon === true)
return;

let lineItem = ` ${log.doubleLightHorizontal} ${formatAggregationResultItem(auditResult.score)} ${auditResult.description}`;
const formattedScore = auditResult.error ? `${log.redify('‽')}` :
`${formatAggregationResultItem(auditResult.score)}`;
let lineItem = ` ${log.doubleLightHorizontal} ${formattedScore} ${auditResult.description}`;
if (auditResult.displayValue) {
lineItem += ` (${log.bold}${auditResult.displayValue}${log.reset})`;
}
Expand Down
1 change: 1 addition & 0 deletions lighthouse-cli/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ interface AuditResult {
debugString: string;
comingSoon?: boolean;
score: number;
error?: boolean;
description: string;
name: string;
category: string;
Expand Down
6 changes: 6 additions & 0 deletions lighthouse-core/aggregator/aggregate.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ class Aggregate {
throw new Error(msg);
}

// Audit resulted in an error, so doesn't contribute to score.
Copy link
Member Author

@brendankenny brendankenny Feb 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For scoring: we're doing kind of a dumb thing on master currently, adding -1/100 as the score for audits currently returning an error result of -1.

Originally I was going to return NaN here for error audit scores, but that seemed unfair to do until all audits had been converted to this system (e.g. an error in user-timing would become a NaN, but an error in first-meaningful-paint would simply be -.001), so I manually set those to contributing 0 to match current master behavior as much as possible.

We can reconsider this (in tandem with #1512 to explicitly communicate that there were errors) when all audits have been converted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brendankenny and I talked this out. I think a "less complete" score that factors in fewer audits makes more sense than seeing NaN for the entire category. Basically, users should never see NaN. That looks like a bug.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, users should never see NaN. That looks like a bug

one question I'm immediately running into is what should it display in the report for these error results. In theory I could continue doing -1 for the numeric ones, but that's not great, and what about the boolean ones?

Could do red X from failing audits, greyed out icon from the coming soon audits, some kind of question mark icon, ..? Anyone have a good idea? Doesn't have to be our symbol for life :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yea.

I like the greyed out "-" icon for the failing ones. We should ditch the "coming soon" audits. They've been coming soon for.....ever. We could also use that icon for tests that we know are not passable for the user's setup (#1175 (comment)) as a way to indicate something is up.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the combo of displaying "-" in red and showing the message in a similar manner to debugString 👍

// TODO: could do NaN instead, as score becomes somewhat meaningless.
if (result.error) {
return 0;
}

if (typeof result === 'undefined' ||
typeof result.score === 'undefined') {
let msg =
Expand Down
13 changes: 13 additions & 0 deletions lighthouse-core/audits/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ class Audit {
throw new Error('Audit meta information must be overridden.');
}

/**
* @param {string} debugString
* @return {!AuditResult}
*/
static generateErrorAuditResult(debugString) {
return this.generateAuditResult({
rawValue: null,
error: true,
debugString
});
}

/**
* @param {!AuditResultInput} result
* @return {!AuditResult}
Expand All @@ -57,6 +69,7 @@ class Audit {
score,
displayValue: `${displayValue}`,
rawValue: result.rawValue,
error: result.error,
debugString: result.debugString,
optimalValue: result.optimalValue,
extendedInfo: result.extendedInfo,
Expand Down
4 changes: 4 additions & 0 deletions lighthouse-core/report/styles/report.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ span, div, p, section, header, h1, h2, li, ul {
--good-color: #1ac123;
--average-color: #ffae00;
--unknown-color: #b3b3b3;
--warning-color: #f6be00;
--gutter-gap: 12px;
--gutter-width: 40px;
--body-font-size: 14px;
Expand Down Expand Up @@ -896,6 +897,9 @@ body {
.score-poor-bg {
background-color: var(--poor-color);
}
.score-warning-bg {
background-color: var(--warning-color);
}
.score-unknown-bg {
background-color: var(--unknown-color);
}
Expand Down
2 changes: 2 additions & 0 deletions lighthouse-core/report/templates/report-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ <h2>{{ aggregation.name }}</h2>
<div class="subitem-result">
{{#if subItem.comingSoon}}
<span class="subitem-result__unknown score-unknown-bg">N/A</span>
{{else if subItem.error}}
<span class="subitem-result__unknown score-warning-bg">N/A</span>
{{else}}
{{#if (is-bool subItem.score)}}
{{#if subItem.score}}
Expand Down
18 changes: 10 additions & 8 deletions lighthouse-core/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,7 @@ class Runner {
if (noArtifact || noTrace) {
log.warn('Runner',
`${artifactName} gatherer, required by audit ${audit.meta.name}, did not run.`);
return audit.generateAuditResult({
rawValue: -1,
debugString: `Required ${artifactName} gatherer did not run.`
});
throw new Error(`Required ${artifactName} gatherer did not run.`);
}

// If artifact was an error, it must be non-fatal (or gatherRunner would
Expand All @@ -186,14 +183,19 @@ class Runner {
const artifactError = artifacts[artifactName];
log.warn('Runner', `${artifactName} gatherer, required by audit ${audit.meta.name},` +
` encountered an error: ${artifactError.message}`);
return audit.generateAuditResult({
rawValue: -1,
debugString: artifactError.message
});
throw new Error(
`Required ${artifactName} gatherer encountered an error: ${artifactError.message}`);
}
}

return audit.audit(artifacts);
}).catch(err => {
if (err.fatal) {
throw err;
}

// Non-fatal error become error audit result.
return audit.generateErrorAuditResult('Audit error: ' + err.message);
}).then(result => {
log.verbose('statusEnd', status);
return result;
Expand Down
47 changes: 46 additions & 1 deletion lighthouse-core/test/aggregator/aggregate-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
const Aggregate = require('../../aggregator/aggregate');
const assert = require('assert');

/* global describe, it*/
/* eslint-env mocha */

describe('Aggregate', () => {
it('filters empty results', () => {
Expand Down Expand Up @@ -211,6 +211,20 @@ describe('Aggregate', () => {
return assert.throws(_ => Aggregate._convertToWeight(result, expected));
});

it('returns 0 if audit result was an error', () => {
const expected = {
expectedValue: true,
weight: 1
};

const result = {
rawValue: null,
error: true,
};

assert.strictEqual(Aggregate._convertToWeight(result, expected), 0);
});

it('scores a set correctly (contributesToScore: true)', () => {
const items = [{
audits: {
Expand Down Expand Up @@ -405,6 +419,37 @@ describe('Aggregate', () => {
return assert.equal(Aggregate.compare(results, items, scored)[0].overall, 1);
});

it('if audit result is an error it does not contribute to score', () => {
const items = [{
audits: {
'test': {
expectedValue: true,
weight: 1
},
'alternate-test': {
expectedValue: 100,
weight: 1
}
}
}];

const errorResult = new Error('error message');
errorResult.name = 'alternate-test';
const results = [{
name: 'test',
rawValue: true,
score: true,
displayValue: ''
}, {
name: 'alternate-test',
rawValue: null,
error: true
}];

const aggregate = Aggregate.compare(results, items, true)[0];
assert.strictEqual(aggregate.overall, 0.5);
});

it('outputs subitems', () => {
const items = [{
audits: {
Expand Down
78 changes: 72 additions & 6 deletions lighthouse-core/test/runner-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ describe('Runner', () => {
});

return Runner.run({}, {url, config}).then(results => {
assert.equal(results.audits['user-timings'].rawValue, -1);
assert.ok(results.audits['user-timings'].debugString);
const auditResult = results.audits['user-timings'];
assert.strictEqual(auditResult.rawValue, null);
assert.strictEqual(auditResult.error, true);
assert.ok(auditResult.debugString.includes('traces'));
});
});

Expand All @@ -158,8 +160,10 @@ describe('Runner', () => {
});

return Runner.run({}, {url, config}).then(results => {
assert.equal(results.audits['is-on-https'].rawValue, -1);
assert.ok(results.audits['is-on-https'].debugString);
const auditResult = results.audits['is-on-https'];
assert.strictEqual(auditResult.rawValue, null);
assert.strictEqual(auditResult.error, true);
assert.ok(auditResult.debugString.includes('HTTPS'));
});
});

Expand All @@ -182,12 +186,74 @@ describe('Runner', () => {
config.artifacts.HTTPS = artifactError;

return Runner.run({}, {url, config}).then(results => {
assert.equal(results.audits['is-on-https'].rawValue, -1);
assert.equal(results.audits['is-on-https'].debugString, errorMessage);
const auditResult = results.audits['is-on-https'];
assert.strictEqual(auditResult.rawValue, null);
assert.strictEqual(auditResult.error, true);
assert.ok(auditResult.debugString.includes(errorMessage));
});
});
});

describe('Bad audit behavior handling', () => {
const testAuditMeta = {
category: 'ThrowThrow',
name: 'throwy-audit',
description: 'Always throws',
requiredArtifacts: []
};

it('produces an error audit result when an audit throws a non-fatal Error', () => {
const errorMessage = 'Audit yourself';
const url = 'https://example.com';
const config = new Config({
audits: [
class ThrowyAudit extends Audit {
static get meta() {
return testAuditMeta;
}
static audit() {
throw new Error(errorMessage);
}
}
],

artifacts: {}
});

return Runner.run({}, {url, config}).then(results => {
const auditResult = results.audits['throwy-audit'];
assert.strictEqual(auditResult.rawValue, null);
assert.strictEqual(auditResult.error, true);
assert.ok(auditResult.debugString.includes(errorMessage));
});
});

it('rejects if an audit throws a fatal error', () => {
const errorMessage = 'Uh oh';
const url = 'https://example.com';
const config = new Config({
audits: [
class FatalThrowyAudit extends Audit {
static get meta() {
return testAuditMeta;
}
static audit() {
const fatalError = new Error(errorMessage);
fatalError.fatal = true;
throw fatalError;
}
}
],

artifacts: {}
});

return Runner.run({}, {url, config}).then(
_ => assert.ok(false),
err => assert.strictEqual(err.message, errorMessage));
});
});

it('accepts performance logs as an artifact', () => {
const url = 'https://example.com';
const config = new Config({
Expand Down