Skip to content

test: cover the cart capability (cart.md) - #108

Open
vishkaty wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:test/cart-capability-conformance
Open

test: cover the cart capability (cart.md)#108
vishkaty wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:test/cart-capability-conformance

Conversation

@vishkaty

Copy link
Copy Markdown
Contributor

What

Adds cart_test.py, covering the cart capability. The suite has no cart
coverage today: the string dev.ucp.shopping.cart appears nowhere in the
repository, and the only occurrence of the word is one English usage in a
fulfillment_structure_test.py docstring. The reference server implements and
advertises the capability, so it is testable now.

Four assertions, each traced to a MUST, each verified on the wire:

assertion source
cart contents win over overlapping fields in the checkout payload cart.md:66
a second conversion of the same cart returns the existing incomplete checkout cart.md:72-74
cancel returns the cart state as it was before deletion cart.md:185
discount codes applied to a cart carry forward to the checkout discount.md:143

Line references are to release/2026-04-08, the version this suite targets.

Kept server agnostic

Issues #101 to #103 point out that assertions elsewhere encode the reference
merchant rather than the specification, so this module avoids that by
construction:

  • line items are compared as a bag of item id and quantity, never by
    server assigned identifiers
  • the conversion identity check compares checkout ids, not totals arithmetic
  • both 200 and 201 are accepted where the specification pins no status
  • the item and discount code come from fixture_ctx, so nothing is hardcoded
  • the discount assertion accepts any of the three wire signals a conformant
    business may use: the echoed code, an applied entry, or a negative
    discount total, because discount.md:145 lets a business drop a code that
    is no longer valid at checkout time

The module gates on the capability being advertised and skips honestly
otherwise, since cart is deliberately not in conformance_input.json
required_capabilities. The discount assertion additionally skips unless the
discount capability declares it extends cart, which discount.md:59 permits it
not to.

Deliberately not asserted

Two nearby rules look assertable and are not, which is worth stating so the
omission does not read as an oversight:

  • cart.md:176 ("full replacement") binds the platform, not the business.
    The business side sentence carries no RFC 2119 keyword, so this suite cannot
    hold a merchant to it.
  • cart.md:186 (subsequent operations return not_found) is a SHOULD, so
    the status after cancel is not asserted.

Testing

Against the reference server at the pinned ucp-sdk==0.4.6, run exactly as the
workflow runs it: 4 passed.

Each assertion was then shown to fail on its own, by mutating the reference
server and re-running. Each mutation failed exactly one assertion and nothing
else:

mutation fails
take line items from the request payload cart contents
disable the existing checkout lookup conversion identity
empty the cart before returning it from cancel cancel state
drop cart discounts on conversion discount carry forward

Removing cart from the advertised profile makes all four skip rather than fail.
ruff check and ruff format --check are clean.

Whole suite run for a control: unchanged. order_test.py fails two tests both
before and after this change, on a pristine tree with a fresh database and this
file absent, so those are pre-existing and unrelated.

Note on #107

This lands as a top level cart_test.py, which is what the current workflow
picks up (for test_file in *_test.py). #107 relocates every module into
shopping/<capability>/. Its diff has no cart content, so there is no overlap,
but if it merges first this file should move to shopping/cart/cart_test.py.
Happy to rebase it that way, or to hold this until #107 lands, whichever suits.

The suite has no cart coverage today. The reference server implements and
advertises dev.ucp.shopping.cart, so the capability is testable, and cart.md
states business obligations that no existing module asserts.

This adds four assertions, each traced to a MUST:

  cart.md:66      cart contents win over overlapping fields in the checkout
                  payload on conversion
  cart.md:72-74   a second conversion of the same cart returns the existing
                  incomplete checkout rather than creating a new one
  cart.md:185     cancel returns the cart state as it was before deletion
  discount.md:143 discount codes applied to a cart carry forward to the
                  checkout the cart converts into

Kept server agnostic: line items are compared as a bag of item id and quantity
rather than by server assigned identifiers, the conversion identity check
compares checkout ids rather than totals arithmetic, both 200 and 201 are
accepted where the specification does not pin a status, and the discount
assertion accepts any of the three wire signals a conformant business may use.
The module gates on the capability being advertised and skips honestly
otherwise, since cart is not in conformance_input.json required_capabilities.

Two nearby rules are deliberately not asserted. cart.md:176 (full replacement)
binds the platform rather than the business, so it is not an obligation this
suite can hold a merchant to. cart.md:186 (subsequent operations return
not_found) is a SHOULD, so the status after cancel is not asserted.

Testing. Against the reference server at the pinned ucp-sdk 0.4.6, the four
assertions pass, and each was shown to fail on its own by mutating the server:
taking line items from the request payload fails the first, disabling the
existing checkout lookup fails the second, emptying the cart before returning it
from cancel fails the third, and dropping cart discounts on conversion fails the
fourth. Removing the capability from the advertised profile makes all four skip
rather than fail. ruff check and ruff format are clean.
@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:needs-triage Signal that the PR is ready for human triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants