---
id: TST-COM-FUL-084
title: Carrier adapters
kind: unit
product_area: commerce
module: fulfillment
revision: 1
status: draft
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
repository: services-commerce
files:
  - modules/shipping/tests/unit/carriers/carrier-adapters.spec.js
implements:
  - ATS-COM-FUL-011-05
  - ATS-COM-FUL-013-02
  - ATS-COM-FUL-013-04
  - ATS-COM-FUL-013-05
  - ATS-COM-FUL-013-06
environment: mock
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 1
isolation: 'In-memory inputs, recorded calls and test-owned doubles; no shared customer records.'
evidence:
  - repository: services-commerce
    path: modules/shipping/tests/unit/carriers/carrier-adapters.spec.js
    test_titles:
      - 'rates nothing, with the warning that says so'
      - 'answers the clerk’s details as the purchased label, under the request’s key'
      - >-
        fails a purchase with no details, not retryable, and one with a cost that is not a whole
        non-negative number
      - voids every label and tracks nothing
      - 'applies the markup in basis points, rounding half away from zero'
      - >-
        quotes through shipping.rate.quote@1 on the account’s connection as commerce, naming the
        account as the binding’s resource and the shipper number
      - 'answers the quoted options with the account’s markup on each, the carrier the account’s'
      - 'asks for the services the request names, else the account’s, and keeps the options to them'
      - 'answers a failed quote as no option with the contract’s code in a warning, never a throw'
      - >-
        answers a quote between addresses that name nothing as no option with a warning, sending
        nothing
      - >-
        fails a label to an address that names nothing invalid.address, not retryable, sending
        nothing
      - >-
        buys a label through shipping.label.purchase@1 under the label’s key, the shipment as the
        subject
      - >-
        answers a purchased label with its tracking number, the carrier cost and the label as a pdf
        data URI, the connection’s default when the request names no format
      - >-
        sends no label format when the request names none, so the connection’s default_label_format
        stands
      - >-
        asks for the label format the request names (zpl for a thermal printer), and answers the
        data URI in it
      - >-
        sends each request as the port’s fields without the account, the label’s key on the
        invocation and never in the request
      - >-
        has a label format the contract does not take (gif) refused by the gateway’s validation, so
        no adapter is asked
      - 'sends no shipper number for an account without one, so the connection’s own setting stands'
      - 'answers a refused purchase as failed with the contract’s code and message, not retryable'
      - answers a purchase the provider could not serve as failed and retryable
      - 'answers an unknown purchase as uncertain with the execution, never bought again'
      - answers a purchase whose key the gateway still holds (in_progress) as uncertain
      - >-
        looks a purchase in flight up through shipping.shipment.lookup@1 by its key, and answers the
        label the carrier holds
      - answers a lookup the carrier holds nothing for as not found
      - 'answers a lookup by the key alone as unknown, as UPS does'
      - >-
        voids through shipping.label.void@1 under the void’s key, by the tracking number and the
        carrier reference
      - answers a refused void as failed with the contract’s code
      - >-
        names each void attempt by its label and its number (void:<label id>:<attempt>), a new key
        for each attempt
      - refuses a void attempt that is not a whole number from 1
      - >-
        voids again after an unknown outcome under a new key, so the gateway runs the retry rather
        than answer from the first execution
      - 'tracks through shipping.shipment.track@1, the statuses the port’s own'
      - >-
        refuses a call the gateway refused before anything ran (no_binding) as 503
        carrier_unavailable with the reason, sent once
      - >-
        refuses a call the gateway answered refused (binding_ineligible) as 503 carrier_unavailable
        with the reason
      - 'refuses an account with no connection as 503 carrier_unavailable, sending nothing'
      - >-
        refuses every call 503 carrier_unavailable in a function without the integrations_invoke
        grant, sending nothing
      - answers a timeout and a rate limit as failed and retryable
      - >-
        answers an invalid request as failed and not retryable, the contract’s code as it is (never
        ups_<code>)
      - >-
        answers a purchase the gateway gave no answer to (IntegrationInvokeFailed) as uncertain, so
        it stays in flight
      - >-
        refuses a purchase on a disconnected connection (IntegrationInvokeRefused) as 503
        carrier_unavailable, not in flight
      - 'answers a rate UPS refused (ups:01) as no option with the refusal’s code in a warning'
      - >-
        answers a rate that timed out, was never answered, was rate limited or unmapped (ups:02 to
        ups:05) as no option with a warning each
      - >-
        answers a label UPS refused (ups:01) as failed refused.shipper_account_invalid, not
        retryable, on every attempt
      - 'answers a label that timed out before send (ups:02) as failed and retryable, nothing sold'
      - >-
        answers a label sold and never answered (ups:03) as uncertain, and the same key asked again
        as that same label, never a second
      - >-
        finds a label sold and never answered (ups:03) by its tracking number, and not by its key
        alone
      - >-
        answers a rate-limited label (ups:04) as failed and retryable, and a new attempt’s key as a
        new execution limited again
      - >-
        answers a label UPS answered with an error the adapter does not map (ups:05) as failed
        invalid.request, not retryable
      - >-
        answers a void UPS refused (ups-01 in the carrier reference) as failed
        refused.void_window_closed
      - >-
        answers a void never answered (ups-03) 503 carrier_unavailable each attempt, each under its
        own key
      - >-
        routes each call to the account’s carrier, and refuses an account whose carrier has no
        adapter
      - >-
        answers unknown for the lookup of a purchase on a carrier with no lookup (the manual
        counter)
    scenario_anchors:
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#applies the
        markup in basis points, rounding half away from zero
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers the
        quoted options with the account’s markup on each, the carrier the account’s
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers a
        failed quote as no option with the contract’s code in a warning, never a throw
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers an
        unknown purchase as uncertain with the execution, never bought again
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers the
        clerk’s details as the purchased label, under the request’s key
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#fails a
        purchase with no details, not retryable, and one with a cost that is not a whole
        non-negative number
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#rates
        nothing, with the warning that says so
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#voids every
        label and tracks nothing
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#buys a label
        through shipping.label.purchase@1 under the label’s key, the shipment as the subject
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#refuses an
        account with no connection as 503 carrier_unavailable, sending nothing
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#refuses
        every call 503 carrier_unavailable in a function without the integrations_invoke grant,
        sending nothing
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers a
        timeout and a rate limit as failed and retryable
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers an
        invalid request as failed and not retryable, the contract’s code as it is (never ups_<code>)
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers a
        purchase the gateway gave no answer to (IntegrationInvokeFailed) as uncertain, so it stays
        in flight
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#refuses a
        purchase on a disconnected connection (IntegrationInvokeRefused) as 503 carrier_unavailable,
        not in flight
      - >-
        services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#names each
        void attempt by its label and its number (void:<label id>:<attempt>), a new key for each
        attempt
---

# Carrier adapters

## Verification Boundary

This suite checks carrier adapters with controlled inputs and recorded dependencies. Its entry points remain within the process.

## What This Suite Proves

The bound scenarios identify the assertions this suite contributes. Source anchors retain the exact test cases; where a capability scenario has several contributing suites, a single binding does not imply that every branch runs here.

## What It Does Not Prove

Controlled inputs do not establish database enforcement, deployed integration or browser behavior. A recorded call is evidence about the adapter contract rather than a remote operation.

## Real Dependencies and Test Doubles

The imported logic is real; test inputs and dependency responses are controlled. Carrier integration answers use the local gateway’s scripted outcomes.

## Must Not Be Doubled

Keep the imported production logic and its request construction real. Record dependency calls and refusals rather than replacing the behavior being asserted.
