Custom Rules

Link to Custom Rules copied to clipboard
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

  1. 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)
        }
    }
  2. 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
   }
  1. 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
        }
    }
}