ada tools update

This commit is contained in:
Josh at WLTechBlog
2025-10-02 11:40:26 -05:00
parent 2ef7512918
commit 2817b8a049
11 changed files with 6010 additions and 180 deletions

View File

@@ -9,6 +9,7 @@ import (
"net/http"
"os"
"strconv"
"strings"
"time"
)
@@ -3253,3 +3254,473 @@ func (c *Client) SelectAllText(tabID, selector string, timeout int) error {
return nil
}
// AxeResults represents the results from running axe-core accessibility tests
type AxeResults struct {
Violations []AxeViolation `json:"violations"`
Passes []AxePass `json:"passes"`
Incomplete []AxeIncomplete `json:"incomplete"`
Inapplicable []AxeInapplicable `json:"inapplicable"`
TestEngine AxeTestEngine `json:"testEngine"`
TestRunner AxeTestRunner `json:"testRunner"`
Timestamp string `json:"timestamp"`
URL string `json:"url"`
}
// AxeViolation represents an accessibility violation found by axe-core
type AxeViolation struct {
ID string `json:"id"`
Impact string `json:"impact"`
Tags []string `json:"tags"`
Description string `json:"description"`
Help string `json:"help"`
HelpURL string `json:"helpUrl"`
Nodes []AxeNode `json:"nodes"`
}
// AxePass represents an accessibility check that passed
type AxePass struct {
ID string `json:"id"`
Impact string `json:"impact"`
Tags []string `json:"tags"`
Description string `json:"description"`
Help string `json:"help"`
HelpURL string `json:"helpUrl"`
Nodes []AxeNode `json:"nodes"`
}
// AxeIncomplete represents an accessibility check that needs manual review
type AxeIncomplete struct {
ID string `json:"id"`
Impact string `json:"impact"`
Tags []string `json:"tags"`
Description string `json:"description"`
Help string `json:"help"`
HelpURL string `json:"helpUrl"`
Nodes []AxeNode `json:"nodes"`
}
// AxeInapplicable represents an accessibility check that doesn't apply to this page
type AxeInapplicable struct {
ID string `json:"id"`
Impact string `json:"impact"`
Tags []string `json:"tags"`
Description string `json:"description"`
Help string `json:"help"`
HelpURL string `json:"helpUrl"`
}
// AxeNode represents a specific DOM node with accessibility issues
type AxeNode struct {
HTML string `json:"html"`
Impact string `json:"impact"`
Target []string `json:"target"`
Any []AxeCheckResult `json:"any"`
All []AxeCheckResult `json:"all"`
None []AxeCheckResult `json:"none"`
}
// AxeCheckResult represents the result of a specific accessibility check
type AxeCheckResult struct {
ID string `json:"id"`
Impact string `json:"impact"`
Message string `json:"message"`
Data map[string]interface{} `json:"data"`
}
// AxeTestEngine represents the axe-core test engine information
type AxeTestEngine struct {
Name string `json:"name"`
Version string `json:"version"`
}
// AxeTestRunner represents the test runner information
type AxeTestRunner struct {
Name string `json:"name"`
}
// InjectAxeCore injects the axe-core library into the page
// If tabID is empty, the current tab will be used
// axeVersion specifies the axe-core version (e.g., "4.8.0"), empty string uses default
// timeout is in seconds, 0 means no timeout
func (c *Client) InjectAxeCore(tabID, axeVersion string, timeout int) error {
params := map[string]string{}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Only include version if it's provided
if axeVersion != "" {
params["version"] = axeVersion
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("inject-axe", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to inject axe-core: %s", resp.Error)
}
return nil
}
// RunAxeCore runs axe-core accessibility tests on the page
// If tabID is empty, the current tab will be used
// options is a map of axe.run() options (can be nil for defaults)
// timeout is in seconds, 0 means no timeout
func (c *Client) RunAxeCore(tabID string, options map[string]interface{}, timeout int) (*AxeResults, error) {
params := map[string]string{}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Include options if provided
if options != nil && len(options) > 0 {
optionsBytes, err := json.Marshal(options)
if err != nil {
return nil, fmt.Errorf("failed to marshal options: %w", err)
}
params["options"] = string(optionsBytes)
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("run-axe", params)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, fmt.Errorf("failed to run axe-core: %s", resp.Error)
}
// Parse the response data
var result AxeResults
dataBytes, err := json.Marshal(resp.Data)
if err != nil {
return nil, fmt.Errorf("failed to marshal response data: %w", err)
}
err = json.Unmarshal(dataBytes, &result)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal axe results: %w", err)
}
return &result, nil
}
// ContrastCheckResult represents the result of contrast checking for text elements
type ContrastCheckResult struct {
TotalElements int `json:"total_elements"`
PassedAA int `json:"passed_aa"`
PassedAAA int `json:"passed_aaa"`
FailedAA int `json:"failed_aa"`
FailedAAA int `json:"failed_aaa"`
UnableToCheck int `json:"unable_to_check"`
Elements []ContrastCheckElement `json:"elements"`
}
// ContrastCheckElement represents a single element's contrast check
type ContrastCheckElement struct {
Selector string `json:"selector"`
Text string `json:"text"`
ForegroundColor string `json:"foreground_color"`
BackgroundColor string `json:"background_color"`
ContrastRatio float64 `json:"contrast_ratio"`
FontSize string `json:"font_size"`
FontWeight string `json:"font_weight"`
IsLargeText bool `json:"is_large_text"`
PassesAA bool `json:"passes_aa"`
PassesAAA bool `json:"passes_aaa"`
RequiredAA float64 `json:"required_aa"`
RequiredAAA float64 `json:"required_aaa"`
Error string `json:"error,omitempty"`
}
// CheckContrast checks color contrast for text elements on the page
// If tabID is empty, the current tab will be used
// selector is optional CSS selector for specific elements (defaults to all text elements)
// timeout is in seconds, 0 means no timeout
func (c *Client) CheckContrast(tabID, selector string, timeout int) (*ContrastCheckResult, error) {
params := map[string]string{}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Only include selector if it's provided
if selector != "" {
params["selector"] = selector
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("check-contrast", params)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, fmt.Errorf("failed to check contrast: %s", resp.Error)
}
// Parse the response data
var result ContrastCheckResult
dataBytes, err := json.Marshal(resp.Data)
if err != nil {
return nil, fmt.Errorf("failed to marshal response data: %w", err)
}
err = json.Unmarshal(dataBytes, &result)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal contrast results: %w", err)
}
return &result, nil
}
// KeyboardTestResult represents the result of keyboard navigation testing
type KeyboardTestResult struct {
TotalInteractive int `json:"total_interactive"`
Focusable int `json:"focusable"`
NotFocusable int `json:"not_focusable"`
NoFocusIndicator int `json:"no_focus_indicator"`
KeyboardTraps int `json:"keyboard_traps"`
TabOrder []KeyboardTestElement `json:"tab_order"`
Issues []KeyboardTestIssue `json:"issues"`
}
// KeyboardTestElement represents an interactive element in tab order
type KeyboardTestElement struct {
Index int `json:"index"`
Selector string `json:"selector"`
TagName string `json:"tag_name"`
Role string `json:"role"`
Text string `json:"text"`
TabIndex int `json:"tab_index"`
HasFocusStyle bool `json:"has_focus_style"`
IsVisible bool `json:"is_visible"`
}
// KeyboardTestIssue represents a keyboard accessibility issue
type KeyboardTestIssue struct {
Type string `json:"type"`
Severity string `json:"severity"`
Element string `json:"element"`
Description string `json:"description"`
}
// TestKeyboardNavigation tests keyboard navigation and accessibility
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) TestKeyboardNavigation(tabID string, timeout int) (*KeyboardTestResult, error) {
params := map[string]string{}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("test-keyboard", params)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, fmt.Errorf("failed to test keyboard navigation: %s", resp.Error)
}
// Parse the response data
var result KeyboardTestResult
dataBytes, err := json.Marshal(resp.Data)
if err != nil {
return nil, fmt.Errorf("failed to marshal response data: %w", err)
}
err = json.Unmarshal(dataBytes, &result)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal keyboard test results: %w", err)
}
return &result, nil
}
// ZoomTestResult represents the result of zoom level testing
type ZoomTestResult struct {
ZoomLevels []ZoomLevelTest `json:"zoom_levels"`
Issues []ZoomTestIssue `json:"issues"`
}
// ZoomLevelTest represents testing at a specific zoom level
type ZoomLevelTest struct {
ZoomLevel float64 `json:"zoom_level"`
ViewportWidth int `json:"viewport_width"`
ViewportHeight int `json:"viewport_height"`
HasHorizontalScroll bool `json:"has_horizontal_scroll"`
ContentWidth int `json:"content_width"`
ContentHeight int `json:"content_height"`
VisibleElements int `json:"visible_elements"`
OverflowingElements int `json:"overflowing_elements"`
TextReadable bool `json:"text_readable"`
}
// ZoomTestIssue represents an issue found during zoom testing
type ZoomTestIssue struct {
ZoomLevel float64 `json:"zoom_level"`
Type string `json:"type"`
Severity string `json:"severity"`
Description string `json:"description"`
Element string `json:"element,omitempty"`
}
// TestZoom tests page at different zoom levels
// If tabID is empty, the current tab will be used
// zoomLevels is an array of zoom levels to test (e.g., []float64{1.0, 2.0, 4.0})
// If empty, defaults to [1.0, 2.0, 4.0]
// timeout is in seconds per zoom level, 0 means no timeout
func (c *Client) TestZoom(tabID string, zoomLevels []float64, timeout int) (*ZoomTestResult, error) {
params := map[string]string{}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Include zoom levels if provided
if len(zoomLevels) > 0 {
levels := make([]string, len(zoomLevels))
for i, level := range zoomLevels {
levels[i] = strconv.FormatFloat(level, 'f', 1, 64)
}
params["zoom_levels"] = strings.Join(levels, ",")
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("test-zoom", params)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, fmt.Errorf("failed to test zoom: %s", resp.Error)
}
// Parse the response data
var result ZoomTestResult
dataBytes, err := json.Marshal(resp.Data)
if err != nil {
return nil, fmt.Errorf("failed to marshal response data: %w", err)
}
err = json.Unmarshal(dataBytes, &result)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal zoom test results: %w", err)
}
return &result, nil
}
// ReflowTestResult represents the result of reflow/responsive testing
type ReflowTestResult struct {
Breakpoints []ReflowBreakpoint `json:"breakpoints"`
Issues []ReflowTestIssue `json:"issues"`
}
// ReflowBreakpoint represents testing at a specific viewport width
type ReflowBreakpoint struct {
Width int `json:"width"`
Height int `json:"height"`
HasHorizontalScroll bool `json:"has_horizontal_scroll"`
ContentWidth int `json:"content_width"`
ContentHeight int `json:"content_height"`
VisibleElements int `json:"visible_elements"`
OverflowingElements int `json:"overflowing_elements"`
ResponsiveLayout bool `json:"responsive_layout"`
}
// ReflowTestIssue represents an issue found during reflow testing
type ReflowTestIssue struct {
Width int `json:"width"`
Type string `json:"type"`
Severity string `json:"severity"`
Description string `json:"description"`
Element string `json:"element,omitempty"`
}
// TestReflow tests page at different viewport widths for responsive design
// If tabID is empty, the current tab will be used
// widths is an array of viewport widths to test (e.g., []int{320, 1280})
// If empty, defaults to [320, 1280] (WCAG 1.4.10 breakpoints)
// timeout is in seconds per width, 0 means no timeout
func (c *Client) TestReflow(tabID string, widths []int, timeout int) (*ReflowTestResult, error) {
params := map[string]string{}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Include widths if provided
if len(widths) > 0 {
widthStrs := make([]string, len(widths))
for i, width := range widths {
widthStrs[i] = strconv.Itoa(width)
}
params["widths"] = strings.Join(widthStrs, ",")
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("test-reflow", params)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, fmt.Errorf("failed to test reflow: %s", resp.Error)
}
// Parse the response data
var result ReflowTestResult
dataBytes, err := json.Marshal(resp.Data)
if err != nil {
return nil, fmt.Errorf("failed to marshal response data: %w", err)
}
err = json.Unmarshal(dataBytes, &result)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal reflow test results: %w", err)
}
return &result, nil
}