feat: Add support for brands (#918) (#964)

* feat: Add support for brands (#918)

* feat: add product brand support with where args, taxonomy filter, and taxonomy mutation input fields

- Register product_brand taxonomy with WPGraphQL (fix indentation from #964)
- Add productBrand/productBrandIn/productBrandNotIn/productBrandId/productBrandIdIn/productBrandIdNotIn
  where args on products connection
- Add product_brand to taxonomy args map and case statements in product connection resolver
- Register additional input fields (display, menuOrder, imageId) on
  CreateProductCategoryInput and UpdateProductCategoryInput mutations
- Split ProductTaxonomyQueriesTest into ProductCategoryQueriesTest,
  ProductTagQueriesTest, ProductCategoryMutationsTest, ProductTagMutationsTest
- Add ProductBrandQueriesTest with 8 tests covering queries, connections,
  hierarchy, where args, taxonomy filter, and CRUD mutations

---------

Co-authored-by: Geoff Taylor <geoff@axistaylor.com>
This commit is contained in:
Pascal Martineau
2026-03-23 12:28:48 -04:00
committed by GitHub
co-authored by Geoff Taylor
parent b62193e6d4
commit e3ca7f895e
12 changed files with 1101 additions and 158 deletions
+462
View File
@@ -0,0 +1,462 @@
<?php
class ProductBrandQueriesTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
/**
* Helper: create a product brand term.
*
* @param string $name Term name.
* @param int $parent_id Optional parent term ID.
*
* @return int Term ID.
*/
private function createProductBrand( $name, $parent_id = 0 ) {
$args = [];
if ( $parent_id ) {
$args['parent'] = $parent_id;
}
$existing = term_exists( $name, 'product_brand' );
if ( $existing ) {
return (int) $existing['term_id'];
}
$term = wp_insert_term( $name, 'product_brand', $args );
$this->assertNotWPError( $term, "Failed to create product_brand term: {$name}" );
return (int) $term['term_id'];
}
/**
* Helper: create a simple product assigned to the given brand term IDs.
*
* @param int[] $brand_ids Brand term IDs.
*
* @return int Product ID.
*/
private function createProductWithBrands( array $brand_ids ) {
$product_id = $this->factory->product->createSimple();
wp_set_object_terms( $product_id, $brand_ids, 'product_brand' );
return $product_id;
}
/**
* Test that the productBrands root query returns brands.
*/
public function testProductBrandsQuery() {
$brand_a = $this->createProductBrand( 'brand-a' );
$brand_b = $this->createProductBrand( 'brand-b' );
$query = '
query {
productBrands(first: 100) {
nodes {
databaseId
name
slug
}
}
}
';
$response = $this->graphql( compact( 'query' ) );
$expected = [
$this->expectedField( 'productBrands.nodes.#.databaseId', $brand_a ),
$this->expectedField( 'productBrands.nodes.#.databaseId', $brand_b ),
$this->expectedField( 'productBrands.nodes.#.slug', 'brand-a' ),
$this->expectedField( 'productBrands.nodes.#.slug', 'brand-b' ),
];
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test that a single productBrand can be queried by slug.
*/
public function testSingleProductBrandBySlug() {
$brand_id = $this->createProductBrand( 'nike' );
$query = '
query ($id: ID!) {
productBrand(id: $id, idType: SLUG) {
databaseId
name
slug
}
}
';
$variables = [ 'id' => 'nike' ];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = [
$this->expectedField( 'productBrand.databaseId', $brand_id ),
$this->expectedField( 'productBrand.slug', 'nike' ),
];
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test the connection from productBrand to products.
*/
public function testProductBrandToProductsConnection() {
$brand_a = $this->createProductBrand( 'acme' );
$brand_b = $this->createProductBrand( 'globex' );
$acme_product_ids = [
$this->createProductWithBrands( [ $brand_a ] ),
$this->createProductWithBrands( [ $brand_a ] ),
$this->createProductWithBrands( [ $brand_a ] ),
];
$globex_product_ids = [
$this->createProductWithBrands( [ $brand_b ] ),
$this->createProductWithBrands( [ $brand_b ] ),
];
$query = '
query ($id: ID!) {
productBrand(id: $id, idType: SLUG) {
databaseId
slug
products(first: 100) {
nodes {
databaseId
}
}
}
}
';
// Query acme brand — should contain acme products, not globex.
$variables = [ 'id' => 'acme' ];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productBrand.databaseId', $brand_a ),
$this->expectedField( 'productBrand.slug', 'acme' ),
],
array_map(
function ( $id ) {
return $this->expectedField( 'productBrand.products.nodes.#.databaseId', $id );
},
$acme_product_ids,
),
array_map(
function ( $id ) {
return $this->not()->expectedField( 'productBrand.products.nodes.#.databaseId', $id );
},
$globex_product_ids,
),
);
$this->assertQuerySuccessful( $response, $expected );
// Query globex brand — should contain globex products, not acme.
$variables = [ 'id' => 'globex' ];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productBrand.databaseId', $brand_b ),
$this->expectedField( 'productBrand.slug', 'globex' ),
],
array_map(
function ( $id ) {
return $this->expectedField( 'productBrand.products.nodes.#.databaseId', $id );
},
$globex_product_ids,
),
array_map(
function ( $id ) {
return $this->not()->expectedField( 'productBrand.products.nodes.#.databaseId', $id );
},
$acme_product_ids,
),
);
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test the connection from product to productBrands.
*/
public function testProductToProductBrandsConnection() {
$brand_a = $this->createProductBrand( 'adidas' );
$brand_b = $this->createProductBrand( 'puma' );
$brand_c = $this->createProductBrand( 'reebok' );
// Product with two brands.
$product_id = $this->createProductWithBrands( [ $brand_a, $brand_b ] );
$query = '
query ($id: ID!) {
product(id: $id, idType: DATABASE_ID) {
databaseId
productBrands {
nodes {
databaseId
slug
}
}
}
}
';
$variables = [ 'id' => $product_id ];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = [
$this->expectedField( 'product.databaseId', $product_id ),
$this->expectedField( 'product.productBrands.nodes.#.databaseId', $brand_a ),
$this->expectedField( 'product.productBrands.nodes.#.databaseId', $brand_b ),
$this->not()->expectedField( 'product.productBrands.nodes.#.databaseId', $brand_c ),
];
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test hierarchical (parent/child) brand queries.
*/
public function testHierarchicalProductBrands() {
$parent_brand = $this->createProductBrand( 'sportswear' );
$child_a = $this->createProductBrand( 'running', $parent_brand );
$child_b = $this->createProductBrand( 'basketball', $parent_brand );
// Query top-level brands with children.
$query = '
query {
productBrands(where: { parent: 0 }) {
nodes {
databaseId
slug
children {
nodes {
databaseId
slug
}
}
}
}
}
';
$response = $this->graphql( compact( 'query' ) );
$expected = [
$this->expectedField( 'productBrands.nodes.#.slug', 'sportswear' ),
];
$this->assertQuerySuccessful( $response, $expected );
// Find the sportswear node and verify children.
$sportswear_node = null;
foreach ( $response['data']['productBrands']['nodes'] as $node ) {
if ( 'sportswear' === $node['slug'] ) {
$sportswear_node = $node;
break;
}
}
$this->assertNotNull( $sportswear_node, 'sportswear brand should exist in response.' );
$this->assertCount( 2, $sportswear_node['children']['nodes'], 'sportswear should have 2 children.' );
$child_slugs = array_column( $sportswear_node['children']['nodes'], 'slug' );
$this->assertContains( 'running', $child_slugs );
$this->assertContains( 'basketball', $child_slugs );
}
/**
* Test filtering products by brand using the where clause.
*/
public function testProductsFilteredByBrand() {
$brand_a = $this->createProductBrand( 'apple' );
$brand_b = $this->createProductBrand( 'samsung' );
$apple_ids = [
$this->createProductWithBrands( [ $brand_a ] ),
$this->createProductWithBrands( [ $brand_a ] ),
];
$samsung_ids = [
$this->createProductWithBrands( [ $brand_b ] ),
];
$query = '
query ($brandSlug: String!) {
products(where: { productBrand: $brandSlug }) {
nodes {
databaseId
}
}
}
';
$variables = [ 'brandSlug' => 'apple' ];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
array_map(
function ( $id ) {
return $this->expectedField( 'products.nodes.#.databaseId', $id );
},
$apple_ids,
),
array_map(
function ( $id ) {
return $this->not()->expectedField( 'products.nodes.#.databaseId', $id );
},
$samsung_ids,
),
);
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test filtering products by brand using the taxonomyFilter parameter.
*/
public function testProductsFilteredByBrandViaTaxonomyFilter() {
$brand_a = $this->createProductBrand( 'toyota' );
$brand_b = $this->createProductBrand( 'honda' );
$toyota_ids = [
$this->createProductWithBrands( [ $brand_a ] ),
$this->createProductWithBrands( [ $brand_a ] ),
];
$honda_ids = [
$this->createProductWithBrands( [ $brand_b ] ),
];
$query = '
query ($input: ProductTaxonomyInput) {
products(where: { taxonomyFilter: $input }) {
nodes {
databaseId
}
}
}
';
$variables = [
'input' => [
'filters' => [
[
'taxonomy' => 'PRODUCT_BRAND',
'terms' => [ 'toyota' ],
],
],
],
];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
array_map(
function ( $id ) {
return $this->expectedField( 'products.nodes.#.databaseId', $id );
},
$toyota_ids,
),
array_map(
function ( $id ) {
return $this->not()->expectedField( 'products.nodes.#.databaseId', $id );
},
$honda_ids,
),
);
$this->assertQuerySuccessful( $response, $expected );
}
/**
* Test CRUD operations on product brands using WPGraphQL core term mutations.
*/
public function testProductBrandCrudMutations() {
$this->loginAsShopManager();
// Create.
$create_query = '
mutation ($input: CreateProductBrandInput!) {
createProductBrand(input: $input) {
productBrand {
databaseId
name
slug
}
}
}
';
$response = $this->graphql(
[
'query' => $create_query,
'variables' => [
'input' => [
'name' => 'New Brand',
],
],
]
);
$expected = [
$this->expectedField( 'createProductBrand.productBrand.databaseId', self::NOT_NULL ),
$this->expectedField( 'createProductBrand.productBrand.name', 'New Brand' ),
$this->expectedField( 'createProductBrand.productBrand.slug', 'new-brand' ),
];
$this->assertQuerySuccessful( $response, $expected );
$brand_id = $response['data']['createProductBrand']['productBrand']['databaseId'];
// Update.
$update_query = '
mutation ($input: UpdateProductBrandInput!) {
updateProductBrand(input: $input) {
productBrand {
databaseId
name
}
}
}
';
$response = $this->graphql(
[
'query' => $update_query,
'variables' => [
'input' => [
'id' => $this->toRelayId( 'term', $brand_id ),
'name' => 'Updated Brand',
],
],
]
);
$expected = [
$this->expectedField( 'updateProductBrand.productBrand.databaseId', $brand_id ),
$this->expectedField( 'updateProductBrand.productBrand.name', 'Updated Brand' ),
];
$this->assertQuerySuccessful( $response, $expected );
// Delete.
$delete_query = '
mutation ($input: DeleteProductBrandInput!) {
deleteProductBrand(input: $input) {
productBrand {
databaseId
name
}
}
}
';
$response = $this->graphql(
[
'query' => $delete_query,
'variables' => [
'input' => [
'id' => $this->toRelayId( 'term', $brand_id ),
],
],
]
);
$expected = [
$this->expectedField( 'deleteProductBrand.productBrand.databaseId', $brand_id ),
];
$this->assertQuerySuccessful( $response, $expected );
$this->assertNull( term_exists( $brand_id, 'product_brand' ) );
}
}
@@ -0,0 +1,184 @@
<?php
class ProductCategoryMutationsTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
/**
* Test CRUD operations on product categories.
*
* Covers the fields available in the WooCommerce REST API:
* name, slug, parent, description, display, image, menu_order.
*/
public function testProductCategoryCrudMutations() {
$this->loginAsShopManager();
// Create an image attachment for use in the category.
$image_id = $this->factory->post->create(
[
'post_status' => 'publish',
'post_title' => 'Category Image',
'post_type' => 'attachment',
]
);
// Create a parent category with all supported fields.
$response = $this->graphql(
[
'query' => '
mutation ($input: CreateProductCategoryInput!) {
createProductCategory(input: $input) {
productCategory {
databaseId
name
slug
description
parentDatabaseId
display
menuOrder
image {
databaseId
}
}
}
}
',
'variables' => [
'input' => [
'name' => 'Electronics',
'slug' => 'electronics',
'description' => 'All electronic products',
'display' => 'BOTH',
'menuOrder' => 5,
'imageId' => $image_id,
],
],
]
);
$expected = [
$this->expectedField( 'createProductCategory.productCategory.databaseId', self::NOT_NULL ),
$this->expectedField( 'createProductCategory.productCategory.name', 'Electronics' ),
$this->expectedField( 'createProductCategory.productCategory.slug', 'electronics' ),
$this->expectedField( 'createProductCategory.productCategory.description', 'All electronic products' ),
$this->expectedField( 'createProductCategory.productCategory.parentDatabaseId', self::IS_NULL ),
$this->expectedField( 'createProductCategory.productCategory.display', 'BOTH' ),
$this->expectedField( 'createProductCategory.productCategory.menuOrder', 5 ),
$this->expectedField( 'createProductCategory.productCategory.image.databaseId', $image_id ),
];
$this->assertQuerySuccessful( $response, $expected );
$parent_id = $response['data']['createProductCategory']['productCategory']['databaseId'];
// Create a child category with parent.
$response = $this->graphql(
[
'query' => '
mutation ($input: CreateProductCategoryInput!) {
createProductCategory(input: $input) {
productCategory {
databaseId
name
slug
description
parentDatabaseId
}
}
}
',
'variables' => [
'input' => [
'name' => 'Smartphones',
'slug' => 'smartphones',
'description' => 'Mobile phones and accessories',
'parentId' => $this->toRelayId( 'term', $parent_id ),
],
],
]
);
$expected = [
$this->expectedField( 'createProductCategory.productCategory.databaseId', self::NOT_NULL ),
$this->expectedField( 'createProductCategory.productCategory.name', 'Smartphones' ),
$this->expectedField( 'createProductCategory.productCategory.slug', 'smartphones' ),
$this->expectedField( 'createProductCategory.productCategory.description', 'Mobile phones and accessories' ),
$this->expectedField( 'createProductCategory.productCategory.parentDatabaseId', $parent_id ),
];
$this->assertQuerySuccessful( $response, $expected );
$child_id = $response['data']['createProductCategory']['productCategory']['databaseId'];
// Update the child category with new display and menu_order.
$update_image_id = $this->factory->post->create(
[
'post_status' => 'publish',
'post_title' => 'Updated Category Image',
'post_type' => 'attachment',
]
);
$response = $this->graphql(
[
'query' => '
mutation ($input: UpdateProductCategoryInput!) {
updateProductCategory(input: $input) {
productCategory {
databaseId
name
slug
description
display
menuOrder
image {
databaseId
}
}
}
}
',
'variables' => [
'input' => [
'id' => $this->toRelayId( 'term', $child_id ),
'name' => 'Mobile Phones',
'slug' => 'mobile-phones',
'description' => 'Updated description',
'display' => 'SUBCATEGORIES',
'menuOrder' => 10,
'imageId' => $update_image_id,
],
],
]
);
$expected = [
$this->expectedField( 'updateProductCategory.productCategory.databaseId', $child_id ),
$this->expectedField( 'updateProductCategory.productCategory.name', 'Mobile Phones' ),
$this->expectedField( 'updateProductCategory.productCategory.slug', 'mobile-phones' ),
$this->expectedField( 'updateProductCategory.productCategory.description', 'Updated description' ),
$this->expectedField( 'updateProductCategory.productCategory.display', 'SUBCATEGORIES' ),
$this->expectedField( 'updateProductCategory.productCategory.menuOrder', 10 ),
$this->expectedField( 'updateProductCategory.productCategory.image.databaseId', $update_image_id ),
];
$this->assertQuerySuccessful( $response, $expected );
// Delete the child category.
$response = $this->graphql(
[
'query' => '
mutation ($input: DeleteProductCategoryInput!) {
deleteProductCategory(input: $input) {
productCategory {
databaseId
name
}
}
}
',
'variables' => [
'input' => [
'id' => $this->toRelayId( 'term', $child_id ),
],
],
]
);
$expected = [
$this->expectedField( 'deleteProductCategory.productCategory.databaseId', $child_id ),
];
$this->assertQuerySuccessful( $response, $expected );
$this->assertNull( term_exists( $child_id, 'product_cat' ) );
}
}
@@ -1,6 +1,6 @@
<?php
class ProductTaxonomyQueriesTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
class ProductCategoryQueriesTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
public function testProductCategoriesToProductsQuery() {
// Create categories.
$clothing_category_id = $this->factory->product->createProductCategory( 'clothing' );
@@ -119,114 +119,6 @@ class ProductTaxonomyQueriesTest extends \Tests\WPGraphQL\WooCommerce\TestCase\W
$this->assertQuerySuccessful( $response, $expected );
}
public function testProductTagsToProductsQuery() {
// Create tags.
$tag1_id = $this->factory->product->createProductTag( 'tag1' );
$tag2_id = $this->factory->product->createProductTag( 'tag2' );
$tag3_id = $this->factory->product->createProductTag( 'tag3' );
// Create products.
$tag1_product_ids = $this->factory->product->create_many( 5, [ 'tag_ids' => [ $tag1_id ] ] );
$tag2_product_ids = $this->factory->product->create_many( 5, [ 'tag_ids' => [ $tag2_id, $tag3_id ] ] );
$tag3_product_ids = $this->factory->product->create_many( 5, [ 'tag_ids' => [ $tag3_id ] ] );
$query = 'query ($id: ID!) {
productTag(id: $id idType: SLUG) {
id
slug
products(first: 100) {
nodes {
databaseId
productTags {
nodes {
id
slug
}
}
}
}
}
}';
$variables = [
'id' => 'tag1'
];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productTag.id', $this->toRelayId( 'term', $tag1_id ) ),
$this->expectedField( 'productTag.slug', 'tag1' ),
],
array_map(
function( $id ) {
return $this->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
$tag1_product_ids,
),
array_map(
function( $id ) {
return $this->not()->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
array_merge( $tag2_product_ids, $tag3_product_ids )
),
);
$this->assertQuerySuccessful( $response, $expected );
$variables = [
'id' => 'tag2'
];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productTag.id', $this->toRelayId( 'term', $tag2_id ) ),
$this->expectedField( 'productTag.slug', 'tag2' ),
],
array_map(
function( $id ) {
return $this->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
$tag2_product_ids,
),
array_map(
function( $id ) {
return $this->not()->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
array_merge( $tag1_product_ids, $tag3_product_ids )
),
);
$this->assertQuerySuccessful( $response, $expected );
$variables = [
'id' => 'tag3'
];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productTag.id', $this->toRelayId( 'term', $tag3_id ) ),
$this->expectedField( 'productTag.slug', 'tag3' ),
],
array_map(
function( $id ) {
return $this->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
array_merge( $tag2_product_ids, $tag3_product_ids )
),
array_map(
function( $id ) {
return $this->not()->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
$tag1_product_ids,
),
);
$this->assertQuerySuccessful( $response, $expected );
}
public function testProductCategoryChildrenConnection() {
// Create parent categories.
$parent_a = $this->factory->product->createProductCategory( 'parent-a' );
+107
View File
@@ -0,0 +1,107 @@
<?php
class ProductTagMutationsTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
/**
* Test CRUD operations on product tags.
*
* Covers the fields available in the WooCommerce REST API:
* name, slug, description.
*/
public function testProductTagCrudMutations() {
$this->loginAsShopManager();
// Create.
$response = $this->graphql(
[
'query' => '
mutation ($input: CreateProductTagInput!) {
createProductTag(input: $input) {
productTag {
databaseId
name
slug
description
}
}
}
',
'variables' => [
'input' => [
'name' => 'Sale Items',
'slug' => 'sale-items',
'description' => 'Products currently on sale',
],
],
]
);
$expected = [
$this->expectedField( 'createProductTag.productTag.databaseId', self::NOT_NULL ),
$this->expectedField( 'createProductTag.productTag.name', 'Sale Items' ),
$this->expectedField( 'createProductTag.productTag.slug', 'sale-items' ),
$this->expectedField( 'createProductTag.productTag.description', 'Products currently on sale' ),
];
$this->assertQuerySuccessful( $response, $expected );
$tag_id = $response['data']['createProductTag']['productTag']['databaseId'];
// Update.
$response = $this->graphql(
[
'query' => '
mutation ($input: UpdateProductTagInput!) {
updateProductTag(input: $input) {
productTag {
databaseId
name
slug
description
}
}
}
',
'variables' => [
'input' => [
'id' => $this->toRelayId( 'term', $tag_id ),
'name' => 'Clearance',
'slug' => 'clearance',
'description' => 'Clearance items',
],
],
]
);
$expected = [
$this->expectedField( 'updateProductTag.productTag.databaseId', $tag_id ),
$this->expectedField( 'updateProductTag.productTag.name', 'Clearance' ),
$this->expectedField( 'updateProductTag.productTag.slug', 'clearance' ),
$this->expectedField( 'updateProductTag.productTag.description', 'Clearance items' ),
];
$this->assertQuerySuccessful( $response, $expected );
// Delete.
$response = $this->graphql(
[
'query' => '
mutation ($input: DeleteProductTagInput!) {
deleteProductTag(input: $input) {
productTag {
databaseId
name
}
}
}
',
'variables' => [
'input' => [
'id' => $this->toRelayId( 'term', $tag_id ),
],
],
]
);
$expected = [
$this->expectedField( 'deleteProductTag.productTag.databaseId', $tag_id ),
];
$this->assertQuerySuccessful( $response, $expected );
$this->assertNull( term_exists( $tag_id, 'product_tag' ) );
}
}
+111
View File
@@ -0,0 +1,111 @@
<?php
class ProductTagQueriesTest extends \Tests\WPGraphQL\WooCommerce\TestCase\WooGraphQLTestCase {
public function testProductTagsToProductsQuery() {
// Create tags.
$tag1_id = $this->factory->product->createProductTag( 'tag1' );
$tag2_id = $this->factory->product->createProductTag( 'tag2' );
$tag3_id = $this->factory->product->createProductTag( 'tag3' );
// Create products.
$tag1_product_ids = $this->factory->product->create_many( 5, [ 'tag_ids' => [ $tag1_id ] ] );
$tag2_product_ids = $this->factory->product->create_many( 5, [ 'tag_ids' => [ $tag2_id, $tag3_id ] ] );
$tag3_product_ids = $this->factory->product->create_many( 5, [ 'tag_ids' => [ $tag3_id ] ] );
$query = 'query ($id: ID!) {
productTag(id: $id idType: SLUG) {
id
slug
products(first: 100) {
nodes {
databaseId
productTags {
nodes {
id
slug
}
}
}
}
}
}';
$variables = [
'id' => 'tag1'
];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productTag.id', $this->toRelayId( 'term', $tag1_id ) ),
$this->expectedField( 'productTag.slug', 'tag1' ),
],
array_map(
function( $id ) {
return $this->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
$tag1_product_ids,
),
array_map(
function( $id ) {
return $this->not()->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
array_merge( $tag2_product_ids, $tag3_product_ids )
),
);
$this->assertQuerySuccessful( $response, $expected );
$variables = [
'id' => 'tag2'
];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productTag.id', $this->toRelayId( 'term', $tag2_id ) ),
$this->expectedField( 'productTag.slug', 'tag2' ),
],
array_map(
function( $id ) {
return $this->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
$tag2_product_ids,
),
array_map(
function( $id ) {
return $this->not()->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
array_merge( $tag1_product_ids, $tag3_product_ids )
),
);
$this->assertQuerySuccessful( $response, $expected );
$variables = [
'id' => 'tag3'
];
$response = $this->graphql( compact( 'query', 'variables' ) );
$expected = array_merge(
[
$this->expectedField( 'productTag.id', $this->toRelayId( 'term', $tag3_id ) ),
$this->expectedField( 'productTag.slug', 'tag3' ),
],
array_map(
function( $id ) {
return $this->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
array_merge( $tag2_product_ids, $tag3_product_ids )
),
array_map(
function( $id ) {
return $this->not()->expectedField( 'productTag.products.nodes.#.databaseId', $id );
},
$tag1_product_ids,
),
);
$this->assertQuerySuccessful( $response, $expected );
}
}