2019-07-09 00:49:11 -04:00
<? php
use WPGraphQL\Type\WPEnumType ;
2022-08-26 20:32:37 -04:00
class CheckoutMutationTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
2022-02-04 15:00:44 -05:00
public function setUp () : void {
// before
parent :: setUp ();
2019-07-09 00:49:11 -04:00
2022-08-26 20:32:37 -04:00
$this -> loginAs ( 0 );
2020-06-09 11:16:18 -04:00
2022-02-04 15:00:44 -05:00
// Turn on tax calculations and store shipping countries. Important!
update_option ( 'woocommerce_ship_to_countries' , 'all' );
update_option ( 'woocommerce_prices_include_tax' , 'no' );
2019-07-09 00:49:11 -04:00
update_option ( 'woocommerce_calc_taxes' , 'yes' );
2022-02-04 15:00:44 -05:00
update_option ( 'woocommerce_tax_round_at_subtotal' , 'no' );
2019-07-09 00:49:11 -04:00
2022-08-26 20:32:37 -04:00
// Turn on guest checkout.
update_option ( 'woocommerce_enable_guest_checkout' , 'yes' );
2022-02-04 15:00:44 -05:00
// Enable payment gateways.
update_option (
'woocommerce_bacs_settings' ,
2022-08-26 14:53:36 -04:00
[
2022-02-04 15:00:44 -05:00
'enabled' => 'yes' ,
'title' => 'Direct bank transfer' ,
'description' => 'Make your payment directly into our bank account. Please use your Order ID as the payment reference. Your order will not be shipped until the funds have cleared in our account.' ,
'instructions' => 'Instructions that will be added to the thank you page and emails.' ,
'account' => '' ,
2022-08-26 14:53:36 -04:00
]
2022-02-04 15:00:44 -05:00
);
2019-07-09 00:49:11 -04:00
2022-02-04 15:00:44 -05:00
update_option (
'woocommerce_stripe_settings' ,
2022-08-26 14:53:36 -04:00
[
2022-02-04 15:00:44 -05:00
'enabled' => 'yes' ,
'title' => 'Credit Card (Stripe)' ,
'description' => 'Pay with your credit card via Stripe' ,
'webhook' => '' ,
'testmode' => 'yes' ,
'test_publishable_key' => defined ( 'STRIPE_API_PUBLISHABLE_KEY' )
? STRIPE_API_PUBLISHABLE_KEY
: getenv ( 'STRIPE_API_PUBLISHABLE_KEY' ),
'test_secret_key' => defined ( 'STRIPE_API_SECRET_KEY' )
? STRIPE_API_SECRET_KEY
: getenv ( 'STRIPE_API_SECRET_KEY' ),
'test_webhook_secret' => '' ,
'publishable_key' => '' ,
'secret_key' => '' ,
'webhook_secret' => '' ,
'inline_cc_form' => 'no' ,
'statement_descriptor' => '' ,
'capture' => 'yes' ,
'payment_request' => 'yes' ,
'payment_request_button_type' => 'buy' ,
'payment_request_button_theme' => 'dark' ,
'payment_request_button_height' => '44' ,
'saved_cards' => 'yes' ,
'logging' => 'no' ,
2022-08-26 14:53:36 -04:00
]
2022-02-04 15:00:44 -05:00
);
2020-04-07 15:15:08 -04:00
2022-02-04 15:00:44 -05:00
// Additional cart fees.
add_action (
'woocommerce_cart_calculate_fees' ,
function () {
$percentage = 0.01 ;
$surcharge = ( WC () -> cart -> cart_contents_total + WC () -> cart -> shipping_total ) * $percentage ;
WC () -> cart -> add_fee ( 'Surcharge' , $surcharge , true , '' );
}
);
2019-07-09 00:49:11 -04:00
2022-02-04 15:00:44 -05:00
// Create a tax rate.
2022-08-26 20:32:37 -04:00
$this -> factory -> tax_rate -> create (
2022-08-26 14:53:36 -04:00
[
2022-02-04 15:00:44 -05:00
'country' => '' ,
'state' => '' ,
'rate' => 20.000 ,
'name' => 'VAT' ,
'priority' => '1' ,
'compound' => '0' ,
'shipping' => '1' ,
'class' => '' ,
2022-08-26 14:53:36 -04:00
]
2022-02-04 15:00:44 -05:00
);
}
2019-07-09 00:49:11 -04:00
2022-08-26 20:32:37 -04:00
private function getCheckoutMutation () {
return '
mutation checkout( $input: CheckoutInput! ) {
checkout( input: $input ) {
clientMutationId
order {
id
databaseId
currency
orderVersion
date
modified
status
discountTotal
discountTax
shippingTotal
shippingTax
cartTax
total
totalTax
subtotal
orderNumber
orderKey
createdVia
pricesIncludeTax
parent {
id
}
customer {
id
}
customerIpAddress
customerUserAgent
customerNote
billing {
firstName
lastName
company
address1
address2
city
state
postcode
country
email
phone
}
shipping {
firstName
lastName
company
address1
address2
city
state
postcode
country
}
paymentMethod
paymentMethodTitle
transactionId
dateCompleted
datePaid
cartHash
shippingAddressMapUrl
hasBillingAddress
hasShippingAddress
isDownloadPermitted
needsShippingAddress
hasDownloadableItem
downloadableItems {
nodes {
url
accessExpires
downloadId
downloadsRemaining
name
product {
databaseId
}
download {
downloadId
}
}
}
needsPayment
needsProcessing
metaData {
key
value
}
couponLines {
nodes {
databaseId
orderId
code
discount
discountTax
coupon {
id
}
}
}
feeLines {
nodes {
databaseId
orderId
amount
name
taxStatus
total
totalTax
taxClass
}
}
shippingLines {
nodes {
databaseId
orderId
methodTitle
total
totalTax
taxClass
}
}
taxLines {
nodes {
rateCode
label
taxTotal
shippingTaxTotal
isCompound
taxRate {
databaseId
}
}
}
lineItems {
nodes {
productId
variationId
quantity
taxClass
subtotal
subtotalTax
total
totalTax
taxStatus
product {
node {
... on SimpleProduct {
id
2022-03-04 23:44:48 -05:00
}
2022-08-26 20:32:37 -04:00
... on VariableProduct {
id
2022-03-04 23:44:48 -05:00
}
2022-08-26 20:32:37 -04:00
}
}
variation {
node {
id
}
}
}
}
}
customer {
id
}
result
redirect
}
}
' ;
}
2019-07-09 00:49:11 -04:00
2022-08-26 20:32:37 -04:00
private function getCartQuery () {
return '
query {
cart {
contents {
nodes {
key
}
}
total
}
}
' ;
}
private function getCheckoutInput ( $overwrite = [] ) {
return array_merge (
2022-08-26 14:53:36 -04:00
[
2022-08-26 20:32:37 -04:00
'paymentMethod' => 'bacs' ,
'shippingMethod' => [ 'flat rate' ],
'customerNote' => 'Test customer note' ,
'billing' => [
'firstName' => 'May' ,
'lastName' => 'Parker' ,
'address1' => '20 Ingram St' ,
'city' => 'New York City' ,
'state' => 'NY' ,
'postcode' => '12345' ,
'country' => 'US' ,
'email' => 'superfreak500@gmail.com' ,
'phone' => '555-555-1234' ,
'overwrite' => true ,
],
'shipping' => [
'firstName' => 'May' ,
'lastName' => 'Parker' ,
'address1' => '20 Ingram St' ,
'city' => 'New York City' ,
'state' => 'NY' ,
'postcode' => '12345' ,
'country' => 'US' ,
],
'metaData' => [
[
'key' => 'test_key' ,
'value' => 'test value' ,
],
],
],
$overwrite
2020-06-09 11:16:18 -04:00
);
2022-02-04 15:00:44 -05:00
}
// tests
public function testCheckoutMutation () {
2022-08-26 20:32:37 -04:00
$this -> loginAsCustomer ();
2022-02-04 15:00:44 -05:00
WC () -> customer -> set_billing_company ( 'Harris Teeter' );
2022-08-26 20:32:37 -04:00
WC () -> customer -> save ();
2022-02-04 15:00:44 -05:00
2022-08-26 20:32:37 -04:00
$variable = $this -> factory -> product_variation -> createSome ();
2022-08-26 14:53:36 -04:00
$product_ids = [
2022-08-26 20:32:37 -04:00
$this -> factory -> product -> createSimple (),
$this -> factory -> product -> createSimple (),
2022-02-04 15:00:44 -05:00
$variable [ 'product' ],
2022-08-26 14:53:36 -04:00
];
2022-02-04 15:00:44 -05:00
$coupon = new WC_Coupon (
2022-08-26 20:32:37 -04:00
$this -> factory -> coupon -> create (
[ 'product_ids' => $product_ids ]
)
2022-02-04 15:00:44 -05:00
);
WC () -> cart -> add_to_cart ( $product_ids [ 0 ], 3 );
WC () -> cart -> add_to_cart ( $product_ids [ 1 ], 6 );
WC () -> cart -> add_to_cart (
2020-10-03 01:28:55 -04:00
$product_ids [ 2 ],
2 ,
$variable [ 'variations' ][ 0 ],
2022-08-26 14:53:36 -04:00
[ 'attribute_pa_color' => 'red' ]
2020-10-03 01:28:55 -04:00
);
2022-02-04 15:00:44 -05:00
WC () -> cart -> apply_coupon ( $coupon -> get_code () );
2019-07-09 00:49:11 -04:00
2022-08-26 20:32:37 -04:00
$variables = [ 'input' => $this -> getCheckoutInput () ];
$query = $this -> getCheckoutMutation ();
2019-07-09 00:49:11 -04:00
2022-02-04 15:00:44 -05:00
/**
2019-07-09 00:49:11 -04:00
* Assertion One
2020-06-09 11:16:18 -04:00
*
2019-07-09 00:49:11 -04:00
* Test mutation and input.
*/
2022-08-26 20:32:37 -04:00
$response = $this -> graphql ( compact ( 'query' , 'variables' ) );
2022-08-26 14:53:36 -04:00
$expected = [
2022-08-26 20:32:37 -04:00
$this -> expectedField ( 'checkout.order.id' , self :: NOT_NULL ),
$this -> expectedField ( 'checkout.order.status' , 'ON_HOLD' ),
$this -> expectedNode (
'checkout.order.metaData' ,
[
$this -> expectedField ( 'key' , 'test_key' ),
$this -> expectedField ( 'value' , 'test value' ),
]
),
$this -> expectedNode (
'checkout.order.couponLines.nodes' ,
[
$this -> expectedField ( 'code' , $coupon -> get_code () ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'discount' , self :: NOT_NULL ),
$this -> expectedField ( 'discountTax' , self :: NOT_NULL ),
$this -> expectedField ( 'coupon' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.feeLines.nodes' ,
[
$this -> expectedField ( 'name' , 'Surcharge' ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'amount' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.shippingLines.nodes' ,
[
$this -> expectedField ( 'methodTitle' , 'Flat rate' ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.taxLines.nodes' ,
[
$this -> expectedField ( 'label' , 'VAT' ),
$this -> expectedField ( 'rateCode' , self :: NOT_NULL ),
$this -> expectedField ( 'taxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'shippingTaxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'isCompound' , self :: NOT_NULL ),
$this -> expectedField ( 'taxRate' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 0 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 1 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 2 ] ),
$this -> expectedField ( 'variationId' , self :: NOT_NULL ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
$this -> expectedField ( 'variation.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedField (
'checkout.customer.id' ,
$this -> toRelayId ( 'customer' , $this -> customer )
),
$this -> expectedField ( 'checkout.result' , 'success' ),
$this -> expectedField ( 'checkout.redirect' , self :: NOT_NULL ),
2022-08-26 14:53:36 -04:00
];
2020-06-09 11:16:18 -04:00
2022-08-26 20:32:37 -04:00
$this -> assertQuerySuccessful ( $response , $expected );
// Confirm cart empty after successful checkout.
$query = $this -> getCartQuery ();
$response = $this -> graphql ( compact ( 'query' ) );
$expected = [
$this -> expectedField ( 'cart.contents.nodes' , [] ),
$this -> expectedField ( 'cart.total' , '$0.00' ),
];
$this -> assertQuerySuccessful ( $response , $expected );
2022-02-04 15:00:44 -05:00
}
2019-07-09 00:49:11 -04:00
2022-02-04 15:00:44 -05:00
public function testCheckoutMutationWithNewAccount () {
2022-08-26 20:32:37 -04:00
$variable = $this -> factory -> product_variation -> createSome ();
2022-08-26 14:53:36 -04:00
$product_ids = [
2022-08-26 20:32:37 -04:00
$this -> factory -> product -> createSimple (),
$this -> factory -> product -> createSimple (),
2022-02-04 15:00:44 -05:00
$variable [ 'product' ],
2022-08-26 14:53:36 -04:00
];
2022-02-04 15:00:44 -05:00
$coupon = new WC_Coupon (
2022-08-26 20:32:37 -04:00
$this -> factory -> coupon -> create (
[ 'product_ids' => $product_ids ]
)
2022-02-04 15:00:44 -05:00
);
2022-08-26 20:32:37 -04:00
2022-02-04 15:00:44 -05:00
WC () -> cart -> add_to_cart ( $product_ids [ 0 ], 3 );
WC () -> cart -> add_to_cart ( $product_ids [ 1 ], 6 );
WC () -> cart -> add_to_cart (
2020-10-03 01:28:55 -04:00
$product_ids [ 2 ],
2 ,
$variable [ 'variations' ][ 0 ],
2022-08-26 14:53:36 -04:00
[ 'attribute_pa_color' => 'red' ]
2020-10-03 01:28:55 -04:00
);
2022-02-04 15:00:44 -05:00
WC () -> cart -> apply_coupon ( $coupon -> get_code () );
2019-07-09 14:05:26 -04:00
2022-08-26 20:32:37 -04:00
$input = [
'account' => [
2022-02-04 15:00:44 -05:00
'username' => 'test_user_1' ,
'password' => 'test_pass' ,
2022-08-26 14:53:36 -04:00
],
];
2022-08-26 20:32:37 -04:00
$variables = [ 'input' => $this -> getCheckoutInput ( $input ) ];
$query = $this -> getCheckoutMutation ();
2019-07-09 14:05:26 -04:00
2022-02-04 15:00:44 -05:00
/**
2019-07-09 14:05:26 -04:00
* Assertion One
2020-06-09 11:16:18 -04:00
*
2019-07-09 14:05:26 -04:00
* Test mutation and input.
*/
2022-08-26 20:32:37 -04:00
$response = $this -> graphql ( compact ( 'query' , 'variables' ) );
2022-08-26 14:53:36 -04:00
$expected = [
2022-08-26 20:32:37 -04:00
$this -> expectedField ( 'checkout.order.id' , self :: NOT_NULL ),
$this -> expectedField ( 'checkout.order.status' , 'ON_HOLD' ),
$this -> expectedNode (
'checkout.order.metaData' ,
[
$this -> expectedField ( 'key' , 'test_key' ),
$this -> expectedField ( 'value' , 'test value' ),
]
),
$this -> expectedNode (
'checkout.order.feeLines.nodes' ,
[
$this -> expectedField ( 'name' , 'Surcharge' ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'amount' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.shippingLines.nodes' ,
[
$this -> expectedField ( 'methodTitle' , 'Flat rate' ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.taxLines.nodes' ,
[
$this -> expectedField ( 'label' , 'VAT' ),
$this -> expectedField ( 'rateCode' , self :: NOT_NULL ),
$this -> expectedField ( 'taxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'shippingTaxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'isCompound' , self :: NOT_NULL ),
$this -> expectedField ( 'taxRate' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 0 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 1 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 2 ] ),
$this -> expectedField ( 'variationId' , self :: NOT_NULL ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
$this -> expectedField ( 'variation.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedField ( 'checkout.customer.id' , self :: NOT_NULL ),
$this -> expectedField ( 'checkout.result' , 'success' ),
$this -> expectedField ( 'checkout.redirect' , self :: NOT_NULL ),
2022-08-26 14:53:36 -04:00
];
2020-06-09 11:16:18 -04:00
2022-08-26 20:32:37 -04:00
$this -> assertQuerySuccessful ( $response , $expected );
// Confirm cart empty after successful checkout.
$query = $this -> getCartQuery ();
$response = $this -> graphql ( compact ( 'query' ) );
$expected = [
$this -> expectedField ( 'cart.contents.nodes' , [] ),
$this -> expectedField ( 'cart.total' , '$0.00' ),
];
$this -> assertQuerySuccessful ( $response , $expected );
2022-02-04 15:00:44 -05:00
}
2019-07-09 14:05:26 -04:00
2022-02-04 15:00:44 -05:00
public function testCheckoutMutationWithNoAccount () {
2022-08-26 20:32:37 -04:00
WC () -> customer -> set_billing_email ( 'superfreak500@gmail.com' );
WC () -> customer -> save ();
$variable = $this -> factory -> product_variation -> createSome ();
2022-08-26 14:53:36 -04:00
$product_ids = [
2022-08-26 20:32:37 -04:00
$this -> factory -> product -> createSimple (),
$this -> factory -> product -> createSimple (),
2022-02-04 15:00:44 -05:00
$variable [ 'product' ],
2022-08-26 14:53:36 -04:00
];
2022-02-04 15:00:44 -05:00
$coupon = new WC_Coupon (
2022-08-26 20:32:37 -04:00
$this -> factory -> coupon -> create (
[ 'product_ids' => $product_ids ]
)
2022-02-04 15:00:44 -05:00
);
2022-08-26 20:32:37 -04:00
2022-02-04 15:00:44 -05:00
WC () -> cart -> add_to_cart ( $product_ids [ 0 ], 3 );
WC () -> cart -> add_to_cart ( $product_ids [ 1 ], 6 );
WC () -> cart -> add_to_cart (
2020-10-03 01:28:55 -04:00
$product_ids [ 2 ],
2 ,
$variable [ 'variations' ][ 0 ],
2022-08-26 14:53:36 -04:00
[ 'attribute_pa_color' => 'red' ]
2020-10-03 01:28:55 -04:00
);
2022-02-04 15:00:44 -05:00
WC () -> cart -> apply_coupon ( $coupon -> get_code () );
2019-07-09 14:05:26 -04:00
2022-08-26 20:32:37 -04:00
$variables = [ 'input' => $this -> getCheckoutInput () ];
$query = $this -> getCheckoutMutation ();
2019-07-09 14:05:26 -04:00
2022-02-04 15:00:44 -05:00
/**
2019-07-09 14:05:26 -04:00
* Assertion One
2020-06-09 11:16:18 -04:00
*
2019-07-09 14:05:26 -04:00
* Test mutation and input.
*/
2022-08-26 20:32:37 -04:00
$response = $this -> graphql ( compact ( 'query' , 'variables' ) );
2022-08-26 14:53:36 -04:00
$expected = [
2022-08-26 20:32:37 -04:00
$this -> expectedField ( 'checkout.order.id' , self :: NOT_NULL ),
$this -> expectedField ( 'checkout.order.status' , 'ON_HOLD' ),
$this -> expectedNode (
'checkout.order.metaData' ,
[
$this -> expectedField ( 'key' , 'test_key' ),
$this -> expectedField ( 'value' , 'test value' ),
]
),
$this -> expectedNode (
'checkout.order.feeLines.nodes' ,
[
$this -> expectedField ( 'name' , 'Surcharge' ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'amount' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.shippingLines.nodes' ,
[
$this -> expectedField ( 'methodTitle' , 'Flat rate' ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.taxLines.nodes' ,
[
$this -> expectedField ( 'label' , 'VAT' ),
$this -> expectedField ( 'rateCode' , self :: NOT_NULL ),
$this -> expectedField ( 'taxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'shippingTaxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'isCompound' , self :: NOT_NULL ),
$this -> expectedField ( 'taxRate' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 0 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 1 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 2 ] ),
$this -> expectedField ( 'variationId' , self :: NOT_NULL ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
$this -> expectedField ( 'variation.node.id' , self :: NOT_NULL ),
]
),
2023-06-21 13:21:29 -04:00
$this -> expectedField ( 'checkout.customer.id' , 'guest' ),
2022-08-26 20:32:37 -04:00
$this -> expectedField ( 'checkout.result' , 'success' ),
$this -> expectedField ( 'checkout.redirect' , self :: NOT_NULL ),
2022-08-26 14:53:36 -04:00
];
2020-06-09 11:16:18 -04:00
2022-08-26 20:32:37 -04:00
$this -> assertQuerySuccessful ( $response , $expected );
// Confirm cart empty after successful checkout.
$query = $this -> getCartQuery ();
$response = $this -> graphql ( compact ( 'query' ) );
$expected = [
$this -> expectedField ( 'cart.contents.nodes' , [] ),
$this -> expectedField ( 'cart.total' , '$0.00' ),
];
$this -> assertQuerySuccessful ( $response , $expected );
2022-02-04 15:00:44 -05:00
}
2020-02-03 19:30:43 -05:00
2022-02-04 15:00:44 -05:00
public function testCheckoutMutationWithPrepaidOrder () {
2022-08-26 20:32:37 -04:00
WC () -> customer -> set_billing_email ( 'superfreak500@gmail.com' );
WC () -> customer -> save ();
2022-08-26 14:53:36 -04:00
$product_ids = [
2022-08-26 20:32:37 -04:00
$this -> factory -> product -> createSimple (
2022-08-26 14:53:36 -04:00
[
2022-02-04 15:00:44 -05:00
'virtual' => true ,
'downloadable' => true ,
2022-08-26 14:53:36 -04:00
]
2022-02-04 15:00:44 -05:00
),
2022-08-26 20:32:37 -04:00
$this -> factory -> product -> createSimple (
2022-08-26 14:53:36 -04:00
[
2022-02-04 15:00:44 -05:00
'virtual' => true ,
'downloadable' => true ,
2022-08-26 14:53:36 -04:00
]
2022-02-04 15:00:44 -05:00
),
2022-08-26 14:53:36 -04:00
];
2022-08-26 20:32:37 -04:00
$coupon = new WC_Coupon (
$this -> factory -> coupon -> create ( [ 'product_ids' => $product_ids ] )
2022-02-04 15:00:44 -05:00
);
2022-08-26 20:32:37 -04:00
2022-02-04 15:00:44 -05:00
WC () -> cart -> add_to_cart ( $product_ids [ 0 ], 3 );
WC () -> cart -> add_to_cart ( $product_ids [ 1 ], 6 );
WC () -> cart -> apply_coupon ( $coupon -> get_code () );
2020-02-03 19:30:43 -05:00
2022-08-26 14:53:36 -04:00
$input = [
2022-08-26 20:32:37 -04:00
'isPaid' => true ,
'transactionId' => 'transaction_id' ,
2022-08-26 14:53:36 -04:00
];
2020-02-03 19:30:43 -05:00
2022-08-26 20:32:37 -04:00
$variables = [ 'input' => $this -> getCheckoutInput ( $input ) ];
$query = $this -> getCheckoutMutation ();
2022-02-04 15:00:44 -05:00
/**
2020-02-03 19:30:43 -05:00
* Assertion One
2020-06-09 11:16:18 -04:00
*
2020-02-03 19:30:43 -05:00
* Test mutation and input.
*/
2022-08-26 20:32:37 -04:00
$response = $this -> graphql ( compact ( 'query' , 'variables' ) );
2022-08-26 14:53:36 -04:00
$expected = [
2022-08-26 20:32:37 -04:00
$this -> expectedField ( 'checkout.order.id' , self :: NOT_NULL ),
$this -> expectedField ( 'checkout.order.status' , 'COMPLETED' ),
$this -> expectedNode (
'checkout.order.metaData' ,
[
$this -> expectedField ( 'key' , 'test_key' ),
$this -> expectedField ( 'value' , 'test value' ),
]
),
$this -> expectedNode (
'checkout.order.feeLines.nodes' ,
[
$this -> expectedField ( 'name' , 'Surcharge' ),
$this -> expectedField ( 'databaseId' , self :: NOT_NULL ),
$this -> expectedField ( 'orderId' , self :: NOT_NULL ),
$this -> expectedField ( 'amount' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.taxLines.nodes' ,
[
$this -> expectedField ( 'label' , 'VAT' ),
$this -> expectedField ( 'rateCode' , self :: NOT_NULL ),
$this -> expectedField ( 'taxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'shippingTaxTotal' , self :: NOT_NULL ),
$this -> expectedField ( 'isCompound' , self :: NOT_NULL ),
$this -> expectedField ( 'taxRate' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 0 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 1 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
2023-06-21 13:21:29 -04:00
$this -> expectedField ( 'checkout.customer.id' , 'guest' ),
2022-08-26 20:32:37 -04:00
$this -> expectedField ( 'checkout.result' , 'success' ),
$this -> expectedField ( 'checkout.redirect' , self :: NOT_NULL ),
2022-08-26 14:53:36 -04:00
];
2019-07-09 14:05:26 -04:00
2022-08-26 20:32:37 -04:00
$this -> assertQuerySuccessful ( $response , $expected );
// Confirm cart empty after successful checkout.
$query = $this -> getCartQuery ();
$response = $this -> graphql ( compact ( 'query' ) );
$expected = [
$this -> expectedField ( 'cart.contents.nodes' , [] ),
$this -> expectedField ( 'cart.total' , '$0.00' ),
];
$this -> assertQuerySuccessful ( $response , $expected );
2022-02-04 15:00:44 -05:00
}
2020-04-07 15:15:08 -04:00
2022-02-04 15:00:44 -05:00
/**
* Returns a new Stripe Customer object
*
* @param string $email Customer email
*
* @return array
*/
private function create_stripe_customer ( $email ) {
2022-08-26 14:53:36 -04:00
$customer = \Stripe\Customer :: create ( [ 'email' => $email ] );
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
// use --debug flag to view.
codecept_debug ( $customer );
return $customer ;
}
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
/**
* Creates a new Stripe Source object, attaches it to the provided customer,
* and returns the Source object
*
* @param array $customer Customer object
*
* @return array
*/
private function create_stripe_source ( $customer ) {
$source = \Stripe\Customer :: createSource (
$customer [ 'id' ],
2022-08-26 14:53:36 -04:00
[ 'source' => 'tok_visa' ]
2022-02-04 15:00:44 -05:00
);
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
// use --debug flag to view.
codecept_debug ( $source );
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
return $source ;
}
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
/**
* Creates a new Payment Intent object, assigns an amount and customer,
* and returns the Payment Intent object
*
* This payment intent is meant to be processed by WooCommerce upon validation
* so do not `confirm=true` must not be passed as a parameter.
*
* @param array $customer Customer object
*
* @return array
*/
private function create_stripe_payment_intent ( $amount , $customer ) {
$payment_intent = \Stripe\PaymentIntent :: create (
2022-08-26 14:53:36 -04:00
[
2022-02-04 15:00:44 -05:00
'amount' => $amount ,
'currency' => 'gbp' ,
2022-08-26 14:53:36 -04:00
'payment_method_types' => [ 'card' ],
2022-02-04 15:00:44 -05:00
'customer' => $customer [ 'id' ],
'payment_method' => $customer [ 'invoice_settings' ][ 'default_payment_method' ],
2022-08-26 14:53:36 -04:00
]
2022-02-04 15:00:44 -05:00
);
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
// use --debug flag to view.
codecept_debug ( $payment_intent );
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
return $payment_intent ;
}
2020-04-03 21:40:17 -04:00
2022-02-04 15:00:44 -05:00
public function testCheckoutMutationWithStripe () {
2022-08-26 20:32:37 -04:00
WC () -> customer -> set_billing_email ( 'superfreak500@gmail.com' );
WC () -> customer -> save ();
2022-02-04 15:00:44 -05:00
// Add items to the cart.
2022-08-26 14:53:36 -04:00
$product_ids = [
2022-08-26 20:32:37 -04:00
$this -> factory -> product -> createSimple (),
$this -> factory -> product -> createSimple (),
2022-08-26 14:53:36 -04:00
];
2022-08-26 20:32:37 -04:00
WC () -> cart -> add_to_cart ( $product_ids [ 0 ], 1 );
WC () -> cart -> add_to_cart ( $product_ids [ 1 ], 1 );
2020-04-07 15:15:08 -04:00
2022-02-04 15:00:44 -05:00
$amount = ( int ) floatval ( WC () -> cart -> get_cart_contents_total () + WC () -> cart -> get_cart_contents_tax () ) * 100 ;
2020-06-09 11:16:18 -04:00
try {
$stripe_customer = $this -> create_stripe_customer ( 'superfreak500@gmail.com' );
2022-02-04 15:00:44 -05:00
$stripe_source = $this -> create_stripe_source ( $stripe_customer );
$payment_intent = $this -> create_stripe_payment_intent ( $amount , $stripe_customer );
2020-06-09 11:16:18 -04:00
} catch ( \Stripe\Exception\AuthenticationException $e ) {
$this -> markTestSkipped ( $e -> getMessage () );
}
2020-04-07 15:15:08 -04:00
2022-08-26 14:53:36 -04:00
$input = [
2022-08-26 20:32:37 -04:00
'paymentMethod' => 'stripe' ,
'metaData' => [
2022-08-26 14:53:36 -04:00
[
2022-02-04 15:00:44 -05:00
'key' => '_stripe_source_id' ,
'value' => $stripe_source [ 'id' ],
2022-08-26 14:53:36 -04:00
],
[
2022-02-04 15:00:44 -05:00
'key' => '_stripe_customer_id' ,
'value' => $stripe_customer [ 'id' ],
2022-08-26 14:53:36 -04:00
],
[
2022-02-04 15:00:44 -05:00
'key' => '_stripe_intent_id' ,
'value' => $payment_intent [ 'id' ],
2022-08-26 14:53:36 -04:00
],
],
];
2020-04-07 15:15:08 -04:00
2022-08-26 20:32:37 -04:00
$variables = [ 'input' => $this -> getCheckoutInput ( $input ) ];
2022-02-04 15:00:44 -05:00
// Remove "metaData" value field and "redirect" link from the mutation output.
2022-08-26 20:32:37 -04:00
$query = '
2020-04-07 15:15:08 -04:00
mutation checkout( $input: CheckoutInput! ) {
checkout( input: $input ) {
clientMutationId
order {
2022-08-26 20:32:37 -04:00
id
status
total
2020-09-16 16:32:14 -04:00
databaseId
2020-04-03 21:40:17 -04:00
metaData { key }
2020-04-07 15:15:08 -04:00
lineItems {
nodes {
productId
variationId
quantity
taxClass
subtotal
subtotalTax
total
totalTax
taxStatus
product {
2022-03-04 23:44:48 -05:00
node {
... on SimpleProduct {
id
}
... on VariableProduct {
id
}
}
2020-04-07 15:15:08 -04:00
}
variation {
2022-03-04 23:44:48 -05:00
node { id }
2020-04-07 15:15:08 -04:00
}
}
}
}
result
}
}
' ;
2022-02-04 15:00:44 -05:00
/**
2020-04-07 15:15:08 -04:00
* Assertion One
2020-06-09 11:16:18 -04:00
*
2020-04-07 15:15:08 -04:00
* Test mutation and input.
*/
2022-08-26 20:32:37 -04:00
$response = $this -> graphql ( compact ( 'query' , 'variables' ) );
2022-08-26 14:53:36 -04:00
$expected = [
2022-08-26 20:32:37 -04:00
$this -> expectedField ( 'checkout.order.id' , self :: NOT_NULL ),
$this -> expectedField ( 'checkout.order.status' , 'PROCESSING' ),
$this -> expectedNode (
'checkout.order.metaData' ,
[ $this -> expectedField ( 'key' , '_stripe_source_id' ) ]
),
$this -> expectedNode (
'checkout.order.metaData' ,
[ $this -> expectedField ( 'key' , '_stripe_customer_id' ) ]
),
$this -> expectedNode (
'checkout.order.metaData' ,
[ $this -> expectedField ( 'key' , '_stripe_intent_id' ) ]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 0 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedNode (
'checkout.order.lineItems.nodes' ,
[
$this -> expectedField ( 'productId' , $product_ids [ 1 ] ),
$this -> expectedField ( 'quantity' , self :: NOT_NULL ),
$this -> expectedField ( 'taxClass' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotal' , self :: NOT_NULL ),
$this -> expectedField ( 'subtotalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'total' , self :: NOT_NULL ),
$this -> expectedField ( 'totalTax' , self :: NOT_NULL ),
$this -> expectedField ( 'taxStatus' , self :: NOT_NULL ),
$this -> expectedField ( 'product.node.id' , self :: NOT_NULL ),
]
),
$this -> expectedField ( 'checkout.result' , 'success' ),
2022-08-26 14:53:36 -04:00
];
2020-04-07 15:15:08 -04:00
2022-08-26 20:32:37 -04:00
$this -> assertQuerySuccessful ( $response , $expected );
// Confirm cart empty after successful checkout.
$query = $this -> getCartQuery ();
$response = $this -> graphql ( compact ( 'query' ) );
$expected = [
$this -> expectedField ( 'cart.contents.nodes' , [] ),
$this -> expectedField ( 'cart.total' , '$0.00' ),
];
$this -> assertQuerySuccessful ( $response , $expected );
2020-07-06 09:10:27 -04:00
}
public function testCheckoutMutationCartItemValidation () {
2020-10-03 01:28:55 -04:00
add_filter ( 'woocommerce_hold_stock_for_checkout' , '__return_false' );
2020-07-06 09:10:27 -04:00
2022-08-26 20:32:37 -04:00
$product_id = $this -> factory -> product -> createSimple (
2022-08-26 14:53:36 -04:00
[
2020-07-06 09:10:27 -04:00
'manage_stock' => true ,
2020-10-03 01:28:55 -04:00
'stock_quantity' => 3 ,
2022-08-26 14:53:36 -04:00
]
2020-07-06 09:10:27 -04:00
);
2020-10-03 01:28:55 -04:00
$key = WC () -> cart -> add_to_cart ( $product_id , 3 );
WC () -> cart -> set_quantity ( $key , 5 );
2020-07-06 09:10:27 -04:00
2022-08-26 20:32:37 -04:00
$input = [
'account' => [
2022-02-04 15:00:44 -05:00
'username' => 'test_user_1' ,
'password' => 'test_pass' ,
2022-08-26 14:53:36 -04:00
],
];
2022-08-26 20:32:37 -04:00
$variables = [ 'input' => $this -> getCheckoutInput ( $input ) ];
$query = $this -> getCheckoutMutation ();
2020-07-06 09:10:27 -04:00
2022-08-26 20:32:37 -04:00
/**
* Assertion One
*
* Ensure that checkout failed when stock is too low.
*/
$response = $this -> graphql ( compact ( 'query' , 'variables' ) );
$expected = [ $this -> expectedField ( 'checkout' , self :: IS_NULL ) ];
2020-07-06 09:10:27 -04:00
2022-08-26 20:32:37 -04:00
$this -> assertQueryError ( $response , $expected );
2020-07-06 09:10:27 -04:00
}
2020-06-09 11:16:18 -04:00
}