Files
larksuite__cli/shortcuts/minutes/minutes_update_test.go
2026-07-14 19:31:29 +08:00

178 lines
4.9 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package minutes
import (
"errors"
"net/http"
"strings"
"testing"
"github.com/larksuite/cli/errs"
"github.com/larksuite/cli/internal/cmdutil"
"github.com/larksuite/cli/internal/httpmock"
"github.com/spf13/cobra"
)
const minutesUpdateTestToken = "obcnexampleminute"
func TestMinutesUpdate_Validate(t *testing.T) {
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
f, _, _, _ := cmdutil.TestFactory(t, defaultConfig())
tests := []struct {
name string
args []string
wantErr string
}{
{
name: "missing minute token",
args: []string{"+update", "--topic", "new title", "--as", "user"},
wantErr: "required flag(s) \"minute-token\" not set",
},
{
name: "missing topic",
args: []string{"+update", "--minute-token", minutesUpdateTestToken, "--as", "user"},
wantErr: "required flag(s) \"topic\" not set",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
parent := &cobra.Command{Use: "minutes"}
MinutesUpdate.Mount(parent, f)
parent.SetArgs(tt.args)
parent.SilenceErrors = true
parent.SilenceUsage = true
err := parent.Execute()
if err == nil {
t.Fatalf("expected error, got nil")
}
if !strings.Contains(err.Error(), tt.wantErr) {
t.Errorf("error should contain %q, got: %s", tt.wantErr, err.Error())
}
})
}
}
func TestMinutesUpdate_ValidateTyped(t *testing.T) {
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
f, _, _, _ := cmdutil.TestFactory(t, defaultConfig())
// ".." triggers ResourceName rejection — hits our Validate, not cobra's required-flag check.
parent := &cobra.Command{Use: "minutes"}
MinutesUpdate.Mount(parent, f)
parent.SetArgs([]string{"+update", "--minute-token", "..", "--topic", "title", "--as", "user"})
parent.SilenceErrors = true
parent.SilenceUsage = true
err := parent.Execute()
if err == nil {
t.Fatalf("expected error, got nil")
}
var ve *errs.ValidationError
if !errors.As(err, &ve) {
t.Fatalf("want *errs.ValidationError, got %T", err)
}
if ve.Subtype != errs.SubtypeInvalidArgument {
t.Errorf("subtype=%q", ve.Subtype)
}
if ve.Param != "--minute-token" {
t.Errorf("param=%q", ve.Param)
}
}
func TestMinutesUpdate_DryRun(t *testing.T) {
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
f, stdout, _, _ := cmdutil.TestFactory(t, defaultConfig())
warmTokenCache(t)
err := mountAndRun(t, MinutesUpdate, []string{
"+update",
"--minute-token", minutesUpdateTestToken,
"--topic", "周会纪要",
"--dry-run", "--as", "user",
}, f, stdout)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
out := stdout.String()
if !strings.Contains(out, "PATCH") {
t.Errorf("expected PATCH method, got:\n%s", out)
}
if !strings.Contains(out, "/open-apis/minutes/v1/minutes/"+minutesUpdateTestToken) {
t.Errorf("expected PATCH /open-apis/minutes/v1/minutes/<token>, got:\n%s", out)
}
if !strings.Contains(out, "周会纪要") {
t.Errorf("expected topic in body, got:\n%s", out)
}
}
func TestMinutesUpdate_Execute(t *testing.T) {
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
f, stdout, _, reg := cmdutil.TestFactory(t, defaultConfig())
warmTokenCache(t)
reg.Register(&httpmock.Stub{
Method: http.MethodPatch,
URL: "/open-apis/minutes/v1/minutes/" + minutesUpdateTestToken,
Body: map[string]interface{}{
"code": 0,
"msg": "ok",
"data": map[string]interface{}{},
},
})
err := mountAndRun(t, MinutesUpdate, []string{
"+update",
"--minute-token", minutesUpdateTestToken,
"--topic", "新标题",
"--format", "json", "--as", "user",
}, f, stdout)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
func TestMinutesUpdate_NoEditPermission(t *testing.T) {
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
f, stdout, _, reg := cmdutil.TestFactory(t, defaultConfig())
warmTokenCache(t)
reg.Register(&httpmock.Stub{
Method: http.MethodPatch,
URL: "/open-apis/minutes/v1/minutes/" + minutesUpdateTestToken,
Body: map[string]interface{}{
"code": 2091005,
"msg": "no edit permission",
},
})
err := mountAndRun(t, MinutesUpdate, []string{
"+update",
"--minute-token", minutesUpdateTestToken,
"--topic", "新标题",
"--format", "json", "--as", "user",
}, f, stdout)
if err == nil {
t.Fatal("expected no-edit-permission error, got nil")
}
p, ok := errs.ProblemOf(err)
if !ok {
t.Fatalf("want typed errs.*, got %T: %v", err, err)
}
if p.Subtype != errs.SubtypePermissionDenied {
t.Errorf("subtype = %q, want %q", p.Subtype, errs.SubtypePermissionDenied)
}
if !strings.Contains(p.Message, "No edit permission") {
t.Errorf("message should be friendly, got: %s", p.Message)
}
if !strings.Contains(p.Message, minutesUpdateTestToken) {
t.Errorf("message should include minute token, got: %s", p.Message)
}
if !strings.Contains(p.Hint, "+apply-permission") {
t.Errorf("hint should mention apply-permission, got: %s", p.Hint)
}
}