visual

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package visual provides visual regression testing capabilities for DSS.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBaselineNotFound indicates no baseline exists for the test.
	ErrBaselineNotFound = errors.New("baseline not found")

	// ErrTestNotFound indicates the requested test does not exist.
	ErrTestNotFound = errors.New("test not found")

	// ErrW3PilotUnavailable indicates w3pilot is not available.
	ErrW3PilotUnavailable = errors.New("w3pilot not available")

	// ErrImageMagickMissing indicates ImageMagick is not installed.
	ErrImageMagickMissing = errors.New("imagemagick not installed")

	// ErrScreenshotFailed indicates screenshot capture failed.
	ErrScreenshotFailed = errors.New("screenshot capture failed")

	// ErrComparisonFailed indicates image comparison failed.
	ErrComparisonFailed = errors.New("image comparison failed")

	// ErrThresholdExceeded indicates the diff exceeded the threshold.
	ErrThresholdExceeded = errors.New("diff threshold exceeded")

	// ErrNavigationFailed indicates page navigation failed.
	ErrNavigationFailed = errors.New("page navigation failed")

	// ErrStabilizationFailed indicates stabilization conditions were not met.
	ErrStabilizationFailed = errors.New("stabilization failed")
)

Standard errors for visual testing.

Functions

func BaselineError

func BaselineError(testID, viewport string, err error) error

BaselineError wraps a baseline error with context.

func CaptureError

func CaptureError(testID, viewport string, err error) error

CaptureError wraps a capture error with context.

func CompareError

func CompareError(testID, viewport string, err error) error

CompareError wraps a comparison error with context.

func DefaultThreshold

func DefaultThreshold() float64

DefaultThreshold returns the default diff threshold (0.1%).

func ExpandTests

func ExpandTests(tests []VisualTest) []struct {
	Test     VisualTest
	Viewport Viewport
}

ExpandTests expands tests with multiple viewports into individual test cases. Returns a list of (test, viewport) pairs.

Types

type BaselineManager

type BaselineManager struct {
	// contains filtered or unexported fields
}

BaselineManager handles baseline storage and retrieval.

func NewBaselineManager

func NewBaselineManager(basePath string) *BaselineManager

NewBaselineManager creates a manager for the given directory.

func (*BaselineManager) DeleteBaseline

func (m *BaselineManager) DeleteBaseline(version, testID, viewport string) error

DeleteBaseline deletes a baseline image.

func (*BaselineManager) GenerateManifest

func (m *BaselineManager) GenerateManifest(version string, suite *VisualTestSuite) (*BaselineManifest, error)

GenerateManifest creates a manifest for the version.

func (*BaselineManager) GetBaseline

func (m *BaselineManager) GetBaseline(version, testID, viewport string) (string, error)

GetBaseline returns the path to a baseline image.

func (*BaselineManager) GetLatestVersion

func (m *BaselineManager) GetLatestVersion() (string, error)

GetLatestVersion returns the most recent baseline version.

func (*BaselineManager) GetVersionPath

func (m *BaselineManager) GetVersionPath(version string) string

GetVersionPath returns the directory path for a specific version.

func (*BaselineManager) ListVersions

func (m *BaselineManager) ListVersions() ([]string, error)

ListVersions returns all available baseline versions.

func (*BaselineManager) LoadManifest

func (m *BaselineManager) LoadManifest(version string) (*BaselineManifest, error)

LoadManifest loads the manifest for a version.

func (*BaselineManager) PruneVersion

func (m *BaselineManager) PruneVersion(version string) error

PruneVersion removes a baseline version and all its images.

func (*BaselineManager) SaveBaseline

func (m *BaselineManager) SaveBaseline(version, testID, viewport string, data []byte) error

SaveBaseline saves a baseline image.

func (*BaselineManager) UpdateLatest

func (m *BaselineManager) UpdateLatest(version string) error

UpdateLatest updates the "latest" symlink to point to a version.

func (*BaselineManager) VerifyBaseline

func (m *BaselineManager) VerifyBaseline(version, testID, viewport string) error

VerifyBaseline verifies a baseline image's checksum.

func (*BaselineManager) VersionExists

func (m *BaselineManager) VersionExists(version string) bool

VersionExists checks if a baseline version exists.

type BaselineManifest

type BaselineManifest struct {
	Version   string            `json:"version"`
	CreatedAt time.Time         `json:"createdAt"`
	CreatedBy string            `json:"createdBy,omitempty"`
	TestSuite string            `json:"testSuite"`
	TestCount int               `json:"testCount"`
	Checksums map[string]string `json:"checksums"` // "testID/viewport" -> SHA256
}

BaselineManifest describes a baseline snapshot.

type BaselineResult

type BaselineResult struct {
	Version   string `json:"version"`
	TestCount int    `json:"testCount"`
	Path      string `json:"path"`
	Errors    int    `json:"errors"`
}

BaselineResult contains the result of baseline generation.

type CaptureOptions

type CaptureOptions struct {
	URL           string
	Selector      string
	Viewport      Viewport
	Stabilization *Stabilization
}

CaptureOptions configures screenshot capture.

type Comparator

type Comparator interface {
	// Compare compares two images and generates a diff image.
	// Returns the comparison result including diff percentage.
	Compare(ctx context.Context, baseline, actual, diffOut string) (*CompareResult, error)
}

Comparator compares images and generates diffs.

func NewComparator

func NewComparator() (Comparator, error)

NewComparator creates the best available comparator. It prefers ImageMagick if available, falling back to pure Go.

type CompareResult

type CompareResult struct {
	DiffPixels  int64   `json:"diffPixels"`
	TotalPixels int64   `json:"totalPixels"`
	DiffPercent float64 `json:"diffPercent"`
	DiffPath    string  `json:"diffPath,omitempty"`
}

CompareResult contains comparison metrics.

type Executor

type Executor struct {
	// contains filtered or unexported fields
}

Executor runs visual tests.

func NewExecutor

func NewExecutor(opts ExecutorOptions) (*Executor, error)

NewExecutor creates a test executor.

func (*Executor) Run

func (e *Executor) Run(ctx context.Context, opts RunOptions) (*VisualTestReport, error)

Run executes visual tests and returns a report.

type ExecutorOptions

type ExecutorOptions struct {
	TestsDir     string // Directory containing visual-tests.yaml
	BaselinesDir string // Directory containing baseline versions
	OutputDir    string // Directory for test results
	Parallel     int    // Number of parallel workers
}

ExecutorOptions configures the executor.

type GoImageComparator

type GoImageComparator struct {
	// contains filtered or unexported fields
}

GoImageComparator is a pure Go image comparator (no ImageMagick required).

func NewGoImageComparator

func NewGoImageComparator() *GoImageComparator

NewGoImageComparator creates a pure Go comparator.

func (*GoImageComparator) Compare

func (c *GoImageComparator) Compare(ctx context.Context, baseline, actual, diffOut string) (*CompareResult, error)

Compare compares two PNG images using pure Go.

func (*GoImageComparator) SetThreshold

func (c *GoImageComparator) SetThreshold(threshold float64)

SetThreshold sets the per-channel difference threshold.

type ImageMagickComparator

type ImageMagickComparator struct {
	// contains filtered or unexported fields
}

ImageMagickComparator uses ImageMagick for comparison.

func NewImageMagickComparator

func NewImageMagickComparator() (*ImageMagickComparator, error)

NewImageMagickComparator creates a comparator using ImageMagick.

func (*ImageMagickComparator) Compare

func (c *ImageMagickComparator) Compare(ctx context.Context, baseline, actual, diffOut string) (*CompareResult, error)

Compare compares two images using ImageMagick.

func (*ImageMagickComparator) SetFuzz

func (c *ImageMagickComparator) SetFuzz(fuzz string)

SetFuzz sets the anti-aliasing tolerance.

type Loader

type Loader struct {
	// contains filtered or unexported fields
}

Loader loads visual test definitions from files.

func NewLoader

func NewLoader(basePath string) *Loader

NewLoader creates a loader for the given base path.

func (*Loader) Load

func (l *Loader) Load() (*VisualTestSuite, error)

Load loads the visual test suite from the base path. It looks for visual-tests.yaml or visual-tests.json.

func (*Loader) LoadFromFile

func (l *Loader) LoadFromFile(path string) (*VisualTestSuite, error)

LoadFromFile loads a visual test suite from a specific file path.

type MCPError

type MCPError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

MCPError represents an MCP error.

type MCPRequest

type MCPRequest struct {
	JSONRPC string         `json:"jsonrpc"`
	ID      int            `json:"id"`
	Method  string         `json:"method"`
	Params  map[string]any `json:"params,omitempty"`
}

MCPRequest represents an MCP JSON-RPC request.

type MCPResponse

type MCPResponse struct {
	JSONRPC string         `json:"jsonrpc"`
	ID      int            `json:"id"`
	Result  map[string]any `json:"result,omitempty"`
	Error   *MCPError      `json:"error,omitempty"`
}

MCPResponse represents an MCP JSON-RPC response.

type RunOptions

type RunOptions struct {
	BaselineVersion string   // Version to compare against (or "latest")
	TestIDs         []string // Specific tests to run (empty = all)
	Viewports       []string // Specific viewports (empty = all)
	Threshold       float64  // Override threshold (0 = use test default)
	UpdateBaseline  bool     // Update baseline instead of comparing
}

RunOptions configures a test run.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides the public API for visual testing.

func NewService

func NewService(opts ServiceOptions) *Service

NewService creates a visual testing service.

func (*Service) CleanResults

func (s *Service) CleanResults() error

CleanResults removes old test results.

func (*Service) GenerateBaseline

func (s *Service) GenerateBaseline(ctx context.Context, version string) (*BaselineResult, error)

GenerateBaseline generates baselines for a new version.

func (*Service) GetBaselineManifest

func (s *Service) GetBaselineManifest(version string) (*BaselineManifest, error)

GetBaselineManifest returns the manifest for a baseline version.

func (*Service) ListBaselineVersions

func (s *Service) ListBaselineVersions() ([]string, error)

ListBaselineVersions returns all available baseline versions.

func (*Service) LoadTestSuite

func (s *Service) LoadTestSuite() (*VisualTestSuite, error)

LoadTestSuite loads the visual test suite.

func (*Service) RunSingleTest

func (s *Service) RunSingleTest(ctx context.Context, testID string, opts *SingleTestOptions) (*VisualTestResult, error)

RunSingleTest runs a single test for debugging.

func (*Service) RunTests

func (s *Service) RunTests(ctx context.Context, opts *TestOptions) (*VisualTestReport, error)

RunTests executes visual tests and returns a report.

func (*Service) SaveReport

func (s *Service) SaveReport(report *VisualTestReport, path string) error

SaveReport saves a test report to a file.

func (*Service) UpdateBaseline

func (s *Service) UpdateBaseline(ctx context.Context, version string, testIDs []string) (*BaselineResult, error)

UpdateBaseline updates specific test baselines.

type ServiceOptions

type ServiceOptions struct {
	TestsDir     string // Directory containing visual-tests.yaml
	BaselinesDir string // Directory containing baseline versions
	OutputDir    string // Directory for test results
	Parallel     int    // Number of parallel workers (default: 4)
}

ServiceOptions configures the visual testing service.

type SingleTestOptions

type SingleTestOptions struct {
	BaselineVersion string  // Version to compare against
	Viewport        string  // Specific viewport to test
	Threshold       float64 // Override threshold
	Headful         bool    // Run browser in headful mode (visible)
}

SingleTestOptions configures a single test run.

type Stabilization

type Stabilization struct {
	WaitForSelector   string `json:"waitForSelector,omitempty" yaml:"waitForSelector,omitempty"`
	WaitForTimeout    int    `json:"waitForTimeout,omitempty" yaml:"waitForTimeout,omitempty"`
	WaitMs            int    `json:"waitMs,omitempty" yaml:"waitMs,omitempty"`
	DisableAnimations bool   `json:"disableAnimations,omitempty" yaml:"disableAnimations,omitempty"`
}

Stabilization defines wait conditions before capturing a screenshot.

func DefaultStabilization

func DefaultStabilization() *Stabilization

DefaultStabilization returns default stabilization settings.

type TestOptions

type TestOptions struct {
	BaselineVersion string   // Version to compare against (default: "latest")
	TestIDs         []string // Specific tests to run (empty = all)
	Viewports       []string // Specific viewports (empty = all)
	Threshold       float64  // Override threshold (0 = use test default)
}

TestOptions configures a test run.

type TestStatus

type TestStatus string

TestStatus represents the outcome of a test.

const (
	// TestStatusPassed indicates the test passed (diff within threshold).
	TestStatusPassed TestStatus = "passed"
	// TestStatusFailed indicates the test failed (diff exceeded threshold).
	TestStatusFailed TestStatus = "failed"
	// TestStatusSkipped indicates the test was skipped.
	TestStatusSkipped TestStatus = "skipped"
	// TestStatusError indicates an error occurred during the test.
	TestStatusError TestStatus = "error"
)

type Viewport

type Viewport struct {
	Name   string `json:"name" yaml:"name"`
	Width  int    `json:"width" yaml:"width"`
	Height int    `json:"height" yaml:"height"`
}

Viewport defines browser viewport dimensions.

func DefaultViewports

func DefaultViewports() []Viewport

DefaultViewports returns the standard viewports for testing.

type VisualTest

type VisualTest struct {
	ID            string         `json:"id" yaml:"id"`
	Name          string         `json:"name,omitempty" yaml:"name,omitempty"`
	Component     string         `json:"component" yaml:"component"`
	Variant       string         `json:"variant,omitempty" yaml:"variant,omitempty"`
	URL           string         `json:"url" yaml:"url"`
	Selector      string         `json:"selector,omitempty" yaml:"selector,omitempty"`
	Viewports     []Viewport     `json:"viewports,omitempty" yaml:"viewports,omitempty"`
	Threshold     float64        `json:"threshold,omitempty" yaml:"threshold,omitempty"`
	Stabilization *Stabilization `json:"stabilization,omitempty" yaml:"stabilization,omitempty"`
	Skip          bool           `json:"skip,omitempty" yaml:"skip,omitempty"`
	SkipReason    string         `json:"skipReason,omitempty" yaml:"skipReason,omitempty"`
}

VisualTest defines a single visual test case.

func FilterByComponent

func FilterByComponent(tests []VisualTest, component string) []VisualTest

FilterByComponent returns tests for a specific component.

func FilterTests

func FilterTests(tests []VisualTest, ids []string) []VisualTest

FilterTests returns tests matching the given IDs.

type VisualTestDefaults

type VisualTestDefaults struct {
	Viewports     []Viewport     `json:"viewports,omitempty" yaml:"viewports,omitempty"`
	Threshold     float64        `json:"threshold,omitempty" yaml:"threshold,omitempty"`
	Stabilization *Stabilization `json:"stabilization,omitempty" yaml:"stabilization,omitempty"`
}

VisualTestDefaults provides default values for all tests in a suite.

type VisualTestError

type VisualTestError struct {
	TestID   string
	Viewport string
	Op       string
	Err      error
}

VisualTestError wraps errors with test context.

func NewTestError

func NewTestError(testID, viewport, op string, err error) *VisualTestError

NewTestError creates a new VisualTestError.

func (*VisualTestError) Error

func (e *VisualTestError) Error() string

Error returns the error message.

func (*VisualTestError) Unwrap

func (e *VisualTestError) Unwrap() error

Unwrap returns the underlying error.

type VisualTestReport

type VisualTestReport struct {
	Timestamp       time.Time          `json:"timestamp"`
	BaselineVersion string             `json:"baselineVersion"`
	Duration        time.Duration      `json:"duration"`
	Summary         VisualTestSummary  `json:"summary"`
	Results         []VisualTestResult `json:"results"`
	Errors          []string           `json:"errors,omitempty"`
}

VisualTestReport contains all test results from a test run.

type VisualTestResult

type VisualTestResult struct {
	TestID       string        `json:"testId"`
	Viewport     string        `json:"viewport"`
	Status       TestStatus    `json:"status"`
	DiffPercent  float64       `json:"diffPercent,omitempty"`
	Threshold    float64       `json:"threshold"`
	Duration     time.Duration `json:"duration"`
	BaselinePath string        `json:"baselinePath,omitempty"`
	ActualPath   string        `json:"actualPath,omitempty"`
	DiffPath     string        `json:"diffPath,omitempty"`
	Error        string        `json:"error,omitempty"`
}

VisualTestResult represents the outcome of a single visual test.

type VisualTestSuite

type VisualTestSuite struct {
	Version     string             `json:"version" yaml:"version"`
	Name        string             `json:"name" yaml:"name"`
	Description string             `json:"description,omitempty" yaml:"description,omitempty"`
	BaseURL     string             `json:"baseUrl,omitempty" yaml:"baseUrl,omitempty"`
	Defaults    VisualTestDefaults `json:"defaults,omitempty" yaml:"defaults,omitempty"`
	Tests       []VisualTest       `json:"tests" yaml:"tests"`
}

VisualTestSuite represents a collection of visual tests.

type VisualTestSummary

type VisualTestSummary struct {
	Total   int `json:"total"`
	Passed  int `json:"passed"`
	Failed  int `json:"failed"`
	Skipped int `json:"skipped"`
	Errors  int `json:"errors"`
}

VisualTestSummary provides aggregate statistics for a test run.

type W3PilotClient

type W3PilotClient struct {
	// contains filtered or unexported fields
}

W3PilotClient wraps communication with w3pilot via MCP.

func NewW3PilotClient

func NewW3PilotClient(ctx context.Context) (*W3PilotClient, error)

NewW3PilotClient starts w3pilot as a subprocess and connects via MCP.

func (*W3PilotClient) CaptureScreenshot

func (c *W3PilotClient) CaptureScreenshot(ctx context.Context, opts CaptureOptions) ([]byte, error)

CaptureScreenshot navigates to URL and captures a screenshot.

func (*W3PilotClient) Close

func (c *W3PilotClient) Close() error

Close terminates the w3pilot subprocess.

func (*W3PilotClient) CloseBrowser

func (c *W3PilotClient) CloseBrowser(ctx context.Context) error

CloseBrowser closes the browser session.

func (*W3PilotClient) ElementScreenshot

func (c *W3PilotClient) ElementScreenshot(ctx context.Context, selector string) ([]byte, error)

ElementScreenshot captures an element screenshot.

func (*W3PilotClient) Evaluate

func (c *W3PilotClient) Evaluate(ctx context.Context, expression string) error

Evaluate runs JavaScript in the page.

func (*W3PilotClient) LaunchBrowser

func (c *W3PilotClient) LaunchBrowser(ctx context.Context, headless bool) error

LaunchBrowser starts a browser session.

func (*W3PilotClient) Navigate

func (c *W3PilotClient) Navigate(ctx context.Context, url string) error

Navigate navigates to a URL.

func (*W3PilotClient) PageScreenshot

func (c *W3PilotClient) PageScreenshot(ctx context.Context) ([]byte, error)

PageScreenshot captures a full page screenshot.

func (*W3PilotClient) SetViewport

func (c *W3PilotClient) SetViewport(ctx context.Context, width, height int) error

SetViewport sets the viewport size.

func (*W3PilotClient) WaitForSelector

func (c *W3PilotClient) WaitForSelector(ctx context.Context, selector string, timeoutMs int) error

WaitForSelector waits for a selector to appear.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL