expectedField( 'coupon.id', $this->toRelayId( 'shop_coupon', $coupon_id ) ), $this->expectedField( 'coupon.databaseId', $coupon->get_id() ), $this->expectedField( 'coupon.code', $coupon->get_code() ), $this->expectedField( 'coupon.amount', floatval( $coupon->get_amount() ) ), $this->expectedField( 'coupon.date', $coupon->get_date_created()->__toString() ), $this->expectedField( 'coupon.modified', $coupon->get_date_modified()->__toString() ), $this->expectedField( 'coupon.discountType', strtoupper( $coupon->get_discount_type() ) ), $this->expectedField( 'coupon.description', $coupon->get_description() ), $this->expectedField( 'coupon.dateExpiry', $this->maybe( $coupon->get_date_expires(), static::IS_NULL ) ), $this->expectedField( 'coupon.usageCount', $coupon->get_usage_count() ), $this->expectedField( 'coupon.individualUse', $coupon->get_individual_use() ), $this->expectedField( 'coupon.usageLimit', $this->maybe( $coupon->get_usage_limit(), static::IS_NULL ) ), $this->expectedField( 'coupon.usageLimitPerUser', $this->maybe( $coupon->get_usage_limit_per_user(), static::IS_NULL ) ), $this->expectedField( 'coupon.limitUsageToXItems', $this->maybe( $coupon->get_limit_usage_to_x_items(), static::IS_NULL ) ), $this->expectedField( 'coupon.freeShipping', $coupon->get_free_shipping() ), $this->expectedField( 'coupon.excludeSaleItems', $coupon->get_exclude_sale_items() ), $this->expectedField( 'coupon.minimumAmount', $this->maybe( $coupon->get_minimum_amount(), static::IS_NULL ) ), $this->expectedField( 'coupon.maximumAmount', $this->maybe( $coupon->get_maximum_amount(), static::IS_NULL ) ), $this->expectedField( 'coupon.emailRestrictions', $this->maybe( $coupon->get_email_restrictions(), static::IS_NULL ) ), ]; foreach ( $coupon->get_product_ids() as $product_id ) { $expected[] = $this->expectedNode( 'coupon.products.nodes', [ 'databaseId' => $product_id ] ); } foreach ( $coupon->get_excluded_product_ids() as $product_id ) { $expected[] = $this->expectedNode( 'coupon.excludedProducts.nodes', [ 'databaseId' => $product_id ] ); } foreach ( $coupon->get_product_categories() as $category_id ) { $expected[] = $this->expectedNode( 'coupon.productCategories.nodes', [ 'productCategoryId' => $category_id ] ); } foreach ( $coupon->get_excluded_product_categories() as $category_id ) { $expected[] = $this->expectedNode( 'coupon.excludedProductCategories.nodes', [ 'productCategoryId' => $category_id ] ); } foreach ( $coupon->get_used_by() as $customer_id ) { $expected[] = $this->expectedNode( 'coupon.usedBy.nodes', [ 'databaseId' => $customer_id ] ); } return $expected; } // tests public function testCouponQuery() { $coupon_id = $this->factory->coupon->create( [ 'code' => '10off', 'amount' => 10, 'discount_type' => 'percent', 'product_ids' => [ $this->factory->product->createSimple() ], 'excluded_product_ids' => [ $this->factory->product->createSimple() ], ] ); $query = ' query ($id: ID!){ coupon(id: $id) { id databaseId code amount date modified discountType description dateExpiry usageCount individualUse usageLimit usageLimitPerUser limitUsageToXItems freeShipping excludeSaleItems minimumAmount maximumAmount emailRestrictions products { nodes { ... on SimpleProduct { databaseId } } } excludedProducts { nodes { ... on SimpleProduct { databaseId } } } productCategories { nodes { productCategoryId } } excludedProductCategories { nodes { productCategoryId } } usedBy { nodes { databaseId } } } } '; /** * Assertion One * * Confirm customer's can't query coupons by ID. */ $this->loginAsCustomer(); $variables = [ 'id' => $this->toRelayId( 'shop_coupon', $coupon_id ) ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $expected = [ $this->expectedField( 'coupon', static::IS_NULL ) ]; $this->assertQuerySuccessful( $response, $expected ); /** * Assertion Two * * Confirm shop managers can query coupons by ID. */ $this->loginAsShopManager(); $response = $this->graphql( compact( 'query', 'variables' ) ); $this->assertQuerySuccessful( $response, $this->expectedCouponData( $coupon_id ) ); } public function testCouponQueryAndIds() { $coupon_id = $this->factory->coupon->create(); $coupon = new \WC_Coupon( $coupon_id ); $relay_id = $this->toRelayId( 'shop_coupon', $coupon_id ); $query = ' query ($id: ID!, $idType: CouponIdTypeEnum) { coupon(id: $id, idType: $idType) { id } } '; /** * Assertion One * * Testing "ID" ID type. */ $this->loginAsShopManager(); $variables = [ 'id' => $relay_id, 'idType' => 'ID', ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $expected = [ $this->expectedField( 'coupon.id', $relay_id ) ]; $this->assertQuerySuccessful( $response, $expected ); /** * Assertion Two * * Testing "DATABASE_ID" ID type */ $variables = [ 'id' => $coupon_id, 'idType' => 'DATABASE_ID', ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $this->assertQuerySuccessful( $response, $expected ); /** * Assertion Three * * Testing "CODE" ID type. */ $variables = [ 'id' => $coupon->get_code(), 'idType' => 'CODE', ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $this->assertQuerySuccessful( $response, $expected ); } public function testCouponsQueryAndWhereArgs() { $coupons = [ $this->factory->coupon->create(), $this->factory->coupon->create( [ 'code' => '20off', 'amount' => 20, 'discount_type' => 'percent', ] ), $this->factory->coupon->create( [ 'code' => 'testcode', 'amount' => 30, 'discount_type' => 'percent', ] ), ]; $query = ' query ($code: String, $include: [Int], $exclude: [Int]) { coupons(where: { code: $code, include: $include, exclude: $exclude }) { nodes { id } } } '; /** * Assertion One * * Should return null due to lack of required capabilities */ $this->loginAsCustomer(); $response = $this->graphql( compact( 'query' ) ); $expected = [ $this->expectedField( 'coupons.nodes', static::IS_FALSY ), ]; $this->assertQuerySuccessful( $response, $expected ); $this->clearLoaderCache( 'wc_post' ); /** * Assertion Two * * Should return data because user has required capabilities */ $this->loginAsShopManager(); $response = $this->graphql( compact( 'query' ) ); $expected = [ $this->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['0'] ) ] ), $this->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['1'] ) ] ), $this->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['2'] ) ] ), ]; $this->assertQuerySuccessful( $response, $expected ); $this->clearLoaderCache( 'wc_post' ); /** * Assertion Three * * Tests 'code' where argument */ $variables = [ 'code' => 'testcode' ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $expected = [ $this->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['2'] ) ] ), $this->not()->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['0'] ) ] ), $this->not()->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['1'] ) ] ), ]; $this->assertQuerySuccessful( $response, $expected ); $this->clearLoaderCache( 'wc_post' ); /** * Assertion Four * * Tests 'include' where argument */ $variables = [ 'include' => $coupons[0] ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $expected = [ $this->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['0'] ) ] ), $this->not()->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['1'] ) ] ), $this->not()->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['2'] ) ] ), ]; $this->assertQuerySuccessful( $response, $expected ); /** * Assertion Five * * Tests 'exclude' where argument */ $variables = [ 'exclude' => $coupons[0] ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $expected = [ $this->not()->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['0'] ) ] ), $this->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['1'] ) ] ), $this->expectedNode( 'coupons.nodes', [ 'id' => $this->toRelayId( 'shop_coupon', $coupons['2'] ) ] ), ]; $this->assertQuerySuccessful( $response, $expected ); } /** * Test coupon productCategories and excludedProductCategories connections. */ public function testCouponProductCategoryConnections() { $this->loginAsShopManager(); // Create a WP category first to force term_id/term_taxonomy_id mismatch // when the product_cat with the same name is created. global $wpdb; $wpdb->insert( $wpdb->terms, [ 'name' => 'cat-a', 'slug' => 'cat-a', 'term_group' => 0, ] ); $shared_term_id = (int) $wpdb->insert_id; // Add term_taxonomy entry for 'category' (consumes a term_taxonomy_id). $wpdb->insert( $wpdb->term_taxonomy, [ 'term_id' => $shared_term_id, 'taxonomy' => 'category', 'description' => '', 'parent' => 0, 'count' => 0, ] ); // Add term_taxonomy entry for 'product_cat' (different term_taxonomy_id, same term_id). $wpdb->insert( $wpdb->term_taxonomy, [ 'term_id' => $shared_term_id, 'taxonomy' => 'product_cat', 'description' => '', 'parent' => 0, 'count' => 0, ] ); $cat_a_tt_id = (int) $wpdb->insert_id; clean_term_cache( $shared_term_id, 'product_cat' ); clean_term_cache( $shared_term_id, 'category' ); // cat-a now has term_id != term_taxonomy_id. $cat_a = $shared_term_id; // Create normal product categories for the rest. $cat_b = $this->factory->product->createProductCategory( 'cat-b' ); $cat_c = $this->factory->product->createProductCategory( 'cat-c' ); // Create coupon with product categories and excluded categories. $coupon_id = $this->factory->coupon->create( [ 'code' => 'catcoupon', 'amount' => 15, 'discount_type' => 'percent', 'product_categories' => [ $cat_a, $cat_b ], 'excluded_product_categories' => [ $cat_c ], ] ); $query = ' query ($id: ID!) { coupon(id: $id) { databaseId productCategories { nodes { databaseId slug } } excludedProductCategories { nodes { databaseId slug } } } } '; $variables = [ 'id' => $this->toRelayId( 'shop_coupon', $coupon_id ) ]; $response = $this->graphql( compact( 'query', 'variables' ) ); $expected = [ $this->expectedField( 'coupon.databaseId', $coupon_id ), $this->expectedNode( 'coupon.productCategories.nodes', [ $this->expectedField( 'slug', 'cat-a' ) ] ), $this->expectedNode( 'coupon.productCategories.nodes', [ $this->expectedField( 'slug', 'cat-b' ) ] ), $this->not()->expectedNode( 'coupon.productCategories.nodes', [ $this->expectedField( 'slug', 'cat-c' ) ] ), $this->expectedNode( 'coupon.excludedProductCategories.nodes', [ $this->expectedField( 'slug', 'cat-c' ) ] ), $this->not()->expectedNode( 'coupon.excludedProductCategories.nodes', [ $this->expectedField( 'slug', 'cat-a' ) ] ), ]; $this->assertQuerySuccessful( $response, $expected ); // Query with where arg to further filter the included categories. $query_with_filter = ' query ($id: ID!, $exclude: [ID]) { coupon(id: $id) { productCategories(where: { exclude: $exclude }) { nodes { slug } } } } '; $variables = [ 'id' => $this->toRelayId( 'shop_coupon', $coupon_id ), 'exclude' => [ $cat_b ], ]; $response = $this->graphql( [ 'query' => $query_with_filter, 'variables' => $variables, ] ); $expected = [ $this->expectedNode( 'coupon.productCategories.nodes', [ $this->expectedField( 'slug', 'cat-a' ) ] ), $this->not()->expectedNode( 'coupon.productCategories.nodes', [ $this->expectedField( 'slug', 'cat-b' ) ] ), ]; $this->assertQuerySuccessful( $response, $expected ); } }