Files
magpie/internal/gui/update_notes_test.go
T
yetone 47f0824c6b gui: the update sheet names the newest release, not the one downloaded hours ago (#910, Moody-Sin), and Names & levels folds where it opened and opens folded (#868, Hu9956)
#910: the header's Update sheet said "Update to v0.1.1020" with v0.1.1024 out. The sheet shows the update the updater downloaded at its last look at the feed, which is every six hours by default (Settings' UpdateEvery), and releases come several a day; usemagpie.ai's feed was current (it answers v0.1.1031 now). The restart itself already asked the feed again (recheck), so only the sheet was behind. Now GET /api/update/notes first asks the feed again, as the restart does, when a version is downloaded and waiting and the feed was last asked over five minutes ago; a newer release starts downloading and the restart waits for it, as one after a recheck does. The answer carries latest, and the sheet retitles itself "Update to v<newest>" with every release's notes up to it. TestUpdateNotesAskTheFeedAgain (a download of 0.1.1020 three hours old, a feed at 0.1.1024: the answer names 0.1.1024 with both releases' notes; asked a moment ago, the feed isn't asked) and update-notes-ask.test.cjs' new case (the sheet names v0.1.403 and lists three releases when the notes name it) fail without the change.

#868 (Hu9956): once Names & levels was open (to set Provider in model names) it couldn't be closed: the only way was its button under the list, out of sight below it, and naming is page state, so it stayed open in every provider editor after until magpie restarted. Now the open list has a quiet title (Names & levels) and Fold at its top, held there while its rows scroll; Fold folds it, the button under the list reads off again and takes the focus, nothing scrolls. An editor opened afresh (no draft yet) has it folded; one redrawn keeps it as it was. en/zh/ja/de ("Fold", "Fold Names & levels"). names-fold.test.cjs (WebKit, en/zh/ja/de: opens folded, the title and Fold, Fold stays at the top while the rows scroll, picking Not on names I set leaves it open and foldable, Fold folds it and turns the button off without scrolling, no left border, a fresh editor opens folded, no select) fails on the old code; name-suffix-where-named, model-price-edit, provider-levels-save, provider-same-as, provider-detect, provider-detect-models, readable-focus and click-scroll pass in WebKit; model-api-preset and provider-levels-scroll fail the same on origin/main. The editor's other fields aren't regrouped.

go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass (TestUserPath and TestClaudeSignedOut timed out once under load and pass alone).
2026-10-05 22:26:54 +08:00

138 lines
5.1 KiB
Go

package gui
import (
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
"time"
"github.com/yetone/magpie/internal/update"
)
// Before an update is put in, the page asks what changed (Hu9956, #844):
// every release after this one up to the update's, newest first, without
// their Install sections; the site's list out of reach, the update's own
// notes; no update, none.
func TestUpdateNotesRoute(t *testing.T) {
feed := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("after") != "0.1.604" || r.URL.Query().Get("upto") != "0.1.607" {
t.Errorf("asked %s", r.URL.RawQuery)
}
json.NewEncoder(w).Encode(map[string]any{"releases": []update.Note{
{Version: "0.1.607", Notes: "- seven\n\n### Install\n\nlinks"},
{Version: "0.1.606", Notes: "- six"},
{Version: "0.1.605", Notes: "- five"},
{Version: "0.1.604", Notes: "- four"},
}})
}))
defer feed.Close()
t.Setenv("MAGPIE_NOTES_FEED", feed.URL)
t.Setenv("MAGPIE_UPDATE_FEED", "http://127.0.0.1:1/")
oldV, oldState, oldLatest, oldIn := Version, updates.state, updates.latest, updates.notesIn
defer func() { Version, updates.state, updates.latest, updates.notesIn = oldV, oldState, oldLatest, oldIn }()
Version = "0.1.604"
updates.mu.Lock()
updates.state, updates.latest, updates.notesIn = "ready", &update.Release{Version: "0.1.607", Notes: "- seven only"}, "en"
updates.mu.Unlock()
mux := http.NewServeMux()
updateRoutes(mux, nil)
get := func() (out struct {
Releases []update.Note `json:"releases"`
Error string `json:"error"`
}) {
rw := httptest.NewRecorder()
mux.ServeHTTP(rw, httptest.NewRequest("GET", "/api/update/notes?lang=en", nil))
if rw.Code != 200 {
t.Fatalf("%d %s", rw.Code, rw.Body)
}
json.Unmarshal(rw.Body.Bytes(), &out)
return out
}
j := get()
var vs []string
for _, n := range j.Releases {
vs = append(vs, n.Version)
}
if len(vs) != 3 || vs[0] != "0.1.607" || vs[2] != "0.1.605" || j.Releases[0].Notes != "- seven" {
t.Fatalf("between: %+v", j)
}
// the site's list out of reach: the update's own notes
t.Setenv("MAGPIE_NOTES_FEED", "http://127.0.0.1:1/")
if j := get(); len(j.Releases) != 1 || j.Releases[0].Version != "0.1.607" || j.Releases[0].Notes != "- seven only" {
t.Fatalf("fallback: %+v", j)
}
// no update: no notes
updates.mu.Lock()
updates.state, updates.latest = "latest", nil
updates.mu.Unlock()
if j := get(); len(j.Releases) != 0 || j.Error != "" {
t.Fatalf("none: %+v", j)
}
}
// The dialog asks the feed again when it was last asked a while ago (#910,
// Moody-Sin: it stopped at v0.1.1020, downloaded hours before, with
// v0.1.1024 out): the newest release is the one it names, with the notes
// of every release up to it.
func TestUpdateNotesAskTheFeedAgain(t *testing.T) {
feedAsked := 0
feed := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
feedAsked++
json.NewEncoder(w).Encode(update.Release{Version: "0.1.1024", Notes: "- twenty-four"})
}))
defer feed.Close()
notes := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
upto := r.URL.Query().Get("upto")
all := []update.Note{{Version: "0.1.1024", Notes: "- twenty-four"}, {Version: "0.1.1020", Notes: "- twenty"}}
if upto == "0.1.1020" {
all = all[1:]
}
json.NewEncoder(w).Encode(map[string]any{"releases": all})
}))
defer notes.Close()
t.Setenv("MAGPIE_UPDATE_FEED", feed.URL)
t.Setenv("MAGPIE_NOTES_FEED", notes.URL)
updates.mu.Lock()
oldState, oldStaged, oldIn, oldLatest, oldAsked, oldV := updates.state, updates.staged, updates.notesIn, updates.latest, updates.asked, Version
Version = "0.1.1010"
// downloaded hours ago; this test's updater can't replace the app, so
// the newer release is left "available" rather than downloaded
updates.state, updates.staged, updates.notesIn = "ready", filepath.Join(t.TempDir(), "staged"), "en"
updates.latest, updates.asked = &update.Release{Version: "0.1.1020", Notes: "- twenty"}, time.Now().Add(-3*time.Hour)
updates.mu.Unlock()
defer func() {
updates.mu.Lock()
updates.state, updates.staged, updates.notesIn, updates.latest, updates.asked, Version = oldState, oldStaged, oldIn, oldLatest, oldAsked, oldV
updates.mu.Unlock()
}()
mux := http.NewServeMux()
updateRoutes(mux, nil)
get := func() (out struct {
Latest string `json:"latest"`
Releases []update.Note `json:"releases"`
}) {
rw := httptest.NewRecorder()
mux.ServeHTTP(rw, httptest.NewRequest("GET", "/api/update/notes?lang=en", nil))
json.Unmarshal(rw.Body.Bytes(), &out)
return out
}
if j := get(); j.Latest != "0.1.1024" || len(j.Releases) != 2 || j.Releases[0].Version != "0.1.1024" {
t.Fatalf("stale: %+v", j)
}
// asked a moment ago: not again
updates.mu.Lock()
updates.state, updates.staged = "ready", filepath.Join(t.TempDir(), "staged")
updates.latest, updates.asked = &update.Release{Version: "0.1.1020", Notes: "- twenty"}, time.Now()
updates.mu.Unlock()
feedAsked = 0
if j := get(); j.Latest != "0.1.1020" || feedAsked != 0 || !strings.Contains(j.Releases[0].Notes, "twenty") {
t.Fatalf("fresh: %+v, feed asked %d", j, feedAsked)
}
}