Skip to content

Commit cebb639

Browse files
committed
Correct Slack notification URLs and add manual trigger test file
1 parent 4b93557 commit cebb639

3 files changed

Lines changed: 130 additions & 3 deletions

File tree

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//go:build manual
2+
3+
// Copyright 2026 Google LLC
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package webhook
18+
19+
import (
20+
"context"
21+
"encoding/json"
22+
"fmt"
23+
"net/http"
24+
"testing"
25+
"time"
26+
27+
"github.com/GoogleChrome/webstatus.dev/lib/workertypes"
28+
)
29+
30+
// TestManualSlackTrigger is a helper "test" that sends a real Slack message.
31+
// To run this test, fill in a valid slackURL below and run:
32+
// go test -v -tags=manual -run TestManualSlackTrigger ./workers/webhook/pkg/webhook
33+
func TestManualSlackTrigger(t *testing.T) {
34+
slackURL := "" // <--- FILL THIS IN
35+
if slackURL == "" {
36+
t.Skip("slackURL not set, skipping manual trigger test")
37+
}
38+
39+
testCases := []struct {
40+
name string
41+
query string
42+
text string
43+
}{
44+
{
45+
name: "Search Query",
46+
query: "baseline_status:newly",
47+
text: "Manual Test: Search update for 'baseline_status:newly'",
48+
},
49+
{
50+
name: "Feature Query",
51+
query: "id:\"anchor-positioning\"",
52+
text: "Manual Test: Feature update for 'Anchor Positioning'",
53+
},
54+
}
55+
56+
for _, tc := range testCases {
57+
t.Run(tc.name, func(t *testing.T) {
58+
summary := workertypes.EventSummary{
59+
SchemaVersion: "v1",
60+
Text: tc.text,
61+
Categories: workertypes.SummaryCategories{Added: 1},
62+
Highlights: []workertypes.SummaryHighlight{
63+
{
64+
Type: workertypes.SummaryHighlightTypeAdded,
65+
FeatureID: "anchor-positioning",
66+
FeatureName: "Anchor Positioning",
67+
},
68+
},
69+
}
70+
summaryRaw, _ := json.Marshal(summary)
71+
72+
job := workertypes.IncomingWebhookDeliveryJob{
73+
WebhookDeliveryJob: workertypes.WebhookDeliveryJob{
74+
WebhookURL: slackURL,
75+
SummaryRaw: summaryRaw,
76+
Metadata: workertypes.DeliveryMetadata{
77+
EventID: "manual-trigger-event",
78+
SearchID: "manual-search-id",
79+
SearchName: tc.name,
80+
Query: tc.query,
81+
Frequency: workertypes.FrequencyImmediate,
82+
GeneratedAt: time.Now(),
83+
},
84+
Triggers: []workertypes.JobTrigger{workertypes.FeaturePromotedToNewly},
85+
ChannelID: "manual-channel-id",
86+
WebhookType: workertypes.WebhookTypeSlack,
87+
},
88+
WebhookEventID: "manual-webhook-event-id",
89+
}
90+
91+
mgr := &slackManager{
92+
frontendBaseURL: "http://localhost:5555",
93+
httpClient: &http.Client{},
94+
stateManager: &noopStateManager{}, // Don't try to write to Spanner
95+
job: job,
96+
}
97+
98+
err := mgr.Send(context.Background())
99+
if err != nil {
100+
t.Errorf("Failed to send Slack message for %s: %v", tc.name, err)
101+
} else {
102+
fmt.Printf("Slack message sent successfully for %s!\n", tc.name)
103+
}
104+
})
105+
}
106+
}
107+
108+
type noopStateManager struct{}
109+
110+
func (n *noopStateManager) RecordSuccess(ctx context.Context, channelID string, sentAt time.Time, webhookEventID string) error {
111+
return nil
112+
}
113+
func (n *noopStateManager) RecordFailure(ctx context.Context, channelID string, err error, failedAt time.Time, isPermanent bool, webhookEventID string) error {
114+
return nil
115+
}

workers/webhook/pkg/webhook/sender_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func TestSender_SendWebhook_Success(t *testing.T) {
8585
if !strings.Contains(payload.Text, "Test Body") {
8686
t.Errorf("payload does not contain expected text: %s", payload.Text)
8787
}
88-
expectedLink := "View Results: https://webstatus.dev/features?q=group%3Acss"
88+
expectedLink := "View Results: https://webstatus.dev/?q=group%3Acss"
8989
if !strings.Contains(payload.Text, expectedLink) {
9090
t.Errorf("payload missing expected link. Got: %s", payload.Text)
9191
}
@@ -239,6 +239,7 @@ func TestSender_SendWebhook_FeatureDeepLink_Success(t *testing.T) {
239239
t.Fatalf("SendWebhook failed: %v", err)
240240
}
241241
}
242+
242243
func TestSender_SendWebhook_HTTPFailure(t *testing.T) {
243244
mockHTTP := &mockHTTPClient{
244245
doFunc: func(_ *http.Request) (*http.Response, error) {

workers/webhook/pkg/webhook/slack.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"net/http"
2424
"net/url"
25+
"strings"
2526
"time"
2627

2728
"github.com/GoogleChrome/webstatus.dev/lib/httputils"
@@ -45,11 +46,21 @@ func (s *slackManager) Send(ctx context.Context) error {
4546
return fmt.Errorf("failed to unmarshal summary: %w", err)
4647
}
4748

48-
resultsURL := fmt.Sprintf("%s/features?q=%s", s.frontendBaseURL, url.QueryEscape(s.job.Metadata.Query))
49+
// Determine the correct results URL.
50+
// 1. Check if it's a feature-specific query (id:"...")
51+
query := s.job.Metadata.Query
52+
var resultsURL string
53+
if strings.HasPrefix(query, "id:\"") && strings.HasSuffix(query, "\"") {
54+
featureKey := strings.TrimSuffix(strings.TrimPrefix(query, "id:\""), "\"")
55+
resultsURL = fmt.Sprintf("%s/features/%s", s.frontendBaseURL, featureKey)
56+
} else {
57+
// 2. Default search results page (at the root)
58+
resultsURL = fmt.Sprintf("%s/?q=%s", s.frontendBaseURL, url.QueryEscape(query))
59+
}
4960

5061
payload := SlackPayload{
5162
Text: fmt.Sprintf("WebStatus.dev Notification: %s\nQuery: %s\nView Results: %s",
52-
summary.Text, s.job.Metadata.Query, resultsURL),
63+
summary.Text, query, resultsURL),
5364
}
5465

5566
payloadBytes, err := json.Marshal(payload)

0 commit comments

Comments
 (0)