mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
test: share the first-page and clock helpers
writeFirstPage answers paged listings in app and services tests, testNow replaces the copied clock, withoutANSI the second color stripper, and the single-entry table test becomes a plain test. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
23 files changed
+58
-97
No files matched your search
@@ -122,7 +122,7 @@ func TestCommentGroupCommentsLikeGh(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
run := func(args ...string) error {
|
run := func(args ...string) error {
|
||||||
out.Reset()
|
out.Reset()
|
||||||
diagnostics.Reset()
|
diagnostics.Reset()
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func TestSearchTables(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
||||||
plainOutput(t, deps)
|
plainOutput(t, deps)
|
||||||
deps.Streams.OutTTY = true
|
deps.Streams.OutTTY = true
|
||||||
|
|||||||
@@ -104,16 +104,12 @@ func TestPullViewCommentsIncludeReviews(t *testing.T) {
|
|||||||
case "/api/v1/repos/alice/project/issues/4/comments":
|
case "/api/v1/repos/alice/project/issues/4/comments":
|
||||||
_, _ = w.Write([]byte(`[{"body":"Looks close","user":{"login":"carol"},"created_at":"2026-01-02T00:00:00Z"}]`))
|
_, _ = w.Write([]byte(`[{"body":"Looks close","user":{"login":"carol"},"created_at":"2026-01-02T00:00:00Z"}]`))
|
||||||
case "/api/v1/repos/alice/project/pulls/4/reviews":
|
case "/api/v1/repos/alice/project/pulls/4/reviews":
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[
|
|
||||||
{"id":1,"body":"Please rename","state":"REQUEST_CHANGES","user":{"login":"alice"},"submitted_at":"2026-01-01T12:00:00Z","comments_count":1},
|
{"id":1,"body":"Please rename","state":"REQUEST_CHANGES","user":{"login":"alice"},"submitted_at":"2026-01-01T12:00:00Z","comments_count":1},
|
||||||
{"id":2,"body":"","state":"APPROVED","user":{"login":"dave"},"submitted_at":"2026-01-03T00:00:00Z"},
|
{"id":2,"body":"","state":"APPROVED","user":{"login":"dave"},"submitted_at":"2026-01-03T00:00:00Z"},
|
||||||
{"id":3,"body":"Draft","state":"PENDING","user":{"login":"erin"},"submitted_at":"2026-01-03T00:00:00Z"},
|
{"id":3,"body":"Draft","state":"PENDING","user":{"login":"erin"},"submitted_at":"2026-01-03T00:00:00Z"},
|
||||||
{"id":4,"body":"Great","state":"APPROVED","user":{"login":"alice"},"submitted_at":"2026-01-03T06:00:00Z"}
|
{"id":4,"body":"Great","state":"APPROVED","user":{"login":"alice"},"submitted_at":"2026-01-03T06:00:00Z"}
|
||||||
]`))
|
]`)
|
||||||
case "/api/v1/repos/alice/project/pulls/4/reviews/1/comments":
|
case "/api/v1/repos/alice/project/pulls/4/reviews/1/comments":
|
||||||
_, _ = w.Write([]byte(`[{"id":9,"body":"Typo here","path":"main.go","position":12,"user":{"login":"alice"},"created_at":"2026-01-01T12:00:00Z"}]`))
|
_, _ = w.Write([]byte(`[{"id":9,"body":"Typo here","path":"main.go","position":12,"user":{"login":"alice"},"created_at":"2026-01-01T12:00:00Z"}]`))
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gitea.dev/tea/internal/auth"
|
"gitea.dev/tea/internal/auth"
|
||||||
"gitea.dev/tea/internal/clierr"
|
"gitea.dev/tea/internal/clierr"
|
||||||
@@ -336,3 +337,14 @@ func plainOutput(t *testing.T, deps Dependencies) {
|
|||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeFirstPage answers the first page of a listing with page and every later page with [].
|
||||||
|
func writeFirstPage(w http.ResponseWriter, r *http.Request, page string) {
|
||||||
|
if r.URL.Query().Get("page") != "1" {
|
||||||
|
page = `[]`
|
||||||
|
}
|
||||||
|
_, _ = w.Write([]byte(page))
|
||||||
|
}
|
||||||
|
|
||||||
|
// testNow is the clock of tests that show relative times.
|
||||||
|
var testNow = time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC)
|
||||||
@@ -151,7 +151,7 @@ func TestMultiItemHumanOutputPagesOnce(t *testing.T) {
|
|||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/api/v1/repos/alice/project/milestones":
|
case "/api/v1/repos/alice/project/milestones":
|
||||||
writeMilestones(w, r, `[{"id":3,"title":"v1"}]`)
|
writeFirstPage(w, r, `[{"id":3,"title":"v1"}]`)
|
||||||
case "/api/v1/repos/alice/project/issues":
|
case "/api/v1/repos/alice/project/issues":
|
||||||
_, _ = w.Write([]byte("[" + issue(1) + "," + issue(2) + "]"))
|
_, _ = w.Write([]byte("[" + issue(1) + "," + issue(2) + "]"))
|
||||||
case "/api/v1/repos/alice/project/issues/1", "/api/v1/repos/alice/project/issues/2":
|
case "/api/v1/repos/alice/project/issues/1", "/api/v1/repos/alice/project/issues/2":
|
||||||
@@ -223,32 +223,23 @@ func TestListsFitTheTerminalAndSplitWhenPiped(t *testing.T) {
|
|||||||
`{"number":5,"title":"支持中文路径 (support CJK paths)","state":"open","user":{"login":""}}]`))
|
`{"number":5,"title":"支持中文路径 (support CJK paths)","state":"open","user":{"login":""}}]`))
|
||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
for group, want := range map[string][2]string{
|
|
||||||
"issue": {
|
|
||||||
"6\tA very long issue title that keeps going and going to see how list output handles wrapping\t\topen\tissue\talice\t\n" +
|
|
||||||
"5\t支持中文路径 (support CJK paths)\t\topen\tissue\t\t\n",
|
|
||||||
"Showing 2 of 2 open issues in alice/project\n\n" +
|
|
||||||
"ID TITLE LABELS AUTHOR UPDATED\n" +
|
|
||||||
"#6 A very long issue ti… alice\n" +
|
|
||||||
"#5 支持中文路径 (suppor…\n",
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
t.Run(group, func(t *testing.T) {
|
|
||||||
deps, out, _ := serverDeps(t, server.URL)
|
deps, out, _ := serverDeps(t, server.URL)
|
||||||
args := []string{group, "list", "-R", "alice/project"}
|
args := []string{"issue", "list", "-R", "alice/project"}
|
||||||
require.NoError(t, Execute(context.Background(), deps, args))
|
require.NoError(t, Execute(context.Background(), deps, args))
|
||||||
require.Equal(t, want[0], out.String())
|
require.Equal(t, "6\tA very long issue title that keeps going and going to see how list output handles wrapping\t\topen\tissue\talice\t\n"+
|
||||||
|
"5\t支持中文路径 (support CJK paths)\t\topen\tissue\t\t\n", out.String())
|
||||||
|
|
||||||
out.Reset()
|
out.Reset()
|
||||||
deps.Streams.OutTTY, deps.Streams.Width = true, 50
|
deps.Streams.OutTTY, deps.Streams.Width = true, 50
|
||||||
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
||||||
require.NoError(t, Execute(context.Background(), deps, args))
|
require.NoError(t, Execute(context.Background(), deps, args))
|
||||||
require.Equal(t, want[1], stripLinks(out.String()))
|
require.Equal(t, "Showing 2 of 2 open issues in alice/project\n\n"+
|
||||||
|
"ID TITLE LABELS AUTHOR UPDATED\n"+
|
||||||
|
"#6 A very long issue ti… alice\n"+
|
||||||
|
"#5 支持中文路径 (suppor…\n", stripLinks(out.String()))
|
||||||
for _, line := range strings.Split(strings.TrimSpace(out.String()), "\n") {
|
for _, line := range strings.Split(strings.TrimSpace(out.String()), "\n") {
|
||||||
require.LessOrEqual(t, runewidth.StringWidth(stripLinks(line)), 50, line)
|
require.LessOrEqual(t, runewidth.StringWidth(stripLinks(line)), 50, line)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stripLinks removes OSC 8 hyperlinks from rendered output.
|
// stripLinks removes OSC 8 hyperlinks from rendered output.
|
||||||
@@ -265,7 +256,7 @@ func stripLinks(s string) string {
|
|||||||
|
|
||||||
// outputApplication returns an application over deps and a command writing to its streams.
|
// outputApplication returns an application over deps and a command writing to its streams.
|
||||||
func outputApplication(deps Dependencies, json string) (*application, *cobra.Command) {
|
func outputApplication(deps Dependencies, json string) (*application, *cobra.Command) {
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
a := &application{deps: deps, options: options{json: json}}
|
a := &application{deps: deps, options: options{json: json}}
|
||||||
cmd := &cobra.Command{Use: "list"}
|
cmd := &cobra.Command{Use: "list"}
|
||||||
cmd.SetOut(deps.Streams.Out)
|
cmd.SetOut(deps.Streams.Out)
|
||||||
@@ -335,7 +326,7 @@ func TestWriteView(t *testing.T) {
|
|||||||
view := func(item listed) terminal.View {
|
view := func(item listed) terminal.View {
|
||||||
return terminal.View{
|
return terminal.View{
|
||||||
Title: item.Title, ID: fmt.Sprintf("#%d", item.Number), Badges: []terminal.Cell{{Text: "Open", Color: "green"}},
|
Title: item.Title, ID: fmt.Sprintf("#%d", item.Number), Badges: []terminal.Cell{{Text: "Open", Color: "green"}},
|
||||||
Meta: "alice opened " + terminal.RelativeTime(time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC), item.Updated), Body: "Steps", Kind: "issue", URL: "https://example.org/1",
|
Meta: "alice opened " + terminal.RelativeTime(testNow, item.Updated), Body: "Steps", Kind: "issue", URL: "https://example.org/1",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item := listed{1, "Login fails", time.Date(2026, 10, 11, 18, 0, 0, 0, time.UTC)}
|
item := listed{1, "Login fails", time.Date(2026, 10, 11, 18, 0, 0, 0, time.UTC)}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ func TestAttachmentTablesDownloadsAndDoneLines(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
||||||
plainOutput(t, deps)
|
plainOutput(t, deps)
|
||||||
run := func(tty bool, args ...string) error {
|
run := func(tty bool, args ...string) error {
|
||||||
|
|||||||
@@ -82,11 +82,7 @@ func TestIssueEditAddAndRemoveLabels(t *testing.T) {
|
|||||||
case r.URL.Path == "/api/v1/orgs/alice":
|
case r.URL.Path == "/api/v1/orgs/alice":
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
case r.URL.Path == "/api/v1/repos/alice/project/labels":
|
case r.URL.Path == "/api/v1/repos/alice/project/labels":
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[{"id":1,"name":"bug"},{"id":2,"name":"docs"},{"id":3,"name":"help"}]`)
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[{"id":1,"name":"bug"},{"id":2,"name":"docs"},{"id":3,"name":"help"}]`))
|
|
||||||
case r.Method == http.MethodGet && r.URL.Path == "/api/v1/repos/alice/project/issues/7":
|
case r.Method == http.MethodGet && r.URL.Path == "/api/v1/repos/alice/project/issues/7":
|
||||||
_, _ = w.Write([]byte(`{"number":7,"labels":[{"id":1,"name":"bug"},{"id":2,"name":"docs"}]}`))
|
_, _ = w.Write([]byte(`{"number":7,"labels":[{"id":1,"name":"bug"},{"id":2,"name":"docs"}]}`))
|
||||||
case r.Method == http.MethodPut && r.URL.Path == "/api/v1/repos/alice/project/issues/7/labels":
|
case r.Method == http.MethodPut && r.URL.Path == "/api/v1/repos/alice/project/issues/7/labels":
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package app
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -107,7 +106,7 @@ func TestIssueListTables(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
args := []string{"issue", "list", "-R", "alice/project", "-L", "3"}
|
args := []string{"issue", "list", "-R", "alice/project", "-L", "3"}
|
||||||
require.NoError(t, Execute(context.Background(), deps, args))
|
require.NoError(t, Execute(context.Background(), deps, args))
|
||||||
require.Equal(t, "7\tShort\tbug, priority/high\topen\tissue\talice\t2026-10-11T18:00:00Z\n"+
|
require.Equal(t, "7\tShort\tbug, priority/high\topen\tissue\talice\t2026-10-11T18:00:00Z\n"+
|
||||||
@@ -131,7 +130,7 @@ func TestIssueListTables(t *testing.T) {
|
|||||||
out.Reset()
|
out.Reset()
|
||||||
deps.Streams.OutTTY = true
|
deps.Streams.OutTTY = true
|
||||||
require.NoError(t, Execute(context.Background(), deps, append(append(args, test.args...), "--no-input")))
|
require.NoError(t, Execute(context.Background(), deps, append(append(args, test.args...), "--no-input")))
|
||||||
require.Equal(t, test.want, stripLinks(stripColors(out.String())))
|
require.Equal(t, test.want, stripLinks(withoutANSI(out.String())))
|
||||||
}
|
}
|
||||||
require.Contains(t, out.String(), "\x1b]8;;https://example.org/i/7\x1b\\\x1b[32m#7\x1b[0m\x1b]8;;\x1b\\")
|
require.Contains(t, out.String(), "\x1b]8;;https://example.org/i/7\x1b\\\x1b[32m#7\x1b[0m\x1b]8;;\x1b\\")
|
||||||
require.Contains(t, out.String(), "\x1b[35mmerged\x1b[0m")
|
require.Contains(t, out.String(), "\x1b[35mmerged\x1b[0m")
|
||||||
@@ -158,11 +157,6 @@ func TestIssueListWebOpensTheFilteredPage(t *testing.T) {
|
|||||||
require.Equal(t, server.URL+"/alice/project/issues?q=login+bug&state=closed", browser.resource)
|
require.Equal(t, server.URL+"/alice/project/issues?q=login+bug&state=closed", browser.resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stripColors removes SGR color sequences from rendered output.
|
|
||||||
func stripColors(s string) string {
|
|
||||||
return regexp.MustCompile("\x1b\\[[0-9;]*m").ReplaceAllString(s, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIssueListKindFilter(t *testing.T) {
|
func TestIssueListKindFilter(t *testing.T) {
|
||||||
var seen string
|
var seen string
|
||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func TestIssueCreationMetadataAndReferenceClearing(t *testing.T) {
|
|||||||
calls := 0
|
calls := 0
|
||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path == "/api/v1/repos/owner/repo/milestones" {
|
if r.URL.Path == "/api/v1/repos/owner/repo/milestones" {
|
||||||
writeMilestones(w, r, `[{"id":4,"title":"Release"}]`)
|
writeFirstPage(w, r, `[{"id":4,"title":"Release"}]`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
calls++
|
calls++
|
||||||
|
|||||||
@@ -96,11 +96,7 @@ func TestLabelsByName(t *testing.T) {
|
|||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method + " " + r.URL.Path {
|
switch r.Method + " " + r.URL.Path {
|
||||||
case "GET /api/v1/repos/alice/project/labels":
|
case "GET /api/v1/repos/alice/project/labels":
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, labels)
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(labels))
|
|
||||||
default:
|
default:
|
||||||
changed = append(changed, r.Method+" "+r.URL.Path+" "+requestFields(t, r, "name", "color", "description"))
|
changed = append(changed, r.Method+" "+r.URL.Path+" "+requestFields(t, r, "name", "color", "description"))
|
||||||
if r.Method == http.MethodDelete {
|
if r.Method == http.MethodDelete {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestBulkMilestoneStateContinuesAfterFailureAndKeepsJSONClean(t *testing.T)
|
|||||||
mutations := []string{}
|
mutations := []string{}
|
||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path == "/api/v1/repos/alice/project/milestones" {
|
if r.URL.Path == "/api/v1/repos/alice/project/milestones" {
|
||||||
writeMilestones(w, r, `[{"id":9,"title":"v9"},{"id":10,"title":"v10"},{"id":11,"title":"v11"}]`)
|
writeFirstPage(w, r, `[{"id":9,"title":"v9"},{"id":10,"title":"v10"},{"id":11,"title":"v11"}]`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := strings.TrimPrefix(r.URL.Path, "/api/v1/repos/alice/project/milestones/")
|
id := strings.TrimPrefix(r.URL.Path, "/api/v1/repos/alice/project/milestones/")
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func TestMilestoneTablesViewsAndDoneLines(t *testing.T) {
|
|||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method + " " + r.URL.Path {
|
switch r.Method + " " + r.URL.Path {
|
||||||
case "GET /api/v1/repos/alice/project/milestones":
|
case "GET /api/v1/repos/alice/project/milestones":
|
||||||
writeMilestones(w, r, `[{"id":5,"title":"later","state":"open"},{"id":4,"title":"v0.9","state":"closed","closed_issues":3},`+
|
writeFirstPage(w, r, `[{"id":5,"title":"later","state":"open"},{"id":4,"title":"v0.9","state":"closed","closed_issues":3},`+
|
||||||
`{"id":3,"title":"v1.0","state":"open","description":"First release","due_on":"2026-12-31T00:00:00Z","open_issues":3,"closed_issues":1}]`)
|
`{"id":3,"title":"v1.0","state":"open","description":"First release","due_on":"2026-12-31T00:00:00Z","open_issues":3,"closed_issues":1}]`)
|
||||||
case "GET /api/v1/repos/alice/project/issues/1", "GET /api/v1/repos/alice/project/issues/2":
|
case "GET /api/v1/repos/alice/project/issues/1", "GET /api/v1/repos/alice/project/issues/2":
|
||||||
_, _ = w.Write([]byte(`{"number":1,"milestone":{"id":4,"title":"v0.9"}}`))
|
_, _ = w.Write([]byte(`{"number":1,"milestone":{"id":4,"title":"v0.9"}}`))
|
||||||
@@ -88,7 +88,7 @@ func TestMilestoneTablesViewsAndDoneLines(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
||||||
plainOutput(t, deps)
|
plainOutput(t, deps)
|
||||||
run := func(tty bool, args ...string) {
|
run := func(tty bool, args ...string) {
|
||||||
@@ -132,7 +132,7 @@ func TestMilestoneEditFormStartsFromTheMilestone(t *testing.T) {
|
|||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method + " " + r.URL.Path {
|
switch r.Method + " " + r.URL.Path {
|
||||||
case "GET /api/v1/repos/alice/project/milestones":
|
case "GET /api/v1/repos/alice/project/milestones":
|
||||||
writeMilestones(w, r, `[{"id":3,"title":"v1.0","description":"First","due_on":"2026-12-31T00:00:00Z"}]`)
|
writeFirstPage(w, r, `[{"id":3,"title":"v1.0","description":"First","due_on":"2026-12-31T00:00:00Z"}]`)
|
||||||
case "PATCH /api/v1/repos/alice/project/milestones/3":
|
case "PATCH /api/v1/repos/alice/project/milestones/3":
|
||||||
require.NoError(t, json.NewDecoder(r.Body).Decode(&edited))
|
require.NoError(t, json.NewDecoder(r.Body).Decode(&edited))
|
||||||
_, _ = w.Write([]byte(`{"id":3,"title":"v1.0.0"}`))
|
_, _ = w.Write([]byte(`{"id":3,"title":"v1.0.0"}`))
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func TestMilestoneEditEditorSeedsDescription(t *testing.T) {
|
|||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch {
|
switch {
|
||||||
case r.Method == http.MethodGet && r.URL.Path == "/api/v1/repos/alice/project/milestones":
|
case r.Method == http.MethodGet && r.URL.Path == "/api/v1/repos/alice/project/milestones":
|
||||||
writeMilestones(w, r, `[{"id":4,"title":"Ship","description":"current notes","state":"open"}]`)
|
writeFirstPage(w, r, `[{"id":4,"title":"Ship","description":"current notes","state":"open"}]`)
|
||||||
case r.Method == http.MethodGet && r.URL.Path == "/api/v1/repos/alice/project/milestones/4":
|
case r.Method == http.MethodGet && r.URL.Path == "/api/v1/repos/alice/project/milestones/4":
|
||||||
_, _ = w.Write([]byte(`{"id":4,"title":"Ship","description":"current notes","state":"open"}`))
|
_, _ = w.Write([]byte(`{"id":4,"title":"Ship","description":"current notes","state":"open"}`))
|
||||||
case r.Method == http.MethodPatch && r.URL.Path == "/api/v1/repos/alice/project/milestones/4":
|
case r.Method == http.MethodPatch && r.URL.Path == "/api/v1/repos/alice/project/milestones/4":
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func TestMilestoneDeleteReturnsJSONSnapshotOnlyAfterSuccess(t *testing.T) {
|
|||||||
calls = append(calls, r.Method)
|
calls = append(calls, r.Method)
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
require.Equal(t, "/api/v1/repos/alice/project/milestones", r.URL.Path)
|
require.Equal(t, "/api/v1/repos/alice/project/milestones", r.URL.Path)
|
||||||
writeMilestones(w, r, `[{"id":9,"title":"Release one","state":"open"}]`)
|
writeFirstPage(w, r, `[{"id":9,"title":"Release one","state":"open"}]`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
require.Equal(t, "/api/v1/repos/alice/project/milestones/9", r.URL.Path)
|
require.Equal(t, "/api/v1/repos/alice/project/milestones/9", r.URL.Path)
|
||||||
@@ -118,14 +118,6 @@ func TestMilestoneIssueCommandsSelectByName(t *testing.T) {
|
|||||||
require.ErrorContains(t, err, "milestone title or ID cannot be empty")
|
require.ErrorContains(t, err, "milestone title or ID cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeMilestones answers a milestone listing with page, a JSON array, as its first and only page.
|
|
||||||
func writeMilestones(w http.ResponseWriter, r *http.Request, page string) {
|
|
||||||
if r.URL.Query().Get("page") != "1" {
|
|
||||||
page = `[]`
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(page))
|
|
||||||
}
|
|
||||||
|
|
||||||
// payloadField returns the JSON request body's field name as text.
|
// payloadField returns the JSON request body's field name as text.
|
||||||
func payloadField(t *testing.T, r *http.Request, name string) string {
|
func payloadField(t *testing.T, r *http.Request, name string) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@@ -139,7 +131,7 @@ func TestMilestonesAcceptTitlesOrIDs(t *testing.T) {
|
|||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method + " " + r.URL.Path {
|
switch r.Method + " " + r.URL.Path {
|
||||||
case "GET /api/v1/repos/alice/project/milestones":
|
case "GET /api/v1/repos/alice/project/milestones":
|
||||||
writeMilestones(w, r, `[{"id":3,"title":"v1.0","state":"open"},{"id":4,"title":"2026","state":"closed"},{"id":5,"title":"v2.0"}]`)
|
writeFirstPage(w, r, `[{"id":3,"title":"v1.0","state":"open"},{"id":4,"title":"2026","state":"closed"},{"id":5,"title":"v2.0"}]`)
|
||||||
case "GET /api/v1/repos/alice/project/milestones/3", "GET /api/v1/repos/alice/project/milestones/4":
|
case "GET /api/v1/repos/alice/project/milestones/3", "GET /api/v1/repos/alice/project/milestones/4":
|
||||||
_, _ = w.Write([]byte(`{"id":3,"title":"v1.0","state":"open"}`))
|
_, _ = w.Write([]byte(`{"id":3,"title":"v1.0","state":"open"}`))
|
||||||
case "PATCH /api/v1/repos/alice/project/milestones/3", "PATCH /api/v1/repos/alice/project/milestones/4":
|
case "PATCH /api/v1/repos/alice/project/milestones/3", "PATCH /api/v1/repos/alice/project/milestones/4":
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ func TestNotificationsListTheInboxByDefault(t *testing.T) {
|
|||||||
}
|
}
|
||||||
deps, out, _ := serverDeps(t, server.URL)
|
deps, out, _ := serverDeps(t, server.URL)
|
||||||
deps.Streams.OutTTY, deps.Streams.Width = true, 100
|
deps.Streams.OutTTY, deps.Streams.Width = true, 100
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
require.NoError(t, Execute(context.Background(), deps, []string{"notification", "list"}))
|
require.NoError(t, Execute(context.Background(), deps, []string{"notification", "list"}))
|
||||||
require.Equal(t, `Showing 2 of 2 unread or pinned notifications in your inbox
|
require.Equal(t, `Showing 2 of 2 unread or pinned notifications in your inbox
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,7 @@ func TestPullDiffColorsHeadersAndHunks(t *testing.T) {
|
|||||||
func TestPullDiffNameOnly(t *testing.T) {
|
func TestPullDiffNameOnly(t *testing.T) {
|
||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
require.Equal(t, "/api/v1/repos/alice/project/pulls/2/files", r.URL.Path)
|
require.Equal(t, "/api/v1/repos/alice/project/pulls/2/files", r.URL.Path)
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[{"filename":"one.txt"},{"filename":"docs/two.md"}]`)
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[{"filename":"one.txt"},{"filename":"docs/two.md"}]`))
|
|
||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, _ := serverDeps(t, server.URL)
|
deps, out, _ := serverDeps(t, server.URL)
|
||||||
|
|||||||
@@ -64,17 +64,13 @@ func refApplication(t *testing.T, gitResults map[string]string) (*application, s
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
require.Equal(t, "/api/v1/repos/alice/project/pulls", r.URL.Path)
|
require.Equal(t, "/api/v1/repos/alice/project/pulls", r.URL.Path)
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[
|
|
||||||
{"number":3,"head":{"ref":"feat/one","repo":{"full_name":"alice/project"}}},
|
{"number":3,"head":{"ref":"feat/one","repo":{"full_name":"alice/project"}}},
|
||||||
{"number":4,"head":{"ref":"feat/two","repo":{"full_name":"alice/project"}}},
|
{"number":4,"head":{"ref":"feat/two","repo":{"full_name":"alice/project"}}},
|
||||||
{"number":17,"head":{"ref":"fix","repo":{"full_name":"bob/project"}}},
|
{"number":17,"head":{"ref":"fix","repo":{"full_name":"bob/project"}}},
|
||||||
{"number":20,"head":{"ref":"dup","repo":{"full_name":"alice/project"}}},
|
{"number":20,"head":{"ref":"dup","repo":{"full_name":"alice/project"}}},
|
||||||
{"number":21,"head":{"ref":"dup","repo":{"full_name":"carol/project"}}}
|
{"number":21,"head":{"ref":"dup","repo":{"full_name":"carol/project"}}}
|
||||||
]`))
|
]`)
|
||||||
}))
|
}))
|
||||||
t.Cleanup(server.Close)
|
t.Cleanup(server.Close)
|
||||||
deps, _, _ := testDeps(t)
|
deps, _, _ := testDeps(t)
|
||||||
|
|||||||
@@ -151,11 +151,7 @@ func TestRepoForkReportsAnExistingFork(t *testing.T) {
|
|||||||
w.WriteHeader(http.StatusConflict)
|
w.WriteHeader(http.StatusConflict)
|
||||||
_, _ = w.Write([]byte(`{"message":"repository is already forked by user [uname: alice, repo path: bob/project, fork path: alice/project-fork]"}`))
|
_, _ = w.Write([]byte(`{"message":"repository is already forked by user [uname: alice, repo path: bob/project, fork path: alice/project-fork]"}`))
|
||||||
case "GET /api/v1/repos/bob/project/forks":
|
case "GET /api/v1/repos/bob/project/forks":
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[{"full_name":"carol/project","owner":{"login":"carol"}},{"full_name":"alice/project-fork","owner":{"login":"alice"}}]`)
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[{"full_name":"carol/project","owner":{"login":"carol"}},{"full_name":"alice/project-fork","owner":{"login":"alice"}}]`))
|
|
||||||
case "GET /api/v1/repos/alice/project-fork":
|
case "GET /api/v1/repos/alice/project-fork":
|
||||||
_, _ = w.Write([]byte(`{"full_name":"alice/project-fork","fork":true,"html_url":"https://gitea.test/alice/project-fork","parent":{"full_name":"bob/project"}}`))
|
_, _ = w.Write([]byte(`{"full_name":"alice/project-fork","fork":true,"html_url":"https://gitea.test/alice/project-fork","parent":{"full_name":"bob/project"}}`))
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func repoTTYDeps(t *testing.T, serverURL string) (Dependencies, *bytes.Buffer, *
|
|||||||
deps, out, diagnostics := serverDeps(t, serverURL)
|
deps, out, diagnostics := serverDeps(t, serverURL)
|
||||||
deps.Getenv = serverEnv(serverURL, map[string]string{"TERM": "dumb"})
|
deps.Getenv = serverEnv(serverURL, map[string]string{"TERM": "dumb"})
|
||||||
deps.Streams.OutTTY, deps.Streams.Width = true, 100
|
deps.Streams.OutTTY, deps.Streams.Width = true, 100
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
return deps, out, diagnostics
|
return deps, out, diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,12 +64,8 @@ func TestTimeTablesAndDoneLines(t *testing.T) {
|
|||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method + " " + r.URL.Path {
|
switch r.Method + " " + r.URL.Path {
|
||||||
case "GET /api/v1/repos/alice/project/times", "GET /api/v1/repos/alice/project/issues/1/times":
|
case "GET /api/v1/repos/alice/project/times", "GET /api/v1/repos/alice/project/issues/1/times":
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[{"id":8,"time":5400,"created":"2026-10-11T18:00:00Z","user_name":"alice","issue":{"number":1,"title":"Login fails","repository":{"full_name":"alice/project"}}},`+
|
||||||
_, _ = w.Write([]byte(`[]`))
|
`{"id":9,"time":900,"created":"2026-10-11T19:00:00Z","user_name":"bob","issue":{"number":2,"title":"Docs"}}]`)
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[{"id":8,"time":5400,"created":"2026-10-11T18:00:00Z","user_name":"alice","issue":{"number":1,"title":"Login fails","repository":{"full_name":"alice/project"}}},` +
|
|
||||||
`{"id":9,"time":900,"created":"2026-10-11T19:00:00Z","user_name":"bob","issue":{"number":2,"title":"Docs"}}]`))
|
|
||||||
case "POST /api/v1/repos/alice/project/issues/1/times":
|
case "POST /api/v1/repos/alice/project/issues/1/times":
|
||||||
changed = append(changed, r.Method+" "+r.URL.Path)
|
changed = append(changed, r.Method+" "+r.URL.Path)
|
||||||
_, _ = w.Write([]byte(`{"id":10,"time":5100,"user_name":"alice","issue":{"number":1,"title":"Login fails"}}`))
|
_, _ = w.Write([]byte(`{"id":10,"time":5100,"user_name":"alice","issue":{"number":1,"title":"Login fails"}}`))
|
||||||
@@ -80,7 +76,7 @@ func TestTimeTablesAndDoneLines(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||||
deps.Now = func() time.Time { return time.Date(2026, 10, 11, 20, 0, 0, 0, time.UTC) }
|
deps.Now = func() time.Time { return testNow }
|
||||||
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
deps.Getenv = serverEnv(server.URL, map[string]string{"NO_COLOR": "1"})
|
||||||
deps.Streams.OutTTY = true
|
deps.Streams.OutTTY = true
|
||||||
run := func(args ...string) error {
|
run := func(args ...string) error {
|
||||||
|
|||||||
@@ -34,11 +34,7 @@ func TestWikiEditRenamesAndKeepsTheContent(t *testing.T) {
|
|||||||
|
|
||||||
func TestWikiListLimitsPagesOnTheClient(t *testing.T) {
|
func TestWikiListLimitsPagesOnTheClient(t *testing.T) {
|
||||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[{"title":"Getting Started","last_commit":{"author":{"name":"alice","date":"2026-10-11T18:00:00Z"}}},{"title":"Home"}]`)
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[{"title":"Getting Started","last_commit":{"author":{"name":"alice","date":"2026-10-11T18:00:00Z"}}},{"title":"Home"}]`))
|
|
||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
deps, out, _ := repoTTYDeps(t, server.URL)
|
deps, out, _ := repoTTYDeps(t, server.URL)
|
||||||
|
|||||||
@@ -75,3 +75,11 @@ func TestNameOrIDPrefersIDsThenExactThenFoldedNames(t *testing.T) {
|
|||||||
require.Equal(t, tc.want, got.id, tc.raw)
|
require.Equal(t, tc.want, got.id, tc.raw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeFirstPage answers the first page of a listing with page and every later page with [].
|
||||||
|
func writeFirstPage(w http.ResponseWriter, r *http.Request, page string) {
|
||||||
|
if r.URL.Query().Get("page") != "1" {
|
||||||
|
page = `[]`
|
||||||
|
}
|
||||||
|
_, _ = w.Write([]byte(page))
|
||||||
|
}
|
||||||
@@ -76,11 +76,7 @@ func TestWikiListAndRevisionsMapCommits(t *testing.T) {
|
|||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/api/v1/repos/alice/project/wiki/pages":
|
case "/api/v1/repos/alice/project/wiki/pages":
|
||||||
assert.Equal(t, "50", r.URL.Query().Get("limit"))
|
assert.Equal(t, "50", r.URL.Query().Get("limit"))
|
||||||
if r.URL.Query().Get("page") != "1" {
|
writeFirstPage(w, r, `[{"title":"Other"},{"title":"Home","html_url":"https://gitea.test/wiki/Home","last_commit":{"sha":"abc","author":{"name":"Alice","email":"author@example.test","date":"2026-10-04T00:00:00Z"}}},{"title":"Draft"}]`)
|
||||||
_, _ = w.Write([]byte(`[]`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, _ = w.Write([]byte(`[{"title":"Other"},{"title":"Home","html_url":"https://gitea.test/wiki/Home","last_commit":{"sha":"abc","author":{"name":"Alice","email":"author@example.test","date":"2026-10-04T00:00:00Z"}}},{"title":"Draft"}]`))
|
|
||||||
case "/api/v1/repos/alice/project/wiki/revisions/Home":
|
case "/api/v1/repos/alice/project/wiki/revisions/Home":
|
||||||
assert.Equal(t, "3", r.URL.Query().Get("page"))
|
assert.Equal(t, "3", r.URL.Query().Get("page"))
|
||||||
_, _ = w.Write([]byte(`{"commits":[{"sha":"abc","message":"Edit","author":{"name":"Alice","email":"author@example.test","date":"2026-10-04T00:00:00Z"}},{"sha":"def","author":null}],"count":2}`))
|
_, _ = w.Write([]byte(`{"commits":[{"sha":"abc","message":"Edit","author":{"name":"Alice","email":"author@example.test","date":"2026-10-04T00:00:00Z"}},{"sha":"def","author":null}],"count":2}`))
|
||||||
|
|||||||
Reference in new issue
Block a user