diff --git a/src/Jobs/MigrateGTIN.php b/src/Jobs/MigrateGTIN.php index 5b76df0ff6..081632a023 100644 --- a/src/Jobs/MigrateGTIN.php +++ b/src/Jobs/MigrateGTIN.php @@ -93,6 +93,11 @@ protected function process_items( array $items ) { continue; } + if ( $product->get_global_unique_id() ) { + $this->debug( $this->error_gtin_already_set( $product ) ); + continue; + } + $gtin = $this->get_gtin( $product ); if ( ! $gtin ) { diff --git a/tests/Unit/Admin/Product/Attributes/Input/AttributeInputCollectionTest.php b/tests/Unit/Admin/Product/Attributes/Input/AttributeInputCollectionTest.php index 2cf127adf7..224f115ee6 100644 --- a/tests/Unit/Admin/Product/Attributes/Input/AttributeInputCollectionTest.php +++ b/tests/Unit/Admin/Product/Attributes/Input/AttributeInputCollectionTest.php @@ -19,6 +19,8 @@ use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\SizeInput; use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\SizeSystemInput; use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\SizeTypeInput; +use Automattic\WooCommerce\GoogleListingsAndAds\Jobs\MigrateGTIN; +use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsInterface; use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\Adult; use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\AgeGroup; use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\AvailabilityDate; @@ -36,6 +38,7 @@ use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\SizeSystem; use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\SizeType; use Automattic\WooCommerce\GoogleListingsAndAds\Tests\Framework\UnitTest; +use PHPUnit\Framework\MockObject\MockObject; /** * Class AttributeInputCollectionTest @@ -45,6 +48,17 @@ * @package Automattic\WooCommerce\GoogleListingsAndAds\Tests\Unit\Admin\Product\Attributes */ class AttributeInputCollectionTest extends UnitTest { + + /** @var MockObject|OptionsInterface $options */ + protected $options; + /** + * Runs before each test is executed. + */ + public function setUp(): void { + parent::setUp(); + $this->options = $this->createMock( OptionsInterface::class ); + } + public function test_adult_input() { $input = new AdultInput(); $input @@ -353,6 +367,36 @@ public function test_gtin_input() { ); } + public function test_gtin_input_not_hidden() { + $input = new GTINInput(); + $input->set_options_object( $this->options ); + $this->options + ->expects( $this->any() ) + ->method( 'get' ) + ->with( OptionsInterface::INSTALL_VERSION ) + ->willReturn( '2.8.6' ); + $input + ->set_id( GTIN::get_id() ) + ->set_name( GTIN::get_id() ); + $input->set_field_visibility(); + $this->assertFalse( $input->is_hidden() ); + } + + public function test_gtin_input_hidden() { + $input = new GTINInput(); + $input->set_options_object( $this->options ); + $this->options + ->expects( $this->any() ) + ->method( 'get' ) + ->with( OptionsInterface::INSTALL_VERSION ) + ->willReturn( '2.8.8' ); + $input + ->set_id( GTIN::get_id() ) + ->set_name( GTIN::get_id() ); + $input->set_field_visibility(); + $this->assertTrue( $input->is_hidden() ); + } + public function test_is_bundle_input() { $input = new IsBundleInput(); $input diff --git a/tests/Unit/Jobs/MigrateGTINTest.php b/tests/Unit/Jobs/MigrateGTINTest.php new file mode 100644 index 0000000000..d1104a05ba --- /dev/null +++ b/tests/Unit/Jobs/MigrateGTINTest.php @@ -0,0 +1,261 @@ +action_scheduler = $this->createMock( ActionScheduler::class ); + $this->options = $this->createMock( OptionsInterface::class ); + $this->monitor = $this->createMock( ActionSchedulerJobMonitor::class ); + $this->product_repository = $this->createMock( ProductRepository::class ); + $this->attribute_manager = $this->createMock( AttributeManager::class ); + $this->job = new MigrateGTIN( + $this->action_scheduler, + $this->monitor, + $this->product_repository, + $this->attribute_manager + ); + + // reduce batch size for testing + add_filter( + 'woocommerce_gla_batched_job_size', + function ( $batch_count, $job_name ) { + if ( self::JOB_NAME === $job_name ) { + return 3; + } + return $batch_count; + }, + 10, + 2 + ); + + $this->job->set_options_object( $this->options ); + $this->job->init(); + } + + public function test_job_name() { + $this->assertEquals( self::JOB_NAME, $this->job->get_name() ); + } + + public function test_schedule_updates_status_to_started() { + $this->options->expects( $this->exactly( 1 ) ) + ->method( 'update' ) + ->with( OptionsInterface::GTIN_MIGRATION_STATUS, MigrateGTIN::GTIN_MIGRATION_STARTED ); + $this->job->schedule(); + } + + public function test_completed_job_updates_status_to_completed() { + $this->options->expects( $this->exactly( 1 ) ) + ->method( 'update' ) + ->with( OptionsInterface::GTIN_MIGRATION_STATUS, MigrateGTIN::GTIN_MIGRATION_COMPLETED ); + $this->job->handle_complete( 2 ); + } + + public function test_single_empty_batch() { + $this->product_repository->expects( $this->once() ) + ->method( 'find_all_product_ids' ) + ->willReturn( [] ); + + $this->action_scheduler->expects( $this->once() ) + ->method( 'has_scheduled_action' )->willReturn( false ); + + $this->action_scheduler->expects( $this->once() ) + ->method( 'schedule_immediate' ) + ->with( self::CREATE_BATCH_HOOK, [ 1 ] ); + + $this->job->schedule(); + + do_action( self::CREATE_BATCH_HOOK, 1 ); + } + + public function test_single_batch() { + $batch = [ 1, 2, 3 ]; + + $this->product_repository->expects( $this->once() ) + ->method( 'find_all_product_ids' ) + ->willReturn( $batch ); + + $this->action_scheduler->expects( $this->exactly( 3 ) ) + ->method( 'has_scheduled_action' )->willReturn( false ); + + $this->action_scheduler->expects( $this->exactly( 3 ) ) + ->method( 'schedule_immediate' ) + ->withConsecutive( + [ self::CREATE_BATCH_HOOK, [ 1 ] ], + [ self::PROCESS_ITEM_HOOK, [ $batch ] ] + ); + + $this->job->schedule(); + + do_action( self::CREATE_BATCH_HOOK, 1 ); + } + + public function test_multiple_batches() { + $batch_one = [ 1, 2, 3 ]; + $batch_two = [ 4, 5, 6 ]; + $batch_three = []; + + $this->action_scheduler->expects( $this->exactly( 5 ) ) + ->method( 'schedule_immediate' ) + ->withConsecutive( + [ self::CREATE_BATCH_HOOK, [ 1 ] ], + [ self::PROCESS_ITEM_HOOK, [ $batch_one ] ], + [ self::CREATE_BATCH_HOOK, [ 2 ] ], + [ self::PROCESS_ITEM_HOOK, [ $batch_two ] ], + [ self::CREATE_BATCH_HOOK, [ 3 ] ], + ); + + $this->product_repository->expects( $this->exactly( 3 ) ) + ->method( 'find_all_product_ids' ) + ->withConsecutive( [ 3, 0 ], [ 3, 3 ], [ 3, 6 ] ) + ->willReturnOnConsecutiveCalls( $batch_one, $batch_two, $batch_three ); + + $this->action_scheduler + ->method( 'has_scheduled_action' ) + ->willReturn( false ); + + $this->job->schedule(); + + do_action( self::CREATE_BATCH_HOOK, 1 ); + do_action( self::CREATE_BATCH_HOOK, 2 ); + do_action( self::CREATE_BATCH_HOOK, 3 ); + } + + public function test_process_item_is_called_by_hook() { + $this->product_repository + ->expects( $this->once() ) + ->method( 'find_by_ids' ) + ->with( [ 1 ] ); + + do_action( self::PROCESS_ITEM_HOOK, [ 1 ] ); + } + + public function test_process_items_sucessfully_updates_gtin() { + $product = WC_Helper_Product::create_simple_product(); + $this->product_repository + ->expects( $this->once() ) + ->method( 'find_by_ids' ) + ->with( [ 1 ] ) + ->willReturn( [ $product ] ); + + $this->attribute_manager + ->expects( $this->once() ) + ->method( 'get_value' ) + ->with( $product, 'gtin' ) + ->willReturn( '1234-5678' ); + + $this->assertEquals( $product->get_global_unique_id(), null ); + $this->job->handle_process_items_action( [ 1 ] ); + $this->assertEquals( $product->get_global_unique_id(), '12345678' ); + } + + public function test_process_items_not_updates_gtin_if_not_found() { + /** @var \WC_Product $product */ + $product = WC_Helper_Product::create_simple_product(); + + $this->product_repository + ->expects( $this->once() ) + ->method( 'find_by_ids' ) + ->with( [ 1 ] ) + ->willReturn( [ $product ] ); + + $this->attribute_manager + ->expects( $this->once() ) + ->method( 'get_value' ) + ->with( $product, 'gtin' ) + ->willReturn( null ); + + $this->assertEquals( $product->get_global_unique_id(), null ); + $this->job->handle_process_items_action( [ 1 ] ); + $this->assertEquals( $product->get_global_unique_id(), null ); + } + + public function test_process_items_not_updates_gtin_if_already_set() { + /** @var \WC_Product $product */ + $product = WC_Helper_Product::create_simple_product(); + $product->set_global_unique_id( '11112222' ); + $product->save(); + + $this->product_repository + ->expects( $this->once() ) + ->method( 'find_by_ids' ) + ->with( [ 1 ] ) + ->willReturn( [ $product ] ); + + $this->attribute_manager + ->expects( $this->never() ) + ->method( 'get_value' ); + + $this->assertEquals( $product->get_global_unique_id(), '11112222' ); + $this->job->handle_process_items_action( [ 1 ] ); + $this->assertEquals( $product->get_global_unique_id(), '11112222' ); + } + + public function test_process_items_not_updates_gtin_if_not_a_number() { + /** @var \WC_Product $product */ + $product = WC_Helper_Product::create_simple_product(); + + $this->product_repository + ->expects( $this->once() ) + ->method( 'find_by_ids' ) + ->with( [ 1 ] ) + ->willReturn( [ $product ] ); + + $this->attribute_manager + ->expects( $this->once() ) + ->method( 'get_value' ) + ->with( $product, 'gtin' ) + ->willReturn( 'not a number' ); + + $this->assertEquals( $product->get_global_unique_id(), null ); + $this->job->handle_process_items_action( [ 1 ] ); + $this->assertEquals( $product->get_global_unique_id(), null ); + } +}