Skip to content

feat(mail): support sharing emails to IM chats#637

Open
chanthuang wants to merge 5 commits intomainfrom
worktree-feat+mail-share-to-chat
Open

feat(mail): support sharing emails to IM chats#637
chanthuang wants to merge 5 commits intomainfrom
worktree-feat+mail-share-to-chat

Conversation

@chanthuang
Copy link
Copy Markdown
Collaborator

@chanthuang chanthuang commented Apr 23, 2026

Summary

Add +share-to-chat shortcut that shares an email or thread as a card to a Lark IM chat (group or individual).

  • Share a single email or an entire thread to any IM conversation
  • Support multiple receiver ID types: chat_id, open_id, user_id, union_id, email
  • Dry-run mode to preview API calls without executing
  • Input validation for mutually exclusive options and receiver ID types

Usage

# Share a single email to a group chat
lark-cli mail +share-to-chat --message-id <id> --receive-id oc_xxx

# Share an entire thread
lark-cli mail +share-to-chat --thread-id <id> --receive-id oc_xxx

# Share to an individual by email
lark-cli mail +share-to-chat --message-id <id> --receive-id user@example.com --receive-id-type email

Test plan

  • Unit tests for validation logic and receiver ID type coverage
  • E2E verification of email card delivery to group and individual chats

Summary by CodeRabbit

  • New Features
    • Added +share-to-chat shortcut to share email messages or threads to Lark IM as interactive cards
    • Supports selecting recipients by multiple ID types (chat, user, email, etc.) and choosing message-id or thread-id
  • Documentation
    • CLI usage, examples, required scopes, and troubleshooting added to mail docs
  • Tests
    • New unit and end-to-end dry-run tests covering validation and success/error flows

Two-step API (create share token → send card) wrapped in a single
shortcut. Supports message-id/thread-id, five receive-id-type variants
(chat_id, open_id, user_id, union_id, email), and dry-run mode.

Change-Id: Ic7b8c01c0d25fef262f35be92555f1fd019bd679
Co-Authored-By: AI
…edit

Add missing safety rule 8 (draft link rule) to skill-template/domains/mail.md
so it survives regeneration. SKILL.md is now produced by `make gen-skills`
in the registry repo rather than hand-edited.

Change-Id: I9cf3605deae8b6de2042e40819fedc304967e78e
Co-Authored-By: AI
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

📝 Walkthrough

Walkthrough

Adds a new MailShareToChat CLI shortcut (+share-to-chat) to share an email message or thread as a card to Lark IM, with flag validation, mailbox resolution, share-token creation, card send, unit and e2e dry-run tests, and documentation updates.

Changes

Cohort / File(s) Summary
Mail Share-to-Chat Implementation
shortcuts/mail/mail_share_to_chat.go, shortcuts/mail/mail_share_to_chat_test.go
New MailShareToChat shortcut and comprehensive unit tests. Implements mutually exclusive --message-id/--thread-id, required --receive-id with typed validation, --mailbox resolution, DryRun and Execute flows: create share-token → send card; tests cover success and error paths.
Shortcut Registration
shortcuts/mail/shortcuts.go
Registers MailShareToChat in the mail shortcuts list.
Domain & Skill Documentation
skill-template/domains/mail.md, skills/lark-mail/SKILL.md
Adds draft callback/link security guidance and documents +share-to-chat feature, required OAuth scopes, CLI examples, permission notes, and adds multi_entity.search to API surface.
User-Facing CLI Guide
skills/lark-mail/references/lark-mail-share-to-chat.md
New CLI reference describing flags, mutual-exclusion rules, dry-run behavior, response fields (card_id, im_message_id), workflows, and common errors.
CLI E2E Dry-Run Tests
tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go
Adds end-to-end dry-run tests that run the CLI and assert two POST calls (create share-token and send card), payloads, endpoint paths, and receive_id_type across subcases.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as User/CLI
    participant Validator as Validator
    participant MailAPI as Mail Service
    participant IMAPI as IM Service

    CLI->>Validator: invoke +share-to-chat (flags)
    Validator->>Validator: validate (message_id xor thread_id, receive_id/type)
    alt validation fails
        Validator-->>CLI: return validation error
    else
        Validator->>MailAPI: POST /mailboxes/{mailbox}/share_token (message_id|thread_id)
        MailAPI-->>Validator: { card_id }
        Validator->>IMAPI: POST /im/messages/send (card_id, receive_id, receive_id_type)
        IMAPI-->>Validator: { im_message_id }
        Validator-->>CLI: output { card_id, im_message_id }
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • infeng
  • zhaoleibd

Poem

🐰 I nibbled a mail and shaped it neat,
A tiny card to send down the street,
Hop, token, bounce — into chat it flew,
card_id glows, im_message_id too! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding support for sharing emails to IM chats, which is the primary feature introduced in this changeset.
Description check ✅ Passed The description covers all required template sections: Summary explains the feature, Changes are implied through Usage examples, and Test Plan documents both unit and E2E test coverage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-feat+mail-share-to-chat

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added domain/mail PR touches the mail domain size/M Single-domain feat or fix with limited business impact labels Apr 23, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
shortcuts/mail/mail_share_to_chat_test.go (2)

103-114: Replace hand-rolled containsStr/searchStr with strings.Contains.

Standard library already provides this; the custom implementation adds noise and an unnecessary len(s) >= len(substr) guard (strings.Contains already handles all cases).

♻️ Proposed diff
 import (
 	"fmt"
+	"strings"
 	"testing"
 )
-				if !containsStr(err.Error(), tt.wantErr) {
+				if !strings.Contains(err.Error(), tt.wantErr) {
 					t.Fatalf("expected error containing %q, got %q", tt.wantErr, err.Error())
 				}
-func containsStr(s, substr string) bool {
-	return len(s) >= len(substr) && searchStr(s, substr)
-}
-
-func searchStr(s, substr string) bool {
-	for i := 0; i <= len(s)-len(substr); i++ {
-		if s[i:i+len(substr)] == substr {
-			return true
-		}
-	}
-	return false
-}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/mail/mail_share_to_chat_test.go` around lines 103 - 114, The file
defines custom containsStr and searchStr functions; replace their usage with the
stdlib strings.Contains and delete these two functions: change any call sites
using containsStr(...) to strings.Contains(...), remove searchStr entirely, and
add "strings" to the imports if not already present so the tests compile.

54-101: Tests duplicate validation logic instead of exercising MailShareToChat.Validate.

validateShareToChat is a parallel reimplementation of the real validation in mail_share_to_chat.go. If someone later changes the production Validate (e.g., adds a receive-id-type, tightens a rule, or modifies the error wrapping with output.ErrValidation), these tests will still pass while the shipped behavior silently diverges. The only thing currently covered end-to-end is validReceiveIDTypes (in TestValidReceiveIDTypes).

Additionally, containsStr() and searchStr() reinvent strings.Contains().

Consider rewriting to drive MailShareToChat.Validate through a real *common.RuntimeContext (as other shortcut tests in this package do via cmdutil.TestFactory and runMountedMailShortcut) so assertions exercise the production code path, the output.ErrValidation wrapping, and avoid duplication.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/mail/mail_share_to_chat_test.go` around lines 54 - 101, The test
duplicates validation logic via validateShareToChat; replace those table-driven
calls with exercising the real MailShareToChat.Validate path using a runtime
context (e.g., create a MailShareToChat instance and call its Validate with a
*common.RuntimeContext built via cmdutil.TestFactory and runMountedMailShortcut
like other shortcuts in this package), remove the validateShareToChat helper,
and assert errors using strings.Contains on the returned error (verifying
output.ErrValidation wrapping where appropriate) instead of the custom
containsStr/searchStr helpers so the unit test follows production validation
logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@shortcuts/mail/mail_share_to_chat_test.go`:
- Around line 103-114: The file defines custom containsStr and searchStr
functions; replace their usage with the stdlib strings.Contains and delete these
two functions: change any call sites using containsStr(...) to
strings.Contains(...), remove searchStr entirely, and add "strings" to the
imports if not already present so the tests compile.
- Around line 54-101: The test duplicates validation logic via
validateShareToChat; replace those table-driven calls with exercising the real
MailShareToChat.Validate path using a runtime context (e.g., create a
MailShareToChat instance and call its Validate with a *common.RuntimeContext
built via cmdutil.TestFactory and runMountedMailShortcut like other shortcuts in
this package), remove the validateShareToChat helper, and assert errors using
strings.Contains on the returned error (verifying output.ErrValidation wrapping
where appropriate) instead of the custom containsStr/searchStr helpers so the
unit test follows production validation logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 08b5827d-e48d-41ab-8d96-7c9ea20fb938

📥 Commits

Reviewing files that changed from the base of the PR and between 600fa50 and 9a3fae8.

📒 Files selected for processing (6)
  • shortcuts/mail/mail_share_to_chat.go
  • shortcuts/mail/mail_share_to_chat_test.go
  • shortcuts/mail/shortcuts.go
  • skill-template/domains/mail.md
  • skills/lark-mail/SKILL.md
  • skills/lark-mail/references/lark-mail-share-to-chat.md

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 23, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@931b5c3ace955ddcf09d953dad3e1cb3ff9cd7f2

🧩 Skill update

Unavailable for this PR because source repo/branch metadata is missing.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

❌ Patch coverage is 80.70175% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.69%. Comparing base (c7ced37) to head (182f993).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/mail/mail_share_to_chat.go 82.14% 9 Missing and 1 partial ⚠️
shortcuts/mail/shortcuts.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #637      +/-   ##
==========================================
+ Coverage   60.37%   60.69%   +0.31%     
==========================================
  Files         408      417       +9     
  Lines       43411    44046     +635     
==========================================
+ Hits        26210    26732     +522     
- Misses      15159    15243      +84     
- Partials     2042     2071      +29     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Add Go doc comments to exported symbols for docstring coverage
- Rewrite tests to exercise MailShareToChat.Validate via RuntimeContext
  instead of duplicating validation logic
- Replace hand-rolled containsStr with strings.Contains
- Add httpmock stubs for execute and error path tests

Change-Id: Ic781494f61e9e844224185844bce7b0c48e8e200
Co-Authored-By: AI
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/mail/mail_share_to_chat_test.go`:
- Around line 88-121: The test TestShareToChatExecuteWithThreadID only checks
for card_002 and doesn't verify om_002 or that the outgoing request used
thread_id, so update the test to assert the response contains "om_002" (same as
the message-id test) and enhance the second httpmock.Stub (the POST to
"/user_mailboxes/me/share_tokens/card_002/send") to capture and assert the
request body includes "thread_id":"t1" (use the httpmock request-capture
facility) to detect regressions where Execute might send message_id instead of
thread_id; keep references to TestShareToChatExecuteWithThreadID,
runMountedMailShortcut, and MailShareToChat when making these changes.
- Around line 1-190: The PR is missing the required dry-run E2E test for the new
MailShareToChat shortcut; add a dry-run E2E test under tests/cli_e2e/dryrun/
that runs the CLI with MailShareToChat and the --dry-run flag while setting
LARKSUITE_CLI_APP_ID, APP_SECRET and BRAND env vars, and assert the generated
request payloads for the create-share-token (messages/share_token) and send-card
(share_tokens/{card_id}/send) calls match the expected structure; implement the
test so it invokes the same command-line invocation used in unit tests (e.g.,
"+share-to-chat" with --message-id/--thread-id and
--receive-id/--receive-id-type) and validates both requests are produced without
actually calling the network.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec6a2c18-7850-4a20-b46b-bf917087a193

📥 Commits

Reviewing files that changed from the base of the PR and between 9a3fae8 and 06820f1.

📒 Files selected for processing (2)
  • shortcuts/mail/mail_share_to_chat.go
  • shortcuts/mail/mail_share_to_chat_test.go

Comment thread shortcuts/mail/mail_share_to_chat_test.go
Comment thread shortcuts/mail/mail_share_to_chat_test.go
Validate request shape (method, URL, mailbox path) under --dry-run
with fake credentials. Covers message-id, thread-id, and custom
mailbox variants.

Change-Id: Iae87bf141cbe4f312d3e9b1fca4ba175052c5c35
Co-Authored-By: AI
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go (1)

89-91: Prefer strconv.Itoa(i) over string(rune('0'+i)) for the gjson index.

The string(rune('0'+i)) trick silently produces non-digit runes once i >= 10, which would cause confusing gjson lookups returning empty strings rather than a clear test failure. Since the current test only iterates 2 URLs it works, but it's a footgun for anyone extending wantURLs. Using strconv.Itoa (or fmt.Sprintf) is clearer and future-proof.

♻️ Proposed refactor
 		out := result.Stdout
 		for i, wantURL := range tt.wantURLs {
-			gotMethod := gjson.Get(out, "api."+string(rune('0'+i))+".method").String()
-			gotURL := gjson.Get(out, "api."+string(rune('0'+i))+".url").String()
+			idx := strconv.Itoa(i)
+			gotMethod := gjson.Get(out, "api."+idx+".method").String()
+			gotURL := gjson.Get(out, "api."+idx+".url").String()

And add "strconv" to the imports.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go` around lines 89 - 91,
The test uses string(rune('0'+i)) to build gjson paths which breaks for i>=10;
replace string(rune('0'+i)) with strconv.Itoa(i) when constructing the gjson key
in the loop that reads wantURLs and sets gotMethod/gotURL (the gjson.Get calls),
and add "strconv" to the imports so multi-digit indices produce correct JSON
lookups and clear failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go`:
- Around line 89-91: The test uses string(rune('0'+i)) to build gjson paths
which breaks for i>=10; replace string(rune('0'+i)) with strconv.Itoa(i) when
constructing the gjson key in the loop that reads wantURLs and sets
gotMethod/gotURL (the gjson.Get calls), and add "strconv" to the imports so
multi-digit indices produce correct JSON lookups and clear failures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e190ed06-955b-4222-b24e-7053a3fffc03

📥 Commits

Reviewing files that changed from the base of the PR and between 06820f1 and 182f993.

📒 Files selected for processing (1)
  • tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go

Comment thread shortcuts/mail/mail_share_to_chat.go Outdated
return common.NewDryRunAPI().
Desc("Share email card: create share token → send card to IM chat").
POST(mailboxPath(mailboxID, "messages", "share_token")).
POST(mailboxPath(mailboxID, "share_tokens", "<card_id>", "send"))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: --dry-run currently previews only the two endpoint URLs, but not the payload/query values that actually distinguish the execution path. In particular, the first POST does not show whether the command will create a share token from message_id or thread_id, and the second POST does not expose receive_id_type / receive_id. That makes the new dry-run mode much less trustworthy for callers, and regressions in those fields will never show up in the dry-run output even if the E2E test passes on URLs alone.

Severity: 🚨 Should Fix

Suggested Fix: Keep DryRun in lockstep with Execute: attach the first request body ({"message_id": ...} or {"thread_id": ...}) to the share-token POST, and attach both receive_id_type and {"receive_id": ...} to the send POST. Then extend the dry-run test to assert those fields as well, not just the URLs.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 931b5c3. DryRun now includes request body and params for both API calls:

  • POST share_token: body: {message_id: ...} or {thread_id: ...}
  • POST send: params: {receive_id_type: ...}, body: {receive_id: ...}

E2E dry-run test updated to assert these fields.

DryRun now mirrors Execute: the share-token POST shows message_id or
thread_id, and the send POST shows receive_id_type and receive_id.
E2E test updated to assert these fields. Also fix strconv.Itoa usage.

Change-Id: I00f8770fd5a12b7354986c5e5077f97cfe5d6653
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go`:
- Around line 101-112: Add an explicit assertion that the dry-run emitted
exactly len(tt.wantURLs) API calls before iterating: compute the number of
entries in the JSON API array from result.Stdout (e.g. use gjson.Get(out,
"api").Array() or gjson.Get(out, "api.#") to get the count), compare it to
len(tt.wantURLs), and fail the test if they differ; place this check just before
the existing for-loop that uses out, tt.wantURLs, and gjson.Get so any
unexpected extra/missing calls are caught.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eae887e6-ccef-4ce5-9f48-d481f5bd7e08

📥 Commits

Reviewing files that changed from the base of the PR and between 182f993 and 931b5c3.

📒 Files selected for processing (2)
  • shortcuts/mail/mail_share_to_chat.go
  • tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go

Comment on lines +101 to +112
out := result.Stdout
for i, wantURL := range tt.wantURLs {
idx := strconv.Itoa(i)
gotMethod := gjson.Get(out, "api."+idx+".method").String()
gotURL := gjson.Get(out, "api."+idx+".url").String()
if gotMethod != "POST" {
t.Fatalf("api[%d].method = %q, want POST\nstdout:\n%s", i, gotMethod, out)
}
if gotURL != wantURL {
t.Fatalf("api[%d].url = %q, want %q\nstdout:\n%s", i, gotURL, wantURL, out)
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Assert the dry-run emits exactly two API calls.

The loop verifies the first two entries, but a regression that adds an unexpected third dry-run request would still pass. Add an API-count assertion before checking the entries.

Proposed test hardening
 			out := result.Stdout
+			gotAPICount := int(gjson.Get(out, "api.#").Int())
+			if gotAPICount != len(tt.wantURLs) {
+				t.Fatalf("api count = %d, want %d\nstdout:\n%s", gotAPICount, len(tt.wantURLs), out)
+			}
 			for i, wantURL := range tt.wantURLs {
 				idx := strconv.Itoa(i)
 				gotMethod := gjson.Get(out, "api."+idx+".method").String()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
out := result.Stdout
for i, wantURL := range tt.wantURLs {
idx := strconv.Itoa(i)
gotMethod := gjson.Get(out, "api."+idx+".method").String()
gotURL := gjson.Get(out, "api."+idx+".url").String()
if gotMethod != "POST" {
t.Fatalf("api[%d].method = %q, want POST\nstdout:\n%s", i, gotMethod, out)
}
if gotURL != wantURL {
t.Fatalf("api[%d].url = %q, want %q\nstdout:\n%s", i, gotURL, wantURL, out)
}
}
out := result.Stdout
gotAPICount := int(gjson.Get(out, "api.#").Int())
if gotAPICount != len(tt.wantURLs) {
t.Fatalf("api count = %d, want %d\nstdout:\n%s", gotAPICount, len(tt.wantURLs), out)
}
for i, wantURL := range tt.wantURLs {
idx := strconv.Itoa(i)
gotMethod := gjson.Get(out, "api."+idx+".method").String()
gotURL := gjson.Get(out, "api."+idx+".url").String()
if gotMethod != "POST" {
t.Fatalf("api[%d].method = %q, want POST\nstdout:\n%s", i, gotMethod, out)
}
if gotURL != wantURL {
t.Fatalf("api[%d].url = %q, want %q\nstdout:\n%s", i, gotURL, wantURL, out)
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_e2e/mail/mail_share_to_chat_dryrun_test.go` around lines 101 - 112,
Add an explicit assertion that the dry-run emitted exactly len(tt.wantURLs) API
calls before iterating: compute the number of entries in the JSON API array from
result.Stdout (e.g. use gjson.Get(out, "api").Array() or gjson.Get(out, "api.#")
to get the count), compare it to len(tt.wantURLs), and fail the test if they
differ; place this check just before the existing for-loop that uses out,
tt.wantURLs, and gjson.Get so any unexpected extra/missing calls are caught.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/mail PR touches the mail domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants