Files
larksuite-cli/shortcuts/doc/docs_update_test.go
SunPeiYang996 e42033f5b5 feat(doc): add v2 API for docs +create / +fetch / +update (#638)
Adds an `--api-version v2` path to the docs shortcuts, backed by the
`docs_ai/v1/documents` OpenAPI. DocxXML is the default document format
and Markdown is available as an alternative. Content input is unified
across the three shortcuts via `--content` + `--doc-format`. The v1
(MCP) path is preserved for backward compatibility and now prints a
deprecation notice on use.

Shortcuts:

  - `docs +create --api-version v2`: create a document from XML or
    Markdown, with optional `--parent-token` or `--parent-position`.
    Bot identity continues to auto-grant the current CLI user
    full_access on the new document.

  - `docs +fetch --api-version v2`: adds `--detail simple|with-ids|full`
    for export granularity and `--scope full|outline|range|keyword|section`
    for partial reads, along with `--context-before` / `--context-after`,
    `--max-depth`, and `--revision-id`.

  - `docs +update --api-version v2`: introduces structured operations
    via `--command`: `str_replace`, `block_delete`, `block_insert_after`,
    `block_copy_insert_after`, `block_replace`, `block_move_after`,
    `overwrite`, `append`.

Framework support in `shortcuts/common`:

  - `OutRaw` / `OutFormatRaw` emit the JSON envelope with HTML escaping
    disabled so XML/HTML document bodies are preserved verbatim.
  - New `Shortcut.PostMount` hook runs after a cobra.Command is fully
    configured; used here to install a version-aware help function
    that hides flags belonging to the inactive `--api-version`.

Also refreshes the lark-doc skill pack (SKILL.md, create/fetch/update
references, new lark-doc-xml and lark-doc-md references, style and
workflow guides), README examples, and downstream skill call sites
(lark-drive, lark-vc, lark-whiteboard, lark-workflow-meeting-summary,
lark-event).

Change-Id: Ide2d86b190a4e21095ae29096e7fb00031d80489
2026-04-23 23:24:30 +08:00

104 lines
2.9 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package doc
import (
"reflect"
"testing"
)
// ── V2 tests ──
func TestValidCommandsV2(t *testing.T) {
expected := map[string]bool{
"str_replace": true,
"block_delete": true,
"block_insert_after": true,
"block_copy_insert_after": true,
"block_replace": true,
"block_move_after": true,
"overwrite": true,
"append": true,
}
if len(validCommandsV2) != len(expected) {
t.Fatalf("expected %d commands, got %d", len(expected), len(validCommandsV2))
}
for cmd := range validCommandsV2 {
if !expected[cmd] {
t.Fatalf("unexpected command %q in validCommandsV2", cmd)
}
}
}
// ── V1 tests ──
func TestIsWhiteboardCreateMarkdown(t *testing.T) {
t.Run("blank whiteboard tags", func(t *testing.T) {
markdown := "<whiteboard type=\"blank\"></whiteboard>\n<whiteboard type=\"blank\"></whiteboard>"
if !isWhiteboardCreateMarkdown(markdown) {
t.Fatalf("expected blank whiteboard markdown to be treated as whiteboard creation")
}
})
t.Run("mermaid code block", func(t *testing.T) {
markdown := "```mermaid\ngraph TD\nA-->B\n```"
if !isWhiteboardCreateMarkdown(markdown) {
t.Fatalf("expected mermaid markdown to be treated as whiteboard creation")
}
})
t.Run("plain markdown", func(t *testing.T) {
markdown := "## plain text"
if isWhiteboardCreateMarkdown(markdown) {
t.Fatalf("did not expect plain markdown to be treated as whiteboard creation")
}
})
}
func TestNormalizeWhiteboardResult(t *testing.T) {
t.Run("adds empty board_tokens when whiteboard creation response omits it", func(t *testing.T) {
result := map[string]interface{}{
"success": true,
}
normalizeWhiteboardResult(result, "<whiteboard type=\"blank\"></whiteboard>")
got, ok := result["board_tokens"].([]string)
if !ok {
t.Fatalf("expected board_tokens to be []string, got %T", result["board_tokens"])
}
if len(got) != 0 {
t.Fatalf("expected empty board_tokens, got %#v", got)
}
})
t.Run("normalizes board_tokens to string slice", func(t *testing.T) {
result := map[string]interface{}{
"board_tokens": []interface{}{"board_1", "board_2"},
}
normalizeWhiteboardResult(result, "<whiteboard type=\"blank\"></whiteboard>")
want := []string{"board_1", "board_2"}
got, ok := result["board_tokens"].([]string)
if !ok {
t.Fatalf("expected board_tokens to be []string, got %T", result["board_tokens"])
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("board_tokens mismatch: got %#v want %#v", got, want)
}
})
t.Run("leaves non whiteboard response unchanged", func(t *testing.T) {
result := map[string]interface{}{
"success": true,
}
normalizeWhiteboardResult(result, "## plain text")
if _, ok := result["board_tokens"]; ok {
t.Fatalf("did not expect board_tokens for non-whiteboard markdown")
}
})
}