@@ -19,10 +19,13 @@ package compose
1919import (
2020 "bytes"
2121 "encoding/json"
22+ "strings"
2223 "testing"
2324
2425 "github.com/docker/cli/cli-plugins/hooks"
2526 "gotest.tools/v3/assert"
27+
28+ "github.com/docker/compose/v5/cmd/formatter"
2629)
2730
2831func TestHandleHook_NoArgs (t * testing.T ) {
@@ -52,7 +55,7 @@ func TestHandleHook_UnknownCommand(t *testing.T) {
5255func TestHandleHook_LogsCommand (t * testing.T ) {
5356 tests := []struct {
5457 rootCmd string
55- wantHint string
58+ wantHint func () string
5659 }{
5760 {rootCmd : "compose logs" , wantHint : composeLogsHint },
5861 {rootCmd : "logs" , wantHint : dockerLogsHint },
@@ -68,7 +71,7 @@ func TestHandleHook_LogsCommand(t *testing.T) {
6871
6972 msg := unmarshalResponse (t , buf .Bytes ())
7073 assert .Equal (t , msg .Type , hooks .NextSteps )
71- assert .Equal (t , msg .Template , tt .wantHint )
74+ assert .Equal (t , msg .Template , tt .wantHint () )
7275 })
7376 }
7477}
@@ -112,14 +115,61 @@ func TestHandleHook_ComposeUpDetached(t *testing.T) {
112115
113116 if tt .wantHint {
114117 msg := unmarshalResponse (t , buf .Bytes ())
115- assert .Equal (t , msg .Template , composeLogsHint )
118+ assert .Equal (t , msg .Template , composeLogsHint () )
116119 } else {
117120 assert .Equal (t , buf .String (), "" )
118121 }
119122 })
120123 }
121124}
122125
126+ func TestHandleHook_HintContainsOSC8Link (t * testing.T ) {
127+ // Ensure ANSI is not suppressed by the test runner environment
128+ t .Setenv ("NO_COLOR" , "" )
129+ t .Setenv ("COMPOSE_ANSI" , "" )
130+ data := marshalHookData (t , hooks.Request {
131+ RootCmd : "compose logs" ,
132+ })
133+ var buf bytes.Buffer
134+ err := handleHook ([]string {data }, & buf )
135+ assert .NilError (t , err )
136+
137+ msg := unmarshalResponse (t , buf .Bytes ())
138+ // Verify the template contains the OSC 8 hyperlink sequence
139+ wantLink := formatter .OSC8Link (deepLink , deepLink )
140+ assert .Assert (t , len (wantLink ) > len (deepLink ), "OSC8Link should wrap the URL with escape sequences" )
141+ assert .Assert (t , strings .Contains (msg .Template , wantLink ), "hint should contain OSC 8 hyperlink" )
142+ }
143+
144+ func TestHandleHook_NoColorDisablesOsc8 (t * testing.T ) {
145+ t .Setenv ("NO_COLOR" , "1" )
146+ data := marshalHookData (t , hooks.Request {
147+ RootCmd : "compose logs" ,
148+ })
149+ var buf bytes.Buffer
150+ err := handleHook ([]string {data }, & buf )
151+ assert .NilError (t , err )
152+
153+ msg := unmarshalResponse (t , buf .Bytes ())
154+ // With NO_COLOR set, the hint should contain the plain URL without escape sequences
155+ assert .Assert (t , strings .Contains (msg .Template , deepLink ), "hint should contain the deep link URL" )
156+ assert .Assert (t , ! strings .Contains (msg .Template , "\033 " ), "hint should not contain ANSI escape sequences" )
157+ }
158+
159+ func TestHandleHook_ComposeAnsiNeverDisablesOsc8 (t * testing.T ) {
160+ t .Setenv ("COMPOSE_ANSI" , "never" )
161+ data := marshalHookData (t , hooks.Request {
162+ RootCmd : "compose logs" ,
163+ })
164+ var buf bytes.Buffer
165+ err := handleHook ([]string {data }, & buf )
166+ assert .NilError (t , err )
167+
168+ msg := unmarshalResponse (t , buf .Bytes ())
169+ assert .Assert (t , strings .Contains (msg .Template , deepLink ), "hint should contain the deep link URL" )
170+ assert .Assert (t , ! strings .Contains (msg .Template , "\033 " ), "hint should not contain ANSI escape sequences" )
171+ }
172+
123173func marshalHookData (t * testing.T , data hooks.Request ) string {
124174 t .Helper ()
125175 b , err := json .Marshal (data )
0 commit comments