Skip to content

Commit c94a9d2

Browse files
authored
core(anchor-elements): don't consider ancestorListeners (#16731)
1 parent 7ff97fd commit c94a9d2

File tree

7 files changed

+26
-42
lines changed

7 files changed

+26
-42
lines changed

cli/test/fixtures/seo/seo-failure-cases.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h2>Anchor text</h2>
5050
document.querySelector('.some-link').addEventListener('mousedown', () => {});
5151
</script>
5252

53-
<!-- FAIL(crawlable-anchors): Link event listener on parent -->
53+
<!-- PASS(crawlable-anchors): Link event listener on parent. No biggie. https://github.com/GoogleChrome/lighthouse/pull/16731 -->
5454
<div class="link-parent"><a>Some link</a></div>
5555
<script>
5656
document.querySelector('.link-parent').addEventListener('click', () => {});

cli/test/smokehouse/test-definitions/seo-failing.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const expectations = {
5757
score: 0,
5858
details: {
5959
items: {
60-
length: 4,
60+
length: 3,
6161
},
6262
},
6363
},

core/audits/seo/crawlable-anchors.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,10 @@ class CrawlableAnchors extends Audit {
5757
href,
5858
attributeNames = [],
5959
listeners = [],
60-
ancestorListeners = [],
6160
}) => {
6261
rawHref = rawHref.replace( /\s/g, '');
6362
name = name.trim();
6463
role = role.trim();
65-
const hasListener = Boolean(listeners.length || ancestorListeners.length);
6664

6765
if (role.length > 0) return;
6866
// Ignore mailto links even if they use one of the failing patterns. See https://github.com/GoogleChrome/lighthouse/issues/11443#issuecomment-694898412
@@ -86,7 +84,8 @@ class CrawlableAnchors extends Audit {
8684
!attributeNames.includes('href') &&
8785
hrefAssociatedAttributes.every(attribute => !attributeNames.includes(attribute))
8886
) {
89-
return hasListener;
87+
// If it has an even listener (e.g. onclick) then we can't assume it's a placeholder. Therefore we consider it failing.
88+
return Boolean(listeners.length);
9089
}
9190

9291
if (href === '') return true;

core/gather/gatherers/anchor-elements.js

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -157,33 +157,17 @@ class AnchorElements extends BaseGatherer {
157157

158158
// DOM.getDocument is necessary for pushNodesByBackendIdsToFrontend to properly retrieve nodeIds if the `DOM` domain was enabled before this gatherer, invoke it to be safe.
159159
await session.sendCommand('DOM.getDocument', {depth: -1, pierce: true});
160-
const anchorsWithEventListeners = anchors.map(async anchor => {
161-
const listeners = await getEventListeners(session, anchor.node.devtoolsNodePath);
162-
163-
/** @type {Set<{type: string}>} */
164-
const ancestorListeners = new Set();
165-
const splitPath = anchor.node.devtoolsNodePath.split(',');
166-
const ancestorListenerPromises = [];
167-
while (splitPath.length >= 2) {
168-
splitPath.length -= 2;
169-
const path = splitPath.join(',');
170-
const promise = getEventListeners(session, path).then(listeners => {
171-
for (const listener of listeners) {
172-
ancestorListeners.add(listener);
173-
}
174-
}).catch(() => {});
175-
ancestorListenerPromises.push(promise);
176-
}
177-
178-
await Promise.all(ancestorListenerPromises);
179160

180-
return {
181-
...anchor,
182-
listeners,
183-
ancestorListeners: Array.from(ancestorListeners),
184-
};
161+
const anchorsWithEventListeners = anchors.map( anchor => {
162+
return getEventListeners(session, anchor.node.devtoolsNodePath).then(listeners => {
163+
return {
164+
...anchor,
165+
listeners,
166+
};
167+
});
185168
});
186169

170+
187171
const result = await Promise.all(anchorsWithEventListeners);
188172
await session.sendCommand('DOM.disable');
189173
return result;

core/scripts/generate-timing-trace.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,19 @@ function saveTraceFromCLI() {
4343
printErrorAndQuit('Lighthouse JSON results not found.');
4444
}
4545

46-
const lhrObject = JSON.parse(fs.readFileSync(filename, 'utf8'));
46+
let text = fs.readFileSync(filename, 'utf8');
47+
// Support reading from HTML too.
48+
if (filename.endsWith('.html') || text.startsWith('<')) {
49+
const startMarker = '__LIGHTHOUSE_JSON__ = ';
50+
const start = text.indexOf(startMarker) + startMarker.length;
51+
const end = text.indexOf(';</script>', start);
52+
if (start === -1 || end === -1) {
53+
printErrorAndQuit('No Lighthouse JSON found in HTML file.');
54+
}
55+
text = text.slice(start, end);
56+
}
57+
58+
const lhrObject = JSON.parse(text);
4759
const jsonStr = createTraceString(lhrObject);
4860

4961
const pathObj = path.parse(filename);

core/test/audits/seo/crawlable-anchors-test.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ function runAudit({
1919
(rawHref || href) ? 'href' : null, role ? 'role' : null, name ? 'name' : null,
2020
].filter(Boolean),
2121
listeners = onclick.trim().length ? [{type: 'click'}] : [],
22-
ancestorListeners = [],
2322
node = {
2423
snippet: '',
2524
devtoolsNodePath: '',
@@ -34,7 +33,6 @@ function runAudit({
3433
href,
3534
name,
3635
listeners,
37-
ancestorListeners,
3836
onclick,
3937
role,
4038
node,
@@ -105,19 +103,13 @@ describe('SEO: Crawlable anchors audit', () => {
105103
rawHref: 'javascript:void(0)',
106104
listeners: [{type: 'nope'}, {type: 'another'}, {type: 'click'}],
107105
});
108-
assert.equal(auditResultWithInvalidHref, 0, 'invalid href with any event listener is a faile');
106+
assert.equal(auditResultWithInvalidHref, 0, 'invalid href with any event listener is a fail');
109107

110108
const auditResultWithNoHref = runAudit({
111109
listeners: [{type: 'nope'}, {type: 'another'}, {type: 'click'}],
112110
});
113111
assert.equal(auditResultWithNoHref, 0, 'no href with any event listener is a fail');
114112

115-
const auditResultWithParentListenerNoHref = runAudit({
116-
ancestorListeners: [{type: 'nope'}, {type: 'another'}, {type: 'click'}],
117-
});
118-
assert.equal(auditResultWithParentListenerNoHref, 0,
119-
'no href with any event listener on a parent is a fail');
120-
121113
const auditResultNoListener = runAudit({
122114
rawHref: '/validPath',
123115
});

types/artifacts.d.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,6 @@ declare module Artifacts {
363363
listeners?: Array<{
364364
type: Crdp.DOMDebugger.EventListener['type']
365365
}>
366-
ancestorListeners?: Array<{
367-
type: Crdp.DOMDebugger.EventListener['type']
368-
}>
369366
}
370367

371368
type BFCacheReasonMap = {

0 commit comments

Comments
 (0)