File: D:/HostingSpaces/SBogers10/shop.komma.nl/tests/Unit/PropertyTest.php
<?php
namespace Tests\Unit;
use App\Attributes\FreeProperties;
use App\Products\Product\ProductTranslation;
use App\Properties\Kms\PropertyService;
use Doctrine\Common\Annotations\Annotation\Attribute;
use Illuminate\Support\Str;
use Komma\KMS\Globalization\Languages\Models\Language;
use App\Products\Product\Product;
use App\Properties\Models\PropertyKey;
use App\Properties\Models\PropertyKeyTranslation;
use App\Properties\Models\Property;
use App\Properties\Models\PropertyValue;
use App\Properties\Models\PropertyValueTranslation;
use PropertyFaker;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class PropertyTest extends TestCase
{
use DatabaseTransactions; //Automatically rolls back database actions after tests
/**
* @group Properties
* @test
*/
public function testPropertyValue()
{
$value = new PropertyValue();
$value->save();
$this->assertDatabaseHas($value->getTable(), ['id' => $value->id]);
}
/**
* @group Properties
* @test
*/
public function testPropertyKey()
{
$key = new PropertyKey();
$key->save();
$this->assertDatabaseHas($key->getTable(), ['id' => $key->id]);
}
/**
* @group Properties
* @test
*/
public function testPropertyValueTranslation()
{
$value = new PropertyValue();
$value->save();
$propertyData = PropertyFaker::property();
$language = Language::find(104);
$translation = new PropertyValueTranslation();
$translation->name = $propertyData[PropertyFaker::VALUE];
$translation->language()->associate($language);
$translation->translatable()->associate($value);
$translation->save();
$this->assertDatabaseHas($translation->getTable(), ['id' => $translation->id]);
}
/**
* @group Properties
* @test
*/
public function testPropertyKeyTranslation()
{
$key = new PropertyKey();
$key->save();
$propertyData = PropertyFaker::property();
$language = Language::find(104);
$translation = new PropertyKeyTranslation();
$translation->name = $propertyData[PropertyFaker::KEY];
$translation->language()->associate($language);
$translation->translatable()->associate($key);
$translation->save();
$this->assertDatabaseHas($translation->getTable(), ['id' => $translation->id]);
}
/**
* @group Properties
* @test
*/
public function testProperty()
{
$propertyData = PropertyFaker::property();
$language = Language::find(104);
$value = new PropertyValue();
$value->save();
$key = new PropertyKey();
$key->save();
$valueTranslation = new PropertyValueTranslation();
$valueTranslation->name = $propertyData[PropertyFaker::VALUE];
$valueTranslation->language()->associate($language);
$valueTranslation->translatable()->associate($value);
$valueTranslation->save();
$keyTranslation = new PropertyKeyTranslation();
$keyTranslation->name = $propertyData[PropertyFaker::KEY];
$keyTranslation->language()->associate($language);
$keyTranslation->translatable()->associate($key);
$keyTranslation->save();
$property = new Property();
$property->code_name = Str::random();
$property->key()->associate($key);
$property->value()->associate($value);
$property->save();
$this->assertDatabaseHas($property->getTable(), ['id' => $property->id]);
}
/**
* @group Properties
* @test
*/
public function testPropertyLinkageToPropertizable()
{
$propertyData = PropertyFaker::property();
$language = Language::find(104);
$value = new PropertyValue();
$value->save();
$key = new PropertyKey();
$key->save();
$valueTranslation = new PropertyValueTranslation();
$valueTranslation->name = $propertyData[PropertyFaker::VALUE];
$valueTranslation->language()->associate($language);
$valueTranslation->translatable()->associate($value);
$valueTranslation->save();
$keyTranslation = new PropertyKeyTranslation();
$keyTranslation->name = $propertyData[PropertyFaker::KEY];
$keyTranslation->language()->associate($language);
$keyTranslation->translatable()->associate($key);
$keyTranslation->save();
$property = new Property();
$property->code_name = Str::random();
$property->key()->associate($key);
$property->value()->associate($value);
$property->save();
$this->assertDatabaseHas($property->getTable(), ['id' => $property->id]);
/** @var ProductTranslation $productTranslation */
$productTranslation = factory(ProductTranslation::class)->create();
$productTranslation->properties()->save($property);
$this->assertDatabaseHas('propertizables', [
'property_id' => $property->id,
'propertizable_id' => $productTranslation->id,
'propertizable_type' => get_class($productTranslation),
]);
}
/**
* @group Properties
* @test
*/
public function testCreationOfNewProperty() {
//Get the language that we are going to associate the Properties attribute. So that it appears like it is from a language tab
$language = Language::where('iso_2', '=', 'nl')->first();
$this->assertNotNull($language);
//Create a ProductTranslation (propertizable). We are going to attach the properties to it.
/** @var ProductTranslation $productTranslation */
$productTranslation = factory(ProductTranslation::class)->create(['language_id' => $language->id]);
//And of course we need a property service for the saving of the process
$propertyService = new PropertyService();
//Fake the creation of property data like it comes from the Properties attribute.
$propertyValue = 'val_test_1';
$propertyKey = 'key_test_1';
$propertyData = [
['id' => -1, 'state' => Property::NEW, 'key' => $propertyKey, 'value' => $propertyValue]
];
//Create the properties attribute, and give it the json representation of the property data we've created earlier. In real life the frontend will give us the data as json too.
$attribute = (new FreeProperties(''))
->mapValueFrom(\Komma\KMS\Core\Attributes\Attribute::ValueFromItself, 'properties')
->setAssociatedLanguage($language)
->setValue(json_encode($propertyData));
//At first, the ProductTranslation will not have any properties.
$this->assertCount(0, $productTranslation->properties()->get());
//Let the property service save the attribute for the product translation
$propertyService->save($productTranslation, collect([$attribute]));
//Now the ProductTranslation must have exactly 1 attribute (that came from the $propertyData)
$this->assertCount(1, $productTranslation->properties()->get());
//Check that that property has 1 value translation and 1 key translation in the given language and that it matches the data we used.
//Due to how the database is constructed, it can only have 1 key and 1 value.
/** @var Property $property */
$property = $productTranslation->properties()->with('key.translations', 'value.translations')->first();
$propertyKeyTranslation = $property->key->translations->where('language_id', '=', $language->id)->first();
$propertyValueTranslation = $property->value->translations->where('language_id', '=', $language->id)->first();
$this->assertNotNull($propertyKeyTranslation);
$this->assertNotNull($propertyValueTranslation);
$this->assertEquals(ucfirst(strtolower($propertyValue)), $propertyValueTranslation->value);
$this->assertEquals(ucfirst(strtolower($propertyKey)), $propertyKeyTranslation->value);
//Now, verify the load process. Basically it looks like the reverse of above.
$attribute->setValue('');
$this->assertEquals('', $attribute->getValue());
$propertyService->load($productTranslation, collect([$attribute]));
$expectedPropertyData = [[
'id' => Property::latest()->first()->id,
'state' => Property::PRISTINE,
'key' => ucfirst(strtolower($propertyKey)),
'value' => ucfirst(strtolower($propertyValue)),
]];
$this->assertEquals(json_encode($expectedPropertyData), $attribute->getValue());
}
/**
* @group Properties
* @test
*/
public function testModificationOfExistingPropertyWithNewKeyAndValue() {
//****************************************************************************//
// Make sure prerequisites are met before the actual testing takes place //
//****************************************************************************//
//Get the language that we are going to associate the Properties attribute. So that it appears like it is from a language tab
$language = Language::where('iso_2', '=', 'nl')->first();
//And of course we need a property service for the saving of the process
$propertyService = new PropertyService();
//Create a ProductTranslation (propertizable). We are going to attach the properties to it.
/** @var ProductTranslation $productTranslation */
$productTranslation = factory(ProductTranslation::class)->create(['language_id' => $language->id]);
//Fake the creation of property data like it comes from the Properties attribute.
$propertyValue = 'val_test_1';
$propertyKey = 'key_test_1';
$propertyData = [
['id' => -1, 'state' => Property::NEW, 'key' => $propertyKey, 'value' => $propertyValue]
];
//Create the properties attribute, and give it the json representation of the property data we've created earlier. In real life the frontend will give us the data as json too.
$attribute = (new FreeProperties(''))
->mapValueFrom(\Komma\KMS\Core\Attributes\Attribute::ValueFromItself, 'properties')
->setAssociatedLanguage($language)
->setValue(json_encode($propertyData));
//Let the property service save the attribute for the product translation
$propertyService->save($productTranslation, collect([$attribute]));
//****************************************************************************//
// Test the modification of an existing property with a new key and value //
// The most important part of this test //
//****************************************************************************//
//Get the existing property so we can compare it later on
$existingProperty = $productTranslation->properties()->with('key.translations', 'value.translations')->first();
$this->assertInstanceOf(Property::class, $existingProperty);
$this->assertTrue($existingProperty->exists);
//Define new values
$newPropertyKey = 'val_test_2';
$newPropertyValue = 'key_test_2';
$newPropertyData = [
['id' => $existingProperty->id, 'state' => Property::DIRTY, 'key' => $newPropertyKey, 'value' => $newPropertyValue]
];
//Use the attribute to give it the new values
$attribute->setValue(json_encode($newPropertyData));
//At first, the ProductTranslation will have 1 property, namely the previously created one.
$properties = $productTranslation->properties()->get();
$this->assertCount(1, $productTranslation->properties()->get());
//Let the property service save the attribute for the product translation
$propertyService->save($productTranslation, collect([$attribute]));
//Then it still should have 1 property!
$this->assertCount(1, $productTranslation->properties()->with('key.translations', 'value.translations')->get());
//But its translations...
$keyTranslation = $productTranslation->properties->first()->key->translations->where('language_id', $language->id)->first();
$valueTranslation = $productTranslation->properties->first()->value->translations->where('language_id', $language->id)->first();
$this->assertInstanceOf(PropertyKeyTranslation::class, $keyTranslation);
$this->assertInstanceOf(PropertyValueTranslation::class, $valueTranslation);
//...must the new translations from the $newPropertyData array
$this->assertEquals(ucfirst(strtolower($newPropertyData[0]['key'])), $keyTranslation->value);
$this->assertEquals(ucfirst(strtolower($newPropertyData[0]['value'])), $valueTranslation->value);
//And the old property key and value must not exist in the database anymore since they are not used by other properties...
$this->assertCount(0, $properties[0]->key()->get());
$this->assertCount(0, $properties[0]->value()->get());
//...but new ones should exist!
$this->assertCount(1, $productTranslation->properties->first()->key()->get());
$this->assertCount(1, $productTranslation->properties->first()->value()->get());
}
/**
* @group Properties
* @test
*/
public function testModificationOfExistingPropertyWithExistingKeyAndValue() {
//****************************************************************************//
// Make sure prerequisites are met before the actual testing takes place //
//****************************************************************************//
//Get the language that we are going to associate the Properties attribute. So that it appears like it is from a language tab
$language = Language::where('iso_2', '=', 'nl')->first();
//And of course we need a property service for the saving of the process
$propertyService = new PropertyService();
//Create a ProductTranslation (propertizable). We are going to attach the properties to it.
/** @var ProductTranslation $productTranslation */
$productTranslation = factory(ProductTranslation::class)->create(['language_id' => $language->id]);
//Fake the creation of property data like it comes from the Properties attribute.
$propertyValue = 'val_test_1';
$propertyKey = 'key_test_1';
$propertyData = [
['id' => -1, 'state' => Property::NEW, 'key' => $propertyKey, 'value' => $propertyValue]
];
//Create the properties attribute, and give it the json representation of the property data we've created earlier. In real life the frontend will give us the data as json too.
$attribute = (new FreeProperties(''))
->mapValueFrom(\Komma\KMS\Core\Attributes\Attribute::ValueFromItself, 'properties')
->setAssociatedLanguage($language)
->setValue(json_encode($propertyData));
//Let the property service save the attribute for the product translation
$propertyService->save($productTranslation, collect([$attribute]));
//Get the existing property so we can compare it later on
$existingProperty = $productTranslation->properties()->with('key.translations', 'value.translations')->first();
$this->assertInstanceOf(Property::class, $existingProperty);
$this->assertTrue($existingProperty->exists);
//****************************************************************************//
// Make a second property in the db, with a new key and value. //
//****************************************************************************//
//Define new values
$newPropertyKey = 'val_test_2';
$newPropertyValue = 'key_test_2';
$secondPropertyData = [
['id' => -1, 'state' => Property::NEW, 'key' => $propertyKey, 'value' => $propertyValue]
];
$attribute->setValue(json_encode($secondPropertyData));
$propertyService->save($productTranslation, collect([$attribute]));
//****************************************************************************//
// Test the modification of an existing property with an existing key and //
// value. These must come from the second property we've created earlier. //
// The most important part of this test. //
//****************************************************************************//
$newPropertyData = [
['id' => $existingProperty->id, 'state' => Property::DIRTY, 'key' => $newPropertyKey, 'value' => $newPropertyValue]
];
//Use the attribute to give it the new values
$attribute->setValue(json_encode($newPropertyData));
//At first, the ProductTranslation will have 2 property, namely the previously created ones.
$properties = $productTranslation->properties()->latest()->get();
$this->assertCount(2, $productTranslation->properties()->get());
//Let the property service save the attribute for the product translation
$propertyService->save($productTranslation, collect([$attribute]));
//Then it still should have 2 properties!
$this->assertCount(2, $productTranslation->properties()->with('key.translations', 'value.translations')->get());
//But its translations...
$keyTranslation = $productTranslation->properties->first()->key->translations->where('language_id', $language->id)->first();
$valueTranslation = $productTranslation->properties->first()->value->translations->where('language_id', $language->id)->first();
$this->assertInstanceOf(PropertyKeyTranslation::class, $keyTranslation);
$this->assertInstanceOf(PropertyValueTranslation::class, $valueTranslation);
//...must the new translations from the $newPropertyData array
$this->assertEquals(ucfirst(strtolower($newPropertyData[0]['key'])), $keyTranslation->value);
$this->assertEquals(ucfirst(strtolower($newPropertyData[0]['value'])), $valueTranslation->value);
//And the old property key and value must exist in the database since they are used by other properties...
$this->assertCount(1, $properties[0]->key()->get());
$this->assertCount(1, $properties[0]->value()->get());
//...but new ones should exist!
$this->assertCount(1, $productTranslation->properties->first()->key()->get());
$this->assertCount(1, $productTranslation->properties->first()->value()->get());
}
/**
* @group Properties
* @test
*/
public function testDeletionOfProperty() {
//Get the language that we are going to associate the Properties attribute. So that it appears like it is from a language tab
$language = Language::where('iso_2', '=', 'nl')->first();
//Create a ProductTranslation (propertizable). We are going to attach the properties to it.
/** @var ProductTranslation $productTranslation */
$productTranslation = factory(ProductTranslation::class)->create(['language_id' => $language->id]);
//And of course we need a property service for the saving of the process
$propertyService = new PropertyService();
//Fake the creation of property data like it comes from the Properties attribute.
$propertyValue = 'val_test_1';
$propertyKey = 'key_test_1';
$propertyData = [
['id' => -1, 'state' => Property::NEW, 'key' => $propertyKey, 'value' => $propertyValue]
];
//Create the properties attribute, and give it the json representation of the property data we've created earlier. In real life the frontend will give us the data as json too.
$attribute = (new FreeProperties())
->mapValueFrom(\Komma\KMS\Core\Attributes\Attribute::ValueFromItself, 'properties')
->setAssociatedLanguage($language)
->setValue(json_encode($propertyData));
//Let the property service save the attribute for the product translation
$propertyService->save($productTranslation, collect([$attribute]));
//Now the ProductTranslation must have exactly 1 attribute (that came from the $propertyData). It also must have 1 key, value and 1 keyTranslation and 1 ValueTranslation
$properties = $productTranslation->properties()->with('key.translations', 'value.translations')->get();
$property = $properties[0];
$this->assertCount(1, $properties);
$this->assertNotNull(1, $property->key);
$this->assertCount(1, $property->key->translations);
$this->assertNotNull(1, $property->value);
$this->assertCount(1, $property->value->translations);
//Delete the property like the model service will do so
$propertyService->destroyForModel($productTranslation);
$this->assertNull(Property::find($property->id));
$this->assertNull(PropertyKey::find($property->key->id));
$this->assertNull(PropertyValue::find($property->value->id));
$property->key->translations->each(function(PropertyKeyTranslation $propertyKeyTranslation) {
$this->assertNull(PropertyKeyTranslation::find($propertyKeyTranslation->id));
});
$property->value->translations->each(function(PropertyValueTranslation $propertyValueTranslation) {
$this->assertNull(PropertyValueTranslation::find($propertyValueTranslation->id));
});
}
}