Adds support for Cart tax_lines (#940)

* Adds support for tax_lines

* devops: cleanup cart tax lines code style and add unit tests

* feat: add tax-aware cost, subtotal, and taxTotal fields to ShippingRate (#802)

* feat: add format arg to ShippingRate cost/subtotal/taxTotal fields, update test for RAW format

* devops: CartQueriesTest updated

---------

Co-authored-by: Geoff Taylor <geoff@axistaylor.com>
This commit is contained in:
MoscoviumAlchemist
2026-03-26 20:09:53 -04:00
committed by GitHub
co-authored by Geoff Taylor
parent f1299846c7
commit ef26bb2479
4 changed files with 345 additions and 9 deletions
+4 -4
View File
@@ -475,7 +475,7 @@ class QLSessionHandlerCest {
supportsShippingCalculator
rates {
id
cost
cost(format: RAW)
label
}
}
@@ -497,14 +497,14 @@ class QLSessionHandlerCest {
$I->expectNode(
'rates',
[
$I->expectField( 'cost', 0 ),
$I->expectField( 'cost', '0' ),
$I->expectField( 'label', 'Flat rate' ),
]
),
$I->expectNode(
'rates',
[
$I->expectField( 'cost', 0 ),
$I->expectField( 'cost', '0' ),
$I->expectField( 'label', 'Free shipping' ),
]
),
@@ -528,7 +528,7 @@ class QLSessionHandlerCest {
supportsShippingCalculator
rates {
id
cost
cost(format: RAW)
label
}
}
+216 -1
View File
@@ -546,6 +546,221 @@ class CartQueriesTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTe
]
);
}
/**
* Test cart taxLines field returns itemized tax data.
*/
public function testCartTaxLines() {
// Enable taxes and set itemized display.
update_option( 'woocommerce_calc_taxes', 'yes' );
update_option( 'woocommerce_tax_total_display', 'itemized' );
// Create a tax rate.
$tax_rate_id = $this->factory->tax_rate->create(
[
'country' => '',
'rate' => '10.0000',
'name' => 'Test Tax',
'priority' => 1,
'compound' => 0,
'shipping' => 1,
'class' => '',
]
);
// Create a product and add to cart.
$product_id = $this->factory->product->createSimple( [ 'regular_price' => '100', 'virtual' => true ] );
WC()->cart->add_to_cart( $product_id );
WC()->cart->calculate_totals();
$query = '
query {
cart {
taxLines {
name
price
rate
}
}
}
';
$response = $this->graphql( compact( 'query' ) );
$expected = [
$this->expectedNode(
'cart.taxLines',
[
$this->expectedField( 'name', 'Test Tax' ),
$this->expectedField( 'price', '$10.00' ),
$this->expectedField( 'rate', '10%' ),
]
),
];
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test cart taxLines returns empty when display is not itemized.
*/
public function testCartTaxLinesEmptyWhenNotItemized() {
update_option( 'woocommerce_calc_taxes', 'yes' );
update_option( 'woocommerce_tax_total_display', 'single' );
$tax_rate_id = $this->factory->tax_rate->create(
[
'country' => '',
'rate' => '10.0000',
'name' => 'Test Tax',
'priority' => 1,
'compound' => 0,
'shipping' => 1,
'class' => '',
]
);
$product_id = $this->factory->product->createSimple( [ 'regular_price' => '100', 'virtual' => true ] );
WC()->cart->add_to_cart( $product_id );
WC()->cart->calculate_totals();
$query = '
query {
cart {
taxLines {
name
price
rate
}
}
}
';
$response = $this->graphql( compact( 'query' ) );
$expected = [
$this->expectedField( 'cart.taxLines', static::IS_FALSY ),
];
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test shipping rate cost includes tax when woocommerce_tax_display_cart is incl.
*/
public function testShippingRateCostIncludesTax() {
// Enable taxes and set display to include tax.
update_option( 'woocommerce_calc_taxes', 'yes' );
update_option( 'woocommerce_tax_display_cart', 'incl' );
// Create a tax rate that applies to shipping.
$this->factory->tax_rate->create(
[
'country' => '',
'rate' => '10.0000',
'name' => 'Shipping Tax',
'priority' => 1,
'compound' => 0,
'shipping' => 1,
'class' => '',
]
);
// Create a physical product and add to cart.
$product_id = $this->factory->product->createSimple( [ 'regular_price' => '50' ] );
WC()->cart->add_to_cart( $product_id );
// Set shipping address so rates are calculated.
WC()->customer->set_shipping_country( 'GB' );
WC()->customer->set_shipping_postcode( 'CB23 1AB' );
WC()->cart->calculate_totals();
$query = '
query {
cart {
availableShippingMethods {
rates {
id
label
cost
subtotal
taxTotal
}
}
}
}
';
$response = $this->graphql( compact( 'query' ) );
// Flat rate is $10, tax is 10% = $1. Cost should be $11 (incl tax), subtotal $10.
$expected = [
$this->expectedField( 'cart.availableShippingMethods.0.rates.0.cost', '$11.00' ),
$this->expectedField( 'cart.availableShippingMethods.0.rates.0.subtotal', '$10.00' ),
$this->expectedField( 'cart.availableShippingMethods.0.rates.0.taxTotal', '$1.00' ),
];
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test shipping rate cost excludes tax when woocommerce_tax_display_cart is excl.
*/
public function testShippingRateCostExcludesTax() {
// Enable taxes and set display to exclude tax.
update_option( 'woocommerce_calc_taxes', 'yes' );
update_option( 'woocommerce_tax_display_cart', 'excl' );
$this->factory->tax_rate->create(
[
'country' => '',
'rate' => '10.0000',
'name' => 'Shipping Tax',
'priority' => 1,
'compound' => 0,
'shipping' => 1,
'class' => '',
]
);
$product_id = $this->factory->product->createSimple( [ 'regular_price' => '50' ] );
WC()->cart->add_to_cart( $product_id );
WC()->customer->set_shipping_country( 'GB' );
WC()->customer->set_shipping_postcode( 'CB23 1AB' );
WC()->cart->calculate_totals();
$query = '
query {
cart {
availableShippingMethods {
rates {
id
label
cost
subtotal
taxTotal
}
}
}
}
';
$response = $this->graphql( compact( 'query' ) );
// Cost and subtotal should both be $10 (excl tax), taxTotal still $1.
$expected = [
$this->expectedObject(
'cart.availableShippingMethods.#',
[
$this->expectedField( 'rates.0.cost', '$10.00' ),
$this->expectedField( 'rates.0.subtotal', '$10.00' ),
$this->expectedField( 'rates.0.taxTotal', '$1.00' ),
]
),
];
$this->assertQuerySuccessful( $response, $expected );
}
}