Products   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 817
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 444
dl 0
loc 817
rs 8.96
c 0
b 0
f 0
wmc 43

25 Methods

Rating   Name   Duplication   Size   Complexity  
A test_get_products_by_shipping_class() 0 18 2
A wpSetUpBeforeClass() 0 4 1
A test_delete_product_with_invalid_id() 0 6 1
A test_create_product_without_permission() 0 12 1
A test_get_product() 0 16 1
A test_get_product_without_permission() 0 5 1
A test_get_products_by_tag() 0 22 2
A test_product_schema_embed() 0 24 3
B test_create_product() 0 90 1
A setUp() 0 3 1
A test_delete_product() 0 11 1
A test_get_products_by_category() 0 35 2
A test_get_products_by_attribute() 0 65 3
A test_products_filter_post_status() 0 41 5
A test_get_products_by_type() 0 30 4
A test_get_featured_products() 0 34 3
A test_products_batch() 0 48 1
A test_get_products() 0 14 1
B test_update_product() 0 106 3
A test_product_schema() 0 7 1
A test_get_products_without_permission() 0 5 1
A test_register_routes() 0 5 1
A test_update_product_with_invalid_id() 0 9 1
A test_delete_product_without_permission() 0 7 1
A test_update_product_without_permission() 0 11 1

How to fix   Complexity   

Complex Class

Complex classes like Products often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Products, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Tests for Products API.
4
 *
5
 * @package WooCommerce\Tests\API
6
 * @since 3.5.0
7
 */
8
9
namespace Automattic\WooCommerce\RestApi\UnitTests\Tests\Version4;
10
11
defined( 'ABSPATH' ) || exit;
12
13
use \WP_REST_Request;
14
use \WC_REST_Unit_Test_Case;
0 ignored issues
show
Bug introduced by
The type WC_REST_Unit_Test_Case was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper;
16
17
 /**
18
  * Products class.
19
  */
20
class Products extends WC_REST_Unit_Test_Case {
21
22
	/**
23
	 * User variable.
24
	 *
25
	 * @var WP_User
0 ignored issues
show
Bug introduced by
The type Automattic\WooCommerce\R...\Tests\Version4\WP_User was not found. Did you mean WP_User? If so, make sure to prefix the type with \.
Loading history...
26
	 */
27
	protected static $user;
28
29
	/**
30
	 * Setup once before running tests.
31
	 *
32
	 * @param object $factory Factory object.
33
	 */
34
	public static function wpSetUpBeforeClass( $factory ) {
35
		self::$user = $factory->user->create(
36
			array(
37
				'role' => 'administrator',
38
			)
39
		);
40
	}
41
42
	/**
43
	 * Setup our test server, endpoints, and user info.
44
	 */
45
	public function setUp() {
46
		parent::setUp();
47
		wp_set_current_user( self::$user );
0 ignored issues
show
Bug introduced by
self::user of type Automattic\WooCommerce\R...\Tests\Version4\WP_User is incompatible with the type integer expected by parameter $id of wp_set_current_user(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

47
		wp_set_current_user( /** @scrutinizer ignore-type */ self::$user );
Loading history...
48
	}
49
50
	/**
51
	 * Test route registration.
52
	 *
53
	 * @since 3.5.0
54
	 */
55
	public function test_register_routes() {
56
		$routes = $this->server->get_routes();
57
		$this->assertArrayHasKey( '/wc/v4/products', $routes );
58
		$this->assertArrayHasKey( '/wc/v4/products/(?P<id>[\d]+)', $routes );
59
		$this->assertArrayHasKey( '/wc/v4/products/batch', $routes );
60
	}
61
62
	/**
63
	 * Test getting products.
64
	 *
65
	 * @since 3.5.0
66
	 */
67
	public function test_get_products() {
68
		ProductHelper::create_external_product();
69
		sleep( 1 ); // So both products have different timestamps.
70
		ProductHelper::create_simple_product();
71
		$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products' ) );
72
		$products = $response->get_data();
73
74
		$this->assertEquals( 200, $response->get_status() );
75
76
		$this->assertEquals( 2, count( $products ) );
77
		$this->assertEquals( 'Dummy Product', $products[0]['name'] );
78
		$this->assertEquals( 'DUMMY SKU', $products[0]['sku'] );
79
		$this->assertEquals( 'Dummy External Product', $products[1]['name'] );
80
		$this->assertEquals( 'DUMMY EXTERNAL SKU', $products[1]['sku'] );
81
	}
82
83
	/**
84
	 * Test getting products without permission.
85
	 *
86
	 * @since 3.5.0
87
	 */
88
	public function test_get_products_without_permission() {
89
		wp_set_current_user( 0 );
90
		ProductHelper::create_simple_product();
91
		$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products' ) );
92
		$this->assertEquals( 401, $response->get_status() );
93
	}
94
95
	/**
96
	 * Test getting a single product.
97
	 *
98
	 * @since 3.5.0
99
	 */
100
	public function test_get_product() {
101
		$simple   = ProductHelper::create_external_product();
102
		$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products/' . $simple->get_id() ) );
103
		$product  = $response->get_data();
104
105
		$this->assertEquals( 200, $response->get_status() );
106
		$this->assertContains(
107
			array(
108
				'id'            => $simple->get_id(),
109
				'name'          => 'Dummy External Product',
110
				'type'          => 'simple',
111
				'status'        => 'publish',
112
				'sku'           => 'DUMMY EXTERNAL SKU',
113
				'regular_price' => 10,
114
			),
115
			$product
116
		);
117
	}
118
119
	/**
120
	 * Test getting single product without permission.
121
	 *
122
	 * @since 3.5.0
123
	 */
124
	public function test_get_product_without_permission() {
125
		wp_set_current_user( 0 );
126
		$product  = ProductHelper::create_simple_product();
127
		$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products/' . $product->get_id() ) );
128
		$this->assertEquals( 401, $response->get_status() );
129
	}
130
131
	/**
132
	 * Test deleting a single product.
133
	 *
134
	 * @since 3.5.0
135
	 */
136
	public function test_delete_product() {
137
		$product = ProductHelper::create_simple_product();
138
139
		$request = new WP_REST_Request( 'DELETE', '/wc/v4/products/' . $product->get_id() );
140
		$request->set_param( 'force', true );
141
		$response = $this->server->dispatch( $request );
142
		$this->assertEquals( 200, $response->get_status() );
143
144
		$response   = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products' ) );
145
		$variations = $response->get_data();
146
		$this->assertEquals( 0, count( $variations ) );
147
	}
148
149
	/**
150
	 * Test deleting a single product without permission.
151
	 *
152
	 * @since 3.5.0
153
	 */
154
	public function test_delete_product_without_permission() {
155
		wp_set_current_user( 0 );
156
		$product = ProductHelper::create_simple_product();
157
		$request = new WP_REST_Request( 'DELETE', '/wc/v4/products/' . $product->get_id() );
158
		$request->set_param( 'force', true );
159
		$response = $this->server->dispatch( $request );
160
		$this->assertEquals( 401, $response->get_status() );
161
	}
162
163
	/**
164
	 * Test deleting a single product with an invalid ID.
165
	 *
166
	 * @since 3.5.0
167
	 */
168
	public function test_delete_product_with_invalid_id() {
169
		wp_set_current_user( 0 );
170
		$request = new WP_REST_Request( 'DELETE', '/wc/v4/products/0' );
171
		$request->set_param( 'force', true );
172
		$response = $this->server->dispatch( $request );
173
		$this->assertEquals( 404, $response->get_status() );
174
	}
175
176
	/**
177
	 * Test editing a single product. Tests multiple product types.
178
	 *
179
	 * @since 3.5.0
180
	 */
181
	public function test_update_product() {
182
		// test simple products.
183
		$product      = ProductHelper::create_simple_product();
184
		$response     = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products/' . $product->get_id() ) );
185
		$data         = $response->get_data();
186
		$date_created = date( 'Y-m-d\TH:i:s', current_time( 'timestamp' ) );
187
188
		$this->assertEquals( 'DUMMY SKU', $data['sku'] );
189
		$this->assertEquals( 10, $data['regular_price'] );
190
		$this->assertEmpty( $data['sale_price'] );
191
192
		$request = new WP_REST_Request( 'PUT', '/wc/v4/products/' . $product->get_id() );
193
		$request->set_body_params(
194
			array(
195
				'sku'          => 'FIXED-SKU',
196
				'sale_price'   => '8',
197
				'description'  => 'Testing',
198
				'date_created' => $date_created,
199
				'images'       => array(
200
					array(
201
						'position' => 0,
202
						'src'      => 'http://cldup.com/Dr1Bczxq4q.png',
203
						'alt'      => 'test upload image',
204
					),
205
				),
206
			)
207
		);
208
		$response = $this->server->dispatch( $request );
209
		$data     = $response->get_data();
210
211
		$this->assertContains( 'Testing', $data['description'] );
212
		$this->assertEquals( '8', $data['price'] );
213
		$this->assertEquals( '8', $data['sale_price'] );
214
		$this->assertEquals( '10', $data['regular_price'] );
215
		$this->assertEquals( 'FIXED-SKU', $data['sku'] );
216
		$this->assertEquals( $date_created, $data['date_created'] );
217
		$this->assertContains( 'Dr1Bczxq4q', $data['images'][0]['src'] );
218
		$this->assertContains( 'test upload image', $data['images'][0]['alt'] );
219
		$product->delete( true );
220
221
		// test variable product (variations are tested in product-variations.php).
222
		$product  = ProductHelper::create_variation_product();
223
		$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products/' . $product->get_id() ) );
224
		$data     = $response->get_data();
225
226
		foreach ( array( 'small', 'large' ) as $term_name ) {
227
			$this->assertContains( $term_name, $data['attributes'][0]['options'] );
228
		}
229
230
		$request = new WP_REST_Request( 'PUT', '/wc/v4/products/' . $product->get_id() );
231
		$request->set_body_params(
232
			array(
233
				'attributes' => array(
234
					array(
235
						'id'        => 0,
236
						'name'      => 'pa_color',
237
						'options'   => array(
238
							'red',
239
							'yellow',
240
						),
241
						'visible'   => false,
242
						'variation' => 1,
243
					),
244
					array(
245
						'id'        => 0,
246
						'name'      => 'pa_size',
247
						'options'   => array(
248
							'small',
249
						),
250
						'visible'   => false,
251
						'variation' => 1,
252
					),
253
				),
254
			)
255
		);
256
		$response = $this->server->dispatch( $request );
257
		$data     = $response->get_data();
258
259
		$this->assertEquals( array( 'small' ), $data['attributes'][0]['options'] );
260
261
		foreach ( array( 'red', 'yellow' ) as $term_name ) {
262
			$this->assertContains( $term_name, $data['attributes'][1]['options'] );
263
		}
264
265
		$product->delete( true );
266
267
		// test external product.
268
		$product  = ProductHelper::create_external_product();
269
		$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products/' . $product->get_id() ) );
270
		$data     = $response->get_data();
271
272
		$this->assertEquals( 'Buy external product', $data['button_text'] );
273
		$this->assertEquals( 'http://woocommerce.com', $data['external_url'] );
274
275
		$request = new WP_REST_Request( 'PUT', '/wc/v4/products/' . $product->get_id() );
276
		$request->set_body_params(
277
			array(
278
				'button_text'  => 'Test API Update',
279
				'external_url' => 'http://automattic.com',
280
			)
281
		);
282
		$response = $this->server->dispatch( $request );
283
		$data     = $response->get_data();
284
285
		$this->assertEquals( 'Test API Update', $data['button_text'] );
286
		$this->assertEquals( 'http://automattic.com', $data['external_url'] );
287
	}
288
289
	/**
290
	 * Test updating a single product without permission.
291
	 *
292
	 * @since 3.5.0
293
	 */
294
	public function test_update_product_without_permission() {
295
		wp_set_current_user( 0 );
296
		$product = ProductHelper::create_simple_product();
297
		$request = new WP_REST_Request( 'PUT', '/wc/v4/products/' . $product->get_id() );
298
		$request->set_body_params(
299
			array(
300
				'sku' => 'FIXED-SKU-NO-PERMISSION',
301
			)
302
		);
303
		$response = $this->server->dispatch( $request );
304
		$this->assertEquals( 401, $response->get_status() );
305
	}
306
307
	/**
308
	 * Test updating a single product with an invalid ID.
309
	 *
310
	 * @since 3.5.0
311
	 */
312
	public function test_update_product_with_invalid_id() {
313
		$request = new WP_REST_Request( 'PUT', '/wc/v4/products/0' );
314
		$request->set_body_params(
315
			array(
316
				'sku' => 'FIXED-SKU-INVALID-ID',
317
			)
318
		);
319
		$response = $this->server->dispatch( $request );
320
		$this->assertEquals( 404, $response->get_status() );
321
	}
322
323
	/**
324
	 * Test creating a single product.
325
	 *
326
	 * @since 3.5.0
327
	 */
328
	public function test_create_product() {
329
330
		$request = new WP_REST_Request( 'POST', '/wc/v4/products/shipping_classes' );
331
		$request->set_body_params(
332
			array(
333
				'name' => 'Test',
334
			)
335
		);
336
		$response          = $this->server->dispatch( $request );
337
		$data              = $response->get_data();
338
		$shipping_class_id = $data['id'];
339
340
		// Create simple.
341
		$request = new WP_REST_Request( 'POST', '/wc/v4/products' );
342
		$request->set_body_params(
343
			array(
344
				'type'           => 'simple',
345
				'name'           => 'Test Simple Product',
346
				'sku'            => 'DUMMY SKU SIMPLE API',
347
				'regular_price'  => '10',
348
				'shipping_class' => 'test',
349
			)
350
		);
351
		$response = $this->server->dispatch( $request );
352
		$data     = $response->get_data();
353
354
		$this->assertEquals( '10', $data['price'] );
355
		$this->assertEquals( '10', $data['regular_price'] );
356
		$this->assertTrue( $data['purchasable'] );
357
		$this->assertEquals( 'DUMMY SKU SIMPLE API', $data['sku'] );
358
		$this->assertEquals( 'Test Simple Product', $data['name'] );
359
		$this->assertEquals( 'simple', $data['type'] );
360
		$this->assertEquals( $shipping_class_id, $data['shipping_class_id'] );
361
362
		// Create external.
363
		$request = new WP_REST_Request( 'POST', '/wc/v4/products' );
364
		$request->set_body_params(
365
			array(
366
				'type'          => 'external',
367
				'name'          => 'Test External Product',
368
				'sku'           => 'DUMMY SKU EXTERNAL API',
369
				'regular_price' => '10',
370
				'button_text'   => 'Test Button',
371
				'external_url'  => 'https://wordpress.org',
372
			)
373
		);
374
		$response = $this->server->dispatch( $request );
375
		$data     = $response->get_data();
376
377
		$this->assertEquals( '10', $data['price'] );
378
		$this->assertEquals( '10', $data['regular_price'] );
379
		$this->assertFalse( $data['purchasable'] );
380
		$this->assertEquals( 'DUMMY SKU EXTERNAL API', $data['sku'] );
381
		$this->assertEquals( 'Test External Product', $data['name'] );
382
		$this->assertEquals( 'external', $data['type'] );
383
		$this->assertEquals( 'Test Button', $data['button_text'] );
384
		$this->assertEquals( 'https://wordpress.org', $data['external_url'] );
385
386
		// Create variable.
387
		$request = new WP_REST_Request( 'POST', '/wc/v4/products' );
388
		$request->set_body_params(
389
			array(
390
				'type'       => 'variable',
391
				'name'       => 'Test Variable Product',
392
				'sku'        => 'DUMMY SKU VARIABLE API',
393
				'attributes' => array(
394
					array(
395
						'id'        => 0,
396
						'name'      => 'pa_size',
397
						'options'   => array(
398
							'small',
399
							'medium',
400
						),
401
						'visible'   => false,
402
						'variation' => 1,
403
					),
404
				),
405
			)
406
		);
407
		$response = $this->server->dispatch( $request );
408
		$data     = $response->get_data();
409
410
		$this->assertEquals( 'DUMMY SKU VARIABLE API', $data['sku'] );
411
		$this->assertEquals( 'Test Variable Product', $data['name'] );
412
		$this->assertEquals( 'variable', $data['type'] );
413
		$this->assertEquals( array( 'small', 'medium' ), $data['attributes'][0]['options'] );
414
415
		$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v4/products' ) );
416
		$products = $response->get_data();
417
		$this->assertEquals( 3, count( $products ) );
418
	}
419
420
	/**
421
	 * Test creating a single product without permission.
422
	 *
423
	 * @since 3.5.0
424
	 */
425
	public function test_create_product_without_permission() {
426
		wp_set_current_user( 0 );
427
428
		$request = new WP_REST_Request( 'POST', '/wc/v4/products' );
429
		$request->set_body_params(
430
			array(
431
				'name'          => 'Test Product',
432
				'regular_price' => '12',
433
			)
434
		);
435
		$response = $this->server->dispatch( $request );
436
		$this->assertEquals( 401, $response->get_status() );
437
	}
438
439
	/**
440
	 * Test batch managing products.
441
	 *
442
	 * @since 3.5.0
443
	 */
444
	public function test_products_batch() {
445
		$product   = ProductHelper::create_simple_product();
446
		$product_2 = ProductHelper::create_simple_product();
447
		$request   = new WP_REST_Request( 'POST', '/wc/v4/products/batch' );
448
		$request->set_body_params(
449
			array(
450
				'update' => array(
451
					array(
452
						'id'          => $product->get_id(),
453
						'description' => 'Updated description.',
454
					),
455
				),
456
				'delete' => array(
457
					$product_2->get_id(),
458
				),
459
				'create' => array(
460
					array(
461
						'sku'           => 'DUMMY SKU BATCH TEST 1',
462
						'regular_price' => '10',
463
						'name'          => 'Test Batch Create 1',
464
						'type'          => 'external',
465
						'button_text'   => 'Test Button',
466
					),
467
					array(
468
						'sku'           => 'DUMMY SKU BATCH TEST 2',
469
						'regular_price' => '20',
470
						'name'          => 'Test Batch Create 2',
471
						'type'          => 'simple',
472
					),
473
				),
474
			)
475
		);
476
		$response = $this->server->dispatch( $request );
477
		$data     = $response->get_data();
478
479
		$this->assertContains( 'Updated description.', $data['update'][0]['description'] );
480
		$this->assertEquals( 'DUMMY SKU BATCH TEST 1', $data['create'][0]['sku'] );
481
		$this->assertEquals( 'DUMMY SKU BATCH TEST 2', $data['create'][1]['sku'] );
482
		$this->assertEquals( 'Test Button', $data['create'][0]['button_text'] );
483
		$this->assertEquals( 'external', $data['create'][0]['type'] );
484
		$this->assertEquals( 'simple', $data['create'][1]['type'] );
485
		$this->assertEquals( $product_2->get_id(), $data['delete'][0]['previous']['id'] );
486
487
		$request  = new WP_REST_Request( 'GET', '/wc/v4/products' );
488
		$response = $this->server->dispatch( $request );
489
		$data     = $response->get_data();
490
491
		$this->assertEquals( 3, count( $data ) );
492
	}
493
494
	/**
495
	 * Tests to make sure you can filter products post statuses by both
496
	 * the status query arg and WP_Query.
497
	 *
498
	 * @since 3.5.0
499
	 */
500
	public function test_products_filter_post_status() {
501
		for ( $i = 0; $i < 8; $i++ ) {
502
			$product = ProductHelper::create_simple_product();
503
			if ( 0 === $i % 2 ) {
504
				wp_update_post(
505
					array(
506
						'ID'          => $product->get_id(),
507
						'post_status' => 'draft',
508
					)
509
				);
510
			}
511
		}
512
513
		// Test filtering with status=publish.
514
		$request = new WP_REST_Request( 'GET', '/wc/v4/products' );
515
		$request->set_param( 'status', 'publish' );
516
		$response = $this->server->dispatch( $request );
517
		$products = $response->get_data();
518
519
		$this->assertEquals( 4, count( $products ) );
520
		foreach ( $products as $product ) {
521
			$this->assertEquals( 'publish', $product['status'] );
522
		}
523
524
		// Test filtering with status=draft.
525
		$request = new WP_REST_Request( 'GET', '/wc/v4/products' );
526
		$request->set_param( 'status', 'draft' );
527
		$response = $this->server->dispatch( $request );
528
		$products = $response->get_data();
529
530
		$this->assertEquals( 4, count( $products ) );
531
		foreach ( $products as $product ) {
532
			$this->assertEquals( 'draft', $product['status'] );
533
		}
534
535
		// Test filtering with no filters - which should return 'any' (all 8).
536
		$request  = new WP_REST_Request( 'GET', '/wc/v4/products' );
537
		$response = $this->server->dispatch( $request );
538
		$products = $response->get_data();
539
540
		$this->assertEquals( 8, count( $products ) );
541
	}
542
543
	/**
544
	 * Test product schema.
545
	 *
546
	 * @since 3.5.0
547
	 */
548
	public function test_product_schema() {
549
		$product    = ProductHelper::create_simple_product();
550
		$request    = new WP_REST_Request( 'OPTIONS', '/wc/v4/products/' . $product->get_id() );
551
		$response   = $this->server->dispatch( $request );
552
		$data       = $response->get_data();
553
		$properties = $data['schema']['properties'];
554
		$this->assertEquals( 65, count( $properties ) );
555
	}
556
557
	/**
558
	 * Test product category.
559
	 *
560
	 * @since 3.5.0
561
	 */
562
	public function test_get_products_by_category() {
563
		// Create one product with a category.
564
		$category = wp_insert_term( 'Some Category', 'product_cat' );
565
566
		$product = new \WC_Product_Simple();
567
		$product->set_category_ids( array( $category['term_id'] ) );
568
		$product->save();
569
570
		// Create one product without category, i.e. Uncategorized.
571
		$product_2 = new \WC_Product_Simple();
572
		$product_2->save();
573
574
		// Test product assigned to a single category.
575
		$query_params = array(
576
			'category' => (string) $category['term_id'],
577
		);
578
		$request      = new WP_REST_Request( 'GET', '/wc/v4/products' );
579
		$request->set_query_params( $query_params );
580
		$response          = $this->server->dispatch( $request );
581
		$response_products = $response->get_data();
582
583
		$this->assertEquals( 200, $response->get_status() );
584
		foreach ( $response_products as $response_product ) {
585
			$this->assertEquals( $product->get_id(), $response_product['id'] );
586
			$this->assertEquals( $product->get_category_ids(), wp_list_pluck( $response_product['categories'], 'id' ) );
587
		}
588
589
		// Test product without categories.
590
		$request          = new WP_REST_Request( 'GET', '/wc/v4/products/' . $product_2->get_id() );
591
		$response         = $this->server->dispatch( $request );
592
		$response_product = $response->get_data();
593
594
		$this->assertEquals( 200, $response->get_status() );
595
		$this->assertCount( 1, $response_product['categories'], print_r( $response_product, true ) );
596
		$this->assertEquals( 'uncategorized', $response_product['categories'][0]['slug'] );
597
598
	}
599
600
	/**
601
	 * Test getting products by product type.
602
	 *
603
	 * @since 3.5.0
604
	 */
605
	public function test_get_products_by_type() {
606
		$simple   = ProductHelper::create_simple_product();
607
		$external = ProductHelper::create_external_product();
608
		$grouped  = ProductHelper::create_grouped_product();
609
		$variable = ProductHelper::create_variation_product();
610
611
		$product_ids_for_type = array(
612
			'simple'   => array( $simple->get_id() ),
613
			'external' => array( $external->get_id() ),
614
			'grouped'  => array( $grouped->get_id() ),
615
			'variable' => array( $variable->get_id() ),
616
		);
617
618
		foreach ( $grouped->get_children() as $additional_product ) {
619
			$product_ids_for_type['simple'][] = $additional_product;
620
		}
621
622
		foreach ( $product_ids_for_type as $product_type => $product_ids ) {
623
			$query_params = array(
624
				'type' => $product_type,
625
			);
626
			$request      = new WP_REST_Request( 'GET', '/wc/v4/products' );
627
			$request->set_query_params( $query_params );
628
			$response          = $this->server->dispatch( $request );
629
			$response_products = $response->get_data();
630
631
			$this->assertEquals( 200, $response->get_status() );
632
			$this->assertEquals( count( $product_ids ), count( $response_products ) );
633
			foreach ( $response_products as $response_product ) {
634
				$this->assertContains( $response_product['id'], $product_ids_for_type[ $product_type ], 'REST API: ' . $product_type . ' not found correctly' );
635
			}
636
		}
637
	}
638
639
	/**
640
	 * Test getting products by featured property.
641
	 *
642
	 * @since 3.5.0
643
	 */
644
	public function test_get_featured_products() {
645
		// Create a featured product.
646
		$feat_product = ProductHelper::create_simple_product();
647
		$feat_product->set_featured( true );
648
		$feat_product->save();
649
650
		// Create a non-featured product.
651
		$nonfeat_product = ProductHelper::create_simple_product();
652
		$nonfeat_product->save();
653
654
		$query_params = array(
655
			'featured' => 'true',
656
		);
657
		$request      = new WP_REST_Request( 'GET', '/wc/v4/products' );
658
		$request->set_query_params( $query_params );
659
		$response          = $this->server->dispatch( $request );
660
		$response_products = $response->get_data();
661
662
		$this->assertEquals( 200, $response->get_status() );
663
		foreach ( $response_products as $response_product ) {
664
			$this->assertEquals( $feat_product->get_id(), $response_product['id'], 'REST API: Featured product not found correctly' );
665
		}
666
667
		$query_params = array(
668
			'featured' => 'false',
669
		);
670
		$request      = new WP_REST_Request( 'GET', '/wc/v4/products' );
671
		$request->set_query_params( $query_params );
672
		$response          = $this->server->dispatch( $request );
673
		$response_products = $response->get_data();
674
675
		$this->assertEquals( 200, $response->get_status() );
676
		foreach ( $response_products as $response_product ) {
677
			$this->assertEquals( $nonfeat_product->get_id(), $response_product['id'], 'REST API: Featured product not found correctly' );
678
		}
679
	}
680
681
	/**
682
	 * Test getting products by shipping class property.
683
	 *
684
	 * @since 3.5.0
685
	 */
686
	public function test_get_products_by_shipping_class() {
687
		$shipping_class_1 = wp_insert_term( 'Bulky', 'product_shipping_class' );
688
689
		$product_1 = new \WC_Product_Simple();
690
		$product_1->set_shipping_class_id( $shipping_class_1['term_id'] );
691
		$product_1->save();
692
693
		$query_params = array(
694
			'shipping_class' => (string) $shipping_class_1['term_id'],
695
		);
696
		$request      = new WP_REST_Request( 'GET', '/wc/v4/products' );
697
		$request->set_query_params( $query_params );
698
		$response          = $this->server->dispatch( $request );
699
		$response_products = $response->get_data();
700
701
		$this->assertEquals( 200, $response->get_status() );
702
		foreach ( $response_products as $response_product ) {
703
			$this->assertEquals( $product_1->get_id(), $response_product['id'] );
704
		}
705
	}
706
707
	/**
708
	 * Test getting products by tag.
709
	 *
710
	 * @since 3.5.0
711
	 */
712
	public function test_get_products_by_tag() {
713
		$test_tag_1 = wp_insert_term( 'Tag 1', 'product_tag' );
714
715
		// Product with a tag.
716
		$product = ProductHelper::create_simple_product();
717
		$product->set_tag_ids( array( $test_tag_1['term_id'] ) );
718
		$product->save();
719
720
		// Product without a tag.
721
		$product_2 = ProductHelper::create_simple_product();
722
723
		$query_params = array(
724
			'tag' => (string) $test_tag_1['term_id'],
725
		);
726
		$request      = new WP_REST_Request( 'GET', '/wc/v4/products' );
727
		$request->set_query_params( $query_params );
728
		$response          = $this->server->dispatch( $request );
729
		$response_products = $response->get_data();
730
731
		$this->assertEquals( 200, $response->get_status() );
732
		foreach ( $response_products as $response_product ) {
733
			$this->assertEquals( $product->get_id(), $response_product['id'] );
734
		}
735
	}
736
737
	/**
738
	 * Test getting products by global attribute.
739
	 *
740
	 * @since 3.5.0
741
	 */
742
	public function test_get_products_by_attribute() {
743
		global $wpdb;
744
745
		// Variable product with 2 different variations.
746
		$variable_product = ProductHelper::create_variation_product();
747
748
		// Terms created by variable product.
749
		$term_large = get_term_by( 'slug', 'large', 'pa_size' );
750
		$term_small = get_term_by( 'slug', 'small', 'pa_size' );
751
752
		// Simple product without attribute.
753
		$product_1 = ProductHelper::create_simple_product();
754
755
		// Simple product with attribute size = large.
756
		$product_2 = ProductHelper::create_simple_product();
757
		$product_2->set_attributes( array( 'pa_size' => 'large' ) );
758
		$product_2->save();
759
760
		// Link the product to the term.
761
		$wpdb->insert(
762
			$wpdb->prefix . 'term_relationships',
763
			array(
764
				'object_id'        => $product_2->get_id(),
765
				'term_taxonomy_id' => $term_large->term_id,
766
				'term_order'       => 0,
767
			)
768
		);
769
770
		// Products with attribute size == large.
771
		$expected_product_ids = array(
772
			$variable_product->get_id(),
773
			$product_2->get_id(),
774
		);
775
		$query_params         = array(
776
			'attribute'      => 'pa_size',
777
			'attribute_term' => (string) $term_large->term_id,
778
		);
779
		$request              = new WP_REST_Request( 'GET', '/wc/v4/products' );
780
		$request->set_query_params( $query_params );
781
		$response          = $this->server->dispatch( $request );
782
		$response_products = $response->get_data();
783
784
		$this->assertEquals( 200, $response->get_status() );
785
		$this->assertEquals( count( $expected_product_ids ), count( $response_products ) );
786
		foreach ( $response_products as $response_product ) {
787
			$this->assertContains( $response_product['id'], $expected_product_ids );
788
		}
789
790
		// Products with attribute size == small.
791
		$expected_product_ids = array(
792
			$variable_product->get_id(),
793
		);
794
		$query_params         = array(
795
			'attribute'      => 'pa_size',
796
			'attribute_term' => (string) $term_small->term_id,
797
		);
798
		$request              = new WP_REST_Request( 'GET', '/wc/v4/products' );
799
		$request->set_query_params( $query_params );
800
		$response          = $this->server->dispatch( $request );
801
		$response_products = $response->get_data();
802
803
		$this->assertEquals( 200, $response->get_status() );
804
		$this->assertEquals( count( $expected_product_ids ), count( $response_products ) );
805
		foreach ( $response_products as $response_product ) {
806
			$this->assertContains( $response_product['id'], $expected_product_ids );
807
		}
808
	}
809
810
	/**
811
	 * Test product schema contains embed fields.
812
	 */
813
	public function test_product_schema_embed() {
814
		$product    = ProductHelper::create_simple_product();
815
		$request    = new WP_REST_Request( 'OPTIONS', '/wc/v4/products/' . $product->get_id() );
816
		$response   = $this->server->dispatch( $request );
817
		$data       = $response->get_data();
818
		$properties = $data['schema']['properties'];
819
820
		$properties_to_embed = array(
821
			'id',
822
			'name',
823
			'slug',
824
			'permalink',
825
			'images',
826
			'description',
827
			'short_description',
828
		);
829
830
		foreach ( $properties as $property_key => $property ) {
831
			if ( in_array( $property_key, $properties_to_embed, true ) ) {
832
				$this->assertEquals( array( 'view', 'edit', 'embed' ), $property['context'] );
833
			}
834
		}
835
836
		$product->delete( true );
837
	}
838
}
839