Skip to content

Commit

Permalink
Allow for filtering out specific Axe measurement entities through reg…
Browse files Browse the repository at this point in the history
…ular expressions (#5894)
  • Loading branch information
wkoot authored Apr 19, 2023
1 parent 91171bb commit 05ae4e1
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ def _include_entity(self, entity: Entity) -> bool:
for tag in tags:
if match_string_or_regular_expression(tag, tags_to_ignore):
return False
if element_include_filter := self._parameter("element_include_filter"):
if not match_string_or_regular_expression(entity["element"], element_include_filter):
return False
if element_exclude_filter := self._parameter("element_exclude_filter"):
if match_string_or_regular_expression(entity["element"], element_exclude_filter):
return False
return True


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,26 @@
from io import StringIO

from base_collectors import CSVFileSourceCollector
from collector_utilities.functions import md5_hash
from collector_utilities.functions import md5_hash, match_string_or_regular_expression
from model import Entities, Entity, SourceResponses


class AxeCSVAccessibility(CSVFileSourceCollector):
"""Collector class to get accessibility violations."""

def _include_entity(self, entity: Entity) -> bool:
"""Return whether to include the violation."""
impact = entity["impact"]
if impact and impact not in self._parameter("impact"):
return False
if element_include_filter := self._parameter("element_include_filter"):
if not match_string_or_regular_expression(entity["element"], element_include_filter):
return False
if element_exclude_filter := self._parameter("element_exclude_filter"):
if match_string_or_regular_expression(entity["element"], element_exclude_filter):
return False
return True

async def _parse_entities(self, responses: SourceResponses) -> Entities:
"""Override to parse the CSV and create the entities."""
entity_attributes = [
Expand All @@ -31,11 +44,11 @@ async def _parse_entities(self, responses: SourceResponses) -> Entities:
for attributes in entity_attributes
)

async def __parse_csv(self, responses: SourceResponses) -> list[dict[str, str]]:
@staticmethod
async def __parse_csv(responses: SourceResponses) -> list[dict[str, str]]:
"""Parse the CSV and return the rows and parsed items ."""
impact_levels = self._parameter("impact")
rows = []
for response in responses:
csv_text = (await response.text()).strip()
rows.extend(list(csv.DictReader(StringIO(csv_text, newline=""))))
return [row for row in rows if row["Impact"] in impact_levels]
return rows
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ async def test_filter_by_tag_ignore(self):
response = await self.collect(get_request_json_return_value=self.json)
self.assert_measurement(response, value="1", entities=[self.expected_entities[1]])

async def test_element_include_filter(self):
"""Test that violations can be filtered by element."""
self.set_source_parameter("element_include_filter", ["html1"])
response = await self.collect(get_request_json_return_value=self.json)
self.assert_measurement(response, value="1", entities=[self.expected_entities[0]])

async def test_element_exclude_filter(self):
"""Test that violations can be filtered by element."""
self.set_source_parameter("element_exclude_filter", ["html1"])
response = await self.collect(get_request_json_return_value=self.json)
self.assert_measurement(response, value="1", entities=[self.expected_entities[1]])

async def test_zipped_json(self):
"""Test that a zip archive with JSON files is processed correctly."""
self.set_source_parameter("url", "axe.zip")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ async def test_filter_by_impact(self):
response = await self.collect(get_request_text=self.csv)
self.assert_measurement(response, value="1")

async def test_element_include_filter(self):
"""Test that violations can be filtered by element."""
self.set_source_parameter("element_include_filter", ["dom2"])
response = await self.collect(get_request_text=self.csv)
self.assert_measurement(response, value="1", entities=[self.expected_entities[1]])

async def test_element_exclude_filter(self):
"""Test that violations can be filtered by element."""
self.set_source_parameter("element_exclude_filter", ["dom2"])
response = await self.collect(get_request_text=self.csv)
self.assert_measurement(response, value="1", entities=[self.expected_entities[0]])

async def test_zipped_csv(self):
"""Test that a zip archive with CSV files is processed correctly."""
self.set_source_parameter("url", "https://example.org/axecsv.zip")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@
metrics=["accessibility"],
)

ELEMENT_INCLUDE_FILTER = MultipleChoiceWithAdditionParameter(
name="Elements to include (regular expressions)",
short_name="element include filter",
help="Elements to include can be specified by regular expression.",
placeholder="all",
metrics=["accessibility"],
)

ELEMENT_EXCLUDE_FILTER = MultipleChoiceWithAdditionParameter(
name="Elements to exclude (regular expressions)",
short_name="element exclude filter",
help="Elements to exclude can be specified by regular expression.",
placeholder="none",
metrics=["accessibility"],
)

RESULT_TYPES = MultipleChoiceParameter(
name="Result types",
help="Limit which result types to count.",
Expand Down Expand Up @@ -101,6 +117,8 @@
parameters=dict(
tags_to_include=TAGS_TO_INCLUDE,
tags_to_ignore=TAGS_TO_IGNORE,
element_include_filter=ELEMENT_INCLUDE_FILTER,
element_exclude_filter=ELEMENT_EXCLUDE_FILTER,
impact=IMPACT,
result_types=RESULT_TYPES,
**access_parameters(ALL_AXE_CORE_METRICS, source_type="an Axe-core report", source_type_format="JSON")
Expand All @@ -115,6 +133,8 @@
parameters=dict(
tags_to_include=TAGS_TO_INCLUDE,
tags_to_ignore=TAGS_TO_IGNORE,
element_include_filter=ELEMENT_INCLUDE_FILTER,
element_exclude_filter=ELEMENT_EXCLUDE_FILTER,
impact=IMPACT,
result_types=RESULT_TYPES,
**access_parameters(["accessibility"], source_type="an Axe report", source_type_format="HTML")
Expand All @@ -127,7 +147,10 @@
description="An Axe accessibility report in CSV format.",
url="https://github.com/ICTU/axe-reports",
parameters=dict(
impact=IMPACT, **access_parameters(["accessibility"], source_type="an Axe report", source_type_format="CSV")
element_include_filter=ELEMENT_INCLUDE_FILTER,
element_exclude_filter=ELEMENT_EXCLUDE_FILTER,
impact=IMPACT,
**access_parameters(["accessibility"], source_type="an Axe report", source_type_format="CSV")
),
entities=dict(
accessibility=dict(
Expand Down
1 change: 1 addition & 0 deletions docs/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ If your currently installed *Quality-time* version is v4.0.0 or older, please re

- Add the possibility in metrics of type missing metrics to exclude certain subjects from a report. Closes [#5119](https://github.com/ICTU/quality-time/issues/5119).
- Add SonarQube issue status rationale to entity data of suppressed violations. Closes [#4926](https://github.com/ICTU/quality-time/issues/4926).
- Allow for filtering out specific Axe measurement entities through regular expressions. Closes [#3328](https://github.com/ICTU/quality-time/issues/3328).

### Changed

Expand Down

0 comments on commit 05ae4e1

Please sign in to comment.