-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
core: normalize creation of NodeValue #11877
Conversation
this is the bounding rect for all of the client rects of the tap target, plus some extra: lighthouse/lighthouse-core/lib/rect-helpers.js Lines 96 to 127 in d584194
not really the same as all the other bounding rects, the danger of trying to unify things in one type :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice! Will definitely make it easier to make things real NodeValue
s
@@ -491,11 +492,11 @@ function getNodeDetailsImpl(element) { | |||
|
|||
const details = { | |||
lhId, | |||
devtoolsNodePath: getNodePath(element), | |||
selector: getNodeSelector(htmlElement), | |||
devtoolsNodePath: getNodePath(element) || '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe the fallbacks (if needed) should go in the individual functions rather than here?
Sure, let's split out the changes to |
path: axeNode.node.devtoolsNodePath, | ||
snippet: axeNode.node.snippet, | ||
boundingRect: axeNode.node.boundingRect, | ||
...Audit.makeNodeValue(axeNode.node), | ||
explanation: axeNode.failureSummary, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't look like this gets included in the report 🤔 . Is it supposed to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
path: axeNode.node.devtoolsNodePath, | ||
snippet: axeNode.node.snippet, | ||
boundingRect: axeNode.node.boundingRect, | ||
...Audit.makeNodeValue(axeNode.node), | ||
explanation: axeNode.failureSummary, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we add
explanation
here?
types/audit-details.d.ts
Outdated
@@ -207,7 +207,7 @@ declare global { | |||
selector?: string; | |||
boundingRect?: Artifacts.Rect; | |||
/** An HTML snippet used to identify the node. */ | |||
snippet?: string; | |||
snippet: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the possible bugs should be relatively minor, but unless we update snippet
to always be a string in Util.prepareReportResult
, this won't be typesafe for old LHRs (and if we have to retain the current if (item.snippet) {
instead, there's not much benefit of making this non-optional)
@@ -146,7 +146,7 @@ class Plugins extends Audit { | |||
|
|||
return { | |||
source: { | |||
type: /** @type {'node'} */ ('node'), | |||
...Audit.makeNodeItem(plugin.node), | |||
snippet: `<${tagName}${attributes}>${params}</${tagName}>`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this ends up rendering completely differently in the report (it was basically just <span class="lh-node"><div class="lh-node__snippet">${snippet}</div></span>
before). Does it work well for this audit (with these sometimes very long snippets)? Should it use the default NodeDetails
snippet instead of its custom one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sometimes very long snippets
examples?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it use the default NodeDetails snippet instead of its custom one?
Maybe, if we wanted to we could parameterize getNodeDetails/Snippet
to accept a list of attribute names (give it SOURCE_PARAMS
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it work well for this audit (with these sometimes very long snippets)?
examples?
unlike the getNodeDetails().snippet
, the plugin attributes
and params
aren't ever truncated in number or string length, so it could be as long as the original page wanted
Should it use the default NodeDetails snippet instead of its custom one?
Maybe, if we wanted to we could parameterize
getNodeDetails/Snippet
to accept a list of attribute names (give itSOURCE_PARAMS
).
yeah, though I guess do we care about the <param>
elements or are the element attributes (plus all the other node details stuff) sufficient to identify it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ehhh let's just use the default snippet so we can keep this simple. it'll be more identifiable now with the devtools node path and everything else, and truncation will prevent the worse cases.
snippet: target.node.snippet, | ||
path: target.node.devtoolsNodePath, | ||
selector: target.node.selector, | ||
...Audit.makeNodeItem(target.node), | ||
boundingRect, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which boundingRect should be used here? Using the boundingRect of all clientRects goes back to the first commit of #10716, but getNodeDetails
also didn't exist back then, so that might have just been the most convenient way to do it at the time. Should it be the just node.boundingRect
? When can the two differ? getBoundingClientRect
should normally contain all child rects, but does it ever differ (transforms or something?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll followup with this in a different PR.
@@ -16,44 +16,52 @@ describe('SEO: Avoids plugins', () => { | |||
[{ | |||
tagName: 'APPLET', | |||
params: [], | |||
node: {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this PR is adding a new EmbeddedContent
artifact property and changing the audit details almost completely and we're trying to reach toward a typed test future (#11728), can these be generated so they're more like the real thing and the output tested to some degree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm struggling to find any actual pages with these elements. The one I found isn't included in our plugin list: https://www.quackit.com/html_5/tags/html_object_tag.cfm (video/quicktime
). Should that type be included?
EDIT: well video/quicktime
is expected to pass in a test. I don't understand the purpose of this audit if a quicktime plugin is acceptable. Is the idea that any video is OK? I suppose since this is an SEO audit video is out of scope, it's just that this audit also could double as a user/compat/browser-friendliness check.
Co-authored-by: Adam Raine <6752989+adamraine@users.noreply.github.com>
… into node-details-yay
Background
node: NodeDetails
property.NodeValue
andNodeDetails
differ trivially:NodeDetails['devtoolsNodePath']
is calledNodeValue['path']
NodeDetails
only optional fields arelhId
andboundingRect
. InNodeValue
, everything is optional.NodeDetails
are created by using the page functiongetNodeDetails
.NodeValue
by using aNodeDetails
, but some audits create their ownNodeValue
without the backing of aNodeDetails
. These few non-standard usages is what forces us to haveNodeValue
be all-optional.(the following categories are not mutually exclusive)
A) Audits that create a
NodeValue
directly from aNodeDetail
(1:1)B) Audits that create a
NodeValue
directly from aNodeDetail
(but misses something. All of these are at least missingboundingRect
/lhId
, so no element screenshots):C) Audits that create a
NodeValue
directly from aNodeDetail
, but override a propertylighthouse/lighthouse-core/audits/seo/tap-targets.js
Line 256 in 2bdf6cb
D) Audits that create a
NodeValue
from something OTHER than aNodeDetail
font-size
(lighthouse/lighthouse-core/audits/seo/font-size.js
Line 120 in 2bdf6cb
hreflang
(sometimes, only ifLinkElement
is from response headers)This PR
NodeValue
from aNodeDetails
, use new functionAudit.makeNodeValue
. This simplifies category A), fixes category B), and makes category C) much more obvious.snippet
required inNodeValue
. This is the strictest we can get with this, without changing anything about usages in category D). It also conceptually make sense... if you want to show something as anode
, but aren't usingNodeDetails
, you should be able to provide something HTML-ish.NodeDetails
are created via the page function, and that function always returnslhId
andboundingRect
, we can make those properties required. This didn't require any code changes, I think it was an oversight in core(full-page-screenshot): resolve node rects during emulation #11536.To be extra sure thatNodeDetails
properties are all present, for the string values do... || ''
. I'm not super convinced about this (and it seems we'd really want to wrap each with atry...catch
to catch the errors we've seen before).