ada tools update
This commit is contained in:
471
client/client.go
471
client/client.go
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user