Skip to content

Improved error handling #4860

@WilcoFiers

Description

@WilcoFiers

Currently: When an error occurs inside a rule, axe will set an error and errorNode property. This is initially set to incomplete, but because nodes is empty. Because there are no nodes, finalizeResults sets this to inapplicable. The v1 reporter than restores that to incomplete by detecting the error property, but leaving nodes empty.

Exceptions:

  • axe's async callback in evaluate accepts errors, but does not assign errorNode
  • matches functions do not assign errorNode
  • if an after function throws, the entire run throws

Additionally, if an error occurs inside a frame, the error is bubbled up and will throw the run.

Goal

  1. Axe-core should be able to recover from errors as much as possible, so that rules that can complete won't be blocked by those that errored out.

  2. Axe should be transparent about what parts of it failed to complete, so that users can understand what was not tested.

  3. Recoverable errors should be reported in the same format as other axe results so they can be given to users without special design considerations

UX

In practice, what users should experience is this:

  • If an error occurs in a rule, the user is given an incomplete result for that rule, with one node

  • If axe fails within a frame (which is almost impossible), we'll report that as a frame-tested incomplete, just like we do if axe failed to inject into that frame.

  • We wouldn't show any error messages or anything like that to users. The actual errors should be sent to datadog. We'll just show a friendly message that the page needs to be tested manually for that particular rule, just like how we do for other incompletes.

What to change

  1. In addition to using an `error` and `errorNode` property, when an error occurs, the node list is replaced with an array with a single node, where the error occurs. A new `none` check is associated with this with the `error-occurred` id. The `data` object is made the serialized error, so that the `data` property will have `message`, `stack`, and `type`, along with optionally `cause`, which should also be serialized.

    Having a NodeResult for each error ensures that tools that store axe results by node can record display errors. By using axe's existing data format for errors we allow the error to be displayed. By serializing the error's properties we ensure it can be transferred, both across frames, as well as between tools. For the `error` and `errorNode` properties should continue to be set.

  2. If we do nothing, the above change will result in error nodes getting passed to after methods. To ensure backward compatibility we'll need to remove error nodes before padding results to after, and add them back in when after is done.

  3. When an after method throws, axe-core should catch the error and report that rule as incomplete, instead of failing completely as it does today. To avoid an overly lengthy number of incompletes, only the first node should be kept, the rest should be set as related nodes, up to a maximum of 10 nodes.

  4. When a matches function throws, the node that was being matched should be recorded, Currently only the error is.

  5. When an Error is passed to an async evaluate's callback, the node that was being evaluated should be recorded. Currently only the error is.

  6. When axe inside a frame errors out, currently the error bubbles up and throws out the entire run. While errors inside rules are caught, an error for example in a node serializer would not be. Instead of failing the entire run, we should treat that frame as though it wasn't tested. The frame should be reported as an error node under the frame-tested rule, with the error associated with the data property.

  7. The heading-order rule should be updated to understand that if we don't have results from a particular frame, the heading immediately following that frame should be passed. The frame-tested result itself should be sufficient to inform users information was missing.

  8. The error property should be documented and typed. An error property on an incomplete result will be the "standard" way axe will expose major failures. Additionally, the frame-tested rule should set a timeout error. All places that set errors should set an errorNode as well.

Future

A nice future addition to this might be that if some a rule errors on some nodes but not others that axe would still show the results it did find. I don't think we'd want to have incompletes for every error. One error can cause another for a future rule, with cache problems and stuff like that. But where we can, showing what we do have would be a good addition.

I'm not sure how common a problem this is. Once we have some of this ticket implemented we'll have logging to be able to see whether this might be worth the effort. In doing this we're going to need to be careful with after methods. Those currently assume they have all relevant content - which they won't if we make this change.

Metadata

Metadata

Assignees

Labels

coreIssues in the core code (lib/core)featNew feature or enhancement

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions