* Add schema validation helper

* Add tests for cart item schema

* Fix schema errors found by tests

* Add tests and fix validation for remaining store API endpoints

* Tweak response for nested diffs

* Array syntax

* Improved nesting and type validation for schema

* Implement and fix type checking across test suite

* Type validation fixes

* Fix null comparison

* Fix array handling

* Switch to number type and support in validation

* Test the tests

* Update tests to use objects which match schema, avoiding JSON encode/decode
This commit is contained in:
Mike Jolley 2020-01-17 11:34:15 +00:00 committed by GitHub
parent f3e4fc2bd4
commit 253a0160f1
29 changed files with 905 additions and 362 deletions

View File

@ -219,7 +219,7 @@ class Products extends WC_REST_Products_Controller {
'has_options' => $product->has_options(),
'is_purchasable' => $product->is_purchasable(),
'is_in_stock' => $product->is_in_stock(),
'add_to_cart' => [
'add_to_cart' => (object) [
'text' => $product->add_to_cart_text(),
'description' => $product->add_to_cart_description(),
],

View File

@ -140,7 +140,7 @@ class ProductCollectionData extends RestController {
$counts = $filters->get_attribute_counts( $filter_request, [ $taxonomy ] );
foreach ( $counts as $key => $value ) {
$data['attribute_counts'][] = [
$data['attribute_counts'][] = (object) [
'term' => $key,
'count' => $value,
];
@ -152,7 +152,7 @@ class ProductCollectionData extends RestController {
$counts = $filters->get_attribute_counts( $request, $taxonomy__and_queries );
foreach ( $counts as $key => $value ) {
$data['attribute_counts'][] = [
$data['attribute_counts'][] = (object) [
'term' => $key,
'count' => $value,
];
@ -166,7 +166,7 @@ class ProductCollectionData extends RestController {
$data['rating_counts'] = [];
foreach ( $counts as $key => $value ) {
$data['rating_counts'][] = [
$data['rating_counts'][] = (object) [
'rating' => $key,
'count' => $value,
];

View File

@ -90,7 +90,7 @@ class CartCouponSchema extends AbstractSchema {
$total_discount_taxes = $cart->get_coupon_discount_tax_totals();
return [
'code' => $coupon_code,
'totals' => array_merge(
'totals' => (object) array_merge(
$this->get_store_currency_response(),
[
'total_discount' => $this->prepare_money_response( isset( $total_discounts[ $coupon_code ] ) ? $total_discounts[ $coupon_code ] : 0, wc_get_price_decimals() ),

View File

@ -89,30 +89,42 @@ class CartItemSchema extends AbstractSchema {
'items' => [
'type' => 'object',
'properties' => [
'id' => [
'id' => [
'description' => __( 'Image ID.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'src' => [
'description' => __( 'Image URL.', 'woo-gutenberg-products-block' ),
'src' => [
'description' => __( 'Full size image URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'format' => 'uri',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'name' => [
'thumbnail' => [
'description' => __( 'Thumbnail URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'format' => 'uri',
'context' => [ 'view', 'edit' ],
],
'srcset' => [
'description' => __( 'Thumbnail srcset for responsive images.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'sizes' => [
'description' => __( 'Thumbnail sizes for responsive images.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'name' => [
'description' => __( 'Image name.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'alt' => [
'alt' => [
'description' => __( 'Image alternative text.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
],
],
@ -205,12 +217,12 @@ class CartItemSchema extends AbstractSchema {
'id' => $product->get_id(),
'quantity' => wc_stock_amount( $cart_item['quantity'] ),
'name' => $product->get_title(),
'short_description' => $short_description,
'sku' => $product->get_sku(),
'short_description' => $short_description,
'permalink' => $product->get_permalink(),
'images' => ( new ProductImages() )->images_to_array( $product ),
'variation' => $this->format_variation_data( $cart_item['variation'], $product ),
'totals' => array_merge(
'totals' => (object) array_merge(
$this->get_store_currency_response(),
[
'line_subtotal' => $this->prepare_money_response( $cart_item['line_subtotal'], wc_get_price_decimals() ),
@ -248,7 +260,10 @@ class CartItemSchema extends AbstractSchema {
$label = wc_attribute_label( str_replace( 'attribute_', '', $name ), $product );
}
$return[ $label ] = $value;
$return[] = [
'attribute' => $label,
'value' => $value,
];
}
return $return;

View File

@ -57,7 +57,7 @@ class CartSchema extends AbstractSchema {
],
'items_weight' => [
'description' => __( 'Total weight (in grams) of all products in the cart.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'type' => 'number',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
@ -179,7 +179,7 @@ class CartSchema extends AbstractSchema {
'items_count' => $cart->get_cart_contents_count(),
'items_weight' => wc_get_weight( $cart->get_cart_contents_weight(), 'g' ),
'needs_shipping' => $cart->needs_shipping(),
'totals' => array_merge(
'totals' => (object) array_merge(
$this->get_store_currency_response(),
[
'total_items' => $this->prepare_money_response( $cart->get_subtotal(), wc_get_price_decimals() ),

View File

@ -122,7 +122,7 @@ class CartShippingRateSchema extends AbstractSchema {
],
'price' => [
'description' => __( 'Price of this shipping rate.', 'woo-gutenberg-products-block' ),
'type' => 'boolean',
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
@ -177,7 +177,7 @@ class CartShippingRateSchema extends AbstractSchema {
*/
public function get_item_response( $package ) {
return [
'destination' => [
'destination' => (object) [
'address_1' => $package['destination']['address_1'],
'address_2' => $package['destination']['address_2'],
'city' => $package['destination']['city'],

View File

@ -166,7 +166,7 @@ class CustomerSchema extends AbstractSchema {
public function get_item_response( $object ) {
return [
'id' => $object->get_id(),
'billing_address' => [
'billing_address' => (object) [
'first_name' => $object->get_billing_first_name(),
'last_name' => $object->get_billing_last_name(),
'company' => $object->get_billing_company(),
@ -179,7 +179,7 @@ class CustomerSchema extends AbstractSchema {
'email' => $object->get_billing_email(),
'phone' => $object->get_billing_phone(),
],
'shipping_address' => [
'shipping_address' => (object) [
'first_name' => $object->get_shipping_first_name(),
'last_name' => $object->get_shipping_last_name(),
'company' => $object->get_shipping_company(),

View File

@ -0,0 +1,80 @@
<?php
/**
* Order Coupon Schema.
*
* @package WooCommerce/Blocks
*/
namespace Automattic\WooCommerce\Blocks\RestApi\StoreApi\Schemas;
defined( 'ABSPATH' ) || exit;
/**
* OrderCouponSchema class.
*/
class OrderCouponSchema extends AbstractSchema {
/**
* The schema item name.
*
* @var string
*/
protected $title = 'order_coupon';
/**
* Cart schema properties.
*
* @return array
*/
protected function get_properties() {
return [
'code' => [
'description' => __( 'The coupons unique code.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'totals' => [
'description' => __( 'Total amounts provided using the smallest unit of the currency.', 'woo-gutenberg-products-block' ),
'type' => 'object',
'context' => [ 'view', 'edit' ],
'readonly' => true,
'properties' => array_merge(
$this->get_store_currency_properties(),
[
'total_discount' => [
'description' => __( 'Total discount applied by this coupon.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'total_discount_tax' => [
'description' => __( 'Total tax removed due to discount applied by this coupon.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
]
),
],
];
}
/**
* Convert an order coupon to an object suitable for the response.
*
* @param \WC_Order_Item_Coupon $coupon Order coupon array.
* @return array
*/
public function get_item_response( \WC_Order_Item_Coupon $coupon ) {
return [
'code' => $coupon->get_code(),
'totals' => (object) array_merge(
$this->get_store_currency_response(),
[
'total_discount' => $this->prepare_money_response( $coupon->get_discount(), wc_get_price_decimals() ),
'total_discount_tax' => $this->prepare_money_response( $coupon->get_discount_tax(), wc_get_price_decimals(), PHP_ROUND_HALF_DOWN ),
]
),
];
}
}

View File

@ -50,19 +50,19 @@ class OrderItemSchema extends AbstractSchema {
],
'name' => [
'description' => __( 'Product name.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'type' => [ 'string', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'sku' => [
'description' => __( 'Stock keeping unit, if applicable.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'type' => [ 'string', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'permalink' => [
'description' => __( 'Product URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'type' => [ 'string', 'null' ],
'format' => 'uri',
'context' => [ 'view', 'edit' ],
'readonly' => true,
@ -75,30 +75,42 @@ class OrderItemSchema extends AbstractSchema {
'items' => [
'type' => 'object',
'properties' => [
'id' => [
'id' => [
'description' => __( 'Image ID.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'src' => [
'description' => __( 'Image URL.', 'woo-gutenberg-products-block' ),
'src' => [
'description' => __( 'Full size image URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'format' => 'uri',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'name' => [
'thumbnail' => [
'description' => __( 'Thumbnail URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'format' => 'uri',
'context' => [ 'view', 'edit' ],
],
'srcset' => [
'description' => __( 'Thumbnail srcset for responsive images.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'sizes' => [
'description' => __( 'Thumbnail sizes for responsive images.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'name' => [
'description' => __( 'Image name.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'alt' => [
'alt' => [
'description' => __( 'Image alternative text.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
],
],
@ -173,9 +185,7 @@ class OrderItemSchema extends AbstractSchema {
}
/**
* Convert a WooCommerce cart item to an object suitable for the response.
*
* @todo Variation is stored to meta - how can we gather for response?
* Convert an order item to an object suitable for the response.
*
* @param \WC_Order_Item_Product $line_item Order line item array.
* @return array
@ -190,9 +200,9 @@ class OrderItemSchema extends AbstractSchema {
'name' => $has_product ? $product->get_title() : null,
'sku' => $has_product ? $product->get_sku() : null,
'permalink' => $has_product ? $product->get_permalink() : null,
'images' => $has_product ? ( new ProductImages() )->images_to_array( $product ) : null,
'images' => $has_product ? ( new ProductImages() )->images_to_array( $product ) : [],
'variation' => $has_product ? $this->format_variation_data( $line_item, $product ) : [],
'totals' => array_merge(
'totals' => (object) array_merge(
$this->get_store_currency_response(),
[
'line_subtotal' => $this->prepare_money_response( $line_item->get_subtotal(), wc_get_price_decimals() ),
@ -239,7 +249,10 @@ class OrderItemSchema extends AbstractSchema {
$label = wc_attribute_label( $name, $product );
}
$return[ $label ] = $value;
$return[] = [
'attribute' => $label,
'value' => $value,
];
}
return $return;

View File

@ -97,25 +97,25 @@ class OrderSchema extends AbstractSchema {
],
'date_paid' => [
'description' => __( "The date the order was paid, in the site's timezone.", 'woo-gutenberg-products-block' ),
'type' => 'date-time',
'type' => [ 'date-time', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'date_paid_gmt' => [
'description' => __( 'The date the order was paid, as GMT.', 'woo-gutenberg-products-block' ),
'type' => 'date-time',
'type' => [ 'date-time', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'date_completed' => [
'description' => __( "The date the order was completed, in the site's timezone.", 'woo-gutenberg-products-block' ),
'type' => 'date-time',
'type' => [ 'date-time', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'date_completed_gmt' => [
'description' => __( 'The date the order was completed, as GMT.', 'woo-gutenberg-products-block' ),
'type' => 'date-time',
'type' => [ 'date-time', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
@ -268,7 +268,7 @@ class OrderSchema extends AbstractSchema {
],
],
'coupons' => [
'description' => __( 'List of applied cart coupons.', 'woo-gutenberg-products-block' ),
'description' => __( 'List of applied coupons.', 'woo-gutenberg-products-block' ),
'type' => 'array',
'context' => [ 'view', 'edit' ],
'readonly' => true,
@ -287,76 +287,6 @@ class OrderSchema extends AbstractSchema {
'properties' => $this->force_schema_readonly( ( new OrderItemSchema() )->get_properties() ),
],
],
'shipping_lines' => [
'description' => __( 'Shipping lines data.', 'woo-gutenberg-products-block' ),
'type' => 'array',
'context' => [ 'view', 'edit' ],
'readonly' => true,
'items' => [
'type' => 'object',
'properties' => [
'id' => [
'description' => __( 'Item ID.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'method_title' => [
'description' => __( 'Shipping method name.', 'woo-gutenberg-products-block' ),
'type' => 'mixed',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'method_id' => [
'description' => __( 'Shipping method ID.', 'woo-gutenberg-products-block' ),
'type' => 'mixed',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'instance_id' => [
'description' => __( 'Shipping instance ID.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'total' => [
'description' => __( 'Line total (after discounts).', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'total_tax' => [
'description' => __( 'Line total tax (after discounts).', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'taxes' => [
'description' => __( 'Line taxes.', 'woo-gutenberg-products-block' ),
'type' => 'array',
'context' => [ 'view', 'edit' ],
'readonly' => true,
'items' => [
'type' => 'object',
'properties' => [
'id' => [
'description' => __( 'Tax rate ID.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'total' => [
'description' => __( 'Tax total.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
],
],
],
],
],
],
'totals' => [
'description' => __( 'Total amounts provided using the smallest unit of the currency.', 'woo-gutenberg-products-block' ),
'type' => 'object',
@ -461,8 +391,8 @@ class OrderSchema extends AbstractSchema {
* @return array
*/
public function get_item_response( \WC_Order $order ) {
$order_item_schema = new OrderItemSchema();
$order_item_schema = new OrderItemSchema();
$order_coupon_schema = new OrderCouponSchema();
return [
'id' => $order->get_id(),
'number' => $order->get_order_number(),
@ -470,14 +400,14 @@ class OrderSchema extends AbstractSchema {
'order_key' => $order->get_order_key(),
'created_via' => $order->get_created_via(),
'prices_include_tax' => $order->get_prices_include_tax(),
'events' => $this->get_events( $order ),
'customer' => [
'events' => (object) $this->get_events( $order ),
'customer' => (object) [
'customer_id' => $order->get_customer_id(),
'customer_ip_address' => $order->get_customer_ip_address(),
'customer_user_agent' => $order->get_customer_user_agent(),
],
'customer_note' => $order->get_customer_note(),
'billing_address' => [
'billing_address' => (object) [
'first_name' => $order->get_billing_first_name(),
'last_name' => $order->get_billing_last_name(),
'company' => $order->get_billing_company(),
@ -490,7 +420,7 @@ class OrderSchema extends AbstractSchema {
'email' => $order->get_billing_email(),
'phone' => $order->get_billing_phone(),
],
'shipping_address' => [
'shipping_address' => (object) [
'first_name' => $order->get_shipping_first_name(),
'last_name' => $order->get_shipping_last_name(),
'company' => $order->get_shipping_company(),
@ -501,8 +431,9 @@ class OrderSchema extends AbstractSchema {
'postcode' => $order->get_shipping_postcode(),
'country' => $order->get_shipping_country(),
],
'coupons' => array_values( array_map( [ $order_coupon_schema, 'get_item_response' ], $order->get_items( 'coupon' ) ) ),
'items' => array_values( array_map( [ $order_item_schema, 'get_item_response' ], $order->get_items( 'line_item' ) ) ),
'totals' => array_merge(
'totals' => (object) array_merge(
$this->get_store_currency_response(),
[
'total_items' => $this->prepare_money_response( $order->get_subtotal(), wc_get_price_decimals() ),

View File

@ -31,7 +31,7 @@ class ProductCollectionDataSchema extends AbstractSchema {
return [
'price_range' => [
'description' => __( 'Min and max prices found in collection of products, provided using the smallest unit of the currency.', 'woo-gutenberg-products-block' ),
'type' => 'object',
'type' => [ 'object', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
'properties' => array_merge(
@ -54,7 +54,7 @@ class ProductCollectionDataSchema extends AbstractSchema {
],
'attribute_counts' => [
'description' => __( 'Returns number of products within attribute terms.', 'woo-gutenberg-products-block' ),
'type' => 'array',
'type' => [ 'array', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
'items' => [
@ -77,7 +77,7 @@ class ProductCollectionDataSchema extends AbstractSchema {
],
'rating_counts' => [
'description' => __( 'Returns number of products with each average rating.', 'woo-gutenberg-products-block' ),
'type' => 'array',
'type' => [ 'array', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
'items' => [
@ -109,7 +109,7 @@ class ProductCollectionDataSchema extends AbstractSchema {
*/
public function get_item_response( $data ) {
return [
'price_range' => ! is_null( $data['min_price'] ) && ! is_null( $data['max_price'] ) ? array_merge(
'price_range' => ! is_null( $data['min_price'] ) && ! is_null( $data['max_price'] ) ? (object) array_merge(
$this->get_store_currency_response(),
[
'min_price' => $this->prepare_money_response( $data['min_price'], wc_get_price_decimals() ),

View File

@ -98,7 +98,7 @@ class ProductSchema extends AbstractSchema {
],
'price_range' => [
'description' => __( 'Price range, if applicable.', 'woo-gutenberg-products-block' ),
'type' => 'object',
'type' => [ 'object', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
'properties' => [
@ -138,23 +138,39 @@ class ProductSchema extends AbstractSchema {
'items' => [
'type' => 'object',
'properties' => [
'id' => [
'id' => [
'description' => __( 'Image ID.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
],
'src' => [
'description' => __( 'Image URL.', 'woo-gutenberg-products-block' ),
'src' => [
'description' => __( 'Full size image URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'format' => 'uri',
'context' => [ 'view', 'edit' ],
],
'name' => [
'thumbnail' => [
'description' => __( 'Thumbnail URL.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'format' => 'uri',
'context' => [ 'view', 'edit' ],
],
'srcset' => [
'description' => __( 'Thumbnail srcset for responsive images.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'sizes' => [
'description' => __( 'Thumbnail sizes for responsive images.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'name' => [
'description' => __( 'Image name.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'alt' => [
'alt' => [
'description' => __( 'Image alternative text.', 'woo-gutenberg-products-block' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
@ -182,7 +198,7 @@ class ProductSchema extends AbstractSchema {
],
'low_stock_remaining' => [
'description' => __( 'Quantity left in stock if stock is low, or null if not applicable.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
'type' => [ 'integer', 'null' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
@ -224,7 +240,7 @@ class ProductSchema extends AbstractSchema {
'sku' => $product->get_sku(),
'description' => apply_filters( 'woocommerce_short_description', $product->get_short_description() ? $product->get_short_description() : wc_trim_string( $product->get_description(), 400 ) ),
'on_sale' => $product->is_on_sale(),
'prices' => $this->get_prices( $product ),
'prices' => (object) $this->get_prices( $product ),
'average_rating' => $product->get_average_rating(),
'review_count' => $product->get_review_count(),
'images' => ( new ProductImages() )->images_to_array( $product ),
@ -232,7 +248,7 @@ class ProductSchema extends AbstractSchema {
'is_purchasable' => $product->is_purchasable(),
'is_in_stock' => $product->is_in_stock(),
'low_stock_remaining' => $this->get_low_stock_remaining( $product ),
'add_to_cart' => [
'add_to_cart' => (object) [
'text' => $product->add_to_cart_text(),
'description' => $product->add_to_cart_description(),
],
@ -274,7 +290,7 @@ class ProductSchema extends AbstractSchema {
* Get price range from certain product types.
*
* @param \WC_Product $product Product instance.
* @return array|null
* @return object|null
*/
protected function get_price_range( \WC_Product $product ) {
$tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
@ -283,7 +299,7 @@ class ProductSchema extends AbstractSchema {
$prices = $product->get_variation_prices( true );
if ( min( $prices['price'] ) !== max( $prices['price'] ) ) {
return [
return (object) [
'min_amount' => $this->prepare_money_response( min( $prices['price'] ), wc_get_price_decimals() ),
'max_amount' => $this->prepare_money_response( max( $prices['price'] ), wc_get_price_decimals() ),
];
@ -301,7 +317,7 @@ class ProductSchema extends AbstractSchema {
}
if ( ! empty( $child_prices ) ) {
return [
return (object) [
'min_amount' => $this->prepare_money_response( min( $child_prices ), wc_get_price_decimals() ),
'max_amount' => $this->prepare_money_response( max( $child_prices ), wc_get_price_decimals() ),
];

View File

@ -43,11 +43,11 @@ class ProductImages {
$thumbnail = wp_get_attachment_image_src( $attachment_id, 'woocommerce_thumbnail' );
$images[] = array(
'id' => $attachment_id,
'id' => (int) $attachment_id,
'src' => current( $attachment ),
'thumbnail' => current( $thumbnail ),
'srcset' => wp_get_attachment_image_srcset( $attachment_id, 'full' ),
'sizes' => wp_get_attachment_image_sizes( $attachment_id, 'full' ),
'srcset' => (string) wp_get_attachment_image_srcset( $attachment_id, 'full' ),
'sizes' => (string) wp_get_attachment_image_sizes( $attachment_id, 'full' ),
'name' => get_the_title( $attachment_id ),
'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ),
);

View File

@ -0,0 +1,132 @@
<?php
/**
* Ensures the helper works.
*
* @package WooCommerce\Blocks\Tests
*/
namespace Automattic\WooCommerce\Blocks\Tests\Helpers;
require_once 'ValidateSchema.php';
use \WC_REST_Unit_Test_Case as TestCase;
/**
* Test Validate schema.
*/
class TestValidateSchema extends TestCase {
/**
* ValidateSchema instance.
*
* @var ValidateSchema
*/
protected $validate;
/**
* Setup schema.
*/
public function setUp() {
$this->validate = new ValidateSchema(
[
'properties' => [
'test_number' => [
'type' => 'number',
],
'test_string' => [
'type' => 'string',
],
'test_integer' => [
'type' => 'integer',
],
'test_object' => [
'type' => 'object',
'properties' => [
'property_1' => [
'type' => 'string',
],
'property_2' => [
'type' => 'string',
],
],
],
'test_array' => [
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'property_1' => [
'type' => 'string',
],
'property_2' => [
'type' => 'string',
],
],
],
],
'test_integer_or_null' => [
'type' => [ 'null', 'integer' ],
],
],
]
);
}
/**
* Validate an object.
*/
public function test_get_diff_from_valid_object() {
$test_object = (object) [
'test_number' => 1.2,
'test_string' => 'Hello',
'test_integer' => 1,
'test_object' => (object) [
'property_1' => 'Prop 1',
'property_2' => 'Prop 2',
],
'test_array' => [
(object) [
'property_1' => 'Prop 1',
'property_2' => 'Prop 2',
],
],
'test_integer_or_null' => null,
];
$diff = $this->validate->get_diff_from_object( $test_object );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
/**
* Validate an object.
*/
public function test_get_diff_from_invalid_object() {
$test_object = (object) [
'test_number' => 'Invalid',
'test_string' => 666,
'test_integer' => 'Nope',
'test_object' => (object) [
'property_1' => 1,
'property_2' => 2,
],
'test_array' => [
(object) [
'property_1' => 1,
'invalid_key' => 2,
],
],
'test_integer_or_null' => 'string',
];
$diff = $this->validate->get_diff_from_object( $test_object );
$this->assertContains( 'test_array:property_2', $diff['missing'], print_r( $diff['missing'], true ) );
$this->assertContains( 'test_array:invalid_key', $diff['no_schema'], print_r( $diff['no_schema'], true ) );
$this->assertContains( 'test_number (string, expected number)', $diff['invalid_type'], print_r( $diff['invalid_type'], true ) );
$this->assertContains( 'test_string (integer, expected string)', $diff['invalid_type'], print_r( $diff['invalid_type'], true ) );
$this->assertContains( 'test_integer (string, expected integer)', $diff['invalid_type'], print_r( $diff['invalid_type'], true ) );
$this->assertContains( 'test_number (string, expected number)', $diff['invalid_type'], print_r( $diff['invalid_type'], true ) );
$this->assertContains( 'test_array:property_1 (integer, expected string)', $diff['invalid_type'], print_r( $diff['invalid_type'], true ) );
$this->assertContains( 'test_integer_or_null (string, expected null, integer)', $diff['invalid_type'], print_r( $diff['invalid_type'], true ) );
}
}

View File

@ -0,0 +1,115 @@
<?php
/**
* Helper used to validate schema differences.
*
* @package WooCommerce\Blocks\Tests
*/
namespace Automattic\WooCommerce\Blocks\Tests\Helpers;
/**
* Validate schema.
*/
class ValidateSchema {
/**
* The schema.
*
* @var array
*/
protected $schema = [];
/**
* Constructor passed schema object.
*
* @param array $schema API schema representation.
*/
public function __construct( $schema ) {
$this->schema = $schema;
}
/**
* Validate properties and return diff.
*
* @param array|object $object Object to compare.
* @param array $schema Schema to find nested properties under.
* @param string $prefix Prefix to append to diff property names.
* @return array
*/
public function get_diff_from_object( $object, $schema = null, $prefix = '' ) {
$missing = [];
$invalid_type = [];
$no_schema = [];
if ( is_null( $schema ) ) {
$schema = $this->schema['properties'];
}
if ( ! is_array( $object ) && ! is_object( $object ) ) {
return [];
}
$object = (array) $object;
$no_schema_diffs = array_diff( array_keys( (array) $object ), array_keys( $schema ) );
foreach ( $no_schema_diffs as $no_schema_diff ) {
$no_schema[] = $prefix . $no_schema_diff;
}
foreach ( $schema as $property_name => $property_schema ) {
// Validate property is set in object. Avoids isset in case value is NULL.
if ( ( is_array( $object ) && ! array_key_exists( $property_name, $object ) ) || ( is_object( $object ) && ! property_exists( $object, $property_name ) ) ) {
$missing[] = $prefix . $property_name;
continue;
}
// Validate type.
$type = gettype( $object[ $property_name ] );
if ( $type && ! $this->validate_type( $type, $property_schema['type'] ) ) {
$expected = is_array( $property_schema['type'] ) ? implode( ', ', $property_schema['type'] ) : $property_schema['type'];
$invalid_type[] = $prefix . $property_name . " ({$type}, expected {$expected})";
continue;
}
// Validate nested props.
if ( isset( $property_schema['items']['properties'] ) ) {
$nested_value = is_array( $object[ $property_name ] ) ? current( $object[ $property_name ] ) : $object[ $property_name ];
if ( $nested_value ) {
$diff = $this->get_diff_from_object(
$nested_value,
$property_schema['items']['properties'],
$prefix . $property_name . ':'
);
$missing = isset( $diff['missing'] ) ? array_merge( $missing, $diff['missing'] ) : $missing;
$invalid_type = isset( $diff['invalid_type'] ) ? array_merge( $invalid_type, $diff['invalid_type'] ) : $invalid_type;
$no_schema = isset( $diff['no_schema'] ) ? array_merge( $no_schema, $diff['no_schema'] ) : $no_schema;
}
}
}
return array_filter(
[
'missing' => array_values( array_filter( $missing ) ),
'invalid_type' => array_values( array_filter( $invalid_type ) ),
'no_schema' => array_values( array_filter( $no_schema ) ),
]
);
}
/**
* Validate type and return if it matches.
*
* @param string $type Type to check.
* @param string|array $expected Expected types.
* @return boolean
*/
protected function validate_type( $type, $expected ) {
$type = strtolower( $type );
$expected = is_array( $expected ) ? $expected : [ $expected ];
if ( in_array( 'number', $expected ) ) {
$expected = array_merge( $expected, [ 'double', 'float', 'integer' ] );
}
return in_array( $type, $expected, true );
}
}

View File

@ -59,11 +59,11 @@ class ProductAttributeTerms extends WC_REST_Unit_Test_Case {
wp_set_current_user( $this->user );
$request = new WP_REST_Request( 'GET', $this->endpoint . '/products/attributes/' . $this->attr_color['attribute_id'] . '/terms' );
$response = $this->server->dispatch( $request );
$response_terms = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 3, count( $response_terms ) );
$term = $response_terms[0];
$this->assertEquals( 3, count( $data ) );
$term = $data[0];
$this->assertArrayHasKey( 'attribute', $term );
$attribute = $term['attribute'];
$this->assertArrayHasKey( 'id', $attribute );
@ -105,9 +105,9 @@ class ProductAttributeTerms extends WC_REST_Unit_Test_Case {
wp_set_current_user( $this->contributor );
$request = new WP_REST_Request( 'GET', $this->endpoint . '/products/attributes/' . $this->attr_size['attribute_id'] . '/terms' );
$response = $this->server->dispatch( $request );
$response_terms = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 4, count( $response_terms ) );
$this->assertEquals( 4, count( $data ) );
}
}

View File

@ -59,11 +59,11 @@ class ProductAttributes extends WC_REST_Unit_Test_Case {
wp_set_current_user( $this->user );
$request = new WP_REST_Request( 'GET', $this->endpoint . '/products/attributes' );
$response = $this->server->dispatch( $request );
$response_attributes = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 2, count( $response_attributes ) );
$attribute = $response_attributes[0];
$this->assertEquals( 2, count( $data ) );
$attribute = $data[0];
$this->assertArrayHasKey( 'id', $attribute );
$this->assertArrayHasKey( 'name', $attribute );
$this->assertArrayHasKey( 'slug', $attribute );
@ -104,10 +104,10 @@ class ProductAttributes extends WC_REST_Unit_Test_Case {
wp_set_current_user( $this->contributor );
$request = new WP_REST_Request( 'GET', $this->endpoint . '/products/attributes/' . $this->attr_size['attribute_id'] );
$response = $this->server->dispatch( $request );
$attribute = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( $this->attr_size['attribute_id'], $attribute['id'] );
$this->assertEquals( $this->attr_size['attribute_name'], $attribute['name'] );
$this->assertEquals( $this->attr_size['attribute_id'], $data['id'] );
$this->assertEquals( $this->attr_size['attribute_name'], $data['name'] );
}
}

View File

@ -79,10 +79,10 @@ class ProductCategories extends WC_REST_Unit_Test_Case {
wp_set_current_user( $this->user );
$request = new WP_REST_Request( 'GET', $this->endpoint . '/products/categories' );
$response = $this->server->dispatch( $request );
$categories = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 4, count( $categories ) ); // Three created and `uncategorized`.
$this->assertEquals( 4, count( $data ) ); // Three created and `uncategorized`.
}
/**
@ -120,10 +120,10 @@ class ProductCategories extends WC_REST_Unit_Test_Case {
$request = new WP_REST_Request( 'GET', $this->endpoint . '/products/categories/' . $this->categories['parent']['term_id'] );
$response = $this->server->dispatch( $request );
$category = $response->get_data();
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( $category['name'], 'Parent Category' );
$this->assertEquals( $category['parent'], 0 );
$this->assertEquals( $category['count'], 2 );
$this->assertEquals( $data['name'], 'Parent Category' );
$this->assertEquals( $data['parent'], 0 );
$this->assertEquals( $data['count'], 2 );
}
}

View File

@ -106,11 +106,10 @@ class Products extends WC_REST_Unit_Test_Case {
sleep( 1 ); // So both products have different timestamps.
$product = ProductHelper::create_simple_product();
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/blocks/products' ) );
$products = $response->get_data();
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 6, count( $products ) );
$this->assertEquals( 6, count( $data ) );
}
/**
@ -160,13 +159,13 @@ class Products extends WC_REST_Unit_Test_Case {
$request->set_param( 'orderby', 'price' );
$request->set_param( 'order', 'asc' );
$response = $this->server->dispatch( $request );
$products = $response->get_data();
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 6, count( $products ) );
$this->assertEquals( 6, count( $data ) );
$this->assertEquals( 'Dummy Product', $products[1]['name'] );
$this->assertEquals( '10', $products[1]['price'] );
$this->assertEquals( 'Dummy Product', $data[1]['name'] );
$this->assertEquals( '10', $data[1]['price'] );
}
/**
@ -202,11 +201,11 @@ class Products extends WC_REST_Unit_Test_Case {
$request = new WP_REST_REQUEST( 'GET', '/wc/blocks/products' );
$request->set_query_params( $query_params );
$response = $this->server->dispatch( $request );
$products = $response->get_data();
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 5, count( $products ) );
$this->assertEquals( 'Visible Product', $products[0]['name'] );
$this->assertEquals( 5, count( $data ) );
$this->assertEquals( 'Visible Product', $data[0]['name'] );
$query_params = array(
'catalog_visibility' => 'catalog',
@ -216,11 +215,11 @@ class Products extends WC_REST_Unit_Test_Case {
$request = new WP_REST_REQUEST( 'GET', '/wc/blocks/products' );
$request->set_query_params( $query_params );
$response = $this->server->dispatch( $request );
$products = $response->get_data();
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 6, count( $products ) );
$this->assertEquals( 'Dummy Product', $products[0]['name'] );
$this->assertEquals( 6, count( $data ) );
$this->assertEquals( 'Dummy Product', $data[0]['name'] );
$query_params = array(
'catalog_visibility' => 'search',
@ -230,11 +229,11 @@ class Products extends WC_REST_Unit_Test_Case {
$request = new WP_REST_REQUEST( 'GET', '/wc/blocks/products' );
$request->set_query_params( $query_params );
$response = $this->server->dispatch( $request );
$products = $response->get_data();
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 6, count( $products ) );
$this->assertEquals( 'Dummy Product', $products[0]['name'] );
$this->assertEquals( 6, count( $data ) );
$this->assertEquals( 'Dummy Product', $data[0]['name'] );
$query_params = array(
'catalog_visibility' => 'hidden',
@ -242,11 +241,11 @@ class Products extends WC_REST_Unit_Test_Case {
$request = new WP_REST_REQUEST( 'GET', '/wc/blocks/products' );
$request->set_query_params( $query_params );
$response = $this->server->dispatch( $request );
$products = $response->get_data();
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 1, count( $products ) );
$this->assertEquals( 'Hidden Product', $products[0]['name'] );
$this->assertEquals( 1, count( $data ) );
$this->assertEquals( 'Hidden Product', $data[0]['name'] );
}
/**
@ -263,11 +262,11 @@ class Products extends WC_REST_Unit_Test_Case {
$request->set_param( 'category', $cats );
$request->set_param( 'category_operator', 'in' );
$response = $this->server->dispatch( $request );
$response_products = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 3, count( $response_products ) );
$this->assertEquals( 3, count( $data ) );
}
/**
@ -284,11 +283,11 @@ class Products extends WC_REST_Unit_Test_Case {
$request->set_param( 'category', $cats );
$request->set_param( 'category_operator', 'and' );
$response = $this->server->dispatch( $request );
$response_products = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 1, count( $response_products ) );
$this->assertEquals( 1, count( $data ) );
}
/**
@ -305,10 +304,10 @@ class Products extends WC_REST_Unit_Test_Case {
$request->set_param( 'category', $cats );
$request->set_param( 'category_operator', 'and' );
$response = $this->server->dispatch( $request );
$response_products = $response->get_data();
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 1, count( $response_products ) );
$this->assertEquals( 1, count( $data ) );
}
}

View File

@ -10,6 +10,8 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use \WC_Helper_Coupon as CouponHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Cart Controller Tests.
@ -38,11 +40,14 @@ class Cart extends TestCase {
$this->products[1]->set_regular_price( 10 );
$this->products[1]->save();
$this->coupon = CouponHelper::create_coupon();
wc_empty_cart();
$this->keys = [];
$this->keys = [];
$this->keys[] = wc()->cart->add_to_cart( $this->products[0]->get_id(), 2 );
$this->keys[] = wc()->cart->add_to_cart( $this->products[1]->get_id(), 1 );
wc()->cart->apply_coupon( $this->coupon->get_code() );
}
/**
@ -66,18 +71,18 @@ class Cart extends TestCase {
$this->assertEquals( false, $data['needs_shipping'] );
$this->assertEquals( '30', $data['items_weight'] );
$this->assertEquals( 'GBP', $data['totals']['currency_code'] );
$this->assertEquals( 2, $data['totals']['currency_minor_unit'] );
$this->assertEquals( '3000', $data['totals']['total_items'] );
$this->assertEquals( '0', $data['totals']['total_items_tax'] );
$this->assertEquals( '0', $data['totals']['total_fees'] );
$this->assertEquals( '0', $data['totals']['total_fees_tax'] );
$this->assertEquals( '0', $data['totals']['total_discount'] );
$this->assertEquals( '0', $data['totals']['total_discount_tax'] );
$this->assertEquals( '0', $data['totals']['total_shipping'] );
$this->assertEquals( '0', $data['totals']['total_shipping_tax'] );
$this->assertEquals( '0', $data['totals']['total_tax'] );
$this->assertEquals( '3000', $data['totals']['total_price'] );
$this->assertEquals( 'GBP', $data['totals']->currency_code );
$this->assertEquals( 2, $data['totals']->currency_minor_unit );
$this->assertEquals( '3000', $data['totals']->total_items );
$this->assertEquals( '0', $data['totals']->total_items_tax );
$this->assertEquals( '0', $data['totals']->total_fees );
$this->assertEquals( '0', $data['totals']->total_fees_tax );
$this->assertEquals( '100', $data['totals']->total_discount );
$this->assertEquals( '0', $data['totals']->total_discount_tax );
$this->assertEquals( '0', $data['totals']->total_shipping );
$this->assertEquals( '0', $data['totals']->total_shipping_tax );
$this->assertEquals( '0', $data['totals']->total_tax );
$this->assertEquals( '2900', $data['totals']->total_price );
}
/**
@ -101,11 +106,26 @@ class Cart extends TestCase {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\Cart();
$cart = wc()->cart;
$response = $controller->prepare_item_for_response( $cart, [] );
$data = $response->get_data();
$this->assertArrayHasKey( 'items_count', $response->get_data() );
$this->assertArrayHasKey( 'items', $response->get_data() );
$this->assertArrayHasKey( 'needs_shipping', $response->get_data() );
$this->assertArrayHasKey( 'items_weight', $response->get_data() );
$this->assertArrayHasKey( 'totals', $response->get_data() );
$this->assertArrayHasKey( 'items_count', $data );
$this->assertArrayHasKey( 'items', $data );
$this->assertArrayHasKey( 'needs_shipping', $data );
$this->assertArrayHasKey( 'items_weight', $data );
$this->assertArrayHasKey( 'totals', $data );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\Cart();
$cart = wc()->cart;
$response = $controller->prepare_item_for_response( $cart, [] );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -11,6 +11,7 @@ use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use \WC_Helper_Coupon as CouponHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Cart Coupons Controller Tests.
@ -62,8 +63,8 @@ class CartCoupons extends TestCase {
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( $this->coupon->get_code(), $data['code'] );
$this->assertEquals( '0', $data['totals']['total_discount'] );
$this->assertEquals( '0', $data['totals']['total_discount_tax'] );
$this->assertEquals( '0', $data['totals']->total_discount );
$this->assertEquals( '0', $data['totals']->total_discount_tax );
}
/**
@ -162,8 +163,22 @@ class CartCoupons extends TestCase {
public function test_prepare_item_for_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartCoupons();
$response = $controller->prepare_item_for_response( $this->coupon->get_code(), [] );
$data = $response->get_data();
$this->assertArrayHasKey( 'code', $response->get_data() );
$this->assertArrayHasKey( 'totals', $response->get_data() );
$this->assertArrayHasKey( 'code', $data );
$this->assertArrayHasKey( 'totals', $data );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartCoupons();
$response = $controller->prepare_item_for_response( $this->coupon->get_code(), [] );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Cart Controller Tests.
@ -19,6 +20,8 @@ class CartItems extends TestCase {
* Setup test products data. Called before every test.
*/
public function setUp() {
global $wpdb;
parent::setUp();
wp_set_current_user( 0 );
@ -27,22 +30,28 @@ class CartItems extends TestCase {
$this->products = [];
// Create some test products.
// Create a test simple product.
$this->products[0] = ProductHelper::create_simple_product( false );
$this->products[0]->set_weight( 10 );
$this->products[0]->set_regular_price( 10 );
$this->products[0]->save();
$this->products[1] = ProductHelper::create_simple_product( false );
$image_url = media_sideload_image( 'http://cldup.com/Dr1Bczxq4q.png', $this->products[0]->get_id(), '', 'src' );
$image_id = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE guid = %s", $image_url ) );
$this->products[0]->set_image_id( $image_id[0] );
$this->products[0]->save();
// Create a test variable product.
$this->products[1] = ProductHelper::create_variation_product( false );
$this->products[1]->set_weight( 10 );
$this->products[1]->set_regular_price( 10 );
$this->products[1]->save();
wc_empty_cart();
$this->keys = [];
$this->keys = [];
$this->keys[] = wc()->cart->add_to_cart( $this->products[0]->get_id(), 2 );
$this->keys[] = wc()->cart->add_to_cart( $this->products[1]->get_id(), 1 );
$this->keys[] = wc()->cart->add_to_cart( $this->products[1]->get_id(), 1, current( $this->products[1]->get_children() ), [ 'size' => 'small' ] );
}
/**
@ -79,8 +88,8 @@ class CartItems extends TestCase {
$this->assertEquals( $this->products[0]->get_sku(), $data['sku'] );
$this->assertEquals( $this->products[0]->get_permalink(), $data['permalink'] );
$this->assertEquals( 2, $data['quantity'] );
$this->assertEquals( '2000', $data['totals']['line_subtotal'] );
$this->assertEquals( '2000', $data['totals']['line_total'] );
$this->assertEquals( '2000', $data['totals']->line_subtotal );
$this->assertEquals( '2000', $data['totals']->line_total );
$request = new WP_REST_Request( 'DELETE', '/wc/store/cart/items/XXX815416f775098fe977004015c6193' );
$response = $this->server->dispatch( $request );
@ -135,7 +144,6 @@ class CartItems extends TestCase {
)
);
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 403, $response->get_status() );
}
@ -161,14 +169,14 @@ class CartItems extends TestCase {
* Test delete item.
*/
public function test_delete_item() {
$request = new WP_REST_Request( 'DELETE', '/wc/store/cart/items/' . $this->keys[0] );
$request = new WP_REST_Request( 'DELETE', '/wc/store/cart/items/' . $this->keys[0] );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 204, $response->get_status() );
$this->assertEmpty( $data );
$request = new WP_REST_Request( 'DELETE', '/wc/store/cart/items/' . $this->keys[0] );
$request = new WP_REST_Request( 'DELETE', '/wc/store/cart/items/' . $this->keys[0] );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
@ -179,7 +187,7 @@ class CartItems extends TestCase {
* Test delete all items.
*/
public function test_delete_items() {
$request = new WP_REST_Request( 'DELETE', '/wc/store/cart/items' );
$request = new WP_REST_Request( 'DELETE', '/wc/store/cart/items' );
$response = $this->server->dispatch( $request );
$data = $response->get_data();
@ -218,15 +226,38 @@ class CartItems extends TestCase {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartItems();
$cart = wc()->cart->get_cart();
$response = $controller->prepare_item_for_response( current( $cart ), [] );
$data = $response->get_data();
$this->assertArrayHasKey( 'key', $response->get_data() );
$this->assertArrayHasKey( 'id', $response->get_data() );
$this->assertArrayHasKey( 'quantity', $response->get_data() );
$this->assertArrayHasKey( 'name', $response->get_data() );
$this->assertArrayHasKey( 'sku', $response->get_data() );
$this->assertArrayHasKey( 'permalink', $response->get_data() );
$this->assertArrayHasKey( 'images', $response->get_data() );
$this->assertArrayHasKey( 'totals', $response->get_data() );
$this->assertArrayHasKey( 'variation', $response->get_data() );
$this->assertArrayHasKey( 'key', $data );
$this->assertArrayHasKey( 'id', $data );
$this->assertArrayHasKey( 'quantity', $data );
$this->assertArrayHasKey( 'name', $data );
$this->assertArrayHasKey( 'sku', $data );
$this->assertArrayHasKey( 'permalink', $data );
$this->assertArrayHasKey( 'images', $data );
$this->assertArrayHasKey( 'totals', $data );
$this->assertArrayHasKey( 'variation', $data );
}
/**
* Test schema matches responses.
*
* Tests schema of both products in cart to cover as much schema as possible.
*/
public function test_schema_matches_response() {
$cart = wc()->cart->get_cart();
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartItems();
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
// Simple product.
$response = $controller->prepare_item_for_response( current( $cart ), [] );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
// Variable product.
$response = $controller->prepare_item_for_response( end( $cart ), [] );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -11,6 +11,8 @@ use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use \WC_Helper_Order as OrderHelper;
use \WC_Helper_Coupon as CouponHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Cart Order Controller Tests.
@ -95,16 +97,16 @@ class CartOrder extends TestCase {
$this->assertArrayHasKey( 'items', $data );
$this->assertArrayHasKey( 'totals', $data );
$this->assertEquals( 'Margaret', $data['billing_address']['first_name'] );
$this->assertEquals( 'Thatchcroft', $data['billing_address']['last_name'] );
$this->assertEquals( '123 South Street', $data['billing_address']['address_1'] );
$this->assertEquals( 'Apt 1', $data['billing_address']['address_2'] );
$this->assertEquals( 'Philadelphia', $data['billing_address']['city'] );
$this->assertEquals( 'PA', $data['billing_address']['state'] );
$this->assertEquals( '19123', $data['billing_address']['postcode'] );
$this->assertEquals( 'US', $data['billing_address']['country'] );
$this->assertEquals( 'test@test.com', $data['billing_address']['email'] );
$this->assertEquals( '', $data['billing_address']['phone'] );
$this->assertEquals( 'Margaret', $data['billing_address']->first_name );
$this->assertEquals( 'Thatchcroft', $data['billing_address']->last_name );
$this->assertEquals( '123 South Street', $data['billing_address']->address_1 );
$this->assertEquals( 'Apt 1', $data['billing_address']->address_2 );
$this->assertEquals( 'Philadelphia', $data['billing_address']->city );
$this->assertEquals( 'PA', $data['billing_address']->state );
$this->assertEquals( '19123', $data['billing_address']->postcode );
$this->assertEquals( 'US', $data['billing_address']->country );
$this->assertEquals( 'test@test.com', $data['billing_address']->email );
$this->assertEquals( '', $data['billing_address']->phone );
$this->assertEquals( 'checkout-draft', $data['status'] );
$this->assertEquals( 2, count( $data['items'] ) );
@ -139,19 +141,38 @@ class CartOrder extends TestCase {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartOrder();
$order = OrderHelper::create_order();
$response = $controller->prepare_item_for_response( $order, [] );
$data = $response->get_data();
$this->assertArrayHasKey( 'id', $response->get_data() );
$this->assertArrayHasKey( 'number', $response->get_data() );
$this->assertArrayHasKey( 'status', $response->get_data() );
$this->assertArrayHasKey( 'order_key', $response->get_data() );
$this->assertArrayHasKey( 'created_via', $response->get_data() );
$this->assertArrayHasKey( 'prices_include_tax', $response->get_data() );
$this->assertArrayHasKey( 'events', $response->get_data() );
$this->assertArrayHasKey( 'customer', $response->get_data() );
$this->assertArrayHasKey( 'billing_address', $response->get_data() );
$this->assertArrayHasKey( 'shipping_address', $response->get_data() );
$this->assertArrayHasKey( 'customer_note', $response->get_data() );
$this->assertArrayHasKey( 'items', $response->get_data() );
$this->assertArrayHasKey( 'totals', $response->get_data() );
$this->assertArrayHasKey( 'id', $data );
$this->assertArrayHasKey( 'number', $data );
$this->assertArrayHasKey( 'status', $data );
$this->assertArrayHasKey( 'order_key', $data );
$this->assertArrayHasKey( 'created_via', $data );
$this->assertArrayHasKey( 'prices_include_tax', $data );
$this->assertArrayHasKey( 'events', $data );
$this->assertArrayHasKey( 'customer', $data );
$this->assertArrayHasKey( 'billing_address', $data );
$this->assertArrayHasKey( 'shipping_address', $data );
$this->assertArrayHasKey( 'customer_note', $data );
$this->assertArrayHasKey( 'items', $data );
$this->assertArrayHasKey( 'totals', $data );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartOrder();
$order = OrderHelper::create_order();
$coupon = CouponHelper::create_coupon();
$order->apply_coupon( $coupon );
$response = $controller->prepare_item_for_response( $order, [] );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -10,6 +10,8 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use \WC_Helper_Shipping;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Cart Shipping Rates Controller Tests.
@ -35,6 +37,8 @@ class CartShippingRates extends TestCase {
wc_empty_cart();
wc()->cart->add_to_cart( $this->products[0]->get_id(), 2 );
wc()->cart->add_to_cart( $this->products[1]->get_id(), 1 );
WC_Helper_Shipping::create_simple_flat_rate();
}
/**
@ -61,12 +65,12 @@ class CartShippingRates extends TestCase {
$this->assertArrayHasKey( 'items', $data[0] );
$this->assertArrayHasKey( 'shipping_rates', $data[0] );
$this->assertEquals( null, $data[0]['destination']['address_1'] );
$this->assertEquals( null, $data[0]['destination']['address_2'] );
$this->assertEquals( null, $data[0]['destination']['city'] );
$this->assertEquals( null, $data[0]['destination']['state'] );
$this->assertEquals( null, $data[0]['destination']['postcode'] );
$this->assertEquals( 'US', $data[0]['destination']['country'] );
$this->assertEquals( null, $data[0]['destination']->address_1 );
$this->assertEquals( null, $data[0]['destination']->address_2 );
$this->assertEquals( null, $data[0]['destination']->city );
$this->assertEquals( null, $data[0]['destination']->state );
$this->assertEquals( null, $data[0]['destination']->postcode );
$this->assertEquals( 'US', $data[0]['destination']->country );
}
/**
@ -94,12 +98,12 @@ class CartShippingRates extends TestCase {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 'Test address 1', $data[0]['destination']['address_1'] );
$this->assertEquals( 'Test address 2', $data[0]['destination']['address_2'] );
$this->assertEquals( 'Test City', $data[0]['destination']['city'] );
$this->assertEquals( 'AL', $data[0]['destination']['state'] );
$this->assertEquals( '90210', $data[0]['destination']['postcode'] );
$this->assertEquals( 'US', $data[0]['destination']['country'] );
$this->assertEquals( 'Test address 1', $data[0]['destination']->address_1 );
$this->assertEquals( 'Test address 2', $data[0]['destination']->address_2 );
$this->assertEquals( 'Test City', $data[0]['destination']->city );
$this->assertEquals( 'AL', $data[0]['destination']->state );
$this->assertEquals( '90210', $data[0]['destination']->postcode );
$this->assertEquals( 'US', $data[0]['destination']->country );
// US address with invalid state.
$request = new WP_REST_Request( 'GET', '/wc/store/cart/shipping-rates' );
@ -118,8 +122,8 @@ class CartShippingRates extends TestCase {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 'AL', $data[0]['destination']['state'] );
$this->assertEquals( 'US', $data[0]['destination']['country'] );
$this->assertEquals( 'AL', $data[0]['destination']->state );
$this->assertEquals( 'US', $data[0]['destination']->country );
}
/**
@ -149,10 +153,11 @@ class CartShippingRates extends TestCase {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartShippingRates();
$packages = wc()->shipping->calculate_shipping( wc()->cart->get_shipping_packages() );
$response = $controller->prepare_item_for_response( current( $packages ), [] );
$data = $response->get_data();
$this->assertArrayHasKey( 'destination', $response->get_data() );
$this->assertArrayHasKey( 'items', $response->get_data() );
$this->assertArrayHasKey( 'shipping_rates', $response->get_data() );
$this->assertArrayHasKey( 'destination', $data );
$this->assertArrayHasKey( 'items', $data );
$this->assertArrayHasKey( 'shipping_rates', $data );
}
/**
@ -169,4 +174,24 @@ class CartShippingRates extends TestCase {
$this->assertArrayHasKey( 'country', $params );
$this->assertArrayHasKey( 'postcode', $params );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\CartShippingRates();
$request = new WP_REST_Request( 'GET', '/wc/store/cart/shipping-rates' );
$request->set_param( 'address_1', 'Test address 1' );
$request->set_param( 'address_2', 'Test address 2' );
$request->set_param( 'city', 'Test City' );
$request->set_param( 'state', 'AL' );
$request->set_param( 'postcode', '90210' );
$request->set_param( 'country', 'US' );
$response = $this->server->dispatch( $request );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( current( $response->get_data() ) );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Customer Controller Tests.
@ -57,12 +58,12 @@ class Customer extends TestCase {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( '123 South Street', $data['billing_address']['address_1'] );
$this->assertEquals( 'Apt 1', $data['billing_address']['address_2'] );
$this->assertEquals( 'Philadelphia', $data['billing_address']['city'] );
$this->assertEquals( 'PA', $data['billing_address']['state'] );
$this->assertEquals( '19123', $data['billing_address']['postcode'] );
$this->assertEquals( 'US', $data['billing_address']['country'] );
$this->assertEquals( '123 South Street', $data['billing_address']->address_1 );
$this->assertEquals( 'Apt 1', $data['billing_address']->address_2 );
$this->assertEquals( 'Philadelphia', $data['billing_address']->city );
$this->assertEquals( 'PA', $data['billing_address']->state );
$this->assertEquals( '19123', $data['billing_address']->postcode );
$this->assertEquals( 'US', $data['billing_address']->country );
// Invalid email.
$request = new WP_REST_Request( 'POST', '/wc/store/customer' );
@ -121,22 +122,57 @@ class Customer extends TestCase {
$response = $controller->prepare_item_for_response( $customer, [] );
$data = $response->get_data();
$this->assertEquals( 'Name', $data['billing_address']['first_name'] );
$this->assertEquals( 'Surname', $data['billing_address']['last_name'] );
$this->assertEquals( '123 South Street', $data['billing_address']['address_1'] );
$this->assertEquals( 'Apt 1', $data['billing_address']['address_2'] );
$this->assertEquals( 'Philadelphia', $data['billing_address']['city'] );
$this->assertEquals( 'PA', $data['billing_address']['state'] );
$this->assertEquals( '19123', $data['billing_address']['postcode'] );
$this->assertEquals( 'US', $data['billing_address']['country'] );
$this->assertEquals( 'Name', $data['billing_address']->first_name );
$this->assertEquals( 'Surname', $data['billing_address']->last_name );
$this->assertEquals( '123 South Street', $data['billing_address']->address_1 );
$this->assertEquals( 'Apt 1', $data['billing_address']->address_2 );
$this->assertEquals( 'Philadelphia', $data['billing_address']->city );
$this->assertEquals( 'PA', $data['billing_address']->state );
$this->assertEquals( '19123', $data['billing_address']->postcode );
$this->assertEquals( 'US', $data['billing_address']->country );
$this->assertEquals( 'Name', $data['shipping_address']['first_name'] );
$this->assertEquals( 'Surname', $data['shipping_address']['last_name'] );
$this->assertEquals( '123 South Street', $data['shipping_address']['address_1'] );
$this->assertEquals( 'Apt 1', $data['shipping_address']['address_2'] );
$this->assertEquals( 'Philadelphia', $data['shipping_address']['city'] );
$this->assertEquals( 'PA', $data['shipping_address']['state'] );
$this->assertEquals( '19123', $data['shipping_address']['postcode'] );
$this->assertEquals( 'US', $data['shipping_address']['country'] );
$this->assertEquals( 'Name', $data['shipping_address']->first_name );
$this->assertEquals( 'Surname', $data['shipping_address']->last_name );
$this->assertEquals( '123 South Street', $data['shipping_address']->address_1 );
$this->assertEquals( 'Apt 1', $data['shipping_address']->address_2 );
$this->assertEquals( 'Philadelphia', $data['shipping_address']->city );
$this->assertEquals( 'PA', $data['shipping_address']->state );
$this->assertEquals( '19123', $data['shipping_address']->postcode );
$this->assertEquals( 'US', $data['shipping_address']->country );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\Customer();
$customer = new \WC_Customer();
$customer->set_billing_first_name( 'Name' );
$customer->set_billing_last_name( 'Surname' );
$customer->set_billing_email( 'test@test.com' );
$customer->set_billing_phone( '+44 01010101011' );
$customer->set_billing_address_1( '123 South Street' );
$customer->set_billing_address_2( 'Apt 1' );
$customer->set_billing_city( 'Philadelphia' );
$customer->set_billing_state( 'PA' );
$customer->set_billing_postcode( '19123' );
$customer->set_billing_country( 'US' );
$customer->set_shipping_first_name( 'Name' );
$customer->set_shipping_last_name( 'Surname' );
$customer->set_shipping_address_1( '123 South Street' );
$customer->set_shipping_address_2( 'Apt 1' );
$customer->set_shipping_city( 'Philadelphia' );
$customer->set_shipping_state( 'PA' );
$customer->set_shipping_postcode( '19123' );
$customer->set_shipping_country( 'US' );
$response = $controller->prepare_item_for_response( $customer, [] );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Product Attributes Controller Tests.
@ -27,10 +28,14 @@ class ProductAttributeTerms extends TestCase {
$this->attributes[0] = ProductHelper::create_attribute( 'color', [ 'red', 'green', 'blue' ] );
$this->attributes[1] = ProductHelper::create_attribute( 'size', [ 'small', 'medium', 'large' ] );
wp_insert_term( 'test', 'pa_size', [
'description' => 'This is a test description',
'slug' => 'test-slug',
] );
wp_insert_term(
'test',
'pa_size',
[
'description' => 'This is a test description',
'slug' => 'test-slug',
]
);
}
/**
@ -99,4 +104,17 @@ class ProductAttributeTerms extends TestCase {
$this->assertArrayHasKey( 'orderby', $params );
$this->assertArrayHasKey( 'hide_empty', $params );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\ProductAttributeTerms();
$response = $controller->prepare_item_for_response( get_term_by( 'name', 'test', 'pa_size' ), [] );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Product Attributes Controller Tests.
@ -24,7 +25,7 @@ class ProductAttributes extends TestCase {
wp_set_current_user( 0 );
$color_attribute = ProductHelper::create_attribute( 'color', [ 'red', 'green', 'blue' ] );
$size_attribute = ProductHelper::create_attribute( 'size', [ 'small', 'medium', 'large' ] );
$size_attribute = ProductHelper::create_attribute( 'size', [ 'small', 'medium', 'large' ] );
$this->attributes = [];
$this->attributes[] = wc_get_attribute( $color_attribute['attribute_id'] );
@ -94,12 +95,26 @@ class ProductAttributes extends TestCase {
public function test_prepare_item_for_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\ProductAttributes();
$response = $controller->prepare_item_for_response( $this->attributes[0], [] );
$data = $response->get_data();
$this->assertArrayHasKey( 'id', $response->get_data() );
$this->assertArrayHasKey( 'name', $response->get_data() );
$this->assertArrayHasKey( 'slug', $response->get_data() );
$this->assertArrayHasKey( 'type', $response->get_data() );
$this->assertArrayHasKey( 'order', $response->get_data() );
$this->assertArrayHasKey( 'has_archives', $response->get_data() );
$this->assertArrayHasKey( 'id', $data );
$this->assertArrayHasKey( 'name', $data );
$this->assertArrayHasKey( 'slug', $data );
$this->assertArrayHasKey( 'type', $data );
$this->assertArrayHasKey( 'order', $data );
$this->assertArrayHasKey( 'has_archives', $data );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\ProductAttributes();
$response = $controller->prepare_item_for_response( $this->attributes[0], [] );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Controller Tests.
@ -23,7 +24,7 @@ class ProductCollectionData extends TestCase {
wp_set_current_user( 0 );
$this->products = [];
$this->products = [];
$this->products[0] = ProductHelper::create_simple_product( false );
$this->products[0]->set_regular_price( 10 );
$this->products[0]->save();
@ -32,31 +33,35 @@ class ProductCollectionData extends TestCase {
$this->products[1]->set_regular_price( 100 );
$this->products[1]->save();
wp_insert_comment( [
'comment_post_ID' => $this->products[0]->get_id(),
'comment_author' => 'admin',
'comment_author_email' => 'woo@woo.local',
'comment_author_url' => '',
'comment_content' => 'Good product.',
'comment_approved' => 1,
'comment_type' => 'review',
'comment_meta' => [
'rating' => 5,
wp_insert_comment(
[
'comment_post_ID' => $this->products[0]->get_id(),
'comment_author' => 'admin',
'comment_author_email' => 'woo@woo.local',
'comment_author_url' => '',
'comment_content' => 'Good product.',
'comment_approved' => 1,
'comment_type' => 'review',
'comment_meta' => [
'rating' => 5,
],
]
] );
);
wp_insert_comment( [
'comment_post_ID' => $this->products[1]->get_id(),
'comment_author' => 'admin',
'comment_author_email' => 'woo@woo.local',
'comment_author_url' => '',
'comment_content' => 'Another very good product.',
'comment_approved' => 1,
'comment_type' => 'review',
'comment_meta' => [
'rating' => 4,
wp_insert_comment(
[
'comment_post_ID' => $this->products[1]->get_id(),
'comment_author' => 'admin',
'comment_author_email' => 'woo@woo.local',
'comment_author_url' => '',
'comment_content' => 'Another very good product.',
'comment_approved' => 1,
'comment_type' => 'review',
'comment_meta' => [
'rating' => 4,
],
]
] );
);
\WC_Comments::clear_transients( $this->products[0]->get_id() );
\WC_Comments::clear_transients( $this->products[1]->get_id() );
@ -93,9 +98,9 @@ class ProductCollectionData extends TestCase {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 2, $data['price_range']['currency_minor_unit'] );
$this->assertEquals( '1000', $data['price_range']['min_price'] );
$this->assertEquals( '10000', $data['price_range']['max_price'] );
$this->assertEquals( 2, $data['price_range']->currency_minor_unit );
$this->assertEquals( '1000', $data['price_range']->min_price );
$this->assertEquals( '10000', $data['price_range']->max_price );
$this->assertEquals( null, $data['attribute_counts'] );
$this->assertEquals( null, $data['rating_counts'] );
}
@ -113,7 +118,7 @@ class ProductCollectionData extends TestCase {
[
'taxonomy' => 'pa_size',
'query_type' => 'and',
]
],
]
);
$response = $this->server->dispatch( $request );
@ -123,8 +128,8 @@ class ProductCollectionData extends TestCase {
$this->assertEquals( null, $data['price_range'] );
$this->assertEquals( null, $data['rating_counts'] );
$this->assertArrayHasKey( 'term', $data['attribute_counts'][0] );
$this->assertArrayHasKey( 'count', $data['attribute_counts'][0] );
$this->assertObjectHasAttribute( 'term', $data['attribute_counts'][0] );
$this->assertObjectHasAttribute( 'count', $data['attribute_counts'][0] );
}
/**
@ -139,16 +144,19 @@ class ProductCollectionData extends TestCase {
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( null, $data['price_range'] );
$this->assertEquals( null, $data['attribute_counts'] );
$this->assertEquals( [
$this->assertEquals(
[
'rating' => 4,
'count' => 1,
(object) [
'rating' => 4,
'count' => 1,
],
(object) [
'rating' => 5,
'count' => 1,
],
],
[
'rating' => 5,
'count' => 1,
]
], $data['rating_counts'] );
$data['rating_counts']
);
}
/**
@ -177,4 +185,30 @@ class ProductCollectionData extends TestCase {
$this->assertArrayHasKey( 'calculate_attribute_counts', $params );
$this->assertArrayHasKey( 'calculate_rating_counts', $params );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
ProductHelper::create_variation_product();
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\ProductCollectionData();
$request = new WP_REST_Request( 'GET', '/wc/store/products/collection-data' );
$request->set_param( 'calculate_price_range', true );
$request->set_param(
'calculate_attribute_counts',
[
[
'taxonomy' => 'pa_size',
'query_type' => 'and',
],
]
);
$request->set_param( 'calculate_rating_counts', true );
$response = $this->server->dispatch( $request );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}

View File

@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Blocks\Tests\RestApi\StoreApi\Controllers;
use \WP_REST_Request;
use \WC_REST_Unit_Test_Case as TestCase;
use \WC_Helper_Product as ProductHelper;
use Automattic\WooCommerce\Blocks\Tests\Helpers\ValidateSchema;
/**
* Products Controller Tests.
@ -19,13 +20,25 @@ class Products extends TestCase {
* Setup test products data. Called before every test.
*/
public function setUp() {
global $wpdb;
parent::setUp();
wp_set_current_user( 0 );
$this->products = [];
$this->products = [];
$this->products[0] = ProductHelper::create_simple_product( true );
$this->products[1] = ProductHelper::create_simple_product( true );
$image_url = media_sideload_image( 'http://cldup.com/Dr1Bczxq4q.png', $this->products[0]->get_id(), '', 'src' );
$image_id = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE guid = %s", $image_url ) );
$this->products[0]->set_image_id( $image_id[0] );
$this->products[0]->save();
$image_url = media_sideload_image( 'http://cldup.com/Dr1Bczxq4q.png', $this->products[1]->get_id(), '', 'src' );
$image_id = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE guid = %s", $image_url ) );
$this->products[1]->set_image_id( $image_id[0] );
$this->products[1]->save();
}
/**
@ -49,14 +62,14 @@ class Products extends TestCase {
$this->assertEquals( $this->products[0]->get_title(), $data['name'] );
$this->assertEquals( $this->products[0]->get_permalink(), $data['permalink'] );
$this->assertEquals( $this->products[0]->get_sku(), $data['sku'] );
$this->assertEquals( $this->products[0]->get_price(), $data['prices']['price'] / ( 10 ** $data['prices']['currency_minor_unit'] ) );
$this->assertEquals( $this->products[0]->get_price(), $data['prices']->price / ( 10 ** $data['prices']->currency_minor_unit ) );
$this->assertEquals( $this->products[0]->get_average_rating(), $data['average_rating'] );
$this->assertEquals( $this->products[0]->get_review_count(), $data['review_count'] );
$this->assertEquals( $this->products[0]->has_options(), $data['has_options'] );
$this->assertEquals( $this->products[0]->is_purchasable(), $data['is_purchasable'] );
$this->assertEquals( $this->products[0]->is_in_stock(), $data['is_in_stock'] );
$this->assertEquals( $this->products[0]->add_to_cart_text(), $data['add_to_cart']['text'] );
$this->assertEquals( $this->products[0]->add_to_cart_description(), $data['add_to_cart']['description'] );
$this->assertEquals( $this->products[0]->add_to_cart_text(), $data['add_to_cart']->text );
$this->assertEquals( $this->products[0]->add_to_cart_description(), $data['add_to_cart']->description );
$this->assertEquals( $this->products[0]->is_on_sale(), $data['on_sale'] );
}
@ -116,22 +129,23 @@ class Products extends TestCase {
public function test_prepare_item_for_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\Products();
$response = $controller->prepare_item_for_response( $this->products[0], [] );
$data = $response->get_data();
$this->assertArrayHasKey( 'id', $response->get_data() );
$this->assertArrayHasKey( 'name', $response->get_data() );
$this->assertArrayHasKey( 'variation', $response->get_data() );
$this->assertArrayHasKey( 'permalink', $response->get_data() );
$this->assertArrayHasKey( 'description', $response->get_data() );
$this->assertArrayHasKey( 'on_sale', $response->get_data() );
$this->assertArrayHasKey( 'sku', $response->get_data() );
$this->assertArrayHasKey( 'prices', $response->get_data() );
$this->assertArrayHasKey( 'average_rating', $response->get_data() );
$this->assertArrayHasKey( 'review_count', $response->get_data() );
$this->assertArrayHasKey( 'images', $response->get_data() );
$this->assertArrayHasKey( 'has_options', $response->get_data() );
$this->assertArrayHasKey( 'is_purchasable', $response->get_data() );
$this->assertArrayHasKey( 'is_in_stock', $response->get_data() );
$this->assertArrayHasKey( 'add_to_cart', $response->get_data() );
$this->assertArrayHasKey( 'id', $data );
$this->assertArrayHasKey( 'name', $data );
$this->assertArrayHasKey( 'variation', $data );
$this->assertArrayHasKey( 'permalink', $data );
$this->assertArrayHasKey( 'description', $data );
$this->assertArrayHasKey( 'on_sale', $data );
$this->assertArrayHasKey( 'sku', $data );
$this->assertArrayHasKey( 'prices', $data );
$this->assertArrayHasKey( 'average_rating', $data );
$this->assertArrayHasKey( 'review_count', $data );
$this->assertArrayHasKey( 'images', $data );
$this->assertArrayHasKey( 'has_options', $data );
$this->assertArrayHasKey( 'is_purchasable', $data );
$this->assertArrayHasKey( 'is_in_stock', $data );
$this->assertArrayHasKey( 'add_to_cart', $data );
}
/**
@ -170,4 +184,17 @@ class Products extends TestCase {
$this->assertArrayHasKey( 'catalog_visibility', $params );
$this->assertArrayHasKey( 'rating', $params );
}
/**
* Test schema matches responses.
*/
public function test_schema_matches_response() {
$controller = new \Automattic\WooCommerce\Blocks\RestApi\StoreApi\Controllers\Products();
$response = $controller->prepare_item_for_response( $this->products[0], [] );
$schema = $controller->get_item_schema();
$validate = new ValidateSchema( $schema );
$diff = $validate->get_diff_from_object( $response->get_data() );
$this->assertEmpty( $diff, print_r( $diff, true ) );
}
}