Custom Rules
Not for use with personal data
The custom rules feature allows you to create new rules to test against and change key behaviors within existing rules.
Let's create a custom rule that checks for the name property of a view. The result criteria will be as follows:
- Not applicable: the name is null
- Fail: the name is not null but is empty
- Success: the name is not null and has some length
Creating the Rule
-
Set up a new class object that inherits from
AxeRule
. Within the initializer, you can set up the rule configuration to specify the following:- What standard you're testing against
- The impact
- A summary of the rule
class CustomRule: AxeRule { public init() { let ruleConfiguration = RuleConf(standard: AxeStandard.BEST_PRACTICE, impact: AxeImpact.MODERATE, summary: "Asserts that when name is present it is not empty.") super.init(ruleConf: ruleConfiguration) } }
-
Next, you'll need to collect the view's properties to test. For our example, we need to access the name property.
override func collectProps(for node: AxeView) -> AxeProps {
let axeProps = AxeProps()
axeProps.add([
.name: node.name
])
return axeProps
}
- Lastly, we'll specify in the
runRule
function what we're testing against, to determine whether the rule has succeeded, failed, or is considered inapplicable.
override func runRule(_ props: AxeProps) throws -> AxeStatus {
guard let name = props.get(.name, withType: String.self) else { return .INAPPLICABLE }
if !name.isEmpty {
return AxeStatus.PASS
} else {
return AxeStatus.FAIL
}
}
Add to axe DevTools
Once you've written the logic for your custom rule, add it to the list of rules axe DevTools knows about by adjusting the configuration. You should set configurations before any tests run and after authentication.
axe?.configuration.customRules.insert(CustomRule())
Complete Example
class CustomRule: AxeRule {
public init() {
let ruleConfiguration = RuleConf(standard: AxeStandard.BEST_PRACTICE,
impact: AxeImpact.MODERATE,
summary: "Asserts that when name is present it is not empty.")
super.init(ruleConf: ruleConfiguration)
}
override func collectProps(for node: AxeView) -> AxeProps {
let axeProps = AxeProps()
axeProps.add([
.name: node.name
])
return axeProps
}
override func runRule(_ props: AxeProps) throws -> AxeStatus {
guard let name = props.get(.name, withType: String.self) else { return .INAPPLICABLE }
if !name.isEmpty {
return AxeStatus.PASS
} else {
return AxeStatus.FAIL
}
}
}