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

feat: Improve perf of axe.run [WWD-1821] #1503

Merged
merged 18 commits into from
Apr 30, 2019
Merged

feat: Improve perf of axe.run [WWD-1821] #1503

merged 18 commits into from
Apr 30, 2019

Conversation

straker
Copy link
Contributor

@straker straker commented Apr 17, 2019

First off, sorry for the massive pr. There's only a handful of files you need to look at, everything else is a refactor.

Here are the important files:

  • lib/commons/aria/is-accessible-ref.js
  • lib/commons/dom/is-visible.js
  • lib/core/utils/is-hidden.js
  • lib/core/public/run-rules.js
  • lib/core/imports/index.js
  • lib/core/utils/flattened-tree.js
  • test/testutils.js

Summary

Cached axe.utils.isHidden, axe.commons.dom.isVisible, axe.commons.aria.isAccessibleRef, and axe.utils.getNodeFromTree. These changes alone cut the time of axe.run in half on a page with >11k DOM nodes: from ~6s to ~3s in Chrome and from ~10s to ~4s in Firefox.

Longdesc

Added a global cache on axe._cache that can be used internally to cache things. The idea is to allow axe to cache results from tree searches so we don't have to do the tree search again (which is usually the slowest part of the code). The cache uses a WeakMap so I also had to add a WeakMap polyfill. Core-js can't be used without import with v3 (no require possible), so I decided against using it (plus it's so big).

Refactored every test/full/**/*.html file where I had to move the include of the test/testutils.js file to after the div#mocha element so beforeEach was defined when testutils needed it so I could default the axe._cache for each run.

Also, a lot of tests and files removed the vNode argument of axe.utils.getNodeFromTree as it was no longer needed. The function itself will still accept the value and ignore it so we don't have to release a breaking change, but I figured we could update the internal code now not to need it. At the next breaking change release we can consider dropping the parameter from the function.

We've decided to hold off on merging the 3 different isHidden functions in axe, mainly because the many different options we have for determining what constitutes hidden pose problems for caching (as the dom.isVisible cache shows). Improving this would help the color-contrast and image-redundant-alt rules as they use dom.isVisible differently, and isHidden was already run on the same nodes earlier.

Here is the before/after of axe.run with performanceTimer: true

Metric Before (ms) After (ms)
audit_start_to_end 6,086.72 2,765.93
axe 6,376.12 3,074.90
rule_accesskeys 24.19 38.25
rule_accesskeys#gather 23.41 37.45
rule_accesskeys#matches 0.01 0.01
rule_accesskeys#runchecks 0.08 0.07
rule_area-alt 23.60 27.39
rule_area-alt#gather 23.26 27.01
rule_area-alt#matches 0.01 0.01
rule_area-alt#runchecks 0.03 0.03
rule_aria-allowed-attr 410.09 373.74
rule_aria-allowed-attr#gather 404.86 368.31
rule_aria-allowed-attr#gather_axe.utils.isHidden 377.78 336.71
rule_aria-allowed-attr#matches 2.63 2.84
rule_aria-allowed-attr#runchecks 2.33 2.32
rule_aria-allowed-role 35.50 46.02
rule_aria-allowed-role#gather 30.70 38.85
rule_aria-allowed-role#matches 0.33 0.35
rule_aria-allowed-role#runchecks 4.20 6.51
rule_aria-dpub-role-fallback 1.07 0.43
rule_aria-dpub-role-fallback#gather 0.78 0.08
rule_aria-dpub-role-fallback#gather_axe.utils.isHidden 0.73 0.06
rule_aria-dpub-role-fallback#matches 0.06 0.08
rule_aria-dpub-role-fallback#runchecks 0.02 0.03
rule_aria-hidden-body 26.55 26.31
rule_aria-hidden-body#gather 18.56 17.43
rule_aria-hidden-body#matches 0.04 0.04
rule_aria-hidden-body#runchecks 7.64 8.54
rule_aria-hidden-focus 37.90 38.52
rule_aria-hidden-focus#gather 24.00 21.54
rule_aria-hidden-focus#matches 0.22 0.23
rule_aria-hidden-focus#runchecks 13.39 16.41
rule_aria-required-attr 1.53 1.14
rule_aria-required-attr#gather 0.71 0.07
rule_aria-required-attr#gather_axe.utils.isHidden 0.69 0.05
rule_aria-required-attr#matches 0.01 0.01
rule_aria-required-attr#runchecks 0.58 0.81
rule_aria-required-children 1.40 3.83
rule_aria-required-children#gather 0.67 0.05
rule_aria-required-children#gather_axe.utils.isHidden 0.66 0.04
rule_aria-required-children#matches 0.01 0.01
rule_aria-required-children#runchecks 0.53 3.50
rule_aria-required-parent 1.38 1.03
rule_aria-required-parent#gather 0.62 0.07
rule_aria-required-parent#gather_axe.utils.isHidden 0.61 0.06
rule_aria-required-parent#matches 0.00 0.00
rule_aria-required-parent#runchecks 0.57 0.69
rule_aria-roles 1.59 1.13
rule_aria-roles#gather 0.64 0.04
rule_aria-roles#gather_axe.utils.isHidden 0.64 0.02
rule_aria-roles#matches 0.00 0.01
rule_aria-roles#runchecks 0.78 0.88
rule_aria-valid-attr 78.39 8.59
rule_aria-valid-attr-value 68.59 10.13
rule_aria-valid-attr-value#gather 64.82 5.58
rule_aria-valid-attr-value#gather_axe.utils.isHidden 64.80 5.56
rule_aria-valid-attr-value#matches 2.78 3.34
rule_aria-valid-attr-value#runchecks 0.75 0.92
rule_aria-valid-attr#gather 75.48 4.70
rule_aria-valid-attr#gather_axe.utils.isHidden 75.45 4.68
rule_aria-valid-attr#matches 2.23 2.98
rule_aria-valid-attr#runchecks 0.43 0.55
rule_autocomplete-valid 71.11 7.16
rule_autocomplete-valid#gather 69.46 5.06
rule_autocomplete-valid#gather_axe.utils.isHidden 69.42 5.01
rule_autocomplete-valid#matches 1.01 1.24
rule_autocomplete-valid#runchecks 0.38 0.52
rule_blink 18.98 11.43
rule_blink#gather 17.91 11.05
rule_blink#matches 0.00 0.01
rule_blink#runchecks 0.04 0.05
rule_button-name 126.84 58.28
rule_button-name#gather 70.76 34.46
rule_button-name#gather_axe.utils.isHidden 1.60 0.12
rule_button-name#matches 0.01 0.01
rule_button-name#runchecks 55.75 23.50
rule_bypass 66.63 84.49
rule_bypass#gather 15.89 19.84
rule_bypass#gather_axe.utils.isHidden 0.07 0.03
rule_bypass#matches 0.07 0.06
rule_bypass#runchecks 50.38 64.30
rule_checkboxgroup 7.67 11.62
rule_checkboxgroup#gather 7.37 11.28
rule_checkboxgroup#gather_axe.utils.isHidden 0.02 0.03
rule_checkboxgroup#matches 0.00 0.00
rule_checkboxgroup#runchecks 0.03 0.04
rule_color-contrast 880.53 802.79
rule_color-contrast#gather 0.00 0.00
rule_color-contrast#matches 157.61 129.40
rule_color-contrast#runchecks 722.65 673.10
rule_definition-list 7.63 8.49
rule_definition-list#gather 7.33 8.17
rule_definition-list#gather_axe.utils.isHidden 0.01 0.01
rule_definition-list#matches 0.00 0.00
rule_definition-list#runchecks 0.04 0.04
rule_dlitem 12.31 45.74
rule_dlitem#gather 11.97 45.37
rule_dlitem#gather_axe.utils.isHidden 0.01 0.01
rule_dlitem#matches 0.00 0.00
rule_dlitem#runchecks 0.06 0.06
rule_document-title 8.29 9.07
rule_document-title#gather 0.06 0.03
rule_document-title#gather_axe.utils.isHidden 0.04 0.01
rule_document-title#matches 0.08 0.06
rule_document-title#runchecks 7.93 8.74
rule_duplicate-id 564.12 4.21
rule_duplicate-id-active 14.30 18.34
rule_duplicate-id-active#gather 8.95 12.20
rule_duplicate-id-active#matches 5.03 5.79
rule_duplicate-id-active#runchecks 0.04 0.04
rule_duplicate-id-aria 550.52 25.44
rule_duplicate-id-aria#gather 0.00 0.01
rule_duplicate-id-aria#matches 550.19 25.09
rule_duplicate-id-aria#runchecks 0.05 0.04
rule_duplicate-id#gather 0.00 0.00
rule_duplicate-id#matches 561.64 1.83
rule_duplicate-id#runchecks 2.16 2.11
rule_empty-heading 35.95 40.45
rule_empty-heading#gather 21.81 24.77
rule_empty-heading#gather_axe.utils.isHidden 0.52 0.03
rule_empty-heading#matches 1.69 2.94
rule_empty-heading#runchecks 12.17 12.45
rule_form-field-multiple-labels 12.16 14.60
rule_form-field-multiple-labels#gather 10.79 13.47
rule_form-field-multiple-labels#gather_axe.utils.isHidden 0.10 0.02
rule_form-field-multiple-labels#matches 0.09 0.09
rule_form-field-multiple-labels#runchecks 0.98 0.75
rule_frame-tested 8.85 10.91
rule_frame-tested#gather 8.54 10.58
rule_frame-tested#gather_axe.utils.isHidden 0.01 0.00
rule_frame-tested#matches 0.00 0.00
rule_frame-tested#runchecks 0.04 0.05
rule_frame-title 0.28 0.25
rule_frame-title-unique 9.66 11.29
rule_frame-title-unique#gather 9.13 10.96
rule_frame-title-unique#gather_axe.utils.isHidden 0.01 0.01
rule_frame-title-unique#matches 0.00 0.00
rule_frame-title-unique#runchecks 0.10 0.05
rule_frame-title#gather 0.02 0.02
rule_frame-title#gather_axe.utils.isHidden 0.00 0.01
rule_frame-title#matches 0.00 0.00
rule_frame-title#runchecks 0.03 0.02
rule_heading-order 35.60 25.61
rule_heading-order#gather 31.45 22.90
rule_heading-order#gather_axe.utils.isHidden 1.04 0.03
rule_heading-order#matches 3.02 1.88
rule_heading-order#runchecks 0.71 0.56
rule_html-has-lang 13.79 8.63
rule_html-has-lang#gather 0.06 0.03
rule_html-has-lang#gather_axe.utils.isHidden 0.04 0.00
rule_html-has-lang#matches 0.06 0.04
rule_html-has-lang#runchecks 13.37 8.36
rule_html-lang-valid 37.81 23.34
rule_html-lang-valid#gather 19.58 11.20
rule_html-lang-valid#gather_axe.utils.isHidden 0.06 0.01
rule_html-lang-valid#matches 0.01 0.01
rule_html-lang-valid#runchecks 17.79 11.85
rule_html-xml-lang-mismatch 10.31 9.67
rule_html-xml-lang-mismatch#gather 9.94 9.34
rule_html-xml-lang-mismatch#gather_axe.utils.isHidden 0.01 0.01
rule_html-xml-lang-mismatch#matches 0.00 0.00
rule_html-xml-lang-mismatch#runchecks 0.05 0.04
rule_image-alt 14.07 15.12
rule_image-alt#gather 13.42 14.53
rule_image-alt#gather_axe.utils.isHidden 0.08 0.03
rule_image-alt#matches 0.01 0.00
rule_image-alt#runchecks 0.33 0.30
rule_image-redundant-alt 142.78 107.16
rule_image-redundant-alt#gather 62.29 33.82
rule_image-redundant-alt#gather_axe.utils.isHidden 31.47 3.50
rule_image-redundant-alt#matches 0.10 0.16
rule_image-redundant-alt#runchecks 80.11 72.90
rule_input-image-alt 12.69 9.29
rule_input-image-alt#gather 12.37 8.97
rule_input-image-alt#gather_axe.utils.isHidden 0.01 0.01
rule_input-image-alt#matches 0.00 0.01
rule_input-image-alt#runchecks 0.05 0.04
rule_label 0.70 0.64
rule_label-title-only 0.71 0.58
rule_label-title-only#gather 0.13 0.03
rule_label-title-only#gather_axe.utils.isHidden 0.12 0.01
rule_label-title-only#matches 0.09 0.11
rule_label-title-only#runchecks 0.25 0.23
rule_label#gather 0.06 0.01
rule_label#gather_axe.utils.isHidden 0.06 0.00
rule_label#matches 0.06 0.05
rule_label#runchecks 0.37 0.37
rule_landmark-banner-is-top-level 11.22 16.12
rule_landmark-banner-is-top-level#gather 10.94 15.77
rule_landmark-banner-is-top-level#gather_axe.utils.isHidden 0.00 0.01
rule_landmark-banner-is-top-level#matches 0.00 0.00
rule_landmark-banner-is-top-level#runchecks 0.04 0.05
rule_landmark-complementary-is-top-level 12.84 13.98
rule_landmark-complementary-is-top-level#gather 12.55 13.66
rule_landmark-complementary-is-top-level#gather_axe.utils.isHidden 0.01 0.01
rule_landmark-complementary-is-top-level#matches 0.00 0.01
rule_landmark-complementary-is-top-level#runchecks 0.03 0.04
rule_landmark-contentinfo-is-top-level 11.05 14.24
rule_landmark-contentinfo-is-top-level#gather 10.78 13.90
rule_landmark-contentinfo-is-top-level#gather_axe.utils.isHidden 0.00 0.01
rule_landmark-contentinfo-is-top-level#matches 0.00 0.00
rule_landmark-contentinfo-is-top-level#runchecks 0.04 0.04
rule_landmark-main-is-top-level 11.40 14.69
rule_landmark-main-is-top-level#gather 11.10 14.34
rule_landmark-main-is-top-level#gather_axe.utils.isHidden 0.01 0.01
rule_landmark-main-is-top-level#matches 0.00 0.01
rule_landmark-main-is-top-level#runchecks 0.04 0.04
rule_landmark-no-duplicate-banner 19.28 24.28
rule_landmark-no-duplicate-banner#gather 0.05 0.03
rule_landmark-no-duplicate-banner#gather_axe.utils.isHidden 0.04 0.01
rule_landmark-no-duplicate-banner#matches 0.00 0.01
rule_landmark-no-duplicate-banner#runchecks 19.02 24.01
rule_landmark-no-duplicate-contentinfo 19.66 23.99
rule_landmark-no-duplicate-contentinfo#gather 0.18 0.02
rule_landmark-no-duplicate-contentinfo#gather_axe.utils.isHidden 0.16 0.00
rule_landmark-no-duplicate-contentinfo#matches 0.00 0.00
rule_landmark-no-duplicate-contentinfo#runchecks 19.22 23.69
rule_landmark-one-main 30.67 38.23
rule_landmark-one-main#gather 0.12 0.02
rule_landmark-one-main#gather_axe.utils.isHidden 0.11 0.00
rule_landmark-one-main#matches 0.00 0.00
rule_landmark-one-main#runchecks 30.28 37.93
rule_layout-table 7.79 9.69
rule_layout-table#gather 7.49 9.35
rule_layout-table#gather_axe.utils.isHidden 0.01 0.01
rule_layout-table#matches 0.01 0.00
rule_layout-table#runchecks 0.04 0.05
rule_link-name 327.73 262.97
rule_link-name#gather 31.25 19.99
rule_link-name#gather_axe.utils.isHidden 15.19 1.00
rule_link-name#matches 0.15 0.18
rule_link-name#runchecks 296.07 242.51
rule_list 24.95 17.14
rule_list#gather 11.43 9.81
rule_list#gather_axe.utils.isHidden 0.79 0.32
rule_list#matches 0.06 0.06
rule_list#runchecks 13.17 7.03
rule_listitem 33.68 20.63
rule_listitem#gather 22.92 12.26
rule_listitem#gather_axe.utils.isHidden 13.67 1.15
rule_listitem#matches 0.15 0.17
rule_listitem#runchecks 10.35 7.85
rule_marquee 7.95 9.52
rule_marquee#gather 7.60 9.18
rule_marquee#matches 0.00 0.01
rule_marquee#runchecks 0.03 0.04
rule_meta-refresh 7.98 10.20
rule_meta-refresh#gather 7.65 9.83
rule_meta-refresh#matches 0.00 0.00
rule_meta-refresh#runchecks 0.04 0.06
rule_meta-viewport 0.61 0.46
rule_meta-viewport-large 11.35 10.49
rule_meta-viewport-large#gather 10.69 9.77
rule_meta-viewport-large#matches 0.01 0.00
rule_meta-viewport-large#runchecks 0.33 0.32
rule_meta-viewport#gather 0.01 0.01
rule_meta-viewport#matches 0.12 0.01
rule_meta-viewport#runchecks 0.26 0.21
rule_object-alt 8.56 10.61
rule_object-alt#gather 8.16 10.29
rule_object-alt#gather_axe.utils.isHidden 0.01 0.00
rule_object-alt#matches 0.00 0.01
rule_object-alt#runchecks 0.06 0.04
rule_page-has-heading-one 23.98 27.38
rule_page-has-heading-one#gather 0.06 0.01
rule_page-has-heading-one#gather_axe.utils.isHidden 0.04 0.00
rule_page-has-heading-one#matches 0.01 0.00
rule_page-has-heading-one#runchecks 23.69 27.13
rule_radiogroup 15.31 27.94
rule_radiogroup#gather 14.97 27.62
rule_radiogroup#gather_axe.utils.isHidden 0.01 0.01
rule_radiogroup#matches 0.00 0.01
rule_radiogroup#runchecks 0.05 0.04
rule_region 913.21 36.31
rule_region#gather 0.05 0.03
rule_region#gather_axe.utils.isHidden 0.04 0.01
rule_region#matches 0.00 0.01
rule_region#runchecks 912.93 36.08
rule_scope-attr-valid 9.42 11.59
rule_scope-attr-valid#gather 9.14 11.29
rule_scope-attr-valid#gather_axe.utils.isHidden 0.01 0.02
rule_scope-attr-valid#matches 0.00 0.01
rule_scope-attr-valid#runchecks 0.04 0.04
rule_server-side-image-map 7.23 9.25
rule_server-side-image-map#gather 6.94 8.91
rule_server-side-image-map#gather_axe.utils.isHidden 0.01 0.01
rule_server-side-image-map#matches 0.00 0.00
rule_server-side-image-map#runchecks 0.04 0.04
rule_skip-link 152.16 15.41
rule_skip-link#gather 12.88 14.41
rule_skip-link#gather_axe.utils.isHidden 0.45 1.14
rule_skip-link#matches 138.95 0.32
rule_skip-link#runchecks 0.05 0.39
rule_tabindex 12.11 13.21
rule_tabindex#gather 11.34 12.32
rule_tabindex#gather_axe.utils.isHidden 1.94 0.11
rule_tabindex#matches 0.01 0.00
rule_tabindex#runchecks 0.49 0.56
rule_table-duplicate-name 0.26 0.32
rule_table-duplicate-name#gather 0.01 0.01
rule_table-duplicate-name#gather_axe.utils.isHidden 0.00 0.01
rule_table-duplicate-name#matches 0.00 0.01
rule_table-duplicate-name#runchecks 0.03 0.04
rule_td-headers-attr 0.23 0.27
rule_td-headers-attr#gather 0.01 0.02
rule_td-headers-attr#gather_axe.utils.isHidden 0.00 0.00
rule_td-headers-attr#matches 0.00 0.00
rule_td-headers-attr#runchecks 0.03 0.03
rule_th-has-data-cells 0.23 0.26
rule_th-has-data-cells#gather 0.01 0.01
rule_th-has-data-cells#gather_axe.utils.isHidden 0.00 0.00
rule_th-has-data-cells#matches 0.00 0.00
rule_th-has-data-cells#runchecks 0.03 0.03
rule_valid-lang 12.55 16.81
rule_valid-lang#gather 12.19 16.43
rule_valid-lang#gather_axe.utils.isHidden 0.04 0.01
rule_valid-lang#matches 0.06 0.06
rule_valid-lang#runchecks 0.05 0.04
rule_video-caption 7.27 9.58
rule_video-caption#gather 6.94 9.21
rule_video-caption#matches 0.00 0.01
rule_video-caption#runchecks 0.04 0.04
rule_video-description 0.24 0.29
rule_video-description#gather 0.01 0.01
rule_video-description#matches 0.00 0.00
rule_video-description#runchecks 0.03 0.04

Closes: #166
Closes: #726
Closes: #1193
Closes: #1464
Closes: WWD-1821
Should help #1497, though need more work to get under the 60s benchmark (mostly in our generate unique selector code)
Might invalidate some vNode caching on #1096

Reviewer checks

Required fields, to be filled out by PR reviewer(s)

  • Follows the commit message policy, appropriate for next version
  • Has documentation updated, a DU ticket, or requires no documentation change
  • Includes new tests, or was unnecessary
  • Code is reviewed for security by: @WilcoFiers

@straker straker requested a review from a team as a code owner April 17, 2019 20:14
Copy link
Member

@stephenmathieson stephenmathieson left a comment

Choose a reason for hiding this comment

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

One small nitpick, but this is amazing!

Please allow some other folks to review, as this touches a lot of stuff.

lib/commons/aria/is-accessible-ref.js Outdated Show resolved Hide resolved
Copy link
Contributor

@WilcoFiers WilcoFiers left a comment

Choose a reason for hiding this comment

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

Not done reviewing yet, but I figured I'd share what I've done so far.

test/checks/aria/required-children.js Show resolved Hide resolved
});
return found;
// TODO: removing vNode is a breaking change, but we can skirt that
// for now by ignoring it if passed in
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if it isn't better to keep getNodeFromTree as is and deprecate it, and have a replacement method that uses cache? Would like to discuss.

Copy link
Member

Choose a reason for hiding this comment

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

👎 from me. I see this as an opportunity for people (us) to continue using the "wrong method". Additionally, as discussed yesterday, there are 3 different methods for figuring out if something is "hidden". Let's not create the same problem here.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a breaking change getNodeFromTree is something that rules can use. Why is this change necessary?

lib/core/utils/is-hidden.js Outdated Show resolved Hide resolved
lib/core/imports/index.js Show resolved Hide resolved
package.json Show resolved Hide resolved
dylanb
dylanb previously requested changes Apr 18, 2019
Copy link
Contributor

@dylanb dylanb left a comment

Choose a reason for hiding this comment

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

Introduces unnecessary breaking changes and does not follow our commit message format

lib/core/public/run-rules.js Outdated Show resolved Hide resolved
lib/core/utils/flattened-tree.js Outdated Show resolved Hide resolved
});
return found;
// TODO: removing vNode is a breaking change, but we can skirt that
// for now by ignoring it if passed in
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a breaking change getNodeFromTree is something that rules can use. Why is this change necessary?

@stephenmathieson
Copy link
Member

Introduces unnecessary breaking changes

What are the breaking changes? Please elaborate. The getNodeFromTree function has the same result as it did previously.

and does not follow our commit message format

Yes it does. Please elaborate.

@straker straker dismissed dylanb’s stale review April 22, 2019 14:21

Removed deprecation comment for a separate commit

jeeyyy
jeeyyy previously requested changes Apr 25, 2019
Copy link
Contributor

@jeeyyy jeeyyy left a comment

Choose a reason for hiding this comment

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

See comments inline.

lib/checks/aria/required-children.js Outdated Show resolved Hide resolved
lib/commons/aria/is-accessible-ref.js Outdated Show resolved Hide resolved
lib/commons/aria/is-accessible-ref.js Show resolved Hide resolved
lib/commons/dom/is-visible.js Outdated Show resolved Hide resolved
lib/commons/text/accessible-text-virtual.js Outdated Show resolved Hide resolved
lib/core/utils/flattened-tree.js Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
.prettierignore Outdated Show resolved Hide resolved
Copy link
Contributor

@WilcoFiers WilcoFiers left a comment

Choose a reason for hiding this comment

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

Missing a few tests. Other than that, LGTM.

lib/commons/dom/is-visible.js Outdated Show resolved Hide resolved
@@ -45,12 +46,16 @@ dom.isVisible = function(el, screenReader, recursed) {
el = el.host; // grab the host Node
}

style = window.getComputedStyle(el, null);
if (node && typeof node[cacheName] !== 'undefined') {
return node[cacheName];
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add 2 tests:

  1. that the cache is set after first accessing this method
  2. that the cache is used when accessing this a second time

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm going to use this comment to group all the tests for caching comments.

We already have code that tests that all of these functions are working as expected. Is there a particular reason you would like the unit tests to be tied to how the function was implemented internally?

One of the nice things about these drastic code changes (especially for getNodeFromTree) is that I could completely swap out the internal implementation and I didn't have to update any of the tests. If we start adding tests that make sure a node is added to the cache, or retrieved from the cache, or that private cache properties are added, then we tie a lot of tests to the implementation of the internal code. We also force changes to that implementation to require changes to the unit tests.

IMO, we shouldn't test the internals of a function as the internals can easily change, creating fragile tests. We should only test that the function returns an expected set of outputs for a given set of inputs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough :)

@@ -47,6 +48,8 @@ function virtualDOMfromNode(node, shadowId) {
return vNodeCache._tabbableElements;
}
};
axe._cache.nodeMap.set(node, vNode);
Copy link
Contributor

Choose a reason for hiding this comment

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

Verify in a test that all virtual nodes are put in cache.

});
return found;
const el = node || vNode;
return axe._cache.nodeMap.get(el);
Copy link
Contributor

Choose a reason for hiding this comment

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

Create a test to show this is accessed from cache.

lib/core/utils/is-hidden.js Outdated Show resolved Hide resolved
@@ -20,7 +21,11 @@ axe.utils.isHidden = function isHidden(el, recursed) {
el = el.host; // grab the host Node
}

var style = window.getComputedStyle(el, null);
if (node && node._isHidden !== null) {
return node._isHidden;
Copy link
Contributor

Choose a reason for hiding this comment

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

As before, please add tests for the caching.

return node;
const idRefsRegex = /^idrefs?$/;

function cacheIdRefs(node, refAttrs) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add tests for axe._cache.idRefs?

lib/commons/aria/is-accessible-ref.js Outdated Show resolved Hide resolved
@WilcoFiers WilcoFiers changed the title feat(*): Improve perf of axe.run [WWD-1821] feat: Improve perf of axe.run [WWD-1821] Apr 30, 2019
@straker straker merged commit a84431a into develop Apr 30, 2019
@straker straker deleted the improvePerf branch April 30, 2019 15:29
@WilcoFiers WilcoFiers added this to the Axe-core 3.3 milestone May 1, 2019
@mohanraj-r
Copy link
Contributor

This is amazing ! Thank you very much @straker
With the recent develop branch axe execution time for one of my pages reduced from ~14000ms to ~5000ms

💡It would be great if we can add some kind of perf tests to validate changes. If there are pointers on how to go about them, please let me know.

stephenmathieson added a commit to mohanraj-r/axe-core that referenced this pull request May 10, 2019
* develop: (50 commits)
  docs: add jsdom example and tests (dequelabs#1530)
  fix(aria-valid-attr-value): allow aria-owns to pass when element is not in the DOM (dequelabs#1526)
  fix(isSkipLink): cache first page link (dequelabs#1525)
  chore: update Babel dependencies (dequelabs#1527)
  chore(package): Update karma to version 4.1.0 (dequelabs#1528)
  feat: Improve perf of axe.run [WWD-1821] (dequelabs#1503)
  fix(prettier): ignore generated api doc files (dequelabs#1522)
  fix(skip-link,region): Allow multiple skiplinks at page top (dequelabs#1496)
  fix(raw-reporter): do not output `DqElement`s (dequelabs#1513)
  fix: Scroll state had top and left properties flipped (dequelabs#1469)
  refactor: commons.color.getBackgroundColor method (dequelabs#1451)
  fix(aria-valid-attr-value): allow aria-controls to pass when element is not in the DOM
  chore: Update husky to the latest version 🚀 (dequelabs#1514)
  style: format HTML files with Prettier (dequelabs#1508)
  test: Fix invalid test html (dequelabs#1502)
  feat(rule): Inline text spacing must be adjustable with custom stylesheets (dequelabs#1446)
  chore: Remove version number from axe.d.ts (dequelabs#1499)
  chore: Update make-dir to the latest version 🚀 (dequelabs#1465)
  fix: Exclude  iframe for html-has-lang rule (Issue 1424) (dequelabs#1430)
  feat(utils): add support for complex CSS selectors (dequelabs#1494)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
8 participants