Files
larksuite__cli/tests/cli_e2e/base/coverage.md
xiaomi-bytedance 723f884e9b feat(base): support BaseApp application mode (#2231)
* feat(base): add BaseApp workspace, page and block shortcuts

Implement the CLI layer of the BaseApp CLI/OpenAPI protocol design: 17 new
shortcuts covering workspace entities, blank app creation, page CRUD and page
block CRUD, plus skill references and dry-run E2E for each.

The data_config validator moves to a neutral block_data_config.go with chart
logic unchanged; list and richText dispatch are new branches, so dashboard
behaviour is untouched. Command spaces stay separate — dashboard commands never
take --app-token and app block commands never take --dashboard-id. The one
exception is +app-block-get-data, which shares the dashboard endpoint, execute
and dry-run hooks and therefore takes --base-token instead of --app-token.

This phase ships no +app-block-delete and no page arrange command; both the
help text and the skill docs spell out that a block type cannot be changed
after creation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(base): implement app mode shortcuts and list components

* feat: support deleting BaseApp via drive delete

* fix: 修复 workspace scope

* fix: correct BaseApp permission scopes

* feat: 新增 moveIn workspace 逻辑

* feat(base): support multi-datasource data_config for BaseApp charts

BaseApp page charts follow section 8 图表协议 of the App CLI RPC 协议,
which differs from dashboard charts by supporting multiple data sources:
base_token is a single top-level value shared by every source, while
table_name/series/count_all/group_by/filter move into each data_sources[]
element (plus top-level data_source_mode and sort). The per-source value
semantics are identical to dashboard charts, so each data_sources[] element
reuses normalizeDataConfig / validateChartDataConfig; the wrapper only adds
the top-level structure. Dashboard charts keep the flat shape; the list
protocol is untouched.

- block_data_config.go: add normalizeAppChartDataConfig /
  validateAppChartDataConfig / validateAppBlockDataConfig
- app_block_create/update: route chart blocks to the multi-datasource
  normalize/validate; refresh tips and examples
- reference doc: rewrite the chart section for the multi-datasource shape
- unit + e2e tests: migrate chart cases to data_sources; add a
  multi-datasource combo case

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(base): map BaseApp richText block type to the wire type "text"

The rich-text widget's API type is "text" (App CLI RPC 协议 §10), but the
CLI exposes the friendlier "richText" alias and was sending it verbatim, so
the backend rejected +app-block-create --type richText with "type is
invalid". Map richText -> text when building the request body; the
user-facing --type richText is unchanged. Add TestAppRichTextTypeMapsToText.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(base): remove internal protocol doc link/reference from skills

The BaseApp skill references pointed at an internal Lark doc (deep link with
a private token) as the source of truth, which must not ship in this repo.
Drop the link and the doc name entirely from the reference markdown and from
code comments; describe behavior in neutral terms ("服务端协议 / 服务端返回和校验")
instead. No functional change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: create workspace for BaseApp when omitted

* fix(base): align BaseApp block protocol

* fix: 删掉废弃的 workspace-entity-remove

* fix(base): align app get reference response

* fix(base): align app shortcuts with API contract

* fix(base): refine app mode shortcut contracts

* fix: use entity_type for workspace entity filtering

* fix: return workspace URLs for base workspace ops

* fix(base): enforce unique app block names

* fix(base): use chart token for app block data

* 明确baseapp边界,不导向到dashboard-arrange

* docs(base): clarify app copy is unsupported

* docs(base): define unsupported app page operations

* fix(base): align app block text type with dashboard

AppMode 的文本组件此前对外叫 richText,发送时再映射成 wire 上的 text,
而读取方向没有反向映射:写进去用 richText、读回来是 text,同一个 CLI
表面自相矛盾,回填或幂等复建时会被枚举校验拒掉。

统一成 text,与 Dashboard 文本组件同名同义:
- appBlockTypes/isAppBlockType/textBlockTypes 去掉 richText
- 删除 appBlockBody 里的 richText → text 发送期映射
- help、枚举、示例、tips 与 baseapp block data_config reference 同步
- 新增回归测试,确保 richText 不再被接受也不再出现在枚举里

richText 不保留别名:+app-* 尚未随已发布版本对外,无存量调用方。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(base): resolve BaseApp URLs

Migrate the net changes from bitable/base_cli!1308 onto the current BaseApp development branch.

* fix(base): remove app block list type filter

* docs: preserve explicit intent when reusing BaseApp blocks

* fix(base): route +app-block-get-data to base_apps endpoint

Move the shortcut off the dashboard route and onto the dedicated
BaseApp block-data endpoint:

- URL: /open-apis/base/v3/base_apps/:app_token/blocks/:block_id/data
- base_token is passed as a required query parameter per the new IDL
- Refresh --block-id description and tips to list all producers of the
  chart_token (create/list/get) and note the cht… prefix
- Update the dryrun test to expect the new URL

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: clarify unsupported BaseApp copy paths

* fix: front-load BaseApp copy stop rule

* fix: surface unsupported PageGroup operations

* fix: preserve PageGroup support boundary

* docs(base): clarify unsupported app block handling

* docs(base): clarify how to read text block content

Text blocks have no /data endpoint; calling +app-block-get-data on
one returns a generic server 500. Point readers at +app-block-get,
whose data_config.text carries the Markdown source.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: clarify immutable BaseApp block types

* docs(base): correct chart date filter format

* docs(base): explain inaccessible app pages

* docs: require workspace removal lookup

* fix(base): return workspace move-in result faithfully

* chore(base): adapt BaseApp changes to upstream main

* fix(base): align app mode changes with upstream scope

* fix(base): address app mode review feedback

* test(base): assert app data transport error contract

* fix(base): satisfy app mode merge requirements

* refactor(base): align app mode filenames

* docs: fix BaseApp rename guidance

* fix(base): remove unsupported workspace icon

* docs(base): clarify app mode concepts and config reuse

---------

Co-authored-by: weibiao.x <weibiao.x@bytedance.com>
Co-authored-by: zhangbinkai.zbk <zhangbinkai.zbk@bytedance.com>
Co-authored-by: yurunjie <yurunjie.xx@bytedance.com>
Co-authored-by: Codex <codex@example.com>
2026-08-13 16:20:34 +08:00

13 KiB

Base CLI E2E Coverage

Metrics

  • Denominator: 89 leaf commands
  • Covered: 30
  • Coverage: 33.7%

Summary

  • TestBase_BasicWorkflow: proves +base-create, +base-get, +table-create, +table-get, and +table-list; key t.Run(...) proof points are get base as bot, get table as bot, and list tables and find created table as bot.
  • TestBaseBlockDryRun: proves the five +base-block-* shortcuts request shapes without touching live data.
  • TestBaseAppWorkflow: live user workflow in an isolated fixture Workspace covering Workspace entity listing, BaseApp create/get, Page create/list/get/update/delete, text Block create/list/get/update, and App cleanup through Drive delete (type=bitable). Set LARK_CLI_E2E_BASEAPP_WORKSPACE_TOKEN to enable it.
  • TestBaseFieldCreateDryRunArrayCompat: proves +field-create dry-run request shape for the internal JSON-array compatibility path.
  • TestBaseFormQuestionsCreateDryRun: proves +form-questions-create preserves its POST body and renders the existing-question guard in command help.
  • TestBaseFormDetailDryRun / TestBaseFormSubmitDryRun: prove shared-form detail and submission request shapes.
  • TestBaseDashboardBlockGetDataDryRun: proves dashboard block data request shapes and identifier handling.
  • TestBaseRecordBatchUpdatePerRecordDryRun: proves +record-batch-update preserves the per-record update_records request shape.
  • TestBaseRecordBatchUpdatePerRecordWorkflow: creates two records, updates different field types in one request, asserts the minimal response contract, reads both records back, verifies a missing record ID is not prevalidated, and cleans up the temporary Base.
  • TestBase_RoleWorkflow: proves +advperm-enable, +role-create, +role-list, +role-get, and +role-update; key t.Run(...) proof points are list as bot, get as bot, and update as bot.
  • TestBaseFormListDryRun_UsesBaseAndTableIdentifiers: proves +form-list dry-run request shape uses Base and table identifiers in the endpoint.
  • TestBaseFormQuestionsCreateVisibleRuleDryRun / TestBaseFormQuestionsUpdateVisibleRuleDryRun: prove +form-questions-create / +form-questions-update dry-run request shape and that the optional visible_rule display condition is transcribed verbatim into the request body.
  • TestBaseTableCopyDryRun: proves +table-copy and +table-copy-status request shapes, including the schema-safe default, table-name path escaping, explicit all+wait orchestration, Cobra duration parsing, and the opaque task ID body.
  • TestBaseTableCopyWorkflow: feature-gated by LARK_CLI_E2E_BASE_TABLE_COPY_READY=1 until the OpenAPI is deployed; creates a source table and record, proves schema-only copy, all no-wait plus status, all wait, record inclusion, and cleanup.
  • Cleanup note: +table-delete and +role-delete only run in cleanup and are intentionally left uncovered.
  • Blocked area: table-copy live integration remains deployment-gated; dashboard, field, most record operations, most form operations, view, and workflow operations still lack deterministic create/read/update workflows in this suite.

Command Table

Status Cmd Type Testcase Key parameter shapes Notes / uncovered reason
✕ base +advperm-disable shortcut none no disable workflow yet
✓ base +advperm-enable shortcut base_role_workflow_test.go::TestBase_RoleWorkflow --base-token
✕ base +base-copy shortcut none no copy workflow yet
✓ base +base-create shortcut base/helpers_test.go::createBaseWithRetry --name; --time-zone helper asserts created base token
✓ base +base-get shortcut base_basic_workflow_test.go::TestBase_BasicWorkflow/get base as bot --base-token
✓ base +base-block-create shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/create --base-token; --type; --name; --parent-id; dry-run only request shape only
✓ base +base-block-delete shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/delete --base-token; --block-id; dry-run only request shape only
✓ base +base-block-list shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/list all,list folder --base-token; optional --parent-id; optional --type; dry-run only request shape only
✓ base +base-block-move shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/move root,move after --base-token; --block-id; optional --parent-id; --after-id; dry-run only request shape only
✓ base +base-block-rename shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/rename --base-token; --block-id; --name; dry-run only request shape only
✕ base +dashboard-arrange shortcut none dashboard workflows not covered
✕ base +dashboard-block-create shortcut none dashboard workflows not covered
✕ base +dashboard-block-delete shortcut none dashboard workflows not covered
✕ base +dashboard-block-get shortcut none dashboard workflows not covered
✓ base +dashboard-block-get-data shortcut base_dashboard_block_get_data_dryrun_test.go --base-token; --dashboard-id; --block-id; dry-run only request shape and identifier handling
✕ base +dashboard-block-list shortcut none dashboard workflows not covered
✕ base +dashboard-block-update shortcut none dashboard workflows not covered
✕ base +dashboard-create shortcut none dashboard workflows not covered
✕ base +dashboard-delete shortcut none dashboard workflows not covered
✕ base +dashboard-get shortcut none dashboard workflows not covered
✕ base +dashboard-list shortcut none dashboard workflows not covered
✕ base +dashboard-update shortcut none dashboard workflows not covered
✕ base +data-query shortcut none no data-query assertions yet
✓ base +field-create shortcut base_field_dryrun_test.go::TestBaseFieldCreateDryRunArrayCompat --base-token; --table-id; --json; dry-run only request shape only
✕ base +field-delete shortcut none field workflows not covered
✕ base +field-get shortcut none field workflows not covered
✕ base +field-list shortcut none field workflows not covered
✕ base +field-search-options shortcut none field workflows not covered
✕ base +field-update shortcut none field workflows not covered
✕ base +form-create shortcut none form workflows not covered
✕ base +form-delete shortcut none form workflows not covered
✓ base +form-detail shortcut base_form_detail_dryrun_test.go::TestBaseFormDetailDryRun --share-token; dry-run only shared-form request shape
✕ base +form-get shortcut none form workflows not covered
✓ base +form-list shortcut base_form_detail_dryrun_test.go::TestBaseFormListDryRun_UsesBaseAndTableIdentifiers --base-token; --table-id; dry-run only request shape only
✓ base +form-questions-create shortcut TestBaseFormQuestionsCreateVisibleRuleDryRun; base_form_questions_create_dryrun_test.go questions[].visible_rule; dry-run request body, visible_rule passthrough, and help guard covered
✕ base +form-questions-delete shortcut none form workflows not covered
✕ base +form-questions-list shortcut none form workflows not covered
✓ base +form-questions-update shortcut TestBaseFormQuestionsUpdateVisibleRuleDryRun questions[].visible_rule dry-run: request shape + visible_rule body passthrough
✓ base +form-submit shortcut base_form_submit_dryrun_test.go::TestBaseFormSubmitDryRun --share-token; --json; dry-run only submission request shape
✕ base +form-update shortcut none form workflows not covered
✓ base +record-batch-create shortcut base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow --base-token; --table-id; --json.create_records seeds heterogeneous live workflow records
✓ base +record-batch-update shortcut base_record_batch_update_dryrun_test.go::TestBaseRecordBatchUpdatePerRecordDryRun; base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow --base-token; --table-id; --json.update_records; dry-run + live heterogeneous select/number update with write-back verification
✕ base +record-delete shortcut none record workflows not covered
✓ base +record-get shortcut base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow --record-id; repeated --field-id; --format json reads back select and number values after batch update
✕ base +record-history-list shortcut none record workflows not covered
✕ base +record-list shortcut none record workflows not covered
✕ base +record-search shortcut none record workflows not covered
✕ base +record-share-link-create shortcut none record workflows not covered
✓ base +record-upload-attachment shortcut base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/upload dry-run only request shape only
✓ base +record-download-attachment shortcut base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/download dry-run only request shape only
✓ base +record-remove-attachment shortcut base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/remove dry-run only request shape only
✕ base +record-upsert shortcut none record workflows not covered
✓ base +role-create shortcut base/helpers_test.go::createRole --base-token; --json helper asserts created role id
✕ base +role-delete shortcut none cleanup only
✓ base +role-get shortcut base_role_workflow_test.go::TestBase_RoleWorkflow/get as bot --base-token; --role-id
✓ base +role-list shortcut base_role_workflow_test.go::TestBase_RoleWorkflow/list as bot --base-token
✓ base +role-update shortcut base_role_workflow_test.go::TestBase_RoleWorkflow/update as bot --base-token; --role-id; --json
✓ base +table-create shortcut base/helpers_test.go::createTableWithRetry --base-token; --name; --fields; optional --view helper asserts table id
✓ base +table-copy shortcut base_table_copy_dryrun_test.go::TestBaseTableCopyDryRun; base_table_copy_workflow_test.go::TestBaseTableCopyWorkflow --table-id ID/name; default --range schema; explicit --range all --wait --timeout dry-run covered; live workflow is deployment-gated and not yet verified
✓ base +table-copy-status shortcut base_table_copy_dryrun_test.go::TestBaseTableCopyDryRun/status; base_table_copy_workflow_test.go::TestBaseTableCopyWorkflow/all no-wait and status opaque --task-id dry-run covered; live polling is deployment-gated and not yet verified
✕ base +table-delete shortcut none cleanup only
✓ base +table-get shortcut base_basic_workflow_test.go::TestBase_BasicWorkflow/get table as bot --base-token; --table-id
✓ base +table-list shortcut base_basic_workflow_test.go::TestBase_BasicWorkflow/list tables and find created table as bot --base-token
✕ base +table-update shortcut none no rename workflow yet
✕ base +title-resolve shortcut none resolver workflow not covered
✕ base +url-resolve shortcut none resolver workflow not covered
✕ base +view-create shortcut none view workflows not covered
✕ base +view-delete shortcut none view workflows not covered
✕ base +view-get shortcut none view workflows not covered
✕ base +view-get-card shortcut none view workflows not covered
✕ base +view-get-filter shortcut none view workflows not covered
✕ base +view-get-group shortcut none view workflows not covered
✕ base +view-get-sort shortcut none view workflows not covered
✕ base +view-get-timebar shortcut none view workflows not covered
✕ base +view-get-visible-fields shortcut none view workflows not covered
✕ base +view-list shortcut none view workflows not covered
✕ base +view-rename shortcut none view workflows not covered
✕ base +view-set-card shortcut none view workflows not covered
✕ base +view-set-filter shortcut none view workflows not covered
✕ base +view-set-group shortcut none view workflows not covered
✕ base +view-set-sort shortcut none view workflows not covered
✕ base +view-set-timebar shortcut none view workflows not covered
✕ base +view-set-visible-fields shortcut none view workflows not covered
✕ base +workflow-create shortcut none workflow CRUD not covered
✕ base +workflow-disable shortcut none workflow CRUD not covered
✕ base +workflow-enable shortcut none workflow CRUD not covered
✕ base +workflow-get shortcut none workflow CRUD not covered
✕ base +workflow-list shortcut none workflow CRUD not covered
✕ base +workflow-update shortcut none workflow CRUD not covered