A community based topic aggregation platform built on atproto
at main 5.8 kB view raw
1package unfurl 2 3import ( 4 "context" 5 "net/http" 6 "net/http/httptest" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12) 13 14func TestFetchKagiKite_Success(t *testing.T) { 15 // Mock Kagi HTML response 16 mockHTML := `<!DOCTYPE html> 17<html> 18<head> 19 <title>FAA orders 10% flight cuts at 40 airports - Kagi News</title> 20 <meta property="og:title" content="FAA orders 10% flight cuts" /> 21 <meta property="og:description" content="Flight restrictions announced" /> 22</head> 23<body> 24 <img src="https://kagiproxy.com/img/DHdCvN_NqVDWU3UyoNZSv86b" alt="Airport runway" /> 25</body> 26</html>` 27 28 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 29 w.Header().Set("Content-Type", "text/html") 30 w.WriteHeader(http.StatusOK) 31 _, _ = w.Write([]byte(mockHTML)) 32 })) 33 defer server.Close() 34 35 ctx := context.Background() 36 37 result, err := fetchKagiKite(ctx, server.URL, 5*time.Second, "TestBot/1.0") 38 39 require.NoError(t, err) 40 assert.Equal(t, "article", result.Type) 41 assert.Equal(t, "FAA orders 10% flight cuts", result.Title) 42 assert.Equal(t, "Flight restrictions announced", result.Description) 43 assert.Contains(t, result.ThumbnailURL, "kagiproxy.com") 44 assert.Equal(t, "kagi", result.Provider) 45 assert.Equal(t, "kite.kagi.com", result.Domain) 46} 47 48func TestFetchKagiKite_NoImage(t *testing.T) { 49 mockHTML := `<!DOCTYPE html> 50<html> 51<head><title>Test Story</title></head> 52<body><p>No images here</p></body> 53</html>` 54 55 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 56 w.Header().Set("Content-Type", "text/html") 57 w.WriteHeader(http.StatusOK) 58 _, _ = w.Write([]byte(mockHTML)) 59 })) 60 defer server.Close() 61 62 ctx := context.Background() 63 64 result, err := fetchKagiKite(ctx, server.URL, 5*time.Second, "TestBot/1.0") 65 66 assert.Error(t, err) 67 assert.Nil(t, result) 68 assert.Contains(t, err.Error(), "no image found") 69} 70 71func TestFetchKagiKite_FallbackToTitle(t *testing.T) { 72 mockHTML := `<!DOCTYPE html> 73<html> 74<head><title>Fallback Title</title></head> 75<body> 76 <img src="https://kagiproxy.com/img/test123" /> 77</body> 78</html>` 79 80 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 81 w.Header().Set("Content-Type", "text/html") 82 w.WriteHeader(http.StatusOK) 83 _, _ = w.Write([]byte(mockHTML)) 84 })) 85 defer server.Close() 86 87 ctx := context.Background() 88 89 result, err := fetchKagiKite(ctx, server.URL, 5*time.Second, "TestBot/1.0") 90 91 require.NoError(t, err) 92 assert.Equal(t, "Fallback Title", result.Title) 93 assert.Contains(t, result.ThumbnailURL, "kagiproxy.com") 94} 95 96func TestFetchKagiKite_ImageWithAltText(t *testing.T) { 97 mockHTML := `<!DOCTYPE html> 98<html> 99<head><title>News Story</title></head> 100<body> 101 <img src="https://kagiproxy.com/img/xyz789" alt="This is the alt text description" /> 102</body> 103</html>` 104 105 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 106 w.Header().Set("Content-Type", "text/html") 107 w.WriteHeader(http.StatusOK) 108 _, _ = w.Write([]byte(mockHTML)) 109 })) 110 defer server.Close() 111 112 ctx := context.Background() 113 114 result, err := fetchKagiKite(ctx, server.URL, 5*time.Second, "TestBot/1.0") 115 116 require.NoError(t, err) 117 assert.Equal(t, "News Story", result.Title) 118 assert.Equal(t, "This is the alt text description", result.Description) 119 assert.Contains(t, result.ThumbnailURL, "kagiproxy.com") 120} 121 122func TestFetchKagiKite_HTTPError(t *testing.T) { 123 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 124 w.WriteHeader(http.StatusNotFound) 125 })) 126 defer server.Close() 127 128 ctx := context.Background() 129 130 result, err := fetchKagiKite(ctx, server.URL, 5*time.Second, "TestBot/1.0") 131 132 assert.Error(t, err) 133 assert.Nil(t, result) 134 assert.Contains(t, err.Error(), "HTTP 404") 135} 136 137func TestFetchKagiKite_Timeout(t *testing.T) { 138 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 139 time.Sleep(2 * time.Second) 140 w.WriteHeader(http.StatusOK) 141 })) 142 defer server.Close() 143 144 ctx := context.Background() 145 146 result, err := fetchKagiKite(ctx, server.URL, 100*time.Millisecond, "TestBot/1.0") 147 148 assert.Error(t, err) 149 assert.Nil(t, result) 150} 151 152func TestFetchKagiKite_MultipleImages_PicksSecond(t *testing.T) { 153 mockHTML := `<!DOCTYPE html> 154<html> 155<head><title>Story with multiple images</title></head> 156<body> 157 <img src="https://kagiproxy.com/img/first123" alt="First image (header/logo)" /> 158 <img src="https://kagiproxy.com/img/second456" alt="Second image" /> 159</body> 160</html>` 161 162 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 163 w.Header().Set("Content-Type", "text/html") 164 w.WriteHeader(http.StatusOK) 165 _, _ = w.Write([]byte(mockHTML)) 166 })) 167 defer server.Close() 168 169 ctx := context.Background() 170 171 result, err := fetchKagiKite(ctx, server.URL, 5*time.Second, "TestBot/1.0") 172 173 require.NoError(t, err) 174 // We skip the first image (often a header/logo) and use the second 175 assert.Contains(t, result.ThumbnailURL, "second456") 176 assert.Equal(t, "Second image", result.Description) 177} 178 179func TestFetchKagiKite_OnlyNonKagiImages_NoMatch(t *testing.T) { 180 mockHTML := `<!DOCTYPE html> 181<html> 182<head><title>Story with non-Kagi images</title></head> 183<body> 184 <img src="https://example.com/img/test.jpg" alt="External image" /> 185</body> 186</html>` 187 188 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 189 w.Header().Set("Content-Type", "text/html") 190 w.WriteHeader(http.StatusOK) 191 _, _ = w.Write([]byte(mockHTML)) 192 })) 193 defer server.Close() 194 195 ctx := context.Background() 196 197 result, err := fetchKagiKite(ctx, server.URL, 5*time.Second, "TestBot/1.0") 198 199 assert.Error(t, err) 200 assert.Nil(t, result) 201 assert.Contains(t, err.Error(), "no image found") 202}