How would you test the cart API response?

Instruction: Write a focused API test that checks the supplied contract and expected result. Explain what a successful HTTP status alone would miss.

Context:

A fictional API returns cart C7 from GET /carts/C7. The independent seed contains a $25.00 subtotal, a $5.00 discount and $3.00 shipping, all in USD. The contract requires HTTP 200, JSON, the matching string ID and currency, and nonnegative safe-integer fields subtotal_cents, discount_cents, shipping_cents and total_cents. Discount cannot exceed subtotal; total equals subtotal minus discount plus shipping. Additional fields are allowed. A test API base URL and independently seeded C7 are available.

Updated

Example Answer

I would check the exact success status, JSON content type, identity, currency, required numeric types and the independently known total of 2,300 cents. I would also assert the monetary relationship across fields. A response can be HTTP 200 while returning another customer's cart, a string instead of cents, or internally inconsistent totals.

The fixture values and the relationship serve different purposes. If every amount were incorrectly doubled, the relationship might still hold, but the fixed expected amounts would fail. I would permit extra fields because the stated contract allows them. This one test establishes the happy-path response; it does not establish authentication, authorization or every discount rule.

Worked exhibit

import { test, expect } from '@playwright/test';

// baseURL points to the exercise API; cart C7 is independently seeded.
test('C7 exposes the agreed monetary contract', async ({ request }) => {
  const response = await request.get('/carts/C7');
  expect(response.status()).toBe(200);
  expect(response.headers()['content-type']).toMatch(/^application\/json\b/);
  const cart = await response.json();
  expect(cart.id).toBe('C7');
  expect(cart.currency).toBe('USD');
  for (const key of ['subtotal_cents', 'discount_cents',
                     'shipping_cents', 'total_cents']) {
    expect(Number.isSafeInteger(cart[key]), key).toBe(true);
    expect(cart[key], key).toBeGreaterThanOrEqual(0);
  }
  expect(cart).toMatchObject({
    subtotal_cents: 2500, discount_cents: 500,
    shipping_cents: 300, total_cents: 2300,
  });
  expect(cart.discount_cents).toBeLessThanOrEqual(cart.subtotal_cents);
  expect(cart.total_cents).toBe(
    cart.subtotal_cents - cart.discount_cents + cart.shipping_cents
  );
});

What the interviewer is assessing

Core checks (1 point each):

  • Asserts 200, JSON, C7 identity and USD.
  • Validates nonnegative safe-integer amounts and independent 2300-cent total.
  • Checks the monetary relationship while permitting added fields.

Stronger (+1 after all core checks): Explains why a fixed expected value catches correlated calculation errors that an invariant alone misses. Equivalent assertion libraries or schema-plus-business assertions receive full credit.

Acceptable alternatives: Schema validation plus independent business checks is equivalent.

Red flags: Checks only status or field presence; derives every expected amount from the response; rejects harmless extra fields despite the contract.

Follow-up

How would you test a missing cart?

Example response: I would use an independently guaranteed unused ID and assert the documented missing-resource status and error code, plus absence of cart data. If the contract specifies 404 with {"code":"cart_not_found"}, those are the assertions. I would not decide that 200 with an empty object is acceptable merely because that is what the implementation currently returns.

Related Questions