# Shop app — checkout and payment test cases

## Basket and totals (CART)

| ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS |
|---|---|---|---|---|---|---|---|
| CART-01 | Changing quantities updates the total | Signed in. Two different items in the basket | 1. Open the basket. 2. Raise the first item's quantity by one. 3. Remove the second item. | The line price and the basket total change straight away and add up to the item price times the quantity. The removed item is still gone after reopening the app. | | | |
| CART-02 | A price change before payment is shown, not hidden | One item in the basket. Its price is changed in the admin after it was added | 1. Open the basket. 2. Tap Checkout. | The new price is shown with a line saying it has changed, before anything is charged. The total on the payment screen matches the new price. | | | |
| CART-03 | An item that sells out is caught before payment | One item in the basket. Its stock is set to zero in the admin after it was added | 1. Tap Checkout. 2. Try to pay. | A message says the item is no longer available, and checkout cannot continue with it in the basket. Nothing is charged and no order is created. | | | |
| CART-04 | A valid discount code is applied once | One item in the basket. A live percentage-off code | 1. Go to checkout. 2. Enter the code and tap Apply. 3. Tap Apply again. | The discount appears as its own line and the total drops by the right amount, once. Applying it again changes nothing. The receipt later shows the same discount. | | | |
| CART-05 | An expired or unknown code is refused clearly | One item in the basket. An expired code | 1. Enter the expired code and tap Apply. 2. Enter a made-up code and tap Apply. | Each attempt shows a message saying why the code was not applied. The total does not change. | | | |
| CART-06 | A code with a minimum spend is removed when the basket drops below it | A code that needs a minimum spend. A basket just over that minimum with the code applied | 1. Remove an item so the basket falls below the minimum. | The discount is removed with a message giving the minimum. The total goes back up before payment, not after. | | | |
| CART-07 | Tax and delivery follow the address | Signed in. One item in the basket. Two saved addresses in places with different tax or delivery rates | 1. Go to checkout with the first address. 2. Note the tax and delivery lines. 3. Switch to the second address. | Tax and delivery are recalculated for the second address before Pay is enabled. The total charged matches the total shown. | | | |

## Address and account (ADDR)

| ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS |
|---|---|---|---|---|---|---|---|
| ADDR-01 | Missing address fields are pointed out, and nothing typed is lost | Signed out. One item in the basket | 1. Check out as a guest. 2. Fill in every address field except the postcode. 3. Tap Continue. | The postcode field is marked with a message saying it is needed. Everything else is still filled in. | | | |
| ADDR-02 | Guest checkout works end to end | Signed out. Test mode. One item in the basket. An email address with no account. Stripe test card 4242 4242 4242 4242, any future expiry, any CVC | 1. Choose Check out as guest. 2. Enter the email and an address. 3. Pay with the test card. | The order is confirmed without creating a password. The receipt goes to the email entered, with a way to view the order. | | | |
| ADDR-03 | Signing in during checkout keeps the basket | Signed out with one item in the basket. An existing account with a different item already in its basket | 1. Tap Checkout. 2. Choose Sign in and sign in. | Checkout continues with the item you had before signing in, and it is clear what happened to the item already in the account's basket. Nothing is silently dropped or doubled. | | | |
| ADDR-04 | Changing country updates currency and delivery | Signed in. One item in the basket. The shop sells in more than one currency | 1. Go to checkout. 2. Change the delivery country to one that uses another currency. | Prices, delivery options and the total switch to the new currency before payment. The amount on the payment screen is in the same currency as the total. | | | |

## Payment (PAY)

| ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS |
|---|---|---|---|---|---|---|---|
| PAY-01 | Pay with a new card | Signed in. Test mode. One item in the basket. Stripe test card 4242 4242 4242 4242, any future expiry, any CVC | 1. Tap Checkout. 2. Enter the test card. 3. Tap Pay. | A confirmation shows an order number and the same total as the basket. The payment appears once in the provider's test dashboard, for that total. The basket is empty. | | | |
| PAY-02 | A declined card is handled | Signed in. Test mode. One item in the basket. Stripe test card 4000 0000 0000 0002 (always declined) | 1. Tap Checkout. 2. Enter the declining card. 3. Tap Pay. | A message says the card was declined and offers another way to pay. The basket keeps its item. No order appears under Orders and no receipt email is sent. | | | |
| PAY-03 | Insufficient funds is explained in plain words | Signed in. Test mode. One item in the basket. Stripe test card 4000 0000 0000 9995 (declined for insufficient funds) | 1. Tap Checkout. 2. Pay with the card. | A message says the card was declined and suggests another card, without showing raw provider codes. The card form stays open so another card can be entered. | | | |
| PAY-04 | An expired card or wrong CVC is pointed out at the field | Signed in. Test mode. One item in the basket. Stripe test cards 4000 0000 0000 0069 (expired) and 4000 0000 0000 0127 (incorrect CVC) | 1. Pay with the expired card. 2. Pay with the incorrect-CVC card. | Each attempt points to the field at fault: the expiry date, then the CVC. The rest of the form keeps what was typed. No order is created. | | | |
| PAY-05 | A 3-D Secure challenge that is passed | Signed in. Test mode. One item in the basket. Stripe test card 4000 0027 6000 3184 (always asks for authentication) | 1. Pay with the card. 2. On the authentication screen, choose to complete it. | The challenge opens inside the checkout, not as a broken or blank page. After passing it the order is confirmed and charged once. | | | |
| PAY-06 | A 3-D Secure challenge that is failed or closed | Signed in. Test mode. One item in the basket. Stripe test card 4000 0027 6000 3184 | 1. Pay with the card. 2. Choose to fail the authentication. 3. Pay again and this time close the challenge without answering. | Both times a message says the payment was not completed. The basket is kept, no order is created, and Pay can be tried again. | | | |
| PAY-07 | Tapping Pay twice charges once | Signed in. Test mode. A saved test card. One item in the basket | 1. Go to checkout. 2. Tap Pay twice, quickly. | The button shows it is working after the first tap. One order is created, one receipt is sent, and the test dashboard shows one payment. | | | |
| PAY-08 | Save a card for next time | Signed in. Test mode. No saved cards. Stripe test card 4242 4242 4242 4242 | 1. Pay with the card and tick Save this card. 2. Start a second checkout. | The saved card shows only its brand, the last four digits and the expiry. Paying with it does not ask for the full number again. | | | |
| PAY-09 | Pay with Apple Pay | Test mode. An Apple sandbox tester account signed in on the iPhone or Mac, with a test card in Wallet. One item in the basket | 1. Tap Checkout. 2. Tap the Apple Pay button. 3. Confirm with Face ID, Touch ID or the passcode. | The Apple Pay sheet shows the shop's name and the same total as the basket. After confirming, the order is confirmed and charged once. | | N/A | |
| PAY-10 | Pay with Google Pay | Test mode, with Google Pay set to its test environment. A Google account with a card in Google Wallet. One item in the basket | 1. Tap Checkout. 2. Tap the Google Pay button. 3. Choose the card and confirm. | The Google Pay sheet shows the same total as the basket. After confirming, the order is confirmed and charged once, and the card in Wallet is not charged for real. | | | N/A |
| PAY-11 | An in-app purchase completes | A test build of the app. An App Store sandbox account on iOS, or a Google Play licence tester account on Android | 1. Open the upgrade screen. 2. Tap Buy. 3. Confirm the purchase in the store sheet. | The store sheet shows the product name and the same price as the app. After confirming, the paid feature unlocks straight away and is still unlocked after closing and reopening the app. | N/A | | |
| PAY-12 | A cancelled in-app purchase leaves nothing unlocked | As PAY-11 | 1. Tap Buy. 2. Cancel the store sheet. | The app returns to the upgrade screen with no error and nothing unlocked. Tapping Buy again opens the store sheet as normal. | N/A | | |
| PAY-13 | Restore a purchase on a fresh install | A sandbox or licence tester account that has already bought the upgrade. The app deleted and reinstalled | 1. Open the upgrade screen. 2. Tap Restore purchases. | The paid feature unlocks without a second charge. | N/A | | |

## Interruptions and network (NET)

| ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS |
|---|---|---|---|---|---|---|---|
| NET-01 | The connection drops after tapping Pay | Signed in. Test mode. A saved test card. One item in the basket | 1. Tap Pay. 2. Turn on aeroplane mode before the confirmation appears. 3. Turn it off again. 4. Open Orders. | The app says the payment may not have gone through and how to check. Orders shows at most one order. Paying again does not charge twice. | | | |
| NET-02 | A slow payment ends in an answer, not an endless spinner | Signed in. Test mode. A saved test card. The connection throttled to a very slow network | 1. Tap Pay. 2. Wait without touching anything. | Pay stays disabled while waiting. The app either confirms the order or says it could not confirm the payment and how to check. It never sits spinning with no message. | | | |
| NET-03 | The app is sent to the background during payment | Signed in. Test mode. A saved test card. One item in the basket | 1. Tap Pay. 2. Go to the home screen straight away. 3. Wait a few seconds, then reopen the app. | The app shows the result of the payment: confirmed, failed or still checking. It does not show an empty checkout with the money taken, or a full basket for an order that went through. | N/A | | |
| NET-04 | Coming back from the bank or wallet app | Signed in. Test mode. A payment method that hands over to another app or a browser tab to approve | 1. Start the payment. 2. Approve it in the other app or tab. 3. Return to the shop. | The shop opens on the confirmation, not on the basket or the home screen. The order is created once. | | | |
| NET-05 | Back or refresh after paying does not pay again | Signed in. Test mode. An order just placed, with its confirmation on screen | 1. Refresh the page, or go back. 2. Go forward again, or open checkout. | The same order is shown, or the basket is empty. No second payment is attempted and nothing asks to resubmit. | | | |

## After the order (ORDER)

| ID | Journey | Preconditions | Steps | Expected result | WEB | AND | IOS |
|---|---|---|---|---|---|---|---|
| ORDER-01 | The confirmation matches what was charged | An order just paid in test mode | 1. Read the confirmation screen. 2. Find the payment in the provider's test dashboard. | The order number, items, delivery address and total on screen match the payment in the dashboard exactly, in the same currency. | | | |
| ORDER-02 | The receipt email arrives and is right | An order just paid in test mode, to an inbox you can open | 1. Open the inbox. | One receipt arrives within a few minutes, with the order number, items, discounts, tax, delivery and total matching the confirmation. The card shows only its last four digits. | | | |
| ORDER-03 | The order appears in order history | Signed in. An order just paid in test mode | 1. Open Orders. | The new order is at the top with its date, status and total. Opening it shows the same details as the receipt. | | | |
| ORDER-04 | A full refund shows on the order | An order paid in test mode, then refunded in full from the admin | 1. Open the order in the app. 2. Check the inbox. | The order shows as refunded, with the amount and date. A refund email arrives. The test dashboard shows one refund for the full amount. | | | |
| ORDER-05 | A partial refund shows the right amount | An order of two items paid in test mode. One item refunded from the admin | 1. Open the order in the app. | The refunded item and its amount are shown, and the amount paid is reduced by exactly that. The other item is unchanged. | | | |
| ORDER-06 | Cancel an order before it is sent | Signed in. An order paid in test mode and not yet dispatched | 1. Open the order. 2. Tap Cancel order and confirm. | The order shows as cancelled, a full refund is issued, and a cancellation email arrives. Cancel is no longer offered once an order has been dispatched. | | | |
