From a0aca466858093351900bc8ff9c71582b709f75f Mon Sep 17 00:00:00 2001 From: j-mendez Date: Sun, 18 Feb 2024 18:07:10 -0500 Subject: [PATCH] feat(cli): add start of kayle cli --- README.md | 63 +++++++++++++++---------- kayle_cli/.gitignore | 4 ++ kayle_cli/Cargo.toml | 12 +++++ kayle_cli/README.md | 57 +++++++++++++++++++++++ kayle_cli/src/main.rs | 76 +++++++++++++++++++++++++++++++ kayle_cli/src/puppeteer_script.rs | 31 +++++++++++++ 6 files changed, 218 insertions(+), 25 deletions(-) create mode 100644 kayle_cli/.gitignore create mode 100644 kayle_cli/Cargo.toml create mode 100644 kayle_cli/README.md create mode 100644 kayle_cli/src/main.rs create mode 100644 kayle_cli/src/puppeteer_script.rs diff --git a/README.md b/README.md index 992b7d4..3c0e46c 100644 --- a/README.md +++ b/README.md @@ -189,31 +189,6 @@ type RunnerConfig = { 1. zh-CN ("Chinese-Simplified") 1. zh-TW ("Chinese-Traditional") -## Testing - -For the comparison between using `fast_htmlcs`, `fast_axecore`, and the metrics for the 3rd party `@axe-core/playwright`. - -1. `yarn build:test` - -Checkout the [playwright-example](./kayle/tests/basic-playwright.spec.ts) or [puppeteer-example](./kayle/tests/basic.ts) for more information. - -## Benchmarks - -1. `fast_htmlcs` runs up to 110x base faster than HTML_CodeSniffer. -1. `fast_axecore` runs up to 2.5x - 15x base faster than the original axe by default and scales the larger the website. - -Currently `fast_htmlcs` runs around 50x faster than axe-core and has several differences of handling the way issues are found. They both capture different cases and is best to used together which this library handles efficiently. - -If you use [`@playwright/axe-core`](https://playwright.dev/docs/next/accessibility-testing) you can swap it out with the following [playwright-axe-example](./kayle/tests/basic-axe-playwright.spec.ts) and get an increase in issues found and major performance boost of at least 100%. You can also include multiple runners to extend the issues beyond the basics in folds. - -## Performance Tips - -As we set the foundation to mark test cases that can pass and increase our target on automating accessibility we have a couple of layers that can make a major difference to the project. The following will save drastic time and money if done. - -1. Use a fast concurrent [crawler](https://github.com/a11ywatch/crawler) to gather all of the html to send to a web accessibility service that can perform audits like [pagemind](https://github.com/a11ywatch/pagemind) over CDP. - -2. Use the pre-compiled browser extensions to avoid over the wire latency `yarn build:extension`. - ## Browser Extension If you want to compile a chrome extension for preloading scripts without needing to worry about bandwidth cost use the following to generate a custom extension to use. @@ -315,6 +290,44 @@ const results = await kayle({ }); ``` +## CLI + +The [kayle CLI](./kayle_cli/) is a work in progress. + +```sh +npm install kayle_cli +``` + +Audit a website url. + +```sh +kayle_cli https://www.somewebsite.com +``` + +## Testing + +For the comparison between using `fast_htmlcs`, `fast_axecore`, and the metrics for the 3rd party `@axe-core/playwright`. + +1. `yarn build:test` + +Checkout the [playwright-example](./kayle/tests/basic-playwright.spec.ts) or [puppeteer-example](./kayle/tests/basic.ts) for more information. + +## Benchmarks + +1. `fast_htmlcs` runs up to 110x base faster than HTML_CodeSniffer. +1. `fast_axecore` runs up to 2.5x - 15x base faster than the original axe by default and scales the larger the website. + +Currently `fast_htmlcs` runs around 50x faster than axe-core and has several differences of handling the way issues are found. They both capture different cases and is best to used together which this library handles efficiently. + +If you use [`@playwright/axe-core`](https://playwright.dev/docs/next/accessibility-testing) you can swap it out with the following [playwright-axe-example](./kayle/tests/basic-axe-playwright.spec.ts) and get an increase in issues found and major performance boost of at least 100%. You can also include multiple runners to extend the issues beyond the basics in folds. + +### Performance Tips + +As we set the foundation to mark test cases that can pass and increase our target on automating accessibility we have a couple of layers that can make a major difference to the project. The following will save drastic time and money if done. + +1. Use a fast concurrent [crawler](https://github.com/a11ywatch/crawler) to gather all of the html to send to a web accessibility service that can perform audits like [pagemind](https://github.com/a11ywatch/pagemind) over CDP. +2. Use the pre-compiled browser extensions to avoid over the wire latency `yarn build:extension`. + ## Developing In order to develop you need yarn v2 installed for the workspace. diff --git a/kayle_cli/.gitignore b/kayle_cli/.gitignore new file mode 100644 index 0000000..9180bc7 --- /dev/null +++ b/kayle_cli/.gitignore @@ -0,0 +1,4 @@ +package.json +start.js +uninstall.js +pre-install.js \ No newline at end of file diff --git a/kayle_cli/Cargo.toml b/kayle_cli/Cargo.toml new file mode 100644 index 0000000..a666ffc --- /dev/null +++ b/kayle_cli/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "kayle_cli" +version = "0.0.1" +edition = "2021" +description = "The kayle CLI for web accessibility auditing" +repository = "https://github.com/a11ywatch/kayle" +categories = ["accessibility"] +authors = ["j-mendez"] +license = "MIT" + +[dependencies] +clap = { version = "4.5.1", features = ["derive"]} \ No newline at end of file diff --git a/kayle_cli/README.md b/kayle_cli/README.md new file mode 100644 index 0000000..79ea955 --- /dev/null +++ b/kayle_cli/README.md @@ -0,0 +1,57 @@ +# kayle_cli + +The kayle CLI, for web accessibility audits. [WIP] + +## Requirements + +Node.js is required. +Install puppeteer globally `npm i puppeteer -g`. + +## Installation + +If Rust is installed. + +```sh +cargo install kayle_cli +# or with node. +npm install kayle_cli +``` + +## Getting Started + +Pass in a list of urls to get the results. + +```sh +The kayle CLI for web accessibility auditing + +Usage: kayle_cli [OPTIONS] + +Commands: + upgrade Upgrade kayle and the dependencies required + configure Configure the audits + help Print this message or the help of the given subcommand(s) + +Options: + -s, --standard + The accessibility standard to run, WCAG2A, WCAG2AA, WCAG2AAA, and Section508 + --include-warnings + Include warnings in the audit [possible values: true, false] + --include-notices + Include notices in the audit [possible values: true, false] + -r, --runners + The accessibility runner to use htmlcs, axecore, or kayle + -h, --help + Print help + -V, --version + Print version +``` + +```sh +kayle_cli https://www.drake.com +{"documentTitle":"Drake Industries | Custom, Durable, High-Quality Labels, Asset Tags and Custom Server Bezels","pageUrl":"https://www.drake.com/","issues":[{"context":"
\n
","selector":"body>:nth-child(2)>:nth-child(1)>:nth-child(2)>:nth-child(1)>:nth-child(1)>:nth-child(2)>:nth-child(1)>:nth-child(1)>:nth-child(2)>:nth-child(1)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_3.1_3_1_A.G141","type":"error","typeCode":1,"message":"The heading structure is not logically nested. This h5 element should be an h2 to be properly nested.","runner":"htmlcs","recurrence":0},{"context":"
Labels
","selector":"#hs_cos_wrapper_module_1569856007055222>:nth-child(1)>:nth-child(2)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_3.1_3_1_A.G141","type":"error","typeCode":1,"message":"The heading structure is not logically nested. This h5 element should be an h3 to be properly nested.","runner":"htmlcs","recurrence":0},{"context":"Learn more","selector":"#hs_cos_wrapper_module_1569856007055222>:nth-child(1)>:nth-child(3)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail","type":"error","typeCode":1,"message":"This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 3.44:1. Recommendation: change text colour to #00171d.","runner":"htmlcs","recurrence":0},{"context":"Learn more","selector":"#hs_cos_wrapper_module_1569856034269224>:nth-child(1)>:nth-child(3)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail","type":"error","typeCode":1,"message":"This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 3.44:1. Recommendation: change text colour to #00171d.","runner":"htmlcs","recurrence":0},{"context":"Learn more","selector":"#hs_cos_wrapper_module_1569856037305225>:nth-child(1)>:nth-child(3)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail","type":"error","typeCode":1,"message":"This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 3.44:1. Recommendation: change text colour to #00171d.","runner":"htmlcs","recurrence":0},{"context":"Learn more","selector":"#hs_cos_wrapper_module_1569856084644237>:nth-child(1)>:nth-child(3)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail","type":"error","typeCode":1,"message":"This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 3.44:1. Recommendation: change text colour to #00171d.","runner":"htmlcs","recurrence":0},{"context":"Learn more","selector":"#hs_cos_wrapper_module_1569856082608235>:nth-child(1)>:nth-child(3)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail","type":"error","typeCode":1,"message":"This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 3.44:1. Recommendation: change text colour to #00171d.","runner":"htmlcs","recurrence":0},{"context":"Learn more","selector":"#hs_cos_wrapper_module_1569856080132233>:nth-child(1)>:nth-child(3)>:nth-child(1)","code":"WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail","type":"error","typeCode":1,"message":"This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 3.44:1. Recommendation: change text colour to #00171d.","runner":"htmlcs","recurrence":0},{"context":"","selector":"#hs_cos_wrapper_module_14725592865174>:nth-child(1)","code":"WCAG2AA.Principle4.Guideline4_1.4_1_2.H91.A.EmptyNoId","type":"error","typeCode":1,"message":"Anchor element found with no link content and no name and/or ID attribute.","runner":"htmlcs","recurrence":0}],"meta":{"errorCount":9,"warningCount":0,"noticeCount":0,"accessScore":100},"automateable":{"missingAltIndexs":[]}}% +``` + +## Todo + +1. Configuration. +2. Allow Opt between puppeteer or playwright. \ No newline at end of file diff --git a/kayle_cli/src/main.rs b/kayle_cli/src/main.rs new file mode 100644 index 0000000..eca3fbb --- /dev/null +++ b/kayle_cli/src/main.rs @@ -0,0 +1,76 @@ +use clap::{Parser, Subcommand}; +use std::ffi::OsString; +use std::process::Command; +mod puppeteer_script; + +#[derive(Debug, Subcommand)] +enum Commands { + /// Upgrade kayle and the dependencies required. + #[command(arg_required_else_help = true)] + Upgrade, + /// Configure the audits. + Configure, + /// The kayle program. + #[command(external_subcommand)] + Kayle(Vec), +} + +/// Web Accessibility Auditing using the kayle engine +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + /// The accessibility standard to run, WCAG2A, WCAG2AA, WCAG2AAA, and Section508. + #[arg(short, long)] + standard: Option, + /// Include warnings in the audit. + #[arg(long)] + include_warnings: Option, + /// Include notices in the audit. + #[arg(long)] + include_notices: Option, + /// The accessibility runner to use htmlcs, axecore, or kayle. + #[arg(short, long)] + runners: Option>, + #[command(subcommand)] + command: Commands, +} + +fn main() { + let args = Args::parse(); + + match args.command { + Commands::Configure => { + println!("Configuration TODO"); + } + Commands::Upgrade => { + Command::new("npm") + .args(["i", "kayle", "-g"]) + .status() + .expect("Failed to execute command - npm install kayle command"); + Command::new("npm") + .args(["i", "puppeteer", "-g"]) + .status() + .expect("Failed to execute command - npm install puppeteer command"); + } + Commands::Kayle(urls) => { + let accessibility_standard = args.standard.unwrap_or_default(); + let include_warnings = args.include_warnings.unwrap_or_default(); + let include_notices = args.include_notices.unwrap_or_default(); + let runners = args.runners.unwrap_or_default().join(","); + + for u in urls.iter() { + Command::new("node") + .args([ + "-e", + puppeteer_script::SCRIPT_EXECUTION, + u.to_str().unwrap(), + &accessibility_standard, + if include_notices { "true"} else { "false" }, + if include_warnings { "true"} else { "false" }, + &runners]) + .status() + .expect("Failed to execute node command. Make sure puppeteer and node is installed."); + } + } + } +} diff --git a/kayle_cli/src/puppeteer_script.rs b/kayle_cli/src/puppeteer_script.rs new file mode 100644 index 0000000..aba0779 --- /dev/null +++ b/kayle_cli/src/puppeteer_script.rs @@ -0,0 +1,31 @@ +pub const SCRIPT_EXECUTION: &'static str = r###" +const { argv, stdout } = require('node:process'); +const puppeteer = require('puppeteer'); +const { kayle, Standard } = require('kayle'); + +const args = argv.slice(1); + +(async () => { + const browser = await puppeteer.launch({ headless: "new" }); + const page = await browser.newPage(); + + if (process.env.LOG_ENABLED) { + page.on("console", (msg) => console.log(msg.text())); + } + + const runners = args[4].split(","); + + const audit = await kayle({ + page, + browser, + runners: runners.length && runners[0] ? runners : ["htmlcs"], + includeWarnings: args[3] === "true", + includeNotices: args[2] === "true", + standard: args[1] || Standard.WCAG2AA, + origin: args[0], + }); + + stdout.write(JSON.stringify(audit)); + process.exit(); +})(); +"###;