Files
larksuite__cli/tests/cli_e2e/sheets/coverage.md
xiongyuanwen-byted 2f8d816512 fix(sheets): make image-upload previews match what Execute sends (#2537)
* fix(sheets): repair the build after the local-office detection move

main does not compile: shortcuts/sheets/lark_sheet_workbook.go references
isOfficeSpreadsheet and officePrefixes, which no longer exist in the package.

Neither PR was wrong on its own. #2531 (merged 10:39) moved local-office token
detection into common.IsLocalOfficeToken and deleted the sheets-local copies;
#2533 (merged 12:48) added errLocalOfficeExportUnsupported, which calls them.
#2533's branch predated the move, so its CI was green against a base that still
had the symbols, and merging it left main broken.

Repoints both references at the moved API. Behaviour is unchanged:
common.IsLocalOfficeToken is the same predicate #2531 moved, and the prefix pair
is the exported form of the same two constants. #2533's own coverage —
TestWorkbookExport_LocalOfficeTokenRejected across the local_office_ prefix, the
fake_office_ prefix, and an interleaved OFL0X token, plus the wiki-node and
dry-run cases — passes unchanged, which is what pins the equivalence.

* fix(sheets): derive dry-run image parent_type from the ref kind, not the token

A `/wiki/` URL reaches a DryRun hook as the wiki node_token: resolving it to the
backing spreadsheet needs the get_node call a preview must not make. Both
image-upload previews fed that node_token straight to sheetMediaParentType, so
the parent_type they showed was derived from a token that is not the one Execute
uploads against. A node_token shaped like an imported office token previewed
office_sheet_file for a spreadsheet that will upload as sheet_image.

sheetsDryRunParentType decides from the ref's kind instead. A wiki ref is native
by construction, not by default: resolveWikiNodeToSpreadsheetToken rejects any
node whose obj_type is not "sheet", and a spreadsheet backed by an imported
office file sits in drive as a "file" node, so it never survives that gate to
reach an upload. Execute is unaffected either way — it derives from the resolved
token. This mirrors slidesDryRunParentType, which the slides domain already
applies for the same reason.

The hooks now hold the parsed ref rather than re-deriving the token from it, so
the kind is visible where the preview is built.

Also records, at uploadSheetMediaFile, that office_sheet_file survives the
multipart path. Slides caps image uploads at 20 MB because upload_prepare
rejects its parent types outright, which raised the question for sheets, whose
deprecated +media-upload has no such cap. Verified against the live API:
upload_prepare accepts both sheet_image and office_sheet_file, and a 20.6 MB
file uploaded with office_sheet_file completes prepare -> 6 x upload_part ->
upload_finish and returns a file_token a float image then accepts.

Tests: sheetsDryRunParentType over both ref kinds, including wiki refs carrying
office-shaped and office-prefixed node tokens; dry-run coverage through the
public flags for +cells-set-image and +float-image-create, each checked against
the identical token as a /wiki/ URL and as a raw spreadsheet token so the two
rows differ only in kind; the same pair added to the e2e dry-run lane. All four
fail against the previous behaviour.

* fix(sheets): send oversized images through the chunked upload, not upload_all

uploadSheetImage always used the single-part endpoint, so an image past the
20 MB ceiling failed with a bare 1061002 "upload media failed: params error"
naming neither the size nor the limit. The capability was already in the domain:
the deprecated sheets +media-upload has dispatched by size since it was written
(backward.uploadSheetMediaFile), which left the same image succeeding through
the old shortcut and failing through +cells-set-image and +float-image-create,
the ones meant to replace it.

uploadSheetImage now picks the endpoint by size the way doc and the deprecated
shortcut already do. The parent_type is unchanged and still comes from
sheetMediaParentType, so the office/native split rides along either branch.

The preview follows the same branch. appendSheetImageUploadDryRun renders one
upload_all under the ceiling and the upload_prepare / upload_part /
upload_finish trio above it, and both image-write hooks now build their upload
step through it rather than each spelling out an upload_all. A preview that
promised a single-part upload for a file the CLI will send in chunks is a
preview of a different request.

Verified against the live API with a 20.6 MB PNG: +cells-set-image and
+float-image-create both complete, the cell reads back holding the uploaded
image_token at the file's real 3000x2400 dimensions, and the dry-run shows the
three chunked steps Execute hits. The same file failed with 1061002 before.

Tests: the chunked branch at exactly one byte past the ceiling, asserted through
upload_prepare's parent_type with upload_all deliberately left unstubbed so a
regression fails loudly; the preview's step list on both sides of the boundary,
as a unit test and in the e2e dry-run lane. All fail against the previous
behaviour.
2026-08-28 14:51:14 +08:00

7.8 KiB

Sheets CLI E2E Coverage

Metrics

  • Denominator: 30 leaf commands
  • Covered: 18
  • Coverage: 60.0%

Summary

  • TestSheets_CRUDE2EWorkflow: proves +create, +info, +write, +read, +append, +find, and +export; key t.Run(...) proof points are create spreadsheet with +create as bot, read data with +read as bot, find cells with +find as bot, and export spreadsheet with +export as bot.
  • TestSheets_CreateWorkflowAsUser: proves the UAT path for sheets +create and sheets +info through create spreadsheet with +create as user and get spreadsheet info with +info as user.
  • TestSheets_SpreadsheetsResource: proves direct spreadsheets create, spreadsheets get, and spreadsheets patch.
  • TestSheets_FilterWorkflow: proves spreadsheet.sheet.filters create, get, update, and delete, with supporting sheet setup through +create, +info, and +write.
  • TestSheets_SheetShortcutsDryRun: proves request shapes for +create-sheet, +copy-sheet, +delete-sheet, and +update-sheet without hitting live APIs.
  • TestSheets_SheetShortcutsWorkflow: proves live +create-sheet, +copy-sheet, +update-sheet, and +delete-sheet flows against a real spreadsheet, with verification through +info.
  • TestSheets_ImageUploadDryRunParentType: dry-run coverage for the drive parent_type an image upload carries, across every surface a local file enters through — +media-upload, +cells-set-image, and +float-image-create. A native spreadsheet must upload as sheet_image and one backed by an imported office file as office_sheet_file; a /wiki/ ref must stay native, because a preview cannot resolve the node and so must not read the split out of the node_token. The negative half matters most: the backend does not validate parent_node against parent_type, so a wrong value uploads successfully and only surfaces later as an image that will not render.
  • TestSheets_ImageUploadDryRunChunked: dry-run coverage for the 20 MB branch in +cells-set-image. Under the ceiling the preview shows one upload_all; one byte past it, the upload_prepare / upload_part / upload_finish trio Execute actually sends. Before that dispatch existed, an oversized image failed on upload_all with a bare 1061002 naming neither the size nor the limit.
  • Cleanup note: workflow-created spreadsheets are cleaned up via drive +delete --type sheet; those cleanup-only executions are not counted as command coverage because no testcase asserts delete behavior as the primary proof surface.

Command Table

Status Cmd Type Testcase Key parameter shapes Notes / uncovered reason
✕ sheets +add-dimension shortcut none no dimension workflow yet
✓ sheets +append shortcut sheets_crud_workflow_test.go::TestSheets_CRUDE2EWorkflow/append rows with +append as bot --spreadsheet-token; --sheet-id; --range; --values
✕ sheets +batch-set-style shortcut none no style workflow yet
✓ sheets +create shortcut sheets_crud_workflow_test.go::TestSheets_CRUDE2EWorkflow/create spreadsheet with +create as bot; sheets_filter_workflow_test.go::TestSheets_FilterWorkflow/create spreadsheet with initial data as bot; sheets_create_workflow_test.go::TestSheets_CreateWorkflowAsUser/create spreadsheet with +create as user --title
✓ sheets +create-sheet shortcut sheets_sheet_shortcuts_workflow_test.go::TestSheets_SheetShortcutsWorkflow/create sheet with +create-sheet as bot --spreadsheet-token; optional --title; optional --index dry-run shape also covered by sheets_sheet_shortcuts_dryrun_test.go
✓ sheets +copy-sheet shortcut sheets_sheet_shortcuts_workflow_test.go::TestSheets_SheetShortcutsWorkflow/copy sheet with +copy-sheet as bot --spreadsheet-token; --sheet-id; optional --title; optional --index dry-run shape also covered by sheets_sheet_shortcuts_dryrun_test.go
✕ sheets +delete-dimension shortcut none no dimension workflow yet
✓ sheets +delete-sheet shortcut sheets_sheet_shortcuts_workflow_test.go::TestSheets_SheetShortcutsWorkflow/delete sheet with +delete-sheet as bot --spreadsheet-token; --sheet-id dry-run shape also covered by sheets_sheet_shortcuts_dryrun_test.go
✓ sheets +export shortcut sheets_crud_workflow_test.go::TestSheets_CRUDE2EWorkflow/export spreadsheet with +export as bot --spreadsheet-token; --file-extension
✓ sheets +find shortcut sheets_crud_workflow_test.go::TestSheets_CRUDE2EWorkflow/find cells with +find as bot --spreadsheet-token; --sheet-id; --find; --range
✓ sheets +info shortcut sheets_crud_workflow_test.go::TestSheets_CRUDE2EWorkflow/get spreadsheet info with +info as bot; sheets_filter_workflow_test.go::TestSheets_FilterWorkflow/get sheet info as bot; sheets_create_workflow_test.go::TestSheets_CreateWorkflowAsUser/get spreadsheet info with +info as user --spreadsheet-token
✕ sheets +insert-dimension shortcut none no dimension workflow yet
✕ sheets +merge-cells shortcut none no merge workflow yet
✕ sheets +move-dimension shortcut none no dimension workflow yet
✓ sheets +read shortcut sheets_crud_workflow_test.go::TestSheets_CRUDE2EWorkflow/read data with +read as bot --spreadsheet-token; --sheet-id; --range
✕ sheets +replace shortcut none no replace workflow yet
✕ sheets +set-style shortcut none no style workflow yet
✕ sheets +unmerge-cells shortcut none no merge workflow yet
✕ sheets +update-dimension shortcut none no dimension workflow yet
✓ sheets +update-sheet shortcut sheets_sheet_shortcuts_workflow_test.go::TestSheets_SheetShortcutsWorkflow/update sheet with +update-sheet as bot --spreadsheet-token; --sheet-id; scalar update flags; optional protect fields dry-run shape also covered by sheets_sheet_shortcuts_dryrun_test.go
✓ sheets +write shortcut sheets_crud_workflow_test.go::TestSheets_CRUDE2EWorkflow/write data with +write as bot; sheets_filter_workflow_test.go::TestSheets_FilterWorkflow/write test data for filtering as bot --spreadsheet-token; --sheet-id; --range; --values
✕ sheets +write-image shortcut none no image workflow yet
✓ sheets spreadsheet.sheet.filters create api sheets_filter_workflow_test.go::TestSheets_FilterWorkflow/create filter with spreadsheet.sheet.filters create as bot spreadsheet_token; sheet_id in --params; filter JSON in --data
✓ sheets spreadsheet.sheet.filters delete api sheets_filter_workflow_test.go::TestSheets_FilterWorkflow/delete filter with spreadsheet.sheet.filters delete as bot spreadsheet_token; sheet_id in --params
✓ sheets spreadsheet.sheet.filters get api sheets_filter_workflow_test.go::TestSheets_FilterWorkflow/get filter with spreadsheet.sheet.filters get as bot spreadsheet_token; sheet_id in --params
✓ sheets spreadsheet.sheet.filters update api sheets_filter_workflow_test.go::TestSheets_FilterWorkflow/update filter with spreadsheet.sheet.filters update as bot spreadsheet_token; sheet_id in --params; filter JSON in --data
✕ sheets spreadsheet.sheets find api none no direct API workflow yet
✓ sheets spreadsheets create api sheets_crud_workflow_test.go::TestSheets_SpreadsheetsResource/create spreadsheet with spreadsheets create as bot title in --data
✓ sheets spreadsheets get api sheets_crud_workflow_test.go::TestSheets_SpreadsheetsResource/get spreadsheet with spreadsheets get as bot spreadsheet_token in --params
✓ sheets spreadsheets patch api sheets_crud_workflow_test.go::TestSheets_SpreadsheetsResource/patch spreadsheet with spreadsheets patch as bot spreadsheet_token in --params; title patch in --data