diff --git a/bin/_env.sh b/bin/_env.sh index 479235e9..c98f40bd 100644 --- a/bin/_env.sh +++ b/bin/_env.sh @@ -1,3 +1,5 @@ +set +u + if [[ -z "$DB_NAME" ]]; then echo "DB_NAME not found" print_usage_instruction @@ -10,7 +12,7 @@ fi DB_HOST=${DB_HOST-localhost} DB_PASS=${DB_PASSWORD-""} WP_VERSION=${WP_VERSION-5} -PHPUNIT_VERSION=${PHPUNIT_VERSION-8.1} +PHPUNIT_VERSION=${PHPUNIT_VERSION-"<=8.1"} PROJECT_ROOT_DIR=$(pwd) WP_CORE_DIR=${WP_CORE_DIR:-local/public} PLUGINS_DIR=${PLUGINS_DIR:-"$WP_CORE_DIR/wp-content/plugins"} diff --git a/bin/_lib.sh b/bin/_lib.sh index e6462e43..d705d1ee 100644 --- a/bin/_lib.sh +++ b/bin/_lib.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set +u + install_wordpress() { if [ -f $WP_CORE_DIR/wp-config.php ]; then echo "Wordpress already installed." @@ -47,7 +49,7 @@ remove_wordpress() { install_local_test_library() { # Install testing library dependencies. composer install - composer require --dev phpunit/phpunit:<=${PHPUNIT_VERSION} + composer require --dev phpunit/phpunit:${PHPUNIT_VERSION} \ lucatume/wp-browser \ codeception/module-asserts \ codeception/module-rest \ diff --git a/includes/class-type-registry.php b/includes/class-type-registry.php index d8d4054a..51fd804b 100644 --- a/includes/class-type-registry.php +++ b/includes/class-type-registry.php @@ -60,6 +60,7 @@ class Type_Registry { // Interfaces. \WPGraphQL\WooCommerce\Type\WPInterface\Product::register_interface( $type_registry ); + \WPGraphQL\WooCommerce\Type\WPInterface\Attribute::register_interface( $type_registry ); \WPGraphQL\WooCommerce\Type\WPInterface\Product_Attribute::register_interface( $type_registry ); \WPGraphQL\WooCommerce\Type\WPInterface\Cart_Error::register_interface( $type_registry ); @@ -78,6 +79,7 @@ class Type_Registry { \WPGraphQL\WooCommerce\Type\WPObject\Tax_Rate_Type::register(); \WPGraphQL\WooCommerce\Type\WPObject\Shipping_Method_Type::register(); \WPGraphQL\WooCommerce\Type\WPObject\Cart_Type::register(); + \WPGraphQL\WooCommerce\Type\WPObject\Simple_Attribute_Type::register(); \WPGraphQL\WooCommerce\Type\WPObject\Variation_Attribute_Type::register(); \WPGraphQL\WooCommerce\Type\WPObject\Payment_Gateway_Type::register(); \WPGraphQL\WooCommerce\Type\WPObject\Meta_Data_Type::register(); diff --git a/includes/type/interface/class-attribute.php b/includes/type/interface/class-attribute.php new file mode 100644 index 00000000..cc56c744 --- /dev/null +++ b/includes/type/interface/class-attribute.php @@ -0,0 +1,52 @@ + __( 'Attribute object', 'wp-graphql-woocommerce' ), + 'fields' => array( + 'name' => array( + 'type' => 'String', + 'description' => __( 'Name of attribute', 'wp-graphql-woocommerce' ), + 'resolve' => function ( $source ) { + return isset( $source['name'] ) ? $source['name'] : null; + }, + ), + 'value' => array( + 'type' => 'String', + 'description' => __( 'Selected value of attribute', 'wp-graphql-woocommerce' ), + 'resolve' => function ( $source ) { + return isset( $source['value'] ) ? $source['value'] : null; + }, + ), + ), + 'resolveType' => function( $value ) use ( &$type_registry ) { + if ( $value->is_taxonomy() ) { + return $type_registry->get_type( 'SimpleAttribute' ); + } else { + return $type_registry->get_type( 'VariationAttribute' ); + } + }, + ) + ); + } +} diff --git a/includes/type/object/class-cart-type.php b/includes/type/object/class-cart-type.php index 4d80dd30..b64a06d4 100644 --- a/includes/type/object/class-cart-type.php +++ b/includes/type/object/class-cart-type.php @@ -308,6 +308,24 @@ class Cart_Type { 'toType' => 'Product', 'fromFieldName' => 'product', 'oneToOne' => true, + 'edgeFields' => array( + 'simpleVariations' => array( + 'type' => array( 'list_of' => 'SimpleAttribute' ), + 'description' => __( 'Simple variation attribute data', 'wp-graphql-woocommerce' ), + 'resolve' => function( $source ) { + $attributes = array(); + + $variation = $source['node']; + $cart_item_data = $source['source']; + $simple_attribute_data = $cart_item_data['variation']; + foreach ( $simple_attribute_data as $name => $value ) { + $attributes[] = compact( 'name', 'value' ); + } + + return $attributes; + }, + ) + ), 'resolve' => function ( $source, array $args, AppContext $context, ResolveInfo $info ) { $id = $source['product_id']; $resolver = new Product_Connection_Resolver( $source, $args, $context, $info ); diff --git a/includes/type/object/class-simple-attribute-type.php b/includes/type/object/class-simple-attribute-type.php new file mode 100644 index 00000000..1d76ed9e --- /dev/null +++ b/includes/type/object/class-simple-attribute-type.php @@ -0,0 +1,31 @@ + __( 'A simple attribute object', 'wp-graphql-woocommerce' ), + 'interfaces' => array( 'Attribute' ), + 'fields' => array(), + ) + ); + } +} diff --git a/includes/type/object/class-variation-attribute-type.php b/includes/type/object/class-variation-attribute-type.php index 1660864d..6de129eb 100644 --- a/includes/type/object/class-variation-attribute-type.php +++ b/includes/type/object/class-variation-attribute-type.php @@ -23,6 +23,7 @@ class Variation_Attribute_Type { 'VariationAttribute', array( 'description' => __( 'A product variation attribute object', 'wp-graphql-woocommerce' ), + 'interfaces' => array( 'Attribute' ), 'fields' => array( 'id' => array( 'type' => array( 'non_null' => 'ID' ), diff --git a/tests/wpunit/CartMutationsTest.php b/tests/wpunit/CartMutationsTest.php index b1028905..79e4a2f2 100644 --- a/tests/wpunit/CartMutationsTest.php +++ b/tests/wpunit/CartMutationsTest.php @@ -819,6 +819,86 @@ class CartMutationsTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQL $this->assertArrayHasKey( 'errors', $not_enough_stock ); } + public function testAddToCartMutationItemEdgeData() { + // Create variable product for later use. + $variation_ids = $this->factory->product_variation->createSome(); + $product = \wc_get_product( $variation_ids['product'] ); + $attribute = new WC_Product_Attribute(); + $attribute->set_id( 0 ); + $attribute->set_name( 'test' ); + $attribute->set_options( array( 'yes', 'no' ) ); + $attribute->set_position( 3 ); + $attribute->set_visible( true ); + $attribute->set_variation( true ); + $attributes = array_values( $product->get_attributes() ); + $attributes[] = $attribute; + $product->set_attributes( $attributes ); + $product->save(); + + $query = ' + mutation( $input: AddToCartInput! ) { + addToCart(input: $input) { + cartItem { + product { + simpleVariations { + name + value + } + node { + databaseId + } + } + } + } + } + '; + + $variables = array( + 'input' => array( + 'clientMutationId' => 'someId', + 'productId' => $variation_ids['product'], + 'quantity' => 3, + 'variationId' => $variation_ids['variations'][1], + 'variation' => array( + array( + 'attributeName' => 'test', + 'attributeValue' => 'yes', + ), + array( + 'attributeName' => 'color', + 'attributeValue' => 'green', + ), + ) + ) + ); + + $response = $this->graphql( compact( 'query', 'variables' ) ); + $expected = array( + $this->expectedObject( + 'addToCart.cartItem.product', + array( + $this->expectedField( 'node.databaseId', $variation_ids['product'] ), + $this->expectedObject( + 'simpleVariations.#', + array( + $this->expectedField( 'name', 'attribute_test' ), + $this->expectedField( 'value', 'yes' ), + ) + ), + $this->expectedObject( + 'simpleVariations.#', + array( + $this->expectedField( 'name', 'attribute_pa_color' ), + $this->expectedField( 'value', 'green' ), + ) + ), + ) + ) + ); + + $this->assertQuerySuccessful( $response, $expected ); + } + public function testAddCartItemsMutationAndErrors() { // Create variable product for later use. $variation_ids = $this->factory->product_variation->createSome();