product_catalog = $I->getCatalog(); } // tests public function testCartMutationsWithValidCartSessionToken( FunctionalTester $I ) { /** * Add item to the cart */ $success = $I->addToCart( array( 'clientMutationId' => 'someId', 'productId' => $this->product_catalog['t-shirt'], 'quantity' => 5, ) ); $I->assertArrayNotHasKey( 'errors', $success ); $I->assertArrayHasKey('data', $success ); $I->assertArrayHasKey('addToCart', $success['data'] ); $I->assertArrayHasKey('cartItem', $success['data']['addToCart'] ); $I->assertArrayHasKey('key', $success['data']['addToCart']['cartItem'] ); $cart_item_key = $success['data']['addToCart']['cartItem']['key']; /** * Assert existence and validity of "woocommerce-session" HTTP header. */ $I->seeHttpHeaderOnce( 'woocommerce-session' ); $session_token = $I->grabHttpHeader( 'woocommerce-session' ); // Decode token JWT::$leeway = 60; $token_data = ! empty( $session_token ) ? JWT::decode( $session_token, 'graphql-woo-cart-session', array( 'HS256' ) ) : null; $I->assertNotEmpty( $token_data ); $I->assertNotEmpty( $token_data->iss ); $I->assertNotEmpty( $token_data->iat ); $I->assertNotEmpty( $token_data->nbf ); $I->assertNotEmpty( $token_data->exp ); $I->assertNotEmpty( $token_data->data ); $I->assertNotEmpty( $token_data->data->customer_id ); $wp_url = getenv( 'WP_URL' ); $I->assertEquals( $token_data->iss, $wp_url ); /** * Make a cart query request with "woocommerce-session" HTTP Header and confirm * correct cart contents. */ $query = ' query { cart { contents { nodes { key } } } } '; $actual = $I->sendGraphQLRequest( $query, null, array( 'woocommerce-session' => "Session {$session_token}" ) ); $expected = array( 'data' => array( 'cart' => array( 'contents' => array( 'nodes' => array( array( 'key' => $cart_item_key, ), ), ), ), ), ); $I->assertEquals( $expected, $actual ); /** * Remove item from the cart */ $success = $I->removeItemsFromCart( array( 'clientMutationId' => 'someId', 'keys' => $cart_item_key, ), array( 'woocommerce-session' => "Session {$session_token}" ) ); $I->assertArrayNotHasKey( 'errors', $success ); $I->assertArrayHasKey('data', $success ); $I->assertArrayHasKey('removeItemsFromCart', $success['data'] ); $I->assertArrayHasKey('cartItems', $success['data']['removeItemsFromCart'] ); $I->assertCount( 1, $success['data']['removeItemsFromCart']['cartItems'] ); /** * Make a cart query request with "woocommerce-session" HTTP Header and confirm * correct cart contents. */ $query = ' query { cart { contents { nodes { key } } } } '; $actual = $I->sendGraphQLRequest( $query, null, array( 'woocommerce-session' => "Session {$session_token}" ) ); $expected = array( 'data' => array( 'cart' => array( 'contents' => array( 'nodes' => array(), ), ), ), ); $I->assertEquals( $expected, $actual ); /** * Restore item to the cart */ $success = $I->restoreCartItems( array( 'clientMutationId' => 'someId', 'keys' => array( $cart_item_key ), ), array( 'woocommerce-session' => "Session {$session_token}" ) ); $I->assertArrayNotHasKey( 'errors', $success ); $I->assertArrayHasKey('data', $success ); $I->assertArrayHasKey('restoreCartItems', $success['data'] ); $I->assertArrayHasKey('cartItems', $success['data']['restoreCartItems'] ); $I->assertCount( 1, $success['data']['restoreCartItems']['cartItems'] ); /** * Make a cart query request with "woocommerce-session" HTTP Header and confirm * correct cart contents. */ $query = ' query { cart { contents { nodes { key } } } } '; $actual = $I->sendGraphQLRequest( $query, null, array( 'woocommerce-session' => "Session {$session_token}" ) ); $expected = array( 'data' => array( 'cart' => array( 'contents' => array( 'nodes' => array( array( 'key' => $cart_item_key, ), ), ), ), ), ); $I->assertEquals( $expected, $actual ); } public function testCartMutationsWithInvalidCartSessionToken( FunctionalTester $I ) { /** * Add item to cart and retrieve session token to corrupt. */ $success = $I->addToCart( array( 'clientMutationId' => 'someId', 'productId' => $this->product_catalog['t-shirt'], 'quantity' => 1, ) ); $I->assertArrayNotHasKey( 'errors', $success ); $I->assertArrayHasKey('data', $success ); $I->assertArrayHasKey('addToCart', $success['data'] ); $I->assertArrayHasKey('cartItem', $success['data']['addToCart'] ); $I->assertArrayHasKey('key', $success['data']['addToCart']['cartItem'] ); $cart_item_key = $success['data']['addToCart']['cartItem']['key']; /** * Retrieve session token from "woocommerce-session" HTTP response header. */ $I->seeHttpHeaderOnce( 'woocommerce-session' ); $valid_token = $I->grabHttpHeader( 'woocommerce-session' ); // Decode token $token_data = ! empty( $valid_token ) ? JWT::decode( $valid_token, 'graphql-woo-cart-session', array( 'HS256' ) ) : null; /** * Attempt to add item to the cart with invalid session token. * GraphQL should throw an error and mutation will fail. */ $invalid_token = $token_data; $invalid_token->data->customer_id = ''; $invalid_token = JWT::encode( $invalid_token, 'graphql-woo-cart-session' ); $failed = $I->addToCart( array( 'clientMutationId' => 'someId', 'productId' => $this->product_catalog['t-shirt'], 'quantity' => 1, ), array( 'woocommerce-session' => "Session {$invalid_token}" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to remove item from the cart with invalid session token. * GraphQL should throw an error and mutation will fail. */ $invalid_token = $token_data; $invalid_token->iss = ''; $invalid_token = JWT::encode( $invalid_token, 'graphql-woo-cart-session' ); $failed = $I->removeItemsFromCart( array( 'clientMutationId' => 'someId', 'keys' => $cart_item_key, ), array( 'woocommerce-session' => "Session {$invalid_token}" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to update quantity of item in the cart with invalid session token. * GraphQL should throw an error and mutation will fail. */ $failed = $I->updateItemQuantities( array( 'clientMutationId' => 'someId', 'items' => array( array( 'key' => $cart_item_key, 'quantity' => 0 ), ), ), array( 'woocommerce-session' => "Session invalid-jwt-token-string" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to empty cart with invalid session token. * GraphQL should throw an error and mutation will fail. */ $failed = $I->emptyCart( array( 'clientMutationId' => 'someId', ), array( 'woocommerce-session' => "Session invalid-jwt-token-string" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to add fee on cart with invalid session token. * GraphQL should throw an error and mutation will fail. */ $failed = $I->addFee( array( 'clientMutationId' => 'someId', 'name' => 'extra_fee', 'amount' => 49.99, ), array( 'woocommerce-session' => "Session invalid-jwt-token-string" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to apply coupon on cart with invalid session token. * GraphQL should throw an error and mutation will fail. * * @Note: No coupons exist in the database, but mutation should fail before that becomes a factor. */ $failed = $I->applyCoupon( array( 'clientMutationId' => 'someId', 'code' => 'some_coupon', ), array( 'woocommerce-session' => "Session invalid-jwt-token-string" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to remove coupon from cart with invalid session token. * GraphQL should throw an error and mutation will fail. * * @Note: No coupons exist on the cart, but mutation should failed before that becomes a factor. */ $failed = $I->removeCoupons( array( 'clientMutationId' => 'someId', 'codes' => array( 'some_coupon' ), ), array( 'woocommerce-session' => "Session invalid-jwt-token-string" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to restore item to the cart with invalid session token. * GraphQL should throw an error and mutation will fail. * * @Note: No items have been removed from the cart in this session, * but mutation should failed before that becomes a factor. */ $failed = $I->restoreCartItems( array( 'clientMutationId' => 'someId', 'keys' => array( $cart_item_key ), ), array( 'woocommerce-session' => "Session invalid-jwt-token-string" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to restore item to the cart with invalid session token. * GraphQL should throw an error and mutation will fail. * * @Note: No items have been removed from the cart in this session, * but mutation should failed before that becomes a factor. */ $failed = $I->updateShippingMethod( array( 'clientMutationId' => 'someId', 'shippingMethods' => array( 'legacy_flat_rate' ), ), array( 'woocommerce-session' => "Session invalid-jwt-token-string" ) ); $I->assertArrayHasKey( 'errors', $failed ); /** * Attempt to query cart with invalid session token. * GraphQL should throw an error and query will fail. */ $query = ' query { cart { contents { nodes { key } } } } '; $failed = $I->sendGraphQLRequest( $query, null, array( 'woocommerce-session' => 'Session invalid-jwt-token-string' ) ); $I->assertArrayHasKey( 'errors', $failed ); } public function testCartSessionDataMutations( FunctionalTester $I ) { /** * Add item to the cart */ $success = $I->addToCart( array( 'clientMutationId' => 'someId', 'productId' => $this->product_catalog['socks'], 'quantity' => 2, ) ); $I->assertArrayNotHasKey( 'errors', $success ); $I->assertArrayHasKey('data', $success ); $I->assertArrayHasKey('addToCart', $success['data'] ); $I->assertArrayHasKey('cartItem', $success['data']['addToCart'] ); $I->assertArrayHasKey('key', $success['data']['addToCart']['cartItem'] ); $cart_item_key = $success['data']['addToCart']['cartItem']['key']; /** * Assert existence and validity of "woocommerce-session" HTTP header. */ $I->seeHttpHeaderOnce( 'woocommerce-session' ); $session_token = $I->grabHttpHeader( 'woocommerce-session' ); // Decode token JWT::$leeway = 60; $token_data = ! empty( $session_token ) ? JWT::decode( $session_token, 'graphql-woo-cart-session', array( 'HS256' ) ) : null; $I->assertNotEmpty( $token_data ); $I->assertNotEmpty( $token_data->iss ); $I->assertNotEmpty( $token_data->iat ); $I->assertNotEmpty( $token_data->nbf ); $I->assertNotEmpty( $token_data->exp ); $I->assertNotEmpty( $token_data->data ); $I->assertNotEmpty( $token_data->data->customer_id ); $wp_url = getenv( 'WP_URL' ); $I->assertEquals( $token_data->iss, $wp_url ); /** * Set shipping address, so shipping rates can be calculated */ $input = array( 'clientMutationId' => 'someId', 'shipping' => array( 'state' => 'New York', 'country' => 'US', 'postcode' => '12345', ) ); $mutation = ' mutation ( $input: UpdateCustomerInput! ){ updateCustomer ( input: $input ) { customer { shipping { state country postcode } } } } '; $actual = $I->sendGraphQLRequest( $mutation, $input, array( 'woocommerce-session' => "Session {$session_token}" ) ); $expected = array( 'data' => array( 'updateCustomer' => array( 'customer' => array( 'shipping' => array( 'state' => 'New York', 'country' => 'US', 'postcode' => '12345' ), ), ), ), ); $I->assertEquals( $expected, $actual ); /** * Make a cart query request with "woocommerce-session" HTTP Header and confirm * correct cart contents and chosen and available shipping methods. */ $query = ' query { cart { contents { nodes { key } } availableShippingMethods { packageDetails supportsShippingCalculator rates { id cost label } } } } '; $actual = $I->sendGraphQLRequest( $query, null, array( 'woocommerce-session' => "Session {$session_token}" ) ); $expected = array( 'data' => array( 'cart' => array( 'contents' => array( 'nodes' => array( array( 'key' => $cart_item_key, ), ), ), 'availableShippingMethods' => array( array( 'packageDetails' => 'socks ×2', 'supportsShippingCalculator' => true, 'rates' => array( array( 'id' => 'flat_rate:7', 'cost' => '0.00', 'label' => 'Flat rate' ), array( 'id' => 'free_shipping:8', 'cost' => '0.00', 'label' => 'Free shipping' ), ) ) ), ), ), ); $I->assertEquals( $expected, $actual ); /** * Update shipping method to 'flat_rate' shipping. */ $mutation = ' mutation ($input: UpdateShippingMethodInput!){ updateShippingMethod(input: $input) { cart { availableShippingMethods { packageDetails supportsShippingCalculator rates { id cost label } } chosenShippingMethod shippingTotal shippingTax subtotal subtotalTax total } } } '; $success = $I->sendGraphQLRequest( $mutation, array( 'clientMutationId' => 'someId', 'shippingMethods' => array( 'flat_rate:7' ), ), array( 'woocommerce-session' => "Session {$session_token}" ) ); $I->assertArrayNotHasKey( 'errors', $success ); $I->assertNotEmpty( $success['data'] ); $I->assertNotEmpty( $success['data']['updateShippingMethod'] ); $I->assertNotEmpty( $success['data']['updateShippingMethod']['cart'] ); $cart = $success['data']['updateShippingMethod']['cart']; $I->assertNotEmpty( $cart['availableShippingMethods'] ); $I->assertEquals( 'flat_rate:7', $cart['chosenShippingMethod'] ); } }