Files
larksuite__cli/tests/cli_e2e/slides/coverage.md
R0bynZhu b343e67639 feat(slides): use office_slide_file parent_type for imported office presentations (#2441)
Image uploads to a presentation hard-coded parent_type=slide_file at every
entry point. Imported "office" presentations carry either a legacy synthetic
token prefix ("fake_office_" / "local_office_") or a 28-character token whose
interleaved product/region marker is "OFL0X", and for those the drive backend
requires parent_type=office_slide_file. This mirrors the office_sheet_file rule
the sheets domain already applies: the token shapes are identical, because an
imported office file is an imported office file whether it backs a spreadsheet
or a deck.

Funnel the selection through one slides-domain helper so the rule lives in a
single place and every image-upload path stays consistent with its own dry-run
preview. As in sheets, the rule stays inside the domain rather than leaking
into common.UploadDriveMediaAllTyped, which mail/doc/drive/base/calendar share.

- Replace the slidesMediaParentType const with slidesMediaParentType(token),
  backed by isOfficePresentation(token); keep the native and office values as
  named constants.
- Route both parent_type call sites through it: uploadSlidesMedia (the Execute
  path shared by +media-upload and the <img src="@path"> placeholder pipeline
  behind +create / +add-slide / +update-slide) and appendSlidesUploadDryRun.
- Known gap, documented at the helper: when --presentation is a wiki URL the
  dry-run only has a "<resolved_slides_token>" placeholder, since the real
  token needs a get_node call the preview must not make, so such a preview
  shows slide_file regardless. Execute is unaffected -- it resolves first.

The negative half of the mapping is what the tests weight most heavily. The
backend does not validate parent_node against parent_type, so a native deck
misread as office still uploads successfully and only surfaces later as an
image that will not render, far from its cause; the marker check is therefore
pinned at its exact length and offsets rather than a looser "contains OFL0X".

Tests:
- shortcuts/slides/slides_media_parent_type_test.go: 14-case pure-function
  table (off-by-one length, prefix appearing mid-string, wiki placeholder),
  a real-multipart Execute assertion across four token shapes, and the
  +add-slide / +update-slide placeholder dry-run previews.
- tests/cli_e2e/slides/slides_image_upload_dryrun_test.go: five cases through
  the built binary, covering every surface a local file can enter through.
- Verified non-vacuous: short-circuiting the office branch fails all three
  package tests plus the e2e lane.

Evidence note: office_slide_file is confirmed accepted by upload_all, and the
symmetry with office_sheet_file is exact, but this has not been exercised
against a real imported-pptx presentation to confirm slide_file fails there.
2026-08-21 15:12:35 +08:00

7.6 KiB

Slides CLI E2E Coverage

Metrics

  • Denominator: 6 leaf commands
  • Covered: 5
  • Coverage: 83.3%

Summary

  • TestSlides_CreateWorkflowAsUser: proves the user slides workflow through create presentation with slide as user and get created presentation xml as user; creates a fresh presentation, asserts returned IDs, then reads back the XML content to prove the title and slide body persisted.
  • TestSlidesCreateRepeatedSlideFileDryRunE2E / TestSlidesCreateSlidesFileAndStdinDryRunE2E / TestSlidesCreateRejectsBothSlideFormsDryRunE2E: cover the +create file inputs through the built binary, which is the only layer that can prove the point of the feature — a multi-line, quote-heavy page reaches slide.content byte-for-byte with no JSON encoder in the caller's hands, and repeated --slide order is page order. The refusal case pins the exit-2 envelope (param: "--slide") that an agent parses to repair its own command; the package test never runs the dispatcher and so cannot see it.
  • TestSlidesAddSlideDryRunE2E / TestSlidesDeleteSlideDryRunE2E: pin the request shapes the unit tests cover, but through the real binary, which is the only layer that proves a full <slide> XML document survives flag parsing with its quotes and angle brackets intact. Delete additionally proves the shortcut runs without --yes, unlike the high-risk-write raw command.
  • TestSlides_SlideAddDeleteWorkflowAsUser: live add/delete round trip on a throwaway presentation created and torn down per run. Asserts against a readback rather than the write's own response, so it proves what the request shape cannot: the returned slide_id addresses a real page, --before-slide-id positions the page between its neighbours instead of merely being forwarded, and the deleted page is gone while both neighbours survive.
  • TestSlidesUpdateSlideDryRunE2E / TestSlidesUpdateAliasDryRunE2E / TestSlidesUpdateSlideRefuses*DryRunE2E: dry-run coverage for +update-slide through the built binary — one request carrying one block_replace part whose block_id is the PAGE id (the whole design; an element id there would replace one element and leave the rest of the page), the slide service alias / +update command alias / --xml spelling, and the two refusals that must not produce a request (a bare element root, and a root id naming a different page).
  • TestSlidesUpdateSlideLiveE2E: required live-backend assertion for +update-slide; creates a throwaway presentation with the lane's bot credential, replaces its page using the returned page id as block_id, reads that page back through +xml-get, verifies the new marker replaced the old marker without changing slide_id, and self-cleans.
  • TestSlides_HistoryWorkflow: opt-in live round-trip coverage for +update-slide; creates a presentation, updates its page in place, asserts the returned slide_id, the persisted marker, and that an element written back with its original id keeps that id, then reverts through slide history and self-cleans. It runs only when LARK_SLIDES_HISTORY_E2E=1 and therefore does not yet exercise the default live lane.
  • TestSlidesReplaceSlideNormalizationDryRunE2E / TestSlidesReplaceSlideEmptyReplacementDryRunE2E / TestSlidesReplaceSlideDryRunE2E: dry-run coverage for +replace-slide through the built binary. The normalization case proves replace / insert, target_id, content, and element become a canonical request and that structured output records all conversions. The other cases preserve the strict boundary: an actually-empty canonical payload still fails, while a legitimate mixed block_replace + block_insert batch remains unchanged.
  • TestSlides_ReplaceSlideAliasWorkflowAsUser: live alias round trip on a throwaway presentation. It reads server-assigned block IDs, replaces one target through replace / target_id / content, inserts another through insert / element, reads the deck back to prove both writes persisted in the requested position while a control block survived, and deletes the presentation in cleanup.
  • TestSlides_ImageUploadDryRunParentType: dry-run coverage for the drive parent_type an image upload carries, across every surface a local file can enter through — +media-upload --file and the <img src="@..."> placeholder pipeline behind +add-slide / +update-slide. A native deck must upload as slide_file and an imported "office" deck as office_slide_file; the negative half matters most, because the backend does not validate parent_node against the parent_type, so a wrong value uploads successfully and only shows up later as an image that will not render.
  • Blocked area: slides +media-upload is still uncovered live because it needs a deterministic local image fixture plus XML follow-up proof that is separate from the base create/read workflow. The dry-run lane above covers the request shape only.

Command Table

Status Cmd Type Testcase Key parameter shapes Notes / uncovered reason
✓ slides +create shortcut slides_create_workflow_test.go::TestSlides_CreateWorkflowAsUser/create presentation with slide as user; slides_create_slide_inputs_dryrun_test.go::TestSlidesCreateRepeatedSlideFileDryRunE2E, TestSlidesCreateSlidesFileAndStdinDryRunE2E, TestSlidesCreateRejectsBothSlideFormsDryRunE2E --title; --slides ["<slide ...>"] / --slides @deck.json / --slides -; repeated --slide @page.xml live lane reads back through raw slides API to prove persisted XML; dry-run lane pins the file inputs and the mutual-exclusion refusal
✓ slides +add-slide shortcut slides_slide_add_delete_dryrun_test.go::TestSlidesAddSlideDryRunE2E; slides_slide_add_delete_workflow_test.go::TestSlides_SlideAddDeleteWorkflowAsUser --slide "<slide ...>"; --before-slide-id; --revision-id live append and insert both verified by reading the deck back
✓ slides +delete-slide shortcut slides_slide_add_delete_dryrun_test.go::TestSlidesDeleteSlideDryRunE2E, TestSlidesDeleteSlideWikiDryRunE2E; slides_slide_add_delete_workflow_test.go::TestSlides_SlideAddDeleteWorkflowAsUser --slide-id; --revision-id; wiki URL live delete runs on a throwaway deck; readback proves the neighbours survive
✓ slides +update-slide shortcut slides_update_slide_dryrun_test.go::TestSlidesUpdateSlideDryRunE2E (+ alias / refusal cases); slides_update_slide_workflow_test.go::TestSlidesUpdateSlideLiveE2E; slides_history_workflow_test.go::TestSlides_HistoryWorkflow (opt-in history/revert) --presentation; --slide-id; --content "<slide ...>"; --revision-id default live CI proves a real in-place update and readback; opt-in workflow adds history/revert and element-id preservation
✓ slides +replace-slide shortcut slides_replace_slide_dryrun_test.go::TestSlidesReplaceSlideNormalizationDryRunE2E, TestSlidesReplaceSlideEmptyReplacementDryRunE2E, TestSlidesReplaceSlideDryRunE2E; slides_replace_slide_workflow_test.go::TestSlides_ReplaceSlideAliasWorkflowAsUser --presentation; --slide-id; canonical and compatibility --parts shapes dry-run pins canonical request construction and validation; live workflow proves alias replace/insert persistence, target ID preservation, insertion ordering, control-block survival, and cleanup
✕ slides +media-upload shortcut slides_image_upload_dryrun_test.go::TestSlides_ImageUploadDryRunParentType (dry-run only) --presentation with a native vs. an imported-office token; --file dry-run lane pins the native/office parent_type split across +media-upload and the @path placeholder pipeline; still ✕ because nothing uploads for real — that needs a stable local image fixture plus follow-up slide XML proof