Skip to content

test(imbot/feishu): wire-level tests against a fake Feishu server#1136

Open
0x0079 wants to merge 1 commit into
claude/fervent-cori-YOHZEfrom
claude/fervent-cori-YOHZE-tests
Open

test(imbot/feishu): wire-level tests against a fake Feishu server#1136
0x0079 wants to merge 1 commit into
claude/fervent-cori-YOHZEfrom
claude/fervent-cori-YOHZE-tests

Conversation

@0x0079

@0x0079 0x0079 commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #1109. Adds a verification layer so Feishu correctness can be checked by go test instead of by clicking buttons in a real Feishu client.

Why

Manual Feishu interaction is expensive and shouldn't be the primary way to verify changes. The previous PRs covered the decode half (event → core.Message) with pure unit tests, but the encode half — the exact HTTP request we send — was only verifiable by hand. That's precisely where the regressions hit: a wrong receive_id_type (open_id cross app), a keyboard that silently vanished, media sent to the wrong endpoint.

How

The Lark SDK lets you inject the base URL and HTTP client (WithOpenBaseUrl + WithHttpClient, where HttpClient is a one-method interface — the SDK's own tests do this). So we point b.client at a local httptest.Server, call each send path, and assert the recorded request. No credentials, no network, deterministic in CI.

bot.client = lark.NewClient("cli_x", "sec_x",
    lark.WithOpenBaseUrl(fake.URL),
    lark.WithHttpClient(fake.Client()))
bot.MarkReady()

Coverage

  • SendMessage plain textmsg_type=text, receive_id_type=open_id for ou_.
  • SendMessage + inline keyboardreceive_id_type=chat_id for oc_, msg_type=interactive, and the button actually renders in the card body (guards both the open_id cross app bug and the vanishing-keyboard bug).
  • SendMessage + card_json — sent verbatim as an interactive message.
  • sendMedia image / file — uploads to /im/v1/images|files first, then a create with the returned key plumbed into the body.
  • EditMessagePATCH /im/v1/messages/:id; DeleteMessageDELETE; ReactPOST .../reactions with the emoji.
  • Inbound replayconvertLarkMessageToCore on an image message yields a feishu://<key> media attachment and a chat-id reply target.

Proof the tests have teeth

Reverting getReceiveIdType to the old buggy mapping (oc_ → open_id) makes the wire test fail with wire_test.go: receive_id_type = "open_id", want chat_id — i.e. it catches the exact open_id cross app regression locally, before any real Feishu call. Restoring the fix turns it green.

Net effect on verification

"Is this change correct?" becomes answerable by go test ./imbot/platform/feishu/.... A real Feishu bot is then only needed for a per-release smoke check that the card actually renders and the WebSocket delivers events — not per change. The existing feishu_e2e_test.go (behind the e2e build tag) already covers that.

https://claude.ai/code/session_014ThTKs7Ft4zptY2pQJDpjZ


Generated by Claude Code

Point the Lark SDK HTTP client at a local httptest server (via
WithOpenBaseUrl + WithHttpClient) and assert the exact outgoing request
for each send path — no real credentials, no manual interaction, runs in
CI deterministically.

Coverage:
- SendMessage plain text: msg_type=text, receive_id_type=open_id for ou_.
- SendMessage with an inline keyboard: receive_id_type=chat_id for oc_,
  msg_type=interactive, and the button actually renders in the card body
  (guards the two bugs that bit us: open_id cross app, and the keyboard
  silently vanishing).
- SendMessage with card_json: sent verbatim as an interactive message.
- sendMedia image/file: uploads to /im/v1/images|files first, then sends
  a create with the returned key plumbed into the body.
- EditMessage: PATCH /im/v1/messages/:id. DeleteMessage: DELETE same.
  React: POST .../reactions with the emoji.
- Inbound replay: convertLarkMessageToCore on an image message yields a
  media attachment (feishu://<key>) and a chat-id reply target.

This makes "is this change correct?" answerable by `go test
./imbot/platform/feishu/...`, leaving live Feishu only for a per-release
render/delivery smoke check rather than per-change verification.

https://claude.ai/code/session_014ThTKs7Ft4zptY2pQJDpjZ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants