
























@@ -8,7 +8,19 @@ import {
88import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
99import type { FeishuProbeResult } from "./types.js";
101011-const { probeFeishuMock } = vi.hoisted(() => ({
11+const {
12+ beginAppRegistrationMock,
13+ getAppOwnerOpenIdMock,
14+ initAppRegistrationMock,
15+ pollAppRegistrationMock,
16+ printQrCodeMock,
17+ probeFeishuMock,
18+} = vi.hoisted(() => ({
19+beginAppRegistrationMock: vi.fn(),
20+getAppOwnerOpenIdMock: vi.fn(),
21+initAppRegistrationMock: vi.fn(),
22+pollAppRegistrationMock: vi.fn(),
23+printQrCodeMock: vi.fn(),
1224probeFeishuMock: vi.fn<() => Promise<FeishuProbeResult>>(async () => ({
1325ok: false,
1426error: "mocked",
@@ -20,13 +32,11 @@ vi.mock("./probe.js", () => ({
2032}));
21332234vi.mock("./app-registration.js", () => ({
23-initAppRegistration: vi.fn(async () => {
24-throw new Error("mocked: scan-to-create not available");
25-}),
26-beginAppRegistration: vi.fn(),
27-pollAppRegistration: vi.fn(),
28-printQrCode: vi.fn(async () => {}),
29-getAppOwnerOpenId: vi.fn(async () => undefined),
35+initAppRegistration: initAppRegistrationMock,
36+beginAppRegistration: beginAppRegistrationMock,
37+pollAppRegistration: pollAppRegistrationMock,
38+printQrCode: printQrCodeMock,
39+getAppOwnerOpenId: getAppOwnerOpenIdMock,
3040}));
31413242import { feishuPlugin } from "./channel.js";
@@ -86,6 +96,116 @@ describe("feishu setup wizard", () => {
8696beforeEach(() => {
8797probeFeishuMock.mockReset();
8898probeFeishuMock.mockResolvedValue({ ok: false, error: "mocked" });
99+initAppRegistrationMock.mockReset();
100+initAppRegistrationMock.mockRejectedValue(new Error("mocked: scan-to-create not available"));
101+beginAppRegistrationMock.mockReset();
102+pollAppRegistrationMock.mockReset();
103+printQrCodeMock.mockReset();
104+printQrCodeMock.mockResolvedValue(undefined);
105+getAppOwnerOpenIdMock.mockReset();
106+getAppOwnerOpenIdMock.mockResolvedValue(undefined);
107+});
108+109+it("uses manual credentials by default instead of starting scan-to-create", async () => {
110+const text = vi.fn().mockResolvedValueOnce("cli_manual").mockResolvedValueOnce("secret_manual");
111+const prompter = createTestWizardPrompter({ text });
112+113+const result = await runSetupWizardConfigure({
114+configure: feishuConfigure,
115+cfg: {} as never,
116+ prompter,
117+runtime: createNonExitingRuntimeEnv(),
118+});
119+120+expect(initAppRegistrationMock).not.toHaveBeenCalled();
121+expect(beginAppRegistrationMock).not.toHaveBeenCalled();
122+expect(result.cfg.channels?.feishu).toMatchObject({
123+appId: "cli_manual",
124+appSecret: "secret_manual",
125+connectionMode: "websocket",
126+domain: "feishu",
127+});
128+});
129+130+it("passes selected domain through scan-to-create and poll", async () => {
131+initAppRegistrationMock.mockResolvedValueOnce(undefined);
132+beginAppRegistrationMock.mockResolvedValueOnce({
133+deviceCode: "device-code",
134+qrUrl: "https://accounts.larksuite.com/qr",
135+userCode: "user-code",
136+interval: 1,
137+expireIn: 10,
138+});
139+pollAppRegistrationMock.mockResolvedValueOnce({
140+status: "success",
141+result: {
142+appId: "cli_lark",
143+appSecret: "secret_lark",
144+domain: "lark",
145+openId: "ou_owner",
146+},
147+});
148+const prompter = createTestWizardPrompter({
149+select: vi
150+.fn()
151+.mockResolvedValueOnce("scan")
152+.mockResolvedValueOnce("lark")
153+.mockResolvedValueOnce("open") as never,
154+});
155+156+const result = await runSetupWizardConfigure({
157+configure: feishuConfigure,
158+cfg: {} as never,
159+ prompter,
160+runtime: createNonExitingRuntimeEnv(),
161+});
162+163+expect(initAppRegistrationMock).toHaveBeenCalledWith("lark");
164+expect(beginAppRegistrationMock).toHaveBeenCalledWith("lark");
165+expect(pollAppRegistrationMock).toHaveBeenCalledWith(
166+expect.objectContaining({
167+deviceCode: "device-code",
168+initialDomain: "lark",
169+tp: "ob_cli_app",
170+}),
171+);
172+expect(result.cfg.channels?.feishu).toMatchObject({
173+appId: "cli_lark",
174+appSecret: "secret_lark",
175+domain: "lark",
176+groupPolicy: "open",
177+requireMention: true,
178+});
179+});
180+181+it("falls back to manual credentials when selected scan-to-create is unavailable", async () => {
182+const text = vi
183+.fn()
184+.mockResolvedValueOnce("cli_from_fallback")
185+.mockResolvedValueOnce("secret_from_fallback");
186+const prompter = createTestWizardPrompter({
187+ text,
188+select: vi
189+.fn()
190+.mockResolvedValueOnce("scan")
191+.mockResolvedValueOnce("feishu")
192+.mockResolvedValueOnce("allowlist") as never,
193+});
194+195+const result = await runSetupWizardConfigure({
196+configure: feishuConfigure,
197+cfg: {} as never,
198+ prompter,
199+runtime: createNonExitingRuntimeEnv(),
200+});
201+202+expect(initAppRegistrationMock).toHaveBeenCalledWith("feishu");
203+expect(beginAppRegistrationMock).not.toHaveBeenCalled();
204+expect(result.cfg.channels?.feishu).toMatchObject({
205+appId: "cli_from_fallback",
206+appSecret: "secret_from_fallback",
207+domain: "feishu",
208+});
89209});
9021091211it("prompts over SecretRef appId/appSecret config objects", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。