Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions cmd/browsers.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ type BrowsersUpdateInput struct {
ProfileName string
ProfileSaveChanges BoolFlag
Viewport string
Force bool
Output string
}

Expand Down Expand Up @@ -589,6 +590,11 @@ func (b BrowsersCmd) Update(ctx context.Context, in BrowsersUpdateInput) error {
return fmt.Errorf("--save-changes requires --profile-id or --profile-name")
}

// Validate --force is only used with a viewport change
if in.Force && !hasViewportChange {
return fmt.Errorf("--force requires --viewport")
}

// Validate that at least one update option is provided
if !hasProxyChange && !hasProfileChange && !hasViewportChange {
return fmt.Errorf("must specify at least one of: --proxy-id, --clear-proxy, --profile-id, --profile-name, or --viewport")
Expand Down Expand Up @@ -622,13 +628,18 @@ func (b BrowsersCmd) Update(ctx context.Context, in BrowsersUpdateInput) error {
if err != nil {
return fmt.Errorf("invalid viewport format: %v", err)
}
params.Viewport = shared.BrowserViewportParam{
Width: width,
Height: height,
params.Viewport = kernel.BrowserUpdateParamsViewport{
BrowserViewportParam: shared.BrowserViewportParam{
Width: width,
Height: height,
},
}
if refreshRate > 0 {
params.Viewport.RefreshRate = kernel.Opt(refreshRate)
}
if in.Force {
params.Viewport.Force = kernel.Opt(true)
}
}

if in.Output != "json" {
Expand Down Expand Up @@ -2122,6 +2133,7 @@ Supported operations:
- Change or remove proxy (--proxy-id or --clear-proxy)
- Load a profile into a session that doesn't have one (--profile-id or --profile-name)
- Change viewport dimensions (--viewport)
- Force viewport resize during active live view or recording (--force with --viewport)

Note: Profiles can only be loaded into sessions that don't already have a profile.`,
Args: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -2159,6 +2171,7 @@ func init() {
browsersUpdateCmd.Flags().String("profile-name", "", "Profile name to load into the browser session (mutually exclusive with --profile-id)")
browsersUpdateCmd.Flags().Bool("save-changes", false, "If set, save changes back to the profile when the session ends")
browsersUpdateCmd.Flags().String("viewport", "", "Browser viewport size (e.g., 1920x1080@25). Supported: 2560x1440@10, 1920x1080@25, 1920x1200@25, 1440x900@25, 1024x768@60, 1200x800@60, 1280x800@60")
browsersUpdateCmd.Flags().Bool("force", false, "Force viewport resize even when a live view or recording/replay is active")

browsersCmd.AddCommand(browsersListCmd)
browsersCmd.AddCommand(browsersCreateCmd)
Expand Down Expand Up @@ -2619,6 +2632,7 @@ func runBrowsersUpdate(cmd *cobra.Command, args []string) error {
profileName, _ := cmd.Flags().GetString("profile-name")
saveChanges, _ := cmd.Flags().GetBool("save-changes")
viewport, _ := cmd.Flags().GetString("viewport")
force, _ := cmd.Flags().GetBool("force")

svc := client.Browsers
b := BrowsersCmd{browsers: &svc}
Expand All @@ -2630,6 +2644,7 @@ func runBrowsersUpdate(cmd *cobra.Command, args []string) error {
ProfileName: profileName,
ProfileSaveChanges: BoolFlag{Set: cmd.Flags().Changed("save-changes"), Value: saveChanges},
Viewport: viewport,
Force: force,
Output: out,
})
}
Expand Down
74 changes: 74 additions & 0 deletions cmd/browsers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1242,3 +1242,77 @@ func TestBrowsersCreate_WithInvalidViewport(t *testing.T) {
out := outBuf.String()
assert.Contains(t, out, "Invalid viewport format")
}

func TestBrowsersUpdate_WithViewportAndForce(t *testing.T) {
setupStdoutCapture(t)
var captured kernel.BrowserUpdateParams
fake := &FakeBrowsersService{UpdateFunc: func(ctx context.Context, id string, body kernel.BrowserUpdateParams, opts ...option.RequestOption) (*kernel.BrowserUpdateResponse, error) {
captured = body
return &kernel.BrowserUpdateResponse{SessionID: "session123"}, nil
}}
b := BrowsersCmd{browsers: fake}

err := b.Update(context.Background(), BrowsersUpdateInput{
Identifier: "session123",
Viewport: "1920x1080@25",
Force: true,
})

assert.NoError(t, err)
assert.Equal(t, int64(1920), captured.Viewport.Width)
assert.Equal(t, int64(1080), captured.Viewport.Height)
assert.True(t, captured.Viewport.RefreshRate.Valid())
assert.Equal(t, int64(25), captured.Viewport.RefreshRate.Value)
assert.True(t, captured.Viewport.Force.Valid())
assert.True(t, captured.Viewport.Force.Value)
}

func TestBrowsersUpdate_WithViewportNoForce(t *testing.T) {
setupStdoutCapture(t)
var captured kernel.BrowserUpdateParams
fake := &FakeBrowsersService{UpdateFunc: func(ctx context.Context, id string, body kernel.BrowserUpdateParams, opts ...option.RequestOption) (*kernel.BrowserUpdateResponse, error) {
captured = body
return &kernel.BrowserUpdateResponse{SessionID: "session123"}, nil
}}
b := BrowsersCmd{browsers: fake}

err := b.Update(context.Background(), BrowsersUpdateInput{
Identifier: "session123",
Viewport: "1920x1080@25",
Force: false,
})

assert.NoError(t, err)
assert.Equal(t, int64(1920), captured.Viewport.Width)
assert.Equal(t, int64(1080), captured.Viewport.Height)
assert.False(t, captured.Viewport.Force.Valid())
}

func TestBrowsersUpdate_ForceWithoutViewport_Errors(t *testing.T) {
setupStdoutCapture(t)
fake := &FakeBrowsersService{}
b := BrowsersCmd{browsers: fake}

err := b.Update(context.Background(), BrowsersUpdateInput{
Identifier: "session123",
Force: true,
})

assert.Error(t, err)
assert.Contains(t, err.Error(), "--force requires --viewport")
}

func TestBrowsersUpdate_ForceWithProxyButNoViewport_Errors(t *testing.T) {
setupStdoutCapture(t)
fake := &FakeBrowsersService{}
b := BrowsersCmd{browsers: fake}

err := b.Update(context.Background(), BrowsersUpdateInput{
Identifier: "session123",
ProxyID: "proxy-123",
Force: true,
})

assert.Error(t, err)
assert.Contains(t, err.Error(), "--force requires --viewport")
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/joho/godotenv v1.5.1
github.com/kernel/kernel-go-sdk v0.40.0
github.com/kernel/kernel-go-sdk v0.42.1
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/pterm/pterm v0.12.80
github.com/samber/lo v1.51.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kernel/kernel-go-sdk v0.40.0 h1:RQON4dE9HwvEcF5wM3WVKs/Om0PCH0eTDEB3iwjOvy4=
github.com/kernel/kernel-go-sdk v0.40.0/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
github.com/kernel/kernel-go-sdk v0.42.1 h1:uDoMNXyfS59fkZ9laJO/qKFAysRrqdg06zNB3uLEdEk=
github.com/kernel/kernel-go-sdk v0.42.1/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
Expand Down