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

report: group third-party entities #14655

Merged
merged 55 commits into from
Mar 6, 2023
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
a9439c1
squashed: group tables by entities
alexnj Jan 28, 2023
2f3076b
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Jan 30, 2023
ce00b64
Implement third-party-summary handling without breaking backward compat.
alexnj Jan 31, 2023
6047d39
bugfix: Unattributable rows were getting removed.
alexnj Jan 31, 2023
87a7d83
would would?
alexnj Jan 31, 2023
46a9e1e
lint error.
alexnj Jan 31, 2023
f4287fc
Review comments from #14697
alexnj Jan 31, 2023
fd5b410
Implement report-side post-aggregation sorting
alexnj Jan 31, 2023
ca8674d
more formal support for pre-aggregated table/opportunity
alexnj Jan 31, 2023
0f51523
i18n changes.
alexnj Jan 31, 2023
32ed520
Strings
alexnj Jan 31, 2023
fad616f
Bugfix: Exclude non-entity-marked results from aggregation.
alexnj Jan 31, 2023
ccdb08c
string proto updates
alexnj Jan 31, 2023
b41b197
Distribute sort order to audits
alexnj Jan 31, 2023
57ed639
Deprecate third-party-summary LinkValue
alexnj Feb 1, 2023
cba2bdd
Review changes: shorter sortedBy
alexnj Feb 1, 2023
b340de9
reinstate LinkValue. We're not there yet.
alexnj Feb 1, 2023
3e808ba
revert unintended change
alexnj Feb 1, 2023
993512b
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 1, 2023
425d1c0
Adjust for backCompat refactor
alexnj Feb 1, 2023
183c65d
cleanup indentation
alexnj Feb 1, 2023
ed9587a
revert changes to fixture
alexnj Feb 1, 2023
b7c9ec2
Fixup existing tests.
alexnj Feb 1, 2023
1b8c824
Add a test to ensure compatibility upgrade works
alexnj Feb 1, 2023
105689d
comments
alexnj Feb 1, 2023
a2a2d5d
Validate design guidelines: no zebra for aggregation
alexnj Feb 1, 2023
5774426
Apply suggestions from code review
alexnj Feb 1, 2023
1a59745
review changes
alexnj Feb 1, 2023
2762cc8
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 2, 2023
b0665fd
adjust to new entity classification format
alexnj Feb 2, 2023
08950a1
Apply suggestions from code review
alexnj Feb 2, 2023
00ff7f4
Review changes.
alexnj Feb 2, 2023
d07bdd0
skipSumming refactor
alexnj Feb 2, 2023
cfa8493
move skipGrouping to makeTable/OpportunityDetails
alexnj Feb 2, 2023
6fcfb3e
rename skipGrouping to isEntityGrouped
alexnj Feb 2, 2023
7de44f8
update comment to reflect new naming
alexnj Feb 2, 2023
6a4cd56
adding tests for table grouping
alexnj Feb 2, 2023
8b8daee
Apply suggestions from code review
alexnj Feb 2, 2023
188d657
Review changes
alexnj Feb 2, 2023
b2148aa
revert the relaxed typechecks for arithmetic
alexnj Feb 3, 2023
ebd6e96
cosmetic: fix indentation of legacy lhr + new viewer
alexnj Feb 3, 2023
6c2b2ac
bugfix: verify zebra-style on third-party checkbox change
alexnj Feb 3, 2023
583ec96
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 3, 2023
2b22e4c
Add a console warning for unknown types + tests for that
alexnj Feb 3, 2023
0a1bc1f
review changes.
alexnj Feb 3, 2023
a27d053
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 4, 2023
7b50d93
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 8, 2023
3990971
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 8, 2023
312724b
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 13, 2023
3ac1b06
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Feb 27, 2023
f708a49
Update header styles to latest design + hover state.
alexnj Feb 28, 2023
90eff93
Update color codes for table from UX.
alexnj Mar 2, 2023
eb7b976
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Mar 2, 2023
9c3b145
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Mar 6, 2023
6799be9
Merge remote-tracking branch 'origin/main' into entity-based-3p-grouping
alexnj Mar 6, 2023
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
17 changes: 15 additions & 2 deletions core/audits/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,12 @@ class Audit {
* @param {LH.Audit.Details.Table['headings']} headings
* @param {LH.Audit.Details.Table['items']} results
* @param {LH.Audit.Details.Table['summary']=} summary
* @param {LH.Audit.Details.Table['sortedBy']=} sortedBy
* @param {LH.Audit.Details.Table['skipSumming']=} skipSumming
* @param {LH.Audit.Details.Table['isEntityGrouped']=} isEntityGrouped
* @return {LH.Audit.Details.Table}
*/
static makeTableDetails(headings, results, summary) {
static makeTableDetails(headings, results, summary, sortedBy, skipSumming, isEntityGrouped) {
Copy link
Member

Choose a reason for hiding this comment

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

Having this many optional params would work a lot better as an options object.

That being said, it's not worth making that change in this PR since it would affect a multitude of audits so this is fine for now.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I had the same feeling as I was expanding the list. We should make it an object at some point. I can follow up as a later refactor PR.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems worth working out first.

If we consider Audit.makeTableDetails part of our stable API (we probably should), then to defer this change post-10.0 we will need to support both all the params one-by-one, plus a single options object (or maybe headings, results, opts for just the optionals, but at that point should probably just collapse all of them into the object). Checking at runtime the number of parameters (or whatever) wouldn't be a big deal, and actually doing a breaking change here will just needlessly break custom audits, so I can see us doing that indefinitely.

Whatever approach we do, we certainly don't want to release a version that has 2 params + 4 optional params, making us have to then support 3 interfaces here indefinitely. So I'd consider this important to address before landing this PR (though, the work to make this a options object should certainly be its own PR)

Copy link
Member Author

@alexnj alexnj Feb 3, 2023

Choose a reason for hiding this comment

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

What should be the signature of the refactored function — makeTableDetails(heading, results, options), with summary collapsed into the object? Who is depending on this other than LH/audit code?

Copy link
Collaborator

@connorjclark connorjclark Feb 3, 2023

Choose a reason for hiding this comment

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

Who is depending on this other than LH/audit code?

Custom audits.

makeTableDetails(heading, results, options) ?

That, or just one options param for everything. Up for debate. Perfect for a (small) PR!

Copy link
Member Author

Choose a reason for hiding this comment

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

#14753

Once finalized, I'll adjust this PR accordingly - should be trivial.

if (results.length === 0) {
return {
type: 'table',
Expand All @@ -143,6 +146,9 @@ class Audit {
headings: headings,
items: results,
summary,
sortedBy,
skipSumming,
isEntityGrouped,
};
}

Expand Down Expand Up @@ -217,9 +223,13 @@ class Audit {
* @param {LH.Audit.Details.Opportunity['items']} items
* @param {number} overallSavingsMs
* @param {number=} overallSavingsBytes
* @param {LH.Audit.Details.Opportunity['sortedBy']=} sortedBy
* @param {LH.Audit.Details.Opportunity['skipSumming']=} skipSumming
* @param {LH.Audit.Details.Opportunity['isEntityGrouped']=} isEntityGrouped
* @return {LH.Audit.Details.Opportunity}
*/
static makeOpportunityDetails(headings, items, overallSavingsMs, overallSavingsBytes) {
static makeOpportunityDetails(headings, items, overallSavingsMs, overallSavingsBytes,
sortedBy, skipSumming, isEntityGrouped) {
Audit.assertHeadingKeysExist(headings, items);

return {
Expand All @@ -228,6 +238,9 @@ class Audit {
items,
overallSavingsMs,
overallSavingsBytes,
sortedBy,
skipSumming,
isEntityGrouped,
};
}

Expand Down
2 changes: 1 addition & 1 deletion core/audits/bootup-time.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class BootupTime extends Audit {
label: str_(UIStrings.columnScriptParse)},
];

const details = BootupTime.makeTableDetails(headings, results, summary);
const details = BootupTime.makeTableDetails(headings, results, summary, ['total']);

const score = Audit.computeLogNormalScore(
{p10: context.options.p10, median: context.options.median},
Expand Down
6 changes: 5 additions & 1 deletion core/audits/byte-efficiency/byte-efficiency-audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const WASTED_MS_FOR_SCORE_OF_ZERO = 5000;
* @property {LH.IcuMessage} [displayValue]
* @property {LH.IcuMessage} [explanation]
* @property {Array<string | LH.IcuMessage>} [warnings]
* @property {Array<string>} [sortedBy]
*/

/**
Expand Down Expand Up @@ -228,7 +229,10 @@ class ByteEfficiencyAudit extends Audit {
displayValue = str_(i18n.UIStrings.displayValueByteSavings, {wastedBytes});
}

const details = Audit.makeOpportunityDetails(result.headings, results, wastedMs, wastedBytes);
const sortedBy = result.sortedBy || ['wastedBytes'];

const details = Audit.makeOpportunityDetails(
result.headings, results, wastedMs, wastedBytes, sortedBy);

return {
explanation: result.explanation,
Expand Down
2 changes: 1 addition & 1 deletion core/audits/byte-efficiency/total-byte-weight.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class TotalByteWeight extends Audit {
{key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize)},
];

const tableDetails = Audit.makeTableDetails(headings, results);
const tableDetails = Audit.makeTableDetails(headings, results, undefined, ['totalBytes']);

return {
score,
Expand Down
3 changes: 2 additions & 1 deletion core/audits/byte-efficiency/uses-long-cache-ttl.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ class CacheHeaders extends Audit {
];

const summary = {wastedBytes: totalWastedBytes};
const details = Audit.makeTableDetails(headings, results, summary);
const details = Audit.makeTableDetails(headings, results, summary,
['totalBytes'], ['cacheLifetimeMs']);

return {
score,
Expand Down
3 changes: 2 additions & 1 deletion core/audits/long-tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class LongTasks extends Audit {
/* eslint-enable max-len */
];

const tableDetails = Audit.makeTableDetails(headings, results);
const tableDetails = Audit.makeTableDetails(headings, results, undefined,
['duration'], ['startTime']);

let displayValue;
if (results.length > 0) {
Expand Down
3 changes: 2 additions & 1 deletion core/audits/mainthread-work-breakdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ class MainThreadWorkBreakdown extends Audit {
];

results.sort((a, b) => categoryTotals[b.group] - categoryTotals[a.group]);
const tableDetails = MainThreadWorkBreakdown.makeTableDetails(headings, results);
const tableDetails = MainThreadWorkBreakdown.makeTableDetails(
headings, results, undefined, ['duration']);

const score = Audit.computeLogNormalScore(
{p10: context.options.p10, median: context.options.median},
Expand Down
2 changes: 1 addition & 1 deletion core/audits/network-rtt.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class NetworkRTT extends Audit {
{key: 'rtt', valueType: 'ms', granularity: 1, label: str_(i18n.UIStrings.columnTimeSpent)},
];

const tableDetails = Audit.makeTableDetails(headings, results);
const tableDetails = Audit.makeTableDetails(headings, results, undefined, ['rtt']);

return {
score: 1,
Expand Down
3 changes: 2 additions & 1 deletion core/audits/network-server-latency.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class NetworkServerLatency extends Audit {
label: str_(i18n.UIStrings.columnTimeSpent)},
];

const tableDetails = Audit.makeTableDetails(headings, results);
const tableDetails = Audit.makeTableDetails(headings, results, undefined,
['serverResponseTime']);

return {
score: Math.max(1 - (maxLatency / 500), 0),
Expand Down
2 changes: 1 addition & 1 deletion core/audits/performance-budget.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class ResourceBudget extends Audit {

return {
details: Audit.makeTableDetails(headers,
this.tableItems(budget, summary)),
this.tableItems(budget, summary), undefined, ['sizeOverBudget']),
score: 1,
};
}
Expand Down
3 changes: 2 additions & 1 deletion core/audits/preload-lcp-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ class PreloadLCPImageAudit extends Audit {
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
{key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.columnWastedMs)},
];
const details = Audit.makeOpportunityDetails(headings, results, wastedMs);
const details = Audit.makeOpportunityDetails(headings, results, wastedMs,
undefined, ['wastedMs']);

// If LCP element was an image and had valid network records (regardless of
// if it should be preloaded), it will be found first in the `initiatorPath`.
Expand Down
13 changes: 6 additions & 7 deletions core/audits/third-party-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,7 @@ class ThirdPartySummary extends Audit {

return {
...stats,
entity: {
type: /** @type {const} */ ('link'),
text: entity.name,
url: entity.homepage || '',
},
entity: entity.name,
subItems: {
type: /** @type {const} */ ('subitems'),
items: ThirdPartySummary.makeSubItems(entity, summaries, stats),
Expand All @@ -234,7 +230,7 @@ class ThirdPartySummary extends Audit {
/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
/* eslint-disable max-len */
{key: 'entity', valueType: 'link', label: str_(UIStrings.columnThirdParty), subItemsHeading: {key: 'url', valueType: 'url'}},
{key: 'entity', valueType: 'text', label: str_(UIStrings.columnThirdParty), subItemsHeading: {key: 'url', valueType: 'url'}},
{key: 'transferSize', granularity: 1, valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize), subItemsHeading: {key: 'transferSize'}},
{key: 'blockingTime', granularity: 1, valueType: 'ms', label: str_(i18n.UIStrings.columnBlockingTime), subItemsHeading: {key: 'blockingTime'}},
/* eslint-enable max-len */
Expand All @@ -247,12 +243,15 @@ class ThirdPartySummary extends Audit {
};
}

const details = Audit.makeTableDetails(headings, results, overallSummary,
undefined, undefined, true);

return {
score: Number(overallSummary.wastedMs <= PASS_THRESHOLD_IN_MS),
displayValue: str_(UIStrings.displayValue, {
timeInMs: overallSummary.wastedMs,
}),
details: Audit.makeTableDetails(headings, results, overallSummary),
details,
};
}
}
Expand Down
3 changes: 2 additions & 1 deletion core/audits/timing-budget.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ class TimingBudget extends Audit {
];

return {
details: Audit.makeTableDetails(headers, this.tableItems(budget, summary)),
details: Audit.makeTableDetails(headers, this.tableItems(budget, summary),
undefined, ['overBudget']),
score: 1,
};
}
Expand Down
3 changes: 2 additions & 1 deletion core/audits/uses-rel-preconnect.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ class UsesRelPreconnectAudit extends Audit {
{key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.columnWastedMs)},
];

const details = Audit.makeOpportunityDetails(headings, results, maxWasted);
const details = Audit.makeOpportunityDetails(headings, results, maxWasted,
undefined, ['wastedMs']);

return {
score: ByteEfficiencyAudit.scoreForWastedMs(maxWasted),
Expand Down
3 changes: 2 additions & 1 deletion core/audits/uses-rel-preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ class UsesRelPreloadAudit extends Audit {
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
{key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.columnWastedMs)},
];
const details = Audit.makeOpportunityDetails(headings, results, wastedMs);
const details = Audit.makeOpportunityDetails(headings, results, wastedMs,
undefined, ['wastedMs']);

return {
score: ByteEfficiencyAudit.scoreForWastedMs(wastedMs),
Expand Down
2 changes: 1 addition & 1 deletion core/audits/work-during-interaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class WorkDuringInteraction extends Audit {
];

return {
table: Audit.makeTableDetails(headings, items),
table: Audit.makeTableDetails(headings, items, undefined, ['total']),
phases,
};
}
Expand Down
17 changes: 17 additions & 0 deletions core/lib/lighthouse-compatibility.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ function upgradeLhrForCompatibility(lhr) {
}
}

// In 10.0, third-party-summary deprecated entity: LinkValue and switched to entity name string
if (audit.id === 'third-party-summary') {
if (audit.details.type === 'opportunity' || audit.details.type === 'table') {
const {headings, items} = audit.details;
if (headings[0].valueType === 'link') {
// Apply upgrade only if we are dealing with an older version (valueType=link marker).
headings[0].valueType = 'text';
for (const item of items) {
if (typeof item.entity === 'object' && item.entity.type === 'link') {
item.entity = item.entity.text;
}
}
audit.details.isEntityGrouped = true;
}
}
}

// TODO: convert printf-style displayValue.
// Added: #5099, v3
// Removed: #6767, v4
Expand Down
1 change: 1 addition & 0 deletions core/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class Runner {
// Reduce payload size in LHR JSON by omitting whats falsy.
if (entity === classifiedEntities.firstParty) shortEntity.isFirstParty = true;
if (entity.isUnrecognized) shortEntity.isUnrecognized = true;
if (entity.category) shortEntity.category = entity.category;
entities.push(shortEntity);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ describe('Byte efficiency base audit', () => {
GatherContext: {gatherMode: 'timespan'},
traces: {defaultPass: trace},
devtoolsLogs: {defaultPass: []},
URL: {},
};
const computedCache = new Map();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function generateArtifacts(records) {

return {
devtoolsLogs: {defaultPass: networkRecordsToDevtoolsLog(records)},
URL: {},
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe('Cache headers audit', () => {
devtoolsLogs: {
[CacheHeadersAudit.DEFAULT_PASS]: devtoolLogs,
},
URL: {},
};
}

Expand Down
16 changes: 4 additions & 12 deletions core/test/audits/third-party-summary-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ describe('Third party summary', () => {
);
expect(results.details.items).toEqual([
{
entity: {
text: 'Google Tag Manager',
type: 'link',
url: 'https://marketingplatform.google.com/about/tag-manager/',
},
entity: 'Google Tag Manager',
mainThreadTime: 127.15300000000003,
blockingTime: 18.186999999999998,
transferSize: 30827,
Expand All @@ -49,11 +45,7 @@ describe('Third party summary', () => {
},
},
{
entity: {
text: 'Google Analytics',
type: 'link',
url: 'https://marketingplatform.google.com/about/analytics/',
},
entity: 'Google Analytics',
mainThreadTime: 95.15599999999999,
blockingTime: 0,
transferSize: 20913,
Expand Down Expand Up @@ -154,8 +146,8 @@ describe('Third party summary', () => {
const resultsOnExternal = await ThirdPartySummary.audit(externalArtifacts, context);
const resultsOnFacebook = await ThirdPartySummary.audit(facebookArtifacts, context);

const externalEntities = resultsOnExternal.details.items.map(item => item.entity.text);
const facebookEntities = resultsOnFacebook.details.items.map(item => item.entity.text);
const externalEntities = resultsOnExternal.details.items.map(item => item.entity);
const facebookEntities = resultsOnFacebook.details.items.map(item => item.entity);

expect(externalEntities).toEqual([
'Google Tag Manager', 'Facebook', 'pwa.rocks', 'Google Analytics']);
Expand Down
8 changes: 8 additions & 0 deletions core/test/audits/work-during-interaction-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Object {
"valueType": "node",
},
],
"isEntityGrouped": undefined,
"items": Array [
Object {
"node": Object {
Expand All @@ -83,6 +84,8 @@ Object {
},
},
],
"skipSumming": undefined,
"sortedBy": undefined,
"summary": undefined,
"type": "table",
},
Expand Down Expand Up @@ -139,6 +142,7 @@ Object {
"valueType": "ms",
},
],
"isEntityGrouped": undefined,
"items": Array [
Object {
"phase": Object {
Expand Down Expand Up @@ -215,6 +219,10 @@ Object {
"total": 285,
},
],
"skipSumming": undefined,
"sortedBy": Array [
"total",
],
"summary": undefined,
"type": "table",
},
Expand Down
Loading