auditmysite 1.4.0

Resource-efficient WCAG 2.1 AA (+ select 2.2 criteria) Accessibility Checker in Rust
Documentation
//! `AuditModule` implementation for Tech-stack detection (#332).

use async_trait::async_trait;
use tracing::warn;

use crate::audit::module::{AuditModule, ModuleContext, ModuleData};
use crate::audit::PipelineConfig;
use crate::error::Result;

use super::analyze_tech_stack;

pub struct TechStackModule;

#[async_trait]
impl AuditModule for TechStackModule {
    fn id(&self) -> &'static str {
        "tech_stack"
    }

    fn label(&self) -> &'static str {
        "Tech Stack"
    }

    fn is_enabled(&self, cfg: &PipelineConfig) -> bool {
        cfg.check_stack
    }

    async fn collect(&self, ctx: &ModuleContext<'_>) -> Result<ModuleData> {
        match analyze_tech_stack(ctx.page, ctx.url).await {
            Ok(ts) => Ok(ModuleData::TechStack(Box::new(ts))),
            Err(e) => {
                warn!("Tech stack analysis failed: {}", e);
                Ok(ModuleData::None)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::TechStackModule;
    use crate::audit::module::AuditModule;
    use crate::audit::PipelineConfig;
    use crate::cli::{InteractiveMode, WcagLevel};

    fn config_with_stack(check_stack: bool) -> PipelineConfig {
        PipelineConfig {
            wcag_level: WcagLevel::AA,
            timeout_secs: 30,
            stability_budget_ms: 1500,
            verbose: false,
            full_audit: false,
            check_performance: false,
            check_seo: false,
            check_security: false,
            check_mobile: false,
            check_dark_mode: false,
            check_design_quality: false,
            check_html_conform: false,
            check_ai_transparency: false,
            check_dns: false,
            check_isolate_third_party_impact: false,
            check_ssr_content: false,
            check_stack,
            rule_filter: crate::wcag::RuleFilterConfig::default(),
            persist_artifacts: false,
            capture_screenshots: false,
            capture_element_evidence: false,
            dismiss_consent: false,
            interactive: InteractiveMode::Off,
            journey_budget_ms: crate::a11y_journey::DEFAULT_BUDGET_MS,
            lang: "de".to_string(),
        }
    }

    #[test]
    fn tech_stack_module_enablement_follows_pipeline_flag() {
        let module = TechStackModule;

        assert!(module.is_enabled(&config_with_stack(true)));
        assert!(!module.is_enabled(&config_with_stack(false)));
    }
}