diff --git a/cmd/auth/login_test.go b/cmd/auth/login_test.go index f52d318a83..50b7f3fc27 100644 --- a/cmd/auth/login_test.go +++ b/cmd/auth/login_test.go @@ -23,6 +23,7 @@ import ( "github.com/larksuite/cli/internal/output" "github.com/larksuite/cli/internal/recovery" "github.com/larksuite/cli/internal/registry" + "github.com/larksuite/cli/shortcuts" "github.com/larksuite/cli/shortcuts/common" "github.com/zalando/go-keyring" ) @@ -310,6 +311,54 @@ func TestGetDomainMetadata_HasTitleAndDescription(t *testing.T) { } } +// TestEveryRegisteredDomain_HasBilingualDescription reconciles every registered +// business domain against service_descriptions.json. +// +// TestGetDomainMetadata_HasTitleAndDescription does not cover this. It asserts on +// buildDomainMeta's output, which falls back to the typed service spec when the +// config has no entry — and that spec carries one string for both languages. So a +// domain missing from the config still passes it, while rendering (for example) a +// Chinese description in English `--help`. attendance and mindnotes shipped that +// way. Asserting on the registry getters checks the config itself, before any +// fallback can paper over the gap. +// +// EmbeddedServicesTyped is the overlay-free parse, so this stays deterministic +// whatever ~/.lark-cli/cache/remote_meta.json happens to hold on the machine. +// A domain that only ever arrives via remote overlay is out of reach here. +func TestEveryRegisteredDomain_HasBilingualDescription(t *testing.T) { + origin := make(map[string]string) // domain name → where it is registered + for _, svc := range registry.EmbeddedServicesTyped() { + origin[svc.Name] = "embedded API meta" + } + for _, sc := range shortcuts.AllShortcuts() { + if _, ok := origin[sc.Service]; !ok { + origin[sc.Service] = "shortcut registration" + } + } + if len(origin) == 0 { + t.Fatal("no registered domains found — the reconciliation would be vacuous") + } + + names := make([]string, 0, len(origin)) + for name := range origin { + names = append(names, name) + } + sort.Strings(names) + + for _, name := range names { + for _, lang := range []string{"en", "zh"} { + if registry.GetServiceTitle(name, lang) == "" { + t.Errorf("domain %q (registered via %s) has no %s title in service_descriptions.json", + name, origin[name], lang) + } + if registry.GetServiceDescription(name, lang) == "" { + t.Errorf("domain %q (registered via %s) has no %s description in service_descriptions.json", + name, origin[name], lang) + } + } + } +} + func TestAuthLoginRun_NonTerminal_NoFlags_RejectsWithHint(t *testing.T) { f, _, stderr, _ := cmdutil.TestFactory(t, &core.CliConfig{ AppID: "cli_test", AppSecret: "secret", Brand: core.BrandFeishu, diff --git a/internal/registry/service_descriptions.json b/internal/registry/service_descriptions.json index 6eea55e7ae..75bad04ec7 100644 --- a/internal/registry/service_descriptions.json +++ b/internal/registry/service_descriptions.json @@ -11,6 +11,10 @@ "en": { "title": "Apps", "description": "Develop, deploy HTML, web pages and applications" }, "zh": { "title": "应用", "description": "开发、部署 HTML、Web 页面和应用" } }, + "attendance": { + "en": { "title": "Attendance", "description": "Attendance check-in result query" }, + "zh": { "title": "考勤打卡", "description": "考勤打卡结果查询" } + }, "base": { "en": { "title": "Base", "description": "Table, field, record, view, dashboard, workflow, form, role & permission management" }, "zh": { "title": "多维表格", "description": "数据表、字段、记录、视图、仪表盘、自动化流程、表单、角色权限管理" } @@ -47,6 +51,10 @@ "en": { "title": "Markdown", "description": "Drive-native Markdown file create, fetch, and overwrite" }, "zh": { "title": "Markdown", "description": "Drive 原生 Markdown 文件的创建、读取和覆盖更新" } }, + "mindnotes": { + "en": { "title": "Mindnote", "description": "Mindnote node listing, creation, and update" }, + "zh": { "title": "思维笔记", "description": "思维笔记节点查询、创建和更新" } + }, "minutes": { "en": { "title": "Minutes", "description": "Minutes content and metadata retrieval" }, "zh": { "title": "妙记", "description": "妙记信息获取、内容查询" }