axe-cuprite 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cd30e650ead2d72475783c40ed7cc6d7d251527913d2b28ae6643402d9d032b
4
- data.tar.gz: a5624b4d65f5859b7fd4a710f79a5bf6fb85b6c9f409e2bc50de393f8563ad86
3
+ metadata.gz: 1005023d8e3178edd24de983e954208d297ee0ca720f33ba822f14c33861b17f
4
+ data.tar.gz: 5b0b13f67c92e8b89d1d4b4f2f9b4957ae71690d60eeb006edd2e9239bd89dd7
5
5
  SHA512:
6
- metadata.gz: 89f99c88d792b73c748f25c4b7a33d0b136a5a939e77f14b6fcbc437f88ab5eb85e4ebf0f182843ce23ea1a04857e619104db06aaf476eb065c9252aebe2c22b
7
- data.tar.gz: 274b40778c354c1ee42a04958fdda2b1f9513f9220d94b300495a62cf86c86d862655d504c1366ead311e65ba1410104f3eec9fc51f280faee098464113d8af9
6
+ metadata.gz: 439317e53b00d1f6a4f4c275f02b5caa9c6d0add981079b809a3363c937fab3431226db540f6163ad908a47b0869782db0b0bfd98f5b229bb121b45b9733acb6
7
+ data.tar.gz: 9ade47a886507d6349a680abd9446fc5191048172b1a40f660a694dc93afa0841528d73a5eb4e281d30960fa4fad4b72e87d359a969c3e15274f9213c76c9587
data/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.1] - 2026-06-09
11
+
12
+ ### Added
13
+ - GitHub Actions CI (`.github/workflows/ci.yml`): runs the RSpec suite under
14
+ Cuprite/headless Chrome across Ruby 3.0–3.4 and a RuboCop lint job, on every
15
+ push to `main` and all pull requests.
16
+
17
+ ### Fixed
18
+ - `Injector#inject_source!` no longer appends a second `<script>` tag when a hard
19
+ injection failure occurs. The retry flow is now a single linear path
20
+ (`execute_script` → check → `add_script_tag` fallback → check → raise), so the
21
+ fallback runs at most once.
22
+
8
23
  ## [0.1.0] - 2026-06-06
9
24
 
10
25
  ### Added
@@ -76,20 +76,17 @@ module AxeCuprite
76
76
 
77
77
  begin
78
78
  @page.execute_script(source)
79
- rescue StandardError => e
80
- raise InjectionError, "Failed to inject axe-core: #{e.message}" unless try_add_script_tag(source)
79
+ rescue StandardError
80
+ nil
81
81
  end
82
+ return true if injected?
82
83
 
84
+ try_add_script_tag(source)
83
85
  return true if injected?
84
86
 
85
- # execute_script silently no-op'd (CSP, sandbox, ...). Try the tag fallback.
86
- if try_add_script_tag(source) && injected?
87
- true
88
- else
89
- raise InjectionError,
90
- "axe-core did not load after injection. A strict Content-Security-Policy " \
91
- "may be blocking script injection on the page under test."
92
- end
87
+ raise InjectionError,
88
+ "axe-core did not load after injection. The page may be blocking " \
89
+ "script injection (e.g. a strict Content-Security-Policy)."
93
90
  end
94
91
 
95
92
  # Run axe and return a Results object. Injects on demand if needed.
@@ -98,9 +95,7 @@ module AxeCuprite
98
95
  ensure_present!
99
96
 
100
97
  raw = evaluate_axe(context, options, timeout)
101
- if raw.is_a?(Hash) && raw["error"]
102
- raise AxeRunError, "axe.run failed: #{raw["error"]}"
103
- end
98
+ raise AxeRunError, "axe.run failed: #{raw["error"]}" if raw.is_a?(Hash) && raw["error"]
104
99
 
105
100
  Results.new(raw)
106
101
  end
@@ -27,7 +27,7 @@ module AxeCuprite
27
27
  @skip_rules = []
28
28
  @tags = []
29
29
  @run_options = {}
30
- @timeout = nil
30
+ @timeout = nil
31
31
  end
32
32
 
33
33
  # --- chainable DSL ----------------------------------------------------
@@ -153,8 +153,8 @@ module AxeCuprite
153
153
  end
154
154
 
155
155
  unless @skip_rules.empty?
156
- opts[:rules] = Normalize.rules(@skip_rules).each_with_object({}) do |id, h|
157
- h[id] = { enabled: false }
156
+ opts[:rules] = Normalize.rules(@skip_rules).to_h do |id|
157
+ [id, { enabled: false }]
158
158
  end
159
159
  end
160
160
 
@@ -167,8 +167,8 @@ module AxeCuprite
167
167
  rule_count = @violations.length
168
168
  node_count = @violations.sum { |v| v.nodes.length }
169
169
  "expected page to be axe-clean, but found #{rule_count} " \
170
- "#{pluralize(rule_count, 'violation')} across #{node_count} " \
171
- "#{pluralize(node_count, 'element')}:"
170
+ "#{pluralize(rule_count, "violation")} across #{node_count} " \
171
+ "#{pluralize(node_count, "element")}:"
172
172
  end
173
173
 
174
174
  def details
@@ -179,7 +179,7 @@ module AxeCuprite
179
179
  lines = []
180
180
  impact = violation.impact || "n/a"
181
181
  lines << " ● [#{impact}] #{violation.id} — #{violation.help} " \
182
- "(#{violation.nodes.length} #{pluralize(violation.nodes.length, 'element')})"
182
+ "(#{violation.nodes.length} #{pluralize(violation.nodes.length, "element")})"
183
183
  lines << " #{violation.help_url}" if violation.help_url
184
184
 
185
185
  violation.nodes.first(MAX_NODES).each do |node|
@@ -187,7 +187,7 @@ module AxeCuprite
187
187
  end
188
188
 
189
189
  remaining = violation.nodes.length - MAX_NODES
190
- lines << " … and #{remaining} more #{pluralize(remaining, 'element')}" if remaining.positive?
190
+ lines << " … and #{remaining} more #{pluralize(remaining, "element")}" if remaining.positive?
191
191
  lines.join("\n")
192
192
  end
193
193
 
@@ -20,8 +20,8 @@ module AxeCuprite
20
20
  end
21
21
  end
22
22
 
23
- if defined?(::RSpec) && ::RSpec.respond_to?(:configure)
24
- ::RSpec.configure do |config|
23
+ if defined?(RSpec) && RSpec.respond_to?(:configure)
24
+ RSpec.configure do |config|
25
25
  config.include AxeCuprite::RSpec::DSL
26
26
  end
27
27
  end
@@ -56,9 +56,7 @@ module AxeCuprite
56
56
  # default_tags become a tag-based runOnly, but only if nothing already
57
57
  # scopes runOnly (an explicit rule/tag selection takes precedence).
58
58
  tags = Normalize.tags(@configuration.default_tags)
59
- if !opts.key?("runOnly") && !tags.empty?
60
- opts["runOnly"] = { "type" => "tag", "values" => tags }
61
- end
59
+ opts["runOnly"] = { "type" => "tag", "values" => tags } if !opts.key?("runOnly") && !tags.empty?
62
60
 
63
61
  # global skip_rules disable rules, without clobbering an explicit caller
64
62
  # setting for the same rule.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module AxeCuprite
4
4
  # Version of the axe-cuprite gem itself.
5
- VERSION = "0.1.0"
5
+ VERSION = "0.1.1"
6
6
 
7
7
  # Version of the axe-core engine vendored under lib/axe/cuprite/vendor/axe.min.js.
8
8
  # Keep this in sync with the vendored file via `rake axe:update`.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: axe-cuprite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdullah Hashim
@@ -58,33 +58,25 @@ dependencies:
58
58
  - !ruby/object:Gem::Version
59
59
  version: '0.17'
60
60
  - !ruby/object:Gem::Dependency
61
- name: rspec
61
+ name: puma
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - "~>"
65
- - !ruby/object:Gem::Version
66
- version: '3.0'
67
- type: :development
68
- prerelease: false
69
- version_requirements: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - "~>"
64
+ - - ">="
72
65
  - !ruby/object:Gem::Version
73
- version: '3.0'
74
- - !ruby/object:Gem::Dependency
75
- name: rake
76
- requirement: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - "~>"
66
+ version: '5.0'
67
+ - - "<"
79
68
  - !ruby/object:Gem::Version
80
- version: '13.0'
69
+ version: '9.0'
81
70
  type: :development
82
71
  prerelease: false
83
72
  version_requirements: !ruby/object:Gem::Requirement
84
73
  requirements:
85
- - - "~>"
74
+ - - ">="
86
75
  - !ruby/object:Gem::Version
87
- version: '13.0'
76
+ version: '5.0'
77
+ - - "<"
78
+ - !ruby/object:Gem::Version
79
+ version: '9.0'
88
80
  - !ruby/object:Gem::Dependency
89
81
  name: rack
90
82
  requirement: !ruby/object:Gem::Requirement
@@ -120,33 +112,82 @@ dependencies:
120
112
  - !ruby/object:Gem::Version
121
113
  version: '2.0'
122
114
  - !ruby/object:Gem::Dependency
123
- name: puma
115
+ name: rake
124
116
  requirement: !ruby/object:Gem::Requirement
125
117
  requirements:
126
- - - ">="
118
+ - - "~>"
127
119
  - !ruby/object:Gem::Version
128
- version: '5.0'
129
- - - "<"
120
+ version: '13.0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
130
126
  - !ruby/object:Gem::Version
131
- version: '9.0'
127
+ version: '13.0'
128
+ - !ruby/object:Gem::Dependency
129
+ name: rspec
130
+ requirement: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '3.0'
132
135
  type: :development
133
136
  prerelease: false
134
137
  version_requirements: !ruby/object:Gem::Requirement
135
138
  requirements:
136
- - - ">="
139
+ - - "~>"
137
140
  - !ruby/object:Gem::Version
138
- version: '5.0'
139
- - - "<"
141
+ version: '3.0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rubocop
144
+ requirement: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - "~>"
140
147
  - !ruby/object:Gem::Version
141
- version: '9.0'
148
+ version: '1.86'
149
+ type: :development
150
+ prerelease: false
151
+ version_requirements: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - "~>"
154
+ - !ruby/object:Gem::Version
155
+ version: '1.86'
156
+ - !ruby/object:Gem::Dependency
157
+ name: rubocop-rake
158
+ requirement: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - "~>"
161
+ - !ruby/object:Gem::Version
162
+ version: '0.7'
163
+ type: :development
164
+ prerelease: false
165
+ version_requirements: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - "~>"
168
+ - !ruby/object:Gem::Version
169
+ version: '0.7'
170
+ - !ruby/object:Gem::Dependency
171
+ name: rubocop-rspec
172
+ requirement: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - "~>"
175
+ - !ruby/object:Gem::Version
176
+ version: '3.0'
177
+ type: :development
178
+ prerelease: false
179
+ version_requirements: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - "~>"
182
+ - !ruby/object:Gem::Version
183
+ version: '3.0'
142
184
  description: |
143
185
  axe-cuprite runs the axe-core accessibility engine against pages rendered in
144
186
  Capybara system/feature tests and exposes the results as RSpec matchers
145
187
  (be_axe_clean / be_accessible). Unlike Deque's official axe-core-capybara gem,
146
188
  it never touches Selenium-specific driver internals: axe is driven entirely
147
189
  through Capybara's driver-neutral JavaScript API, so it works with Cuprite
148
- (the Ferrum/CDP headless-Chrome driver) and any other real-browser driver.
149
- The headline use case is catching WCAG color-contrast failures in CI.
190
+ and any other real-browser driver.
150
191
  email:
151
192
  - abdullah@guidedrails.com
152
193
  executables: []