From a473b75e4664724fd018c8ceca083977cf72991e Mon Sep 17 00:00:00 2001 From: j-mendez Date: Mon, 19 Feb 2024 07:53:24 -0500 Subject: [PATCH] feat(cli): add clip options --- kayle_cli/Cargo.lock | 2 +- kayle_cli/Cargo.toml | 2 +- kayle_cli/README.md | 31 +++++++- kayle_cli/src/main.rs | 120 +++++++++++++++++++++++++++-- kayle_cli/src/playwright_script.rs | 13 +++- kayle_cli/src/puppeteer_script.rs | 13 +++- 6 files changed, 164 insertions(+), 17 deletions(-) diff --git a/kayle_cli/Cargo.lock b/kayle_cli/Cargo.lock index 8f7cdbf..ab16133 100644 --- a/kayle_cli/Cargo.lock +++ b/kayle_cli/Cargo.lock @@ -110,7 +110,7 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "kayle_cli" -version = "0.0.2" +version = "0.0.3" dependencies = [ "clap", "serde", diff --git a/kayle_cli/Cargo.toml b/kayle_cli/Cargo.toml index 3802345..891199d 100644 --- a/kayle_cli/Cargo.toml +++ b/kayle_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kayle_cli" -version = "0.0.3" +version = "0.0.5" edition = "2021" description = "The kayle CLI for web accessibility auditing" repository = "https://github.com/a11ywatch/kayle" diff --git a/kayle_cli/README.md b/kayle_cli/README.md index fba914d..fb07d40 100644 --- a/kayle_cli/README.md +++ b/kayle_cli/README.md @@ -67,11 +67,40 @@ Options: - htmlcs: htmlcs - axe: axe + -w, --wait-for + WaitFor event for content to exist + + Possible values: + - load: Waits till the window load event + - domcontent-loaded: The dom loaded content first + - commit: Wait for the commit event. Playwright only + - network-idle: Waits till there are no more network connections for at least 500 ms. Playwright only + - network-idle1: Waits till there are no more network connections for at least 500 ms. Puppeteer only + - network-idle2: Waits till there are no more than 2 network connections for at least 500 ms. Puppeteer only + + --allow-images + Allow images to render, useful when setting clip option for bounding box + + [possible values: true, false] + + --clip + Get the bounding box of an element + + [possible values: true, false] + + --clip-dir + The directory to store clip images + + --clip-2-base64 + Convert the clip to a base64 image + + [possible values: true, false] + --automation-lib The automation lib to use either puppeteer or playwright Possible values: - - puppeteer: The puppeteer library. Defaults to this + - puppeteer: The puppeteer library. The Default - playwright: The playwright library by microsoft -h, --help diff --git a/kayle_cli/src/main.rs b/kayle_cli/src/main.rs index 1718365..0fce169 100644 --- a/kayle_cli/src/main.rs +++ b/kayle_cli/src/main.rs @@ -11,6 +11,7 @@ mod puppeteer_script; use serde::{Deserialize, Serialize}; #[derive(Debug, Subcommand, Serialize, Deserialize)] +/// The CLI commands to run. enum Commands { /// Upgrade kayle and the dependencies required. Upgrade, @@ -27,7 +28,7 @@ enum Commands { #[derive(Debug, Default, Clone, PartialEq, ValueEnum, Serialize, Deserialize)] enum AutomationLib { #[default] - /// The puppeteer library. Defaults to this. + /// The puppeteer library. The Default. Puppeteer, /// The playwright library by microsoft Playwright, @@ -72,7 +73,7 @@ enum AccessibilityRunner { } impl AccessibilityRunner { - /// get the standard to string + /// get the runner to string pub fn to_str(&self) -> &'static str { match self { AccessibilityRunner::Kayle => "kayle", @@ -82,6 +83,56 @@ impl AccessibilityRunner { } } +/// Wait for events. +#[derive(Debug, Default, Clone, PartialEq, ValueEnum, Serialize, Deserialize)] +enum WaitFor { + #[default] + /// Waits till the window load event. + Load, + /// The dom loaded content first + DomcontentLoaded, + /// Wait for the commit event. Playwright only. + Commit, + /// Waits till there are no more network connections for at least 500 ms. Playwright only. + NetworkIdle, + /// Waits till there are no more network connections for at least 500 ms. Puppeteer only. + NetworkIdle1, + /// Waits till there are no more than 2 network connections for at least 500 ms. Puppeteer only. + NetworkIdle2, +} + +impl WaitFor { + /// get the wait_for event to string + pub fn to_str(&self, puppeteer: bool) -> &'static str { + match self { + WaitFor::Load => "load", + WaitFor::DomcontentLoaded => "domcontentloaded", + WaitFor::Commit => if puppeteer { "networkidle2" } else { "commit" }, + WaitFor::NetworkIdle => { + if puppeteer { + "networkidle1" + } else { + "networkidle" + } + } + WaitFor::NetworkIdle1 => { + if puppeteer { + "networkidle1" + } else { + "networkidle" + } + } + WaitFor::NetworkIdle2 => { + if puppeteer { + "networkidle2" + } else { + "networkidle" + } + } + } + } +} + /// Web Accessibility Auditing using the kayle engine #[derive(Parser, Serialize, Deserialize, Debug)] #[command(version, about, long_about = None)] @@ -98,9 +149,25 @@ struct Args { /// The accessibility runner to use htmlcs, axecore, or kayle. #[arg(short, long)] runners: Option>, + /// WaitFor event for content to exist. + #[arg(short, long, value_enum)] + wait_for: Option, + #[arg(long)] + /// Allow images to render, useful when setting clip option for bounding box. + allow_images: Option, + #[arg(long)] + /// Get the bounding box of an element. + clip: Option, + #[arg(long)] + /// The directory to store clip images. + clip_dir: Option, + #[arg(long)] + /// Convert the clip to a base64 image. + clip_2_base64: Option, #[arg(long, value_enum)] /// The automation lib to use either puppeteer or playwright. automation_lib: Option, + /// The commands for the CLI. #[command(subcommand)] command: Commands, } @@ -197,6 +264,40 @@ fn main() -> io::Result<()> { .map(|r| r.to_str()) .collect::>() .join(","); + let wait_for = if args.wait_for.is_some() { + args.wait_for + } else { + loaded_config.wait_for + } + .unwrap_or_default(); + + let allow_images = if args.allow_images.is_some() { + args.allow_images + } else { + loaded_config.allow_images + } + .unwrap_or_default(); + + let clip = if args.clip.is_some() { + args.clip + } else { + loaded_config.clip + } + .unwrap_or_default(); + + let clip_dir = if args.clip_dir.is_some() { + args.clip_dir + } else { + loaded_config.clip_dir + } + .unwrap_or_default(); + + let clip_2_base64 = if args.clip_2_base64.is_some() { + args.clip_2_base64 + } else { + loaded_config.clip_2_base64 + } + .unwrap_or_default(); let headless_script = if puppeteer { puppeteer_script::SCRIPT_EXECUTION @@ -208,12 +309,19 @@ fn main() -> io::Result<()> { Command::new("node") .args([ "-e", - headless_script, - u.to_str().unwrap(), - &accessibility_standard.to_str(), + headless_script, + u.to_str().unwrap(), + &accessibility_standard.to_str(), if include_notices { "true"} else { "false" }, if include_warnings { "true"} else { "false" }, - &runners]) + &runners, + &wait_for.to_str(puppeteer), + if allow_images { "true"} else { "false" }, + if clip { "true"} else { "false" }, + &clip_dir, + if clip_2_base64 { "true"} else { "false" }, + + ]) .status() .expect(if puppeteer { "Failed to execute node command - make sure node and puppeteer is installed." diff --git a/kayle_cli/src/playwright_script.rs b/kayle_cli/src/playwright_script.rs index 8090865..38f4495 100644 --- a/kayle_cli/src/playwright_script.rs +++ b/kayle_cli/src/playwright_script.rs @@ -19,11 +19,16 @@ const args = argv.slice(1); 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], + standard: args[1] || Standard.WCAG2AA, + includeNotices: args[2] === "true", + includeWarnings: args[3] === "true", + runners: runners.length && runners[0] ? runners : ["htmlcs"], + waitUntil: args[5], + allowImages: args[6] === "true", + clip: args[7] === "true", + clipDir: args[8], + clip2Base64: args[9], }); stdout.write(JSON.stringify(audit)); diff --git a/kayle_cli/src/puppeteer_script.rs b/kayle_cli/src/puppeteer_script.rs index 872d105..122e3bb 100644 --- a/kayle_cli/src/puppeteer_script.rs +++ b/kayle_cli/src/puppeteer_script.rs @@ -19,11 +19,16 @@ const args = argv.slice(1); 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], + standard: args[1] || Standard.WCAG2AA, + includeNotices: args[2] === "true", + includeWarnings: args[3] === "true", + runners: runners.length && runners[0] ? runners : ["htmlcs"], + waitUntil: args[5], + allowImages: args[6] === "true", + clip: args[7] === "true", + clipDir: args[8], + clip2Base64: args[9], }); stdout.write(JSON.stringify(audit));