From 91bebdb038723b0620b07eef806a825658ae8988 Mon Sep 17 00:00:00 2001 From: Adam Cutler Date: Sat, 25 Mar 2023 14:14:01 -0400 Subject: [PATCH] fix: work with extremely large results (#291) * fix: work with extremely large results * add test * back to ff? * test pls * waits? * 60M is too large * stop comparing html. selenium adds attributes --- .../e2e/selenium/spec/api_spec.rb | 20 ++++++++++---- packages/axe-core-api/lib/axe/api/run.rb | 26 ++++++++++++++++--- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/axe-core-api/e2e/selenium/spec/api_spec.rb b/packages/axe-core-api/e2e/selenium/spec/api_spec.rb index 848a7c4c..c2cb7ce7 100644 --- a/packages/axe-core-api/e2e/selenium/spec/api_spec.rb +++ b/packages/axe-core-api/e2e/selenium/spec/api_spec.rb @@ -4,9 +4,9 @@ require "axe/core" require "axe/api/run" -options = Selenium::WebDriver::Firefox::Options.new -options.add_argument('--headless') -$driver = Selenium::WebDriver.for :firefox, options: options +options = Selenium::WebDriver::Chrome::Options.new +# options.add_argument('--headless') +$driver = Selenium::WebDriver.for :chrome, options: options Run = Axe::API::Run @@ -20,6 +20,7 @@ def run_axe(run = Run.new) $axe_post_43x = Axe::Configuration.instance.jslib $crasher_js = File.read File.join($fixture_root, "axe-crasher.js") $force_legacy_js = File.read File.join($fixture_root, "axe-force-legacy.js") +$large_partial_js = File.read File.join($fixture_root, "axe-large-partial.js") def fixture(filename) "http://localhost:8000" + filename @@ -56,7 +57,7 @@ def recursive_compact(thing) elsif thing.is_a?(Hash) thing.each_with_object({}) do |(k,v), h| v = recursive_compact(v) - h[k] = v unless [nil, [], {}].include?(v) + h[k] = v unless ([nil, [], {}].include?(v) or k == :html) end else thing @@ -92,7 +93,7 @@ def recursive_compact(thing) end describe "frame tests" do - it "injects into nested iframes" do + it "injects into nested iframes", :fo => true do $driver.get fixture "/nested-iframes.html" res = run_axe expect(res.results.violations).not_to be_empty @@ -268,6 +269,15 @@ def recursive_compact(thing) expect { run_axe }.to raise_error /finishRun failed/ } end + + it "works with large results", :nt => true do + $driver.get fixture "/index.html" + res = with_js($axe_post_43x + $large_partial_js) { run_axe } + + + expect(res.results.passes.length).to eq 1 + expect(res.results.passes[0].id).to eq :'duplicate-id' + end end diff --git a/packages/axe-core-api/lib/axe/api/run.rb b/packages/axe-core-api/lib/axe/api/run.rb index e7bc5451..6949f306 100644 --- a/packages/axe-core-api/lib/axe/api/run.rb +++ b/packages/axe-core-api/lib/axe/api/run.rb @@ -36,9 +36,19 @@ def analyze_post_43x(page, lib) partial_results = run_partial_recursive(page, @context, lib, true) throw partial_results if partial_results.respond_to?("key?") and partial_results.key?("errorMessage") results = within_about_blank_context(page) { |page| + partial_res_str = partial_results.to_json + size_limit = 20_000_000 + while not partial_res_str.empty? do + chunk_size = size_limit + chunk_size = partial_res_str.length if chunk_size > partial_res_str.length + chunk = partial_res_str[0..chunk_size-1] + partial_res_str = partial_res_str[chunk_size..-1] + store_chunk page, chunk + end + Common::Loader.new(page, lib).load_top_level Axe::Configuration.instance.jslib begin - axe_finish_run page, partial_results + axe_finish_run page rescue raise StandardError.new "axe.finishRun failed. Please check out https://github.com/dequelabs/axe-core-gems/blob/develop/error-handling.md" end @@ -138,12 +148,20 @@ def run_partial_recursive(page, context, lib, top_level = false) return results end - def axe_finish_run(page, partial_results) + def store_chunk(page, chunk) + script = <<-JS + const chunk = arguments[0]; + window.partialResults ??= ''; + window.partialResults += chunk; + JS + page.execute_script_fixed script, chunk + end + def axe_finish_run(page) script = <<-JS - const partialResults = arguments[0]; + const partialResults = JSON.parse(window.partialResults || '[]'); return axe.finishRun(partialResults); JS - page.execute_script_fixed script, partial_results + page.execute_script_fixed script end def axe_shadow_select(page, frame_selector)