| package bridge |
|
|
| import ( |
| "context" |
| "strings" |
| "testing" |
|
|
| "github.com/pinchtab/pinchtab/internal/config" |
| ) |
|
|
| func TestClickAction_UsesCoordinatePathIncludingZeroZero(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
|
|
| ctx, cancel := context.WithCancel(context.Background()) |
| cancel() |
|
|
| _, err := b.Actions[ActionClick](ctx, ActionRequest{HasXY: true, X: 0, Y: 0}) |
| if err == nil { |
| t.Fatal("expected error from cancelled context") |
| } |
| if strings.Contains(err.Error(), "need selector") { |
| t.Fatalf("expected coordinate path, got selector/ref validation error: %v", err) |
| } |
| } |
|
|
| func TestDoubleClickAction_UsesCoordinatePathIncludingZeroZero(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
|
|
| ctx, cancel := context.WithCancel(context.Background()) |
| cancel() |
|
|
| _, err := b.Actions[ActionDoubleClick](ctx, ActionRequest{HasXY: true, X: 0, Y: 0}) |
| if err == nil { |
| t.Fatal("expected error from cancelled context") |
| } |
| if strings.Contains(err.Error(), "need selector") { |
| t.Fatalf("expected coordinate path, got selector/ref validation error: %v", err) |
| } |
| } |
|
|
| func TestHoverAction_UsesCoordinatePath(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
|
|
| ctx, cancel := context.WithCancel(context.Background()) |
| cancel() |
|
|
| _, err := b.Actions[ActionHover](ctx, ActionRequest{HasXY: true, X: 12.5, Y: 34.5}) |
| if err == nil { |
| t.Fatal("expected error from cancelled context") |
| } |
| if strings.Contains(err.Error(), "need selector") { |
| t.Fatalf("expected coordinate path, got selector/ref validation error: %v", err) |
| } |
| } |
|
|
| func TestCheckAction_Registered(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
| if _, ok := b.Actions[ActionCheck]; !ok { |
| t.Fatal("ActionCheck not registered in action registry") |
| } |
| } |
|
|
| func TestUncheckAction_Registered(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
| if _, ok := b.Actions[ActionUncheck]; !ok { |
| t.Fatal("ActionUncheck not registered in action registry") |
| } |
| } |
|
|
| func TestCheckAction_RequiresSelectorOrRef(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
| _, err := b.Actions[ActionCheck](context.Background(), ActionRequest{}) |
| if err == nil { |
| t.Fatal("expected error when no selector/ref/nodeId provided") |
| } |
| if !strings.Contains(err.Error(), "need selector") { |
| t.Fatalf("expected 'need selector' error, got: %v", err) |
| } |
| } |
|
|
| func TestUncheckAction_RequiresSelectorOrRef(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
| _, err := b.Actions[ActionUncheck](context.Background(), ActionRequest{}) |
| if err == nil { |
| t.Fatal("expected error when no selector/ref/nodeId provided") |
| } |
| if !strings.Contains(err.Error(), "need selector") { |
| t.Fatalf("expected 'need selector' error, got: %v", err) |
| } |
| } |
|
|
| func TestCheckAction_WithNodeID_UsesResolveNode(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
|
|
| ctx, cancel := context.WithCancel(context.Background()) |
| cancel() |
|
|
| _, err := b.Actions[ActionCheck](ctx, ActionRequest{NodeID: 42}) |
| if err == nil { |
| t.Fatal("expected error from cancelled context") |
| } |
| |
| if strings.Contains(err.Error(), "need selector") { |
| t.Fatalf("expected CDP path, got validation error: %v", err) |
| } |
| } |
|
|
| func TestUncheckAction_WithSelector_UsesCSSPath(t *testing.T) { |
| b := New(context.TODO(), nil, &config.RuntimeConfig{}) |
|
|
| ctx, cancel := context.WithCancel(context.Background()) |
| cancel() |
|
|
| _, err := b.Actions[ActionUncheck](ctx, ActionRequest{Selector: "#my-checkbox"}) |
| if err == nil { |
| t.Fatal("expected error from cancelled context") |
| } |
| if strings.Contains(err.Error(), "need selector") { |
| t.Fatalf("expected CSS path, got validation error: %v", err) |
| } |
| } |
|
|
| func TestXpathString(t *testing.T) { |
| tests := []struct { |
| input string |
| expected string |
| }{ |
| {"hello", "'hello'"}, |
| {"it's", "concat('it', \"'\", 's')"}, |
| {"say \"hi\"", "'say \"hi\"'"}, |
| {"it's a \"test\"", "concat('it', \"'\", 's a \"test\"')"}, |
| {"", "''"}, |
| } |
| for _, tt := range tests { |
| t.Run(tt.input, func(t *testing.T) { |
| result := xpathString(tt.input) |
| if result != tt.expected { |
| t.Errorf("xpathString(%q) = %q, want %q", tt.input, result, tt.expected) |
| } |
| }) |
| } |
| } |
|
|