chore: import upstream snapshot with attribution
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
clie2e "github.com/larksuite/cli/tests/cli_e2e"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func TestMarkdownCreateDryRun_Content(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+create",
|
||||
"--name", "README.md",
|
||||
"--content", "# hello",
|
||||
"--folder-token", "fldcnMarkdownDryRun",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_all")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/metas/batch_query")
|
||||
assert.Contains(t, output, `"with_url": true`)
|
||||
assert.Contains(t, output, `"file_name": "README.md"`)
|
||||
assert.Contains(t, output, `"parent_node": "fldcnMarkdownDryRun"`)
|
||||
assert.Contains(t, output, `"parent_type": "explorer"`)
|
||||
assert.Contains(t, output, `"size": 7`)
|
||||
}
|
||||
|
||||
func TestMarkdownCreateDryRun_WikiTarget(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+create",
|
||||
"--name", "README.md",
|
||||
"--content", "# hello",
|
||||
"--wiki-token", "wikcnMarkdownDryRun",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_all")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/metas/batch_query")
|
||||
assert.Contains(t, output, `"with_url": true`)
|
||||
assert.Contains(t, output, `"file_name": "README.md"`)
|
||||
assert.Contains(t, output, `"parent_node": "wikcnMarkdownDryRun"`)
|
||||
assert.Contains(t, output, `"parent_type": "wiki"`)
|
||||
assert.Contains(t, output, `"size": 7`)
|
||||
}
|
||||
|
||||
func TestMarkdownCreateDryRun_FileShowsConcreteSize(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
dir := t.TempDir()
|
||||
content := "# hi\n"
|
||||
require.NoError(t, os.WriteFile(dir+"/note.md", []byte(content), 0o644))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+create",
|
||||
"--file", "note.md",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
WorkDir: dir,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_all")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/metas/batch_query")
|
||||
assert.Contains(t, output, `"with_url": true`)
|
||||
assert.Contains(t, output, `"file": "@note.md"`)
|
||||
assert.Contains(t, output, `"size": 5`)
|
||||
}
|
||||
|
||||
func TestMarkdownCreateDryRun_RejectsEmptyContent(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+create",
|
||||
"--name", "empty.md",
|
||||
"--content", "",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
if api := gjson.Get(result.Stdout, "api"); api.IsArray() && len(api.Array()) > 0 {
|
||||
t.Fatalf("dry-run api list must be empty when validation fails\nstdout:\n%s", result.Stdout)
|
||||
}
|
||||
errMsg := gjson.Get(result.Stdout, "error").String()
|
||||
assert.Contains(t, errMsg, "empty markdown content is not supported")
|
||||
}
|
||||
|
||||
func TestMarkdownDiffDryRun_RemoteVsRemote(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+diff",
|
||||
"--file-token", "boxcnMarkdownDryRun",
|
||||
"--from-version", "7633658129540910621",
|
||||
"--to-version", "7633658129540910628",
|
||||
"--context-lines", "1",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/boxcnMarkdownDryRun/download")
|
||||
assert.Contains(t, output, `"mode": "remote_vs_remote"`)
|
||||
assert.Contains(t, output, `"version": "7633658129540910621"`)
|
||||
assert.Contains(t, output, `"version": "7633658129540910628"`)
|
||||
assert.Contains(t, output, `"context_lines": 1`)
|
||||
}
|
||||
|
||||
func TestMarkdownDiffDryRun_RemoteVsLocal(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, os.WriteFile(dir+"/draft.md", []byte("# draft\n"), 0o644))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+diff",
|
||||
"--file-token", "boxcnMarkdownDryRun",
|
||||
"--file", "./draft.md",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
WorkDir: dir,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/boxcnMarkdownDryRun/download")
|
||||
assert.Contains(t, output, `"mode": "remote_vs_local"`)
|
||||
assert.Contains(t, output, `"local_file": "./draft.md"`)
|
||||
}
|
||||
|
||||
func TestMarkdownCreateDryRun_RejectsEmptyWikiToken(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+create",
|
||||
"--name", "README.md",
|
||||
"--content", "# hello",
|
||||
"--wiki-token", "",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 2)
|
||||
assert.Contains(t, result.Stdout+result.Stderr, "--wiki-token cannot be empty")
|
||||
}
|
||||
|
||||
func TestMarkdownFetchDryRun_OutputFile(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+fetch",
|
||||
"--file-token", "boxcnMarkdownDryRun",
|
||||
"--output", "./copy.md",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/boxcnMarkdownDryRun/download")
|
||||
assert.Contains(t, output, `"output": "./copy.md"`)
|
||||
}
|
||||
|
||||
func TestMarkdownOverwriteDryRun_ContentFile(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
dir := t.TempDir()
|
||||
content := "# overwrite test\n"
|
||||
require.NoError(t, os.WriteFile(dir+"/input.md", []byte(content), 0o644))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+overwrite",
|
||||
"--file-token", "boxcnMarkdownDryRun",
|
||||
"--content", "@input.md",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
WorkDir: dir,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/metas/batch_query")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_all")
|
||||
assert.Contains(t, output, `"file_token": "boxcnMarkdownDryRun"`)
|
||||
assert.Contains(t, output, `"size": 17`)
|
||||
}
|
||||
|
||||
func TestMarkdownOverwriteDryRun_RejectsEmptyFile(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, os.WriteFile(dir+"/empty.md", []byte{}, 0o644))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+overwrite",
|
||||
"--file-token", "boxcnMarkdownDryRun",
|
||||
"--file", "empty.md",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
WorkDir: dir,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
if api := gjson.Get(result.Stdout, "api"); api.IsArray() && len(api.Array()) > 0 {
|
||||
t.Fatalf("dry-run api list must be empty when validation fails\nstdout:\n%s", result.Stdout)
|
||||
}
|
||||
errMsg := gjson.Get(result.Stdout, "error").String()
|
||||
assert.Contains(t, errMsg, "empty markdown content is not supported")
|
||||
}
|
||||
|
||||
func TestMarkdownPatchDryRun_Content(t *testing.T) {
|
||||
setMarkdownDryRunConfigEnv(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
result, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+patch",
|
||||
"--file-token", "boxcnMarkdownDryRun",
|
||||
"--pattern", "TODO",
|
||||
"--content", "DONE",
|
||||
"--dry-run",
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
result.AssertExitCode(t, 0)
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/boxcnMarkdownDryRun/download")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/metas/batch_query")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_all")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_prepare")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_part")
|
||||
assert.Contains(t, output, "/open-apis/drive/v1/files/upload_finish")
|
||||
}
|
||||
|
||||
func setMarkdownDryRunConfigEnv(t *testing.T) {
|
||||
t.Helper()
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
||||
t.Setenv("LARKSUITE_CLI_APP_ID", "markdown_dryrun_test")
|
||||
t.Setenv("LARKSUITE_CLI_APP_SECRET", "markdown_dryrun_secret")
|
||||
t.Setenv("LARKSUITE_CLI_BRAND", "feishu")
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
clie2e "github.com/larksuite/cli/tests/cli_e2e"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func TestMarkdownLifecycleWorkflow(t *testing.T) {
|
||||
if os.Getenv("LARK_MARKDOWN_E2E") == "" {
|
||||
t.Skip("set LARK_MARKDOWN_E2E=1 to run markdown live workflow after backend version support is deployed")
|
||||
}
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
||||
clie2e.SkipWithoutUserToken(t)
|
||||
|
||||
parentT := t
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
suffix := clie2e.GenerateSuffix()
|
||||
fileName := "lark-cli-e2e-markdown-" + suffix + ".md"
|
||||
initialContent := "# Initial\n\nhello markdown workflow\n"
|
||||
patchedContent := "# Initial\n\nhello patched workflow\n"
|
||||
updatedContent := "# Updated\n\nnew body\n"
|
||||
|
||||
createResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+create",
|
||||
"--name", fileName,
|
||||
"--content", initialContent,
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
createResult.AssertExitCode(t, 0)
|
||||
createResult.AssertStdoutStatus(t, true)
|
||||
|
||||
fileToken := gjson.Get(createResult.Stdout, "data.file_token").String()
|
||||
require.NotEmpty(t, fileToken, "stdout:\n%s", createResult.Stdout)
|
||||
|
||||
parentT.Cleanup(func() {
|
||||
cleanupCtx, cleanupCancel := clie2e.CleanupContext()
|
||||
defer cleanupCancel()
|
||||
|
||||
deleteResult, deleteErr := clie2e.RunCmd(cleanupCtx, clie2e.Request{
|
||||
Args: []string{
|
||||
"drive", "+delete",
|
||||
"--file-token", fileToken,
|
||||
"--type", "file",
|
||||
"--yes",
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
clie2e.ReportCleanupFailure(parentT, "delete markdown file "+fileToken, deleteResult, deleteErr)
|
||||
})
|
||||
|
||||
fetchInitialResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+fetch",
|
||||
"--file-token", fileToken,
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
fetchInitialResult.AssertExitCode(t, 0)
|
||||
fetchInitialResult.AssertStdoutStatus(t, true)
|
||||
require.Equal(t, initialContent, gjson.Get(fetchInitialResult.Stdout, "data.content").String(), "stdout:\n%s", fetchInitialResult.Stdout)
|
||||
|
||||
patchResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+patch",
|
||||
"--file-token", fileToken,
|
||||
"--pattern", "hello markdown workflow",
|
||||
"--content", "hello patched workflow",
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
patchResult.AssertExitCode(t, 0)
|
||||
patchResult.AssertStdoutStatus(t, true)
|
||||
require.Equal(t, true, gjson.Get(patchResult.Stdout, "data.updated").Bool(), "stdout:\n%s", patchResult.Stdout)
|
||||
require.Equal(t, int64(1), gjson.Get(patchResult.Stdout, "data.match_count").Int(), "stdout:\n%s", patchResult.Stdout)
|
||||
require.NotEmpty(t, gjson.Get(patchResult.Stdout, "data.version").String(), "stdout:\n%s", patchResult.Stdout)
|
||||
|
||||
fetchPatchedResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+fetch",
|
||||
"--file-token", fileToken,
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
fetchPatchedResult.AssertExitCode(t, 0)
|
||||
fetchPatchedResult.AssertStdoutStatus(t, true)
|
||||
require.Equal(t, patchedContent, gjson.Get(fetchPatchedResult.Stdout, "data.content").String(), "stdout:\n%s", fetchPatchedResult.Stdout)
|
||||
|
||||
overwriteResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+overwrite",
|
||||
"--file-token", fileToken,
|
||||
"--content", updatedContent,
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
overwriteResult.AssertExitCode(t, 0)
|
||||
overwriteResult.AssertStdoutStatus(t, true)
|
||||
require.NotEmpty(t, gjson.Get(overwriteResult.Stdout, "data.version").String(), "stdout:\n%s", overwriteResult.Stdout)
|
||||
|
||||
fetchUpdatedResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+fetch",
|
||||
"--file-token", fileToken,
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
fetchUpdatedResult.AssertExitCode(t, 0)
|
||||
fetchUpdatedResult.AssertStdoutStatus(t, true)
|
||||
require.Equal(t, updatedContent, gjson.Get(fetchUpdatedResult.Stdout, "data.content").String(), "stdout:\n%s", fetchUpdatedResult.Stdout)
|
||||
|
||||
historyResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"drive", "+version-history",
|
||||
"--file-token", fileToken,
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
historyResult.AssertExitCode(t, 0)
|
||||
historyResult.AssertStdoutStatus(t, true)
|
||||
|
||||
latestVersion := gjson.Get(overwriteResult.Stdout, "data.version").String()
|
||||
require.NotEmpty(t, latestVersion, "stdout:\n%s", overwriteResult.Stdout)
|
||||
|
||||
versions := gjson.Get(historyResult.Stdout, "data.versions").Array()
|
||||
require.GreaterOrEqual(t, len(versions), 2, "stdout:\n%s", historyResult.Stdout)
|
||||
|
||||
var previousVersion string
|
||||
// version-history returns versions in descending chronological order;
|
||||
// pick the first non-latest as the previous version.
|
||||
for _, version := range versions {
|
||||
candidate := version.Get("version").String()
|
||||
if candidate != "" && candidate != latestVersion {
|
||||
previousVersion = candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
require.NotEmpty(t, previousVersion, "stdout:\n%s", historyResult.Stdout)
|
||||
|
||||
diffResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+diff",
|
||||
"--file-token", fileToken,
|
||||
"--from-version", previousVersion,
|
||||
"--to-version", latestVersion,
|
||||
},
|
||||
DefaultAs: "user",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
diffResult.AssertExitCode(t, 0)
|
||||
diffResult.AssertStdoutStatus(t, true)
|
||||
|
||||
assert.True(t, gjson.Get(diffResult.Stdout, "data.changed").Bool(), "stdout:\n%s", diffResult.Stdout)
|
||||
assert.Equal(t, "remote_vs_remote", gjson.Get(diffResult.Stdout, "data.mode").String(), "stdout:\n%s", diffResult.Stdout)
|
||||
assert.Equal(t, previousVersion, gjson.Get(diffResult.Stdout, "data.from_version").String(), "stdout:\n%s", diffResult.Stdout)
|
||||
assert.Equal(t, latestVersion, gjson.Get(diffResult.Stdout, "data.to_version").String(), "stdout:\n%s", diffResult.Stdout)
|
||||
assert.GreaterOrEqual(t, len(gjson.Get(diffResult.Stdout, "data.hunks").Array()), 1, "stdout:\n%s", diffResult.Stdout)
|
||||
|
||||
diffText := gjson.Get(diffResult.Stdout, "data.diff").String()
|
||||
assert.True(t, strings.Contains(diffText, "-hello markdown workflow") || strings.Contains(diffText, "-# Initial"), "stdout:\n%s", diffResult.Stdout)
|
||||
assert.True(t, strings.Contains(diffText, "+new body") || strings.Contains(diffText, "+# Updated"), "stdout:\n%s", diffResult.Stdout)
|
||||
}
|
||||
|
||||
func TestMarkdownCreateWorkflow_WikiParent(t *testing.T) {
|
||||
if os.Getenv("LARK_MARKDOWN_E2E") == "" {
|
||||
t.Skip("set LARK_MARKDOWN_E2E=1 to run markdown live workflow after backend version support is deployed")
|
||||
}
|
||||
|
||||
wikiToken := strings.TrimSpace(os.Getenv("LARK_MARKDOWN_E2E_WIKI_TOKEN"))
|
||||
if wikiToken == "" {
|
||||
t.Skip("set LARK_MARKDOWN_E2E_WIKI_TOKEN to run markdown live workflow against a wiki parent node")
|
||||
}
|
||||
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
||||
|
||||
parentT := t
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
suffix := clie2e.GenerateSuffix()
|
||||
fileName := "lark-cli-e2e-markdown-wiki-" + suffix + ".md"
|
||||
initialContent := "# Wiki Parent\n\nhello wiki markdown workflow\n"
|
||||
|
||||
createResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+create",
|
||||
"--wiki-token", wikiToken,
|
||||
"--name", fileName,
|
||||
"--content", initialContent,
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
createResult.AssertExitCode(t, 0)
|
||||
createResult.AssertStdoutStatus(t, true)
|
||||
|
||||
fileToken := gjson.Get(createResult.Stdout, "data.file_token").String()
|
||||
require.NotEmpty(t, fileToken, "stdout:\n%s", createResult.Stdout)
|
||||
require.NotEmpty(t, gjson.Get(createResult.Stdout, "data.url").String(), "stdout:\n%s", createResult.Stdout)
|
||||
|
||||
parentT.Cleanup(func() {
|
||||
requireDeleteWikiHostedMarkdownFile(parentT, fileToken)
|
||||
})
|
||||
|
||||
fetchResult, err := clie2e.RunCmd(ctx, clie2e.Request{
|
||||
Args: []string{
|
||||
"markdown", "+fetch",
|
||||
"--file-token", fileToken,
|
||||
},
|
||||
DefaultAs: "bot",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
fetchResult.AssertExitCode(t, 0)
|
||||
fetchResult.AssertStdoutStatus(t, true)
|
||||
require.Equal(t, initialContent, gjson.Get(fetchResult.Stdout, "data.content").String(), "stdout:\n%s", fetchResult.Stdout)
|
||||
}
|
||||
|
||||
func requireDeleteWikiHostedMarkdownFile(parentT *testing.T, fileToken string) {
|
||||
parentT.Helper()
|
||||
|
||||
request := clie2e.Request{
|
||||
Args: []string{
|
||||
"drive", "+delete",
|
||||
"--file-token", fileToken,
|
||||
"--type", "file",
|
||||
"--yes",
|
||||
},
|
||||
}
|
||||
|
||||
for _, identity := range []string{"bot", "user"} {
|
||||
cleanupCtx, cleanupCancel := clie2e.CleanupContext()
|
||||
result, err := clie2e.RunCmd(cleanupCtx, clie2e.Request{
|
||||
Args: request.Args,
|
||||
DefaultAs: identity,
|
||||
})
|
||||
cleanupCancel()
|
||||
if err == nil && result != nil && result.ExitCode == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
parentT.Fatalf("cleanup failed: could not delete wiki-hosted markdown file %s with either bot or user identity", fileToken)
|
||||
}
|
||||
Reference in New Issue
Block a user