Cover outlook discussions in endpoint responses
This commit is contained in:
@@ -1314,10 +1314,9 @@ func TestOutlookRoutesJSONSuccess(t *testing.T) {
|
||||
|
||||
var payload struct {
|
||||
Data struct {
|
||||
LocationID string `json:"locationId"`
|
||||
Outlooks []struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"outlooks"`
|
||||
LocationID string `json:"locationId"`
|
||||
Outlooks []map[string]any `json:"outlooks"`
|
||||
Discussions []outlookDiscussionCheck `json:"discussions"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil {
|
||||
@@ -1326,9 +1325,20 @@ func TestOutlookRoutesJSONSuccess(t *testing.T) {
|
||||
if payload.Data.LocationID != "stl" {
|
||||
t.Fatalf("expected locationId stl, got %q", payload.Data.LocationID)
|
||||
}
|
||||
if len(payload.Data.Outlooks) != 1 || payload.Data.Outlooks[0].ID != "cat-1" {
|
||||
if len(payload.Data.Outlooks) != 1 || payload.Data.Outlooks[0]["id"] != "cat-1" {
|
||||
t.Fatalf("unexpected outlooks payload: %+v", payload.Data.Outlooks)
|
||||
}
|
||||
for _, field := range []string{"headline", "summary", "discussion"} {
|
||||
if _, ok := payload.Data.Outlooks[0][field]; ok {
|
||||
t.Fatalf("expected outlook polygon to omit %s, got %+v", field, payload.Data.Outlooks[0])
|
||||
}
|
||||
}
|
||||
if len(payload.Data.Discussions) != 1 {
|
||||
t.Fatalf("expected one discussion, got %+v", payload.Data.Discussions)
|
||||
}
|
||||
if payload.Data.Discussions[0].Day != 1 || payload.Data.Discussions[0].Headline != "Day 1 headline" {
|
||||
t.Fatalf("unexpected discussions payload: %+v", payload.Data.Discussions)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1369,7 +1379,8 @@ func TestOutlookTextResponseUsesTemplate(t *testing.T) {
|
||||
t.Fatalf("expected text/plain content type, got %q", w.Header().Get("Content-Type"))
|
||||
}
|
||||
body := w.Body.String()
|
||||
if !strings.Contains(body, "Convective Outlook") || !strings.Contains(body, "Outlooks: 1") {
|
||||
if !strings.Contains(body, "Convective Outlook") || !strings.Contains(body, "Outlooks: 1") ||
|
||||
!strings.Contains(body, "Discussions: 1") || !strings.Contains(body, "Day 1 discussion") {
|
||||
t.Fatalf("expected outlook text template body, got %q", body)
|
||||
}
|
||||
}
|
||||
@@ -1390,11 +1401,15 @@ func TestOutlookXMLResponseRenders(t *testing.T) {
|
||||
if !strings.Contains(w.Body.String(), "<LocationID>stl</LocationID>") {
|
||||
t.Fatalf("expected outlook XML payload, got %q", w.Body.String())
|
||||
}
|
||||
if !strings.Contains(w.Body.String(), "<Discussions>") || !strings.Contains(w.Body.String(), "<Headline>Day 1 headline</Headline>") {
|
||||
t.Fatalf("expected outlook XML discussions, got %q", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutlookFilteredNoMatchReturnsEmptyOutlooks(t *testing.T) {
|
||||
run := testOutlookRun()
|
||||
run.Outlooks = []model.WeatherOutlook{}
|
||||
run.Discussions = []model.WeatherOutlookDiscussion{}
|
||||
h := newHandler(t, &fakeService{outlookRun: run}, "/outlooks/convective")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
@@ -1407,8 +1422,9 @@ func TestOutlookFilteredNoMatchReturnsEmptyOutlooks(t *testing.T) {
|
||||
|
||||
var payload struct {
|
||||
Data struct {
|
||||
LocationID string `json:"locationId"`
|
||||
Outlooks []model.WeatherOutlook `json:"outlooks"`
|
||||
LocationID string `json:"locationId"`
|
||||
Outlooks []model.WeatherOutlook `json:"outlooks"`
|
||||
Discussions []model.WeatherOutlookDiscussion `json:"discussions"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil {
|
||||
@@ -1420,6 +1436,39 @@ func TestOutlookFilteredNoMatchReturnsEmptyOutlooks(t *testing.T) {
|
||||
if payload.Data.Outlooks == nil || len(payload.Data.Outlooks) != 0 {
|
||||
t.Fatalf("expected empty outlooks slice, got %+v", payload.Data.Outlooks)
|
||||
}
|
||||
if payload.Data.Discussions == nil || len(payload.Data.Discussions) != 0 {
|
||||
t.Fatalf("expected empty discussions slice, got %+v", payload.Data.Discussions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutlookTimezoneQuery(t *testing.T) {
|
||||
h := newHandler(t, &fakeService{outlookRun: testOutlookRun()}, "/outlooks/convective")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/outlooks/convective?tz=CDT", nil)
|
||||
h.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
var payload outlookTimePayload
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil {
|
||||
t.Fatalf("decode outlook payload: %v", err)
|
||||
}
|
||||
assertOffsetSeconds(t, payload.Data.AsOf, -5*60*60)
|
||||
assertOffsetSeconds(t, *payload.Data.IssuedAt, -5*60*60)
|
||||
if len(payload.Data.Outlooks) != 1 {
|
||||
t.Fatalf("expected one outlook, got %+v", payload.Data.Outlooks)
|
||||
}
|
||||
assertOffsetSeconds(t, payload.Data.Outlooks[0].ValidFrom, -5*60*60)
|
||||
assertOffsetSeconds(t, payload.Data.Outlooks[0].ValidTo, -5*60*60)
|
||||
assertOffsetSeconds(t, payload.Data.Outlooks[0].IssuedAt, -5*60*60)
|
||||
assertOffsetSeconds(t, payload.Data.Outlooks[0].ExpiresAt, -5*60*60)
|
||||
if len(payload.Data.Discussions) != 1 || payload.Data.Discussions[0].UpdatedAt == nil {
|
||||
t.Fatalf("expected one discussion with updatedAt, got %+v", payload.Data.Discussions)
|
||||
}
|
||||
assertOffsetSeconds(t, *payload.Data.Discussions[0].UpdatedAt, -5*60*60)
|
||||
}
|
||||
|
||||
func TestOutlookQueryParamsConstructFilter(t *testing.T) {
|
||||
@@ -2211,7 +2260,7 @@ func testRenderers(t *testing.T) *render.Registry {
|
||||
"discussion_long_term.txt.tmpl": "Forecast Discussion Long Term",
|
||||
"forecast_hourly.txt.tmpl": "Forecast text",
|
||||
"forecast_narrative.txt.tmpl": "Narrative Forecast",
|
||||
"outlooks_convective.txt.tmpl": "Convective Outlook\n{{if .Data}}Outlooks: {{len .Data.Outlooks}}{{else}}No convective outlook data available.{{end}}",
|
||||
"outlooks_convective.txt.tmpl": "Convective Outlook\n{{if .Data}}Outlooks: {{len .Data.Outlooks}}\nDiscussions: {{len .Data.Discussions}}{{range .Data.Discussions}}\nDiscussion: {{.Discussion}}{{end}}{{else}}No convective outlook data available.{{end}}",
|
||||
"weatherstories.txt.tmpl": "Weather Stories",
|
||||
"weatherstories_latest.txt.tmpl": "Latest Weather Story",
|
||||
"alerts_active.txt.tmpl": "Alerts text",
|
||||
@@ -2250,6 +2299,7 @@ func setOutlookNowForTest(t *testing.T, now time.Time) {
|
||||
|
||||
func testOutlookRun() *model.WeatherOutlookRun {
|
||||
issuedAt := time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC)
|
||||
discussionUpdatedAt := issuedAt.Add(30 * time.Minute)
|
||||
return &model.WeatherOutlookRun{
|
||||
LocationID: "stl",
|
||||
LocationName: "St. Louis",
|
||||
@@ -2270,6 +2320,13 @@ func testOutlookRun() *model.WeatherOutlookRun {
|
||||
ContainsLocation: true,
|
||||
Geometry: []byte(`{"type":"Point","coordinates":[-90.2,38.6]}`),
|
||||
}},
|
||||
Discussions: []model.WeatherOutlookDiscussion{{
|
||||
Day: 1,
|
||||
Headline: "Day 1 headline",
|
||||
Summary: "Day 1 summary",
|
||||
Discussion: "Day 1 discussion",
|
||||
UpdatedAt: &discussionUpdatedAt,
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2343,6 +2400,27 @@ type discussionFocusedTimePayload struct {
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type outlookDiscussionCheck struct {
|
||||
Day int `json:"day"`
|
||||
Headline string `json:"headline"`
|
||||
}
|
||||
|
||||
type outlookTimePayload struct {
|
||||
Data struct {
|
||||
AsOf time.Time `json:"asOf"`
|
||||
IssuedAt *time.Time `json:"issuedAt"`
|
||||
Outlooks []struct {
|
||||
ValidFrom time.Time `json:"validFrom"`
|
||||
ValidTo time.Time `json:"validTo"`
|
||||
IssuedAt time.Time `json:"issuedAt"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
} `json:"outlooks"`
|
||||
Discussions []struct {
|
||||
UpdatedAt *time.Time `json:"updatedAt"`
|
||||
} `json:"discussions"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func decodeForecastTimePayload(t *testing.T, w *httptest.ResponseRecorder) forecastTimePayload {
|
||||
t.Helper()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user