ensure cart totals update when items are removed or quantity changed (https://github.com/woocommerce/woocommerce-blocks/pull/1840)

* ensure cart totals update when items are removed (prototype):
- return complete cart object from DELETE cart/items/:key
- use receiveCart on client to update whole cart including total

* move API endpoint for removing cart items to cart controller:
- returns full cart schema so should be part of cart controller
- is now a POST request with param - not strict REST
- fix up client action to use new API

* move API test for removing cart items (API has moved)

* use correct path for remove API in tests (doh!)

* add extra API test for remove_cart_item with bad key => 404 (experiment)

* experiment: delete test_remove_cart_item, does test_remove_bad_cart_item work?

* reinstate test_remove_cart_item with single valid request

* remove unnecessary newline

* tidy comments in PHP api tests, rerun travis?

* remove test_remove_cart_item which may be causing problems

* reinstate troublesome remove cart item api test (experiment):
- see if this works now travis issue is resolved

* whitespace

* show correct total when changing cart item quantity:
- move update cart item quantity API to cart controller
  - & return full cart response
- update js action to new API route & receive full cart response

* simplify test_remove_cart_item API test - now just tests a valid remove succeeds

* remove test_update_item (API has moved) +
+ experimentally remove test_remove_bad_cart_item
  - testing if cart remove tests interact with each other

* fix tests (🤞) - pass params in body, not as query params

* reinstate test for re-deleting same item

* update API docs - update/delete cart item have moved to /cart

* add response data checks to new cart API tests:
- extra protection against expected 404 "false positives"

* reinstate API test for changing cart item quantity

* fix remove cart item body tests - MIA items return error code, not cart

* fix test - quantity param is int not string

* attempt fix 404ing test_update_item:
- only allow POST, remove trailing `/`
- align array equals for good measure :)

* fix action for update-item - method=POST, now takes body params

* fix response body asserts in test_update_item

* reinstate update_item and delete_item on CartItems controller

* typos + examples in new cart items API docs

* reorder previous cart item docs to minimise diff/churn

* reinstate tabs in docs response example
This commit is contained in:
Rua Haszard 2020-03-06 08:11:39 +13:00 committed by GitHub
parent 52feba4f85
commit 5a26d2708e
4 changed files with 203 additions and 10 deletions

View File

@ -199,13 +199,13 @@ export function* removeItemFromCart( cartItemKey ) {
yield itemQuantityPending( cartItemKey, true ); yield itemQuantityPending( cartItemKey, true );
try { try {
yield apiFetch( { const cart = yield apiFetch( {
path: `/wc/store/cart/items/${ cartItemKey }`, path: `/wc/store/cart/remove-item/?key=${ cartItemKey }`,
method: 'DELETE', method: 'POST',
cache: 'no-store', cache: 'no-store',
} ); } );
yield receiveRemovedItem( cartItemKey ); yield receiveCart( cart );
} catch ( error ) { } catch ( error ) {
yield receiveError( error ); yield receiveError( error );
} }
@ -227,15 +227,17 @@ export function* changeCartItemQuantity( cartItemKey, quantity ) {
yield itemQuantityPending( cartItemKey, true ); yield itemQuantityPending( cartItemKey, true );
try { try {
const result = yield apiFetch( { const cart = yield apiFetch( {
path: `/wc/store/cart/items/${ cartItemKey }?quantity=${ quantity }`, path: `/wc/store/cart/update-item`,
method: 'PUT', method: 'POST',
data: {
key: cartItemKey,
quantity,
},
cache: 'no-store', cache: 'no-store',
} ); } );
if ( result ) { yield receiveCart( cart );
yield receiveCartItem( result );
}
} catch ( error ) { } catch ( error ) {
yield receiveError( error ); yield receiveError( error );
} }

View File

@ -103,6 +103,44 @@ class Cart extends RestController {
'schema' => [ $this, 'get_public_item_schema' ], 'schema' => [ $this, 'get_public_item_schema' ],
] ]
); );
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/remove-item',
[
[
'methods' => 'POST',
'callback' => [ $this, 'remove_cart_item' ],
'args' => [
'key' => [
'description' => __( 'Unique identifier (key) for the cart item.', 'woo-gutenberg-products-block' ),
'type' => 'string',
],
],
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/update-item',
[
[
'methods' => 'POST',
'callback' => [ $this, 'update_cart_item' ],
'args' => [
'key' => [
'description' => __( 'Unique identifier (key) for the cart item to update.', 'woo-gutenberg-products-block' ),
'type' => 'string',
],
'quantity' => [
'description' => __( 'New quantity of the item in the cart.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
],
],
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
} }
/** /**
@ -193,6 +231,54 @@ class Cart extends RestController {
return $response; return $response;
} }
/**
* Delete a single cart item.
*
* @param \WP_Rest_Request $request Full data about the request.
* @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
*/
public function remove_cart_item( $request ) {
$controller = new CartController();
$cart = $controller->get_cart_instance();
$cart_item = $controller->get_cart_item( $request['key'] );
if ( ! $cart_item ) {
return new RestError( 'woocommerce_rest_cart_invalid_key', __( 'Cart item does not exist.', 'woo-gutenberg-products-block' ), array( 'status' => 404 ) );
}
$cart->remove_cart_item( $request['key'] );
$data = $this->prepare_item_for_response( $cart, $request );
$response = rest_ensure_response( $data );
return $response;
}
/**
* Change quantity for specified cart item.
*
* @param \WP_Rest_Request $request Full data about the request.
* @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
*/
public function update_cart_item( $request ) {
$controller = new CartController();
$cart = $controller->get_cart_instance();
$cart_item = $controller->get_cart_item( $request['key'] );
if ( ! $cart_item ) {
return new RestError( 'woocommerce_rest_cart_invalid_key', __( 'Cart item does not exist.', 'woo-gutenberg-products-block' ), array( 'status' => 404 ) );
}
if ( isset( $request['quantity'] ) ) {
$cart->set_quantity( $request['key'], $request['quantity'] );
}
$data = $this->prepare_item_for_response( $cart, $request );
$response = rest_ensure_response( $data );
return $response;
}
/** /**
* Cart item schema. * Cart item schema.
* *

View File

@ -308,6 +308,8 @@ Example response:
## Cart API ## Cart API
### Get the cart
```http ```http
GET /cart GET /cart
``` ```
@ -455,6 +457,43 @@ Example response:
} }
``` ```
### Edit single cart item
Change the quantity of a cart item.
```http
PUT /cart/update-item/
```
| Attribute | Type | Required | Description |
| :--------- | :------ | :------: | :--------------------------------- |
| `key` | string | Yes | The key of the cart item to edit. |
| `quantity` | integer | Yes | Quantity of this item in the cart. |
Returns the full cart object (same response as `GET /cart`).
```http
curl --request POST "https://example-store.com/wp-json/wc/store/cart/update-item?key=1ff1de774005f8da13f42943881c655f&quantity=3"
```
### Delete single cart item
Delete/remove an item from the cart.
```http
POST /cart/remove-item/
```
| Attribute | Type | Required | Description |
| :-------- | :----- | :------: | :-------------------------------- |
| `key` | string | Yes | The key of the cart item to edit. |
Returns the full cart object (same response as `GET /cart`).
```http
curl --request POST "https://example-store.com/wp-json/wc/store/cart/remove-item?key=1ff1de774005f8da13f42943881c655f"
```
## Cart items API ## Cart items API
### List cart items ### List cart items

View File

@ -85,6 +85,72 @@ class Cart extends TestCase {
$this->assertEquals( '2900', $data['totals']->total_price ); $this->assertEquals( '2900', $data['totals']->total_price );
} }
/**
* Test removing a nonexistent cart item.
*/
public function test_remove_bad_cart_item() {
// Test removing a bad cart item - should return 404.
$request = new WP_REST_Request( 'POST', '/wc/store/cart/remove-item' );
$request->set_body_params(
array(
'key' => 'bad_item_key_123',
)
);
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 404, $response->get_status() );
$this->assertEquals( 'woocommerce_rest_cart_invalid_key', $data['code'] );
}
/**
* Test remove cart item.
*/
public function test_remove_cart_item() {
// Test removing a valid cart item - should return updated cart.
$request = new WP_REST_Request( 'POST', '/wc/store/cart/remove-item' );
$request->set_body_params(
array(
'key' => $this->keys[0],
)
);
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 1, $data['items_count'] );
$this->assertEquals( 1, count( $data['items'] ) );
$this->assertEquals( '10', $data['items_weight'] );
$this->assertEquals( '1000', $data['totals']->total_items );
// Test removing same item again - should return 404 (item is already removed).
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 404, $response->get_status() );
$this->assertEquals( 'woocommerce_rest_cart_invalid_key', $data['code'] );
}
/**
* Test changing the quantity of a cart item.
*/
public function test_update_item() {
$request = new WP_REST_Request( 'POST', '/wc/store/cart/update-item' );
$request->set_body_params(
array(
'key' => $this->keys[0],
'quantity' => 10,
)
);
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 10, $data['items'][0]['quantity'] );
$this->assertEquals( 11, $data['items_count'] );
$this->assertEquals( '11000', $data['totals']->total_items );
}
/** /**
* Test applying coupon to cart. * Test applying coupon to cart.
*/ */