-
Notifications
You must be signed in to change notification settings - Fork 791
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
refactor: make element spec processing more cosistent #4093
Conversation
@@ -203,7 +203,7 @@ describe('Configure Options', function () { | |||
}; | |||
|
|||
var iframe = document.createElement('iframe'); | |||
iframe.src = '/test/mock/frames/context.html'; | |||
iframe.src = '/test/mock/frames/noHtml-config.html'; |
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 original test was configure
ing in the top frame but not the child frame. This isn't supported and doesn't provide the protection noHtml
is intended to (the thing that the test after this one is verifying). However, previously, the original test worked despite testing an unsupported configuration because there was an extra round trip through DqElement
in the top frame involved that no longer exists.
I think it's preferable to break the old pattern and demand that configure must be called consistently in each frame, so I changed the test rather than forcing a top-frame-only noHtml
configure to suppress html
properties from child frame results, but if that feels too concerning for backcompat reasons you could address it by adding an audit.noHtml
test into the process-aggregate.js
code that's filling in html
from node.source
.
Should the default serializer take into account options like options.selectors? I wonder if this could have bad performance implications. Otherwise I like that we can add custom element data to results with this. One problem I see is that custom properties wouldn't be copied over in the reporter processAggregate, so if we use this we would need to implement a custom reporter (probably having to re-implement everything in processAggregate). |
811d4aa
to
9c48f1c
Compare
assert.isNull(passes[0].nodes[0].any[0].relatedNodes[0].html); | ||
assert.isNull(violations[0].nodes[0].any[0].relatedNodes[0].html); |
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.
Prior to this, node.html
would be null
, but relatedNode.html
was "Undefined"
. That was a bug.
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.
We probably need to add the setRunOptions
to run virtual rule as well.
lib/core/utils/node-serializer.js
Outdated
serializer = newSerializer; | ||
} | ||
|
||
Object.assign(nodeSerializer, { |
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.
Adding functions onto another function hides those functions from the user. They won't get code completion nor typescript support for this. Is there a reason you didn't want to have nodeSerializer
be an object with a setSerializer
function?
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 wouldn't you be able to type / get intellisense on this? I think this would do it:
type NodeToSpec = <T extends SerialDqElement = SerialDqElement>
(node: VirtualNode | Element) => T;
type MergeSpecs = <T extends SerialDqElement = SerialDqElement>
(parentSpec: SerialDqElement, childSpec: SerialDqElement) => T;
interface Utils {
nodeSerializer: {
({ isSpec, mergeSpecs }: { isSpec?: NodeToSpec, mergeSpecs?: MergeSpecs }): void,
isSpec: NodeToSpec,
mergeSpecs: NodeToSpec
}
But sure, this could also just be an object with a "set" function if you want. I like this approach better personally, but it's not a big deal.
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.
As discussed, I'm replacing this with a .update()
method.
…re into dbjorge/node-serializer
This isn't useful, as the only time DqElement will be part of runVirtualRule is if that vNode includes an actualNode. But then if you do that, this throws because const fixture = document.querySelector('#fixture')
fixture.innerHTML = '<i role="invalid-role"></i>'
const vNode = axe.setup(fixture.firstElementChild);
const result = axe.runVirtualRule('aria-roles', vNode);
// TypeError: Cannot read properties of undefined (reading 'role="invalid-role"') If there's ever a use case for it, solving for it belongs in a different PR. |
cebf827
to
d1b07e1
Compare
@WilcoFiers I just have the two most recent unresolved comments remaining (it's technically my PR so I can't "request changes") |
e546e14
to
c59ad63
Compare
Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com>
LGTM (still technically my PR, so @straker will need to approve) |
* suitable for JSON.stringify to consume. Output must include all properties | ||
* that DqElement.toJSON() would have. Will always be invoked from the | ||
* input element's original page context. | ||
* @property {Function} mergeSpecs (Optional) Merges two specs (produced by toSpec) which |
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 this also include a note about needing to pass through all properties that DqElement.mergeSpec
would pass through (ancestry
, selector
, etc.) just like the note for toSpec
?
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 don't think that's crucial, but if you have a suggestion I'll put it in 😁
Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com>
This API was added in pr dequelabs#4093, but TS definitions were never added.
This API was added in pr dequelabs#4093, but TS definitions were never added.
This API was added in pr #4093, but TS definitions were never added. For simplicity I'm using SerialDqElement in the API. We could introduce a generic for the custom serialized type (T extends SerialDqElement), but it's hard to consistently use it everywhere (AxeReporter, NodeSerializer.dqElmToSpec). I also fixed DqElement.mergeSpecs which is needed to implement a custom node serializer: it exists on the constructor and not on the individual instances
This PR implements hooks for customizing how
DqElement
s are serialized.Opening this as a draft for @WilcoFiers to pick up since I wasn't able to get it finished before heading off. The implementation is complete and it's passing integration tests (both old and new), but it still needs unit test updates (both to test the changes and also to fix up existing tests that relied on result nodes sometimes being
DqElements
).After this PR, the only usage of
DqElement
withinaxe-core
itself is always of formnew DqElement(node, options).toJSON()
, ie, serialized immediately after construction. I think this suggests that it'd be a better design to drop the class entirely and just have aserializeVirtualNode
function instead that isn't unnecessarily stateful, but that's likely too breaking. We might consider markingDqElement
as deprecated, though, to try to mitigate folks getting confused and thinking that they should be using it.Closes: #3471