1package desktop
2
3import (
4 "context"
5 "errors"
6 "os/exec"
7 "testing"
8
9 "github.com/bnema/dumber/internal/application/port/mocks"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12)
13
14func TestBrowserLauncher_LaunchURL_ReturnsWithoutSpawningWhenRelayDelivers(t *testing.T) {
15 relay := mocks.NewMockBrowserLaunchRelay(t)
16 relay.EXPECT().DeliverOpenFreshWindow(context.Background(), "https://example.com").Return(true, nil)
17
18 launcher := NewBrowserLauncher(relay)
19 spawned := false
20 launcher.resolveExecutablePath = func() (string, error) {
21 t.Fatal("expected executable path resolution to be skipped")
22 return "", nil
23 }
24 launcher.startDetachedProcess = func(_ *exec.Cmd) error {
25 spawned = true
26 return nil
27 }
28
29 err := launcher.LaunchURL(context.Background(), "https://example.com")
30
31 require.NoError(t, err)
32 assert.False(t, spawned)
33}
34
35func TestBrowserLauncher_LaunchURL_FallsBackToSpawnWhenRelayMisses(t *testing.T) {
36 relay := mocks.NewMockBrowserLaunchRelay(t)
37 relay.EXPECT().DeliverOpenFreshWindow(context.Background(), "https://example.com").Return(false, nil)
38
39 launcher := NewBrowserLauncher(relay)
40 launcher.resolveExecutablePath = func() (string, error) {
41 return "/usr/bin/dumber", nil
42 }
43
44 var gotCmd *exec.Cmd
45 launcher.startDetachedProcess = func(cmd *exec.Cmd) error {
46 gotCmd = cmd
47 return nil
48 }
49
50 err := launcher.LaunchURL(context.Background(), "https://example.com")
51
52 require.NoError(t, err)
53 require.NotNil(t, gotCmd)
54 assert.Equal(t, "/usr/bin/dumber", gotCmd.Path)
55 assert.Equal(t, []string{"/usr/bin/dumber", "browse", "https://example.com"}, gotCmd.Args)
56}
57
58func TestBrowserLauncher_LaunchURL_ReturnsUnconfirmedErrorWhenRelayDeliveryIsAmbiguous(t *testing.T) {
59 relay := mocks.NewMockBrowserLaunchRelay(t)
60 relay.EXPECT().DeliverOpenFreshWindow(context.Background(), "https://example.com").Return(true, ErrBrowserLaunchRelayUnconfirmed)
61
62 launcher := NewBrowserLauncher(relay)
63 launcher.resolveExecutablePath = func() (string, error) {
64 t.Fatal("expected executable path resolution to be skipped")
65 return "", nil
66 }
67 launcher.startDetachedProcess = func(_ *exec.Cmd) error {
68 t.Fatal("expected launch to stop after ambiguous relay delivery")
69 return nil
70 }
71
72 err := launcher.LaunchURL(context.Background(), "https://example.com")
73
74 require.Error(t, err)
75 assert.ErrorIs(t, err, ErrBrowserLaunchUnconfirmed)
76}
77
78func TestBrowserLauncher_LaunchURL_PropagatesRelayError(t *testing.T) {
79 relay := mocks.NewMockBrowserLaunchRelay(t)
80 wantErr := errors.New("relay exploded")
81 relay.EXPECT().DeliverOpenFreshWindow(context.Background(), "https://example.com").Return(false, wantErr)
82
83 launcher := NewBrowserLauncher(relay)
84 launcher.resolveExecutablePath = func() (string, error) {
85 t.Fatal("expected executable path resolution to be skipped")
86 return "", nil
87 }
88 launcher.startDetachedProcess = func(_ *exec.Cmd) error {
89 t.Fatal("expected launch to stop after relay error")
90 return nil
91 }
92
93 err := launcher.LaunchURL(context.Background(), "https://example.com")
94
95 require.Error(t, err)
96 require.ErrorIs(t, err, wantErr)
97 assert.NotContains(t, err.Error(), "https://example.com")
98}
99
100func TestBrowserLauncher_LaunchURL_NilLauncherReturnsError(t *testing.T) {
101 var launcher *BrowserLauncher
102
103 err := launcher.LaunchURL(context.Background(), "https://example.com")
104
105 require.Error(t, err)
106 assert.Contains(t, err.Error(), "unavailable")
107}