Skip to content

Commit

Permalink
Merge pull request #88 from RonasIT/add-nova-test-trait
Browse files Browse the repository at this point in the history
Add nova test trait
  • Loading branch information
DenTray authored Dec 14, 2023
2 parents f8ee1f2 + 2ca150a commit 78bc60d
Show file tree
Hide file tree
Showing 18 changed files with 718 additions and 2 deletions.
127 changes: 127 additions & 0 deletions src/Tests/ModelTestState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php

namespace RonasIT\Support\Tests;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use PHPUnit\Framework\Assert;
use RonasIT\Support\Traits\FixturesTrait;

class ModelTestState extends Assert
{
use FixturesTrait;

protected Collection $state;
protected Model $model;
protected array $jsonFields;

public function __construct(string $modelClassName)
{
$this->model = new $modelClassName();
$this->state = $this->getDataSet($this->model->getTable());
$this->jsonFields = $this->getModelJSONFields();
}

public function assertNotChanged(): void
{
$changes = $this->getChanges();

$this->assertEquals([
'updated' => [],
'created' => [],
'deleted' => []
], $changes);
}

public function assertChangesEqualsFixture(string $fixture, bool $exportMode = false): void
{
$changes = $this->getChanges();

$this->assertEqualsFixture($fixture, $changes, $exportMode);
}

protected function getChanges(): array
{
$updatedData = $this->getDataSet($this->model->getTable());

$updatedRecords = [];
$deletedRecords = [];

$this->state->each(function ($originItem) use (&$updatedData, &$updatedRecords, &$deletedRecords) {
$updatedItemIndex = $updatedData->search(fn ($updatedItem) => $updatedItem['id'] === $originItem['id']);

if ($updatedItemIndex === false) {
$deletedRecords[] = $originItem;
} else {
$updatedItem = $updatedData->get($updatedItemIndex);
$changes = array_diff_assoc($updatedItem, $originItem);

if (!empty($changes)) {
$updatedRecords[] = array_merge(['id' => $originItem['id']], $changes);
}

$updatedData->forget($updatedItemIndex);
}
});

return [
'updated' => $this->prepareChanges($updatedRecords),
'created' => $this->prepareChanges($updatedData->values()->toArray()),
'deleted' => $this->prepareChanges($deletedRecords)
];
}

protected function prepareChanges(array $changes): array
{
$jsonFields = Arr::wrap($this->jsonFields);

if (empty($jsonFields)) {
return $changes;
}

return array_map(function ($item) use ($jsonFields) {
foreach ($jsonFields as $jsonField) {
if (Arr::has($item, $jsonField)) {
$item[$jsonField] = json_decode($item[$jsonField], true);
}
}

return $item;
}, $changes);
}

protected function getModelJSONFields(): array
{
$casts = $this->model->getCasts();

$jsonCasts = array_filter($casts, fn ($cast) => $this->isJsonCast($cast));

return array_keys($jsonCasts);
}

protected function isJsonCast(string $cast): bool
{
return ($cast === 'array') || (class_exists($cast) && is_subclass_of($cast, CastsAttributes::class));
}

protected function getFixturePath(string $fixtureName): string
{
$class = get_class($this);
$explodedClass = explode('\\', $class);
$className = Arr::last($explodedClass);
$table = $this->model->getTable();

return base_path("tests/fixtures/{$className}/changes/{$table}/{$fixtureName}");
}

protected function getDataSet(string $table, string $orderField = 'id'): Collection
{
return DB::table($table)
->orderBy($orderField)
->get()
->map(fn ($record) => (array) $record);
}
}
20 changes: 20 additions & 0 deletions src/Traits/AuthTestTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace RonasIT\Support\Traits;

use Illuminate\Auth\SessionGuard;

trait AuthTestTrait
{
public function actingViaSession(int $userId): self
{
$guard = 'session';
$hash = sha1(SessionGuard::class);

$this->withSession([
"login_{$guard}_{$hash}" => $userId,
]);

return $this;
}
}
35 changes: 35 additions & 0 deletions tests/AuthTestTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace RonasIT\Support\Tests;

use Illuminate\Support\Arr;
use RonasIT\Support\Tests\Support\Traits\MockTrait;
use RonasIT\Support\Traits\AuthTestTrait;
use RonasIT\Support\Traits\FixturesTrait;

class AuthTestTraitTest extends HelpersTestCase
{
use FixturesTrait, MockTrait, AuthTestTrait;

public function testActingViaSession()
{
$userId = 1;

$this->actingViaSession($userId);

$session = $this->app['session']->getDrivers()['array'];
$loginSession = $this->getLoginSession($session);

$this->assertNotEmpty($loginSession);
$this->assertEquals('laravel_session', $session->getName());
$this->assertEquals(array_values($loginSession), [$userId]);
}

public function testActingWithEmptySession()
{
$session = Arr::get($this->app['session']->getDrivers(), 'array', collect());
$loginSession = $this->getLoginSession($session);

$this->assertEmpty($loginSession);
}
}
20 changes: 19 additions & 1 deletion tests/HelpersTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

namespace RonasIT\Support\Tests;

use RonasIT\Support\Traits\FixturesTrait;
use ReflectionClass;
use RonasIT\Support\HelpersServiceProvider;
use RonasIT\Support\Traits\FixturesTrait;
use Orchestra\Testbench\TestCase as BaseTest;

class HelpersTestCase extends BaseTest
Expand Down Expand Up @@ -45,4 +46,21 @@ protected function assertSettablePropertiesReset($class): void
$this->assertEquals([], $attachedRelations);
$this->assertEquals([], $attachedRelationsCount);
}

public function getLoginSession($session): array
{
return array_filter(
$session->all(),
fn ($key) => strpos($key, 'login_session_') === 0,
ARRAY_FILTER_USE_KEY
);
}

protected function getProtectedProperty(ReflectionClass $reflectionClass, string $methodName, $objectInstance)
{
$property = $reflectionClass->getProperty($methodName);
$property->setAccessible(true);

return $property->getValue($objectInstance);
}
}
60 changes: 60 additions & 0 deletions tests/ModelTestStateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace RonasIT\Support\Tests;

use ReflectionClass;
use RonasIT\Support\Tests\Support\Mock\TestModel;
use RonasIT\Support\Tests\Support\Traits\ModelTestStateMockTrait;
use RonasIT\Support\Tests\Support\Traits\MockTrait;

class ModelTestStateTest extends HelpersTestCase
{
use ModelTestStateMockTrait;
use MockTrait;

public function setUp(): void
{
parent::setUp();

self::$tables = null;

putenv('FAIL_EXPORT_JSON=false');
}

public function testInitialization()
{
$datasetMock = collect($this->getJsonFixture('initialization/dataset.json'));
$originRecords = collect($this->getJsonFixture('initialization/origin_records.json'));

$this->mockGettingDataset($datasetMock);

$modelTestState = new ModelTestState(TestModel::class);
$reflectionClass = new ReflectionClass($modelTestState);

$jsonFields = $this->getProtectedProperty($reflectionClass, 'jsonFields', $modelTestState);
$state = $this->getProtectedProperty($reflectionClass, 'state', $modelTestState);

$this->assertNotEmpty($jsonFields);
$this->assertEquals(['json_field', 'castable_field'], $jsonFields);
$this->assertEquals($originRecords, $state);
}

public function testAssertChangesEqualsFixture()
{
$initialDatasetMock = collect($this->getJsonFixture('changes_equals_fixture/initial_dataset.json'));
$changedDatasetMock = collect($this->getJsonFixture('changes_equals_fixture/changed_dataset.json'));
$this->mockGettingDatasetForChanges($changedDatasetMock, $initialDatasetMock);

$modelTestState = new ModelTestState(TestModel::class);
$modelTestState->assertChangesEqualsFixture('assertion_fixture.json');
}

public function testAssertNoChanges()
{
$datasetMock = collect($this->getJsonFixture('get_without_changes/dataset.json'));
$this->mockGettingDataset($datasetMock);

$modelTestState = new ModelTestState(TestModel::class);
$modelTestState->assertNotChanged();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[
{
"id": 1,
"user_id": 1,
"title": "Title1",
"text": "Text1",
"is_public": true,
"description": null,
"json_column": {
"field1": "value",
"field2": [
2,
3
],
"field3": {
"one": 1,
"two": 2
}
},
"created_at": "2018-10-10 10:10:10",
"updated_at": "2018-10-10 10:10:10"
},
{
"id": 2,
"user_id": 2,
"title": "Title2",
"text": "Text2",
"is_public": true,
"description": null,
"json_column": {
"one": "first value",
"two": "second value"
},
"created_at": "2018-10-10 10:10:10",
"updated_at": "2018-10-10 10:10:10"
},
{
"id": 3,
"user_id": 3,
"title": "Title3",
"text": "Text3",
"is_public": true,
"description": null,
"json_column": [
2,
"two"
],
"created_at": "2018-10-10 10:10:10",
"updated_at": "2018-10-10 10:10:10"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[
{
"id": 1,
"user_id": 1,
"title": "Title1",
"text": "Text1",
"is_public": true,
"description": null,
"json_column": "{\"field1\": \"value\", \"field2\": [2, 3], \"field3\": {\"one\": 1, \"two\": 2}}",
"created_at": "2018-10-10 10:10:10",
"updated_at": "2018-10-10 10:10:10"
},
{
"id": 2,
"user_id": 2,
"title": "Title2",
"text": "Text2",
"is_public": true,
"description": null,
"json_column": "{\"one\": \"first value\", \"two\": \"second value\"}",
"created_at": "2018-10-10 10:10:10",
"updated_at": "2018-10-10 10:10:10"
},
{
"id": 3,
"user_id": 3,
"title": "Title3",
"text": "Text3",
"is_public": true,
"description": null,
"json_column": "[2, \"two\"]",
"created_at": "2018-10-10 10:10:10",
"updated_at": "2018-10-10 10:10:10"
}
]
Loading

0 comments on commit 78bc60d

Please sign in to comment.