mirror of
https://github.com/wp-graphql/wp-graphql-woocommerce.git
synced 2026-08-14 12:53:44 +02:00
* fix: improve i18n compatibility for WPML, Polylang, and non-latin character support - Add Label::get_safe_enum_name() utility with optional transliteration for non-latin tax class/attribute/taxonomy names (#637, #409) - Add "Transliterate non-latin characters" admin setting - Replace get_page_by_path() with WP_Query for product slug resolution so WPML/Polylang can hook into the standard query pipeline (#403, #368) - Split product connections: `products` (toType: Product) and `productsWithVariations` (toType: ProductUnion) so i18n plugins can register language where args on the standard type name (#811, #952) - Add ProductTypesWithVariationsEnum for the ProductUnion connection - Add i18n compatibility tests * chore: Linter compliances met
334 lines
12 KiB
PHP
334 lines
12 KiB
PHP
<?php
|
|
|
|
use WPGraphQL\Type\WPEnumType;
|
|
|
|
class ProductVariationQueriesTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
|
|
public function expectedProductVariationData( $id ) {
|
|
$data = new WC_Product_Variation( $id );
|
|
|
|
return [
|
|
$this->expectedField( 'productVariation.id', $this->toRelayId( 'post', $id ) ),
|
|
$this->expectedField( 'productVariation.databaseId', $data->get_id() ),
|
|
$this->expectedField( 'productVariation.name', $data->get_name() ),
|
|
$this->expectedField( 'productVariation.date', $data->get_date_created()->__toString() ),
|
|
$this->expectedField(
|
|
'productVariation.modified',
|
|
! empty( $data->get_date_created() )
|
|
? $data->get_date_created()->__toString()
|
|
: static::IS_NULL
|
|
),
|
|
$this->expectedField( 'productVariation.description', ! empty( $data->get_description() ) ? $data->get_description() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.sku', $data->get_sku() ),
|
|
$this->expectedField( 'productVariation.price', ! empty( $data->get_price() ) ? \wc_graphql_price( $data->get_price() ) : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.regularPrice', ! empty( $data->get_regular_price() ) ? \wc_graphql_price( $data->get_regular_price() ) : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.salePrice', ! empty( $data->get_sale_price() ) ? \wc_graphql_price( $data->get_sale_price() ) : static::IS_NULL ),
|
|
$this->expectedField(
|
|
'productVariation.dateOnSaleFrom',
|
|
! empty( $data->get_date_on_sale_from() )
|
|
? $data->get_date_on_sale_from()
|
|
: static::IS_NULL
|
|
),
|
|
$this->expectedField(
|
|
'productVariation.dateOnSaleTo',
|
|
! empty( $data->get_date_on_sale_to() )
|
|
? $data->get_date_on_sale_to()
|
|
: static::IS_NULL
|
|
),
|
|
$this->expectedField( 'productVariation.onSale', $data->is_on_sale() ),
|
|
$this->expectedField( 'productVariation.status', $data->get_status() ),
|
|
$this->expectedField( 'productVariation.purchasable', ! empty( $data->is_purchasable() ) ? $data->is_purchasable() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.virtual', $data->is_virtual() ),
|
|
$this->expectedField( 'productVariation.downloadable', $data->is_downloadable() ),
|
|
$this->expectedField( 'productVariation.downloadLimit', ! empty( $data->get_download_limit() ) ? $data->get_download_limit() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.downloadExpiry', ! empty( $data->get_download_expiry() ) ? $data->get_download_expiry() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.taxStatus', strtoupper( $data->get_tax_status() ) ),
|
|
$this->expectedField(
|
|
'productVariation.taxClass',
|
|
! empty( $data->get_tax_class() )
|
|
? WPEnumType::get_safe_name( $data->get_tax_class() )
|
|
: 'STANDARD'
|
|
),
|
|
$this->expectedField(
|
|
'productVariation.manageStock',
|
|
! empty( $data->get_manage_stock() )
|
|
? WPEnumType::get_safe_name( $data->get_manage_stock() )
|
|
: static::IS_NULL
|
|
),
|
|
$this->expectedField( 'productVariation.stockQuantity', ! empty( $data->get_stock_quantity() ) ? $data->get_stock_quantity() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.stockStatus', ProductHelper::get_stock_status_enum( $data->get_stock_status() ) ),
|
|
$this->expectedField(
|
|
'productVariation.backorders',
|
|
! empty( $data->get_backorders() )
|
|
? WPEnumType::get_safe_name( $data->get_backorders() )
|
|
: static::IS_NULL
|
|
),
|
|
$this->expectedField( 'productVariation.backordersAllowed', $data->backorders_allowed() ),
|
|
$this->expectedField( 'productVariation.weight', ! empty( $data->get_weight() ) ? $data->get_weight() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.length', ! empty( $data->get_length() ) ? $data->get_length() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.width', ! empty( $data->get_width() ) ? $data->get_width() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.height', ! empty( $data->get_height() ) ? $data->get_height() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.menuOrder', $data->get_menu_order() ),
|
|
$this->expectedField( 'productVariation.purchaseNote', ! empty( $data->get_purchase_note() ) ? $data->get_purchase_note() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.shippingClass', ! empty( $data->get_shipping_class() ) ? $data->get_shipping_class() : static::IS_NULL ),
|
|
$this->expectedField(
|
|
'productVariation.catalogVisibility',
|
|
! empty( $data->get_catalog_visibility() )
|
|
? WPEnumType::get_safe_name( $data->get_catalog_visibility() )
|
|
: static::IS_NULL
|
|
),
|
|
$this->expectedField( 'productVariation.hasAttributes', ! empty( $data->has_attributes() ) ? $data->has_attributes() : static::IS_NULL ),
|
|
$this->expectedField( 'productVariation.type', WPEnumType::get_safe_name( $data->get_type() ) ),
|
|
$this->expectedField( 'productVariation.parent.node.id', $this->toRelayId( 'post', $data->get_parent_id() ) ),
|
|
];
|
|
}
|
|
|
|
// tests
|
|
public function testVariationQuery() {
|
|
// Create product variations.
|
|
$products = $this->factory->product_variation->createSome(
|
|
$this->factory->product->createVariable()
|
|
);
|
|
$variation_id = $products['variations'][0];
|
|
$id = $this->toRelayId( 'post', $variation_id );
|
|
|
|
// Create query.
|
|
$query = '
|
|
query ($id: ID, $idType: ProductVariationIdTypeEnum) {
|
|
productVariation(id: $id, idType: $idType) {
|
|
id
|
|
databaseId
|
|
name
|
|
date
|
|
modified
|
|
description
|
|
sku
|
|
price
|
|
regularPrice
|
|
salePrice
|
|
dateOnSaleFrom
|
|
dateOnSaleTo
|
|
onSale
|
|
status
|
|
purchasable
|
|
virtual
|
|
downloadable
|
|
downloadLimit
|
|
downloadExpiry
|
|
taxStatus
|
|
taxClass
|
|
manageStock
|
|
stockQuantity
|
|
stockStatus
|
|
backorders
|
|
backordersAllowed
|
|
weight
|
|
length
|
|
width
|
|
height
|
|
menuOrder
|
|
purchaseNote
|
|
shippingClass
|
|
catalogVisibility
|
|
hasAttributes
|
|
type
|
|
parent {
|
|
node { id }
|
|
}
|
|
}
|
|
}
|
|
';
|
|
|
|
/**
|
|
* Assertion One
|
|
*
|
|
* Tests "ID" ID type.
|
|
*/
|
|
$variables = [
|
|
'id' => $id,
|
|
'idType' => 'ID',
|
|
];
|
|
$response = $this->graphql( compact( 'query', 'variables' ) );
|
|
$expected = $this->expectedProductVariationData( $variation_id );
|
|
|
|
$this->assertQuerySuccessful( $response, $expected );
|
|
|
|
$this->clearLoaderCache( 'wc_post' );
|
|
|
|
/**
|
|
* Assertion Two
|
|
*
|
|
* Tests "DATABASE_ID" ID type.
|
|
*/
|
|
$variables = [
|
|
'id' => $variation_id,
|
|
'idType' => 'DATABASE_ID',
|
|
|
|
];
|
|
$response = $this->graphql( compact( 'query', 'variables' ) );
|
|
$expected = $this->expectedProductVariationData( $variation_id );
|
|
|
|
$this->assertQuerySuccessful( $response, $expected );
|
|
}
|
|
|
|
public function testProductVariationToMediaItemConnections() {
|
|
// Create product variations.
|
|
$products = $this->factory->product_variation->createSome(
|
|
$this->factory->product->createVariable()
|
|
);
|
|
$variation_id = $products['variations'][1];
|
|
$id = $this->toRelayId( 'post', $variation_id );
|
|
$product = wc_get_product( $variation_id );
|
|
|
|
// Create query.
|
|
$query = '
|
|
query ($id: ID!) {
|
|
productVariation(id: $id) {
|
|
id
|
|
image {
|
|
id
|
|
}
|
|
}
|
|
}
|
|
';
|
|
|
|
$variables = [ 'id' => $id ];
|
|
$response = $this->graphql( compact( 'query', 'variables' ) );
|
|
$expected = [
|
|
$this->expectedField( 'productVariation.id', $id ),
|
|
$this->expectedField( 'productVariation.image.id', $this->toRelayId( 'post', $product->get_image_id() ) ),
|
|
];
|
|
|
|
$this->assertQuerySuccessful( $response, $expected );
|
|
}
|
|
|
|
public function testProductVariationDownloads() {
|
|
// Create product variations.
|
|
$products = $products = $this->factory->product_variation->createSome(
|
|
$this->factory->product->createVariable()
|
|
);
|
|
$variation_id = $products['variations'][0];
|
|
$id = $this->toRelayId( 'post', $variation_id );
|
|
$product = wc_get_product( $variation_id );
|
|
$downloads = (array) array_values( $product->get_downloads() );
|
|
|
|
// Create query.
|
|
$query = '
|
|
query ($id: ID!) {
|
|
productVariation(id: $id) {
|
|
id
|
|
downloads {
|
|
name
|
|
downloadId
|
|
filePathType
|
|
fileType
|
|
fileExt
|
|
allowedFileType
|
|
fileExists
|
|
file
|
|
}
|
|
}
|
|
}
|
|
';
|
|
|
|
$variables = [ 'id' => $id ];
|
|
$response = $this->graphql( compact( 'query', 'variables' ) );
|
|
$expected = [
|
|
$this->expectedField( 'productVariation.id', $id ),
|
|
$this->expectedNode(
|
|
'productVariation.downloads',
|
|
[
|
|
$this->expectedField( 'name', $downloads[0]->get_name() ),
|
|
$this->expectedField( 'downloadId', $downloads[0]->get_id() ),
|
|
$this->expectedField( 'filePathType', $downloads[0]->get_type_of_file_path() ),
|
|
$this->expectedField( 'fileType', $downloads[0]->get_file_type() ),
|
|
$this->expectedField( 'fileExt', $downloads[0]->get_file_extension() ),
|
|
$this->expectedField( 'allowedFileType', $downloads[0]->is_allowed_filetype() ),
|
|
$this->expectedField( 'fileExists', $downloads[0]->file_exists() ),
|
|
$this->expectedField( 'file', $downloads[0]->get_file() ),
|
|
]
|
|
),
|
|
];
|
|
|
|
$this->assertQuerySuccessful( $response, $expected );
|
|
}
|
|
|
|
public function testProductsQueriesWithVariations() {
|
|
// Create noise products.
|
|
$product_id = $this->factory->product->createVariable(
|
|
[
|
|
'attribute_data' => [ $this->factory->product->createAttribute( 'print', [ 'polka-dot', 'stripe', 'flames' ] ) ],
|
|
],
|
|
);
|
|
$variation_id = $this->factory->product_variation->create(
|
|
[
|
|
'parent_id' => $product_id,
|
|
'attributes' => [
|
|
'pattern' => 'polka-dot',
|
|
],
|
|
'image_id' => null,
|
|
'regular_price' => 10,
|
|
]
|
|
);
|
|
|
|
|
|
$other_variation_id = $this->factory->product_variation->create(
|
|
[
|
|
'parent_id' => $product_id,
|
|
'attributes' => [
|
|
'pattern' => 'stripe',
|
|
],
|
|
'image_id' => null,
|
|
'regular_price' => 10,
|
|
]
|
|
);
|
|
|
|
$query = '
|
|
query ( $type: ProductTypesWithVariationsEnum, $typeIn: [ProductTypesWithVariationsEnum], $includeVariations: Boolean ) {
|
|
productsWithVariations( where: { type: $type, typeIn: $typeIn includeVariations: $includeVariations } ) {
|
|
nodes {
|
|
id
|
|
}
|
|
}
|
|
}
|
|
';
|
|
|
|
/**
|
|
* Assert default results without "type", or "typeIn" excludes product variations.
|
|
*/
|
|
$response = $this->graphql( compact( 'query' ) );
|
|
$expected = [
|
|
$this->expectedField( 'productsWithVariations.nodes.0.id', $this->toRelayId( 'post', $product_id ) ),
|
|
$this->not()->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $variation_id ) ),
|
|
$this->not()->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $other_variation_id ) ),
|
|
];
|
|
|
|
$this->assertQuerySuccessful( $response, $expected );
|
|
|
|
/**
|
|
* Assert result with "type" set to "VARIATION" only return variations.
|
|
*/
|
|
$variables = [ 'type' => 'VARIATION' ];
|
|
$response = $this->graphql( compact( 'query', 'variables' ) );
|
|
$expected = [
|
|
$this->not()->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $product_id ) ),
|
|
$this->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $variation_id ) ),
|
|
$this->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $other_variation_id ) ),
|
|
];
|
|
|
|
$this->assertQuerySuccessful( $response, $expected );
|
|
|
|
/**
|
|
* Assert result with "includeVariations" returns products and variations.
|
|
*/
|
|
$variables = [ 'includeVariations' => true ];
|
|
$response = $this->graphql( compact( 'query', 'variables' ) );
|
|
$expected = [
|
|
$this->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $product_id ) ),
|
|
$this->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $variation_id ) ),
|
|
$this->expectedField( 'productsWithVariations.nodes.#.id', $this->toRelayId( 'post', $other_variation_id ) ),
|
|
];
|
|
|
|
$this->assertQuerySuccessful( $response, $expected );
|
|
}
|
|
}
|