From 37f2dce9906a6b4f3696f3a513cf907d2cb108f5 Mon Sep 17 00:00:00 2001 From: DaltonMcCleery Date: Tue, 9 Jul 2024 10:25:03 -0500 Subject: [PATCH] Adds: tests --- phpunit.xml | 22 ++++++ tests/Pest.php | 60 +++++++++++++++ tests/RemoteModelTest.php | 151 ++++++++++++++++++++++++++++++++++++++ tests/TestCase.php | 54 ++++++++++++++ 4 files changed, 287 insertions(+) create mode 100644 phpunit.xml create mode 100644 tests/Pest.php create mode 100644 tests/RemoteModelTest.php create mode 100644 tests/TestCase.php diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..b1beae2 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,22 @@ + + + + + tests + + + + + ./src + + + + + + + + diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..7516385 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,60 @@ +in('./'); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +// + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +function mockDefaultHttpResponse(): array +{ + return [ + 'yourdomain.com/api/celebrities*' => Http::response([ + 'total' => 1, + 'per_page' => 15, + 'current_page' => 1, + 'last_page' => 1, + 'data' => [ + [ + 'id' => 999, + 'name' => 'Dwayne Johnson', + ] + ] + ]), + ]; +} diff --git a/tests/RemoteModelTest.php b/tests/RemoteModelTest.php new file mode 100644 index 0000000..deb4070 --- /dev/null +++ b/tests/RemoteModelTest.php @@ -0,0 +1,151 @@ + Http::sequence() + // Initial schema call. + ->push([ + 'total' => 2, + 'per_page' => 1, + 'current_page' => 1, + 'last_page' => 2, + 'data' => [ + [ + 'id' => 888, + 'name' => 'The Rock', + ] + ] + ]) + // Loading data API calls. + ->push([ + 'total' => 2, + 'per_page' => 1, + 'current_page' => 1, + 'last_page' => 2, + 'data' => [ + [ + 'id' => 888, + 'name' => 'The Rock', + ] + ] + ]) + ->push([ + 'total' => 2, + 'per_page' => 1, + 'current_page' => 2, + 'last_page' => 2, + 'data' => [ + [ + 'id' => 999, + 'name' => 'Dwayne Johnson', + ] + ] + ]), + ]); + + expect(Celebrity::where('name', 'Dwayne Johnson')->first()->id)->toBe(999) + ->and(Celebrity::where('name', 'The Rock')->first()->id)->toBe(888); +}); + +it('loads user from where query', function () { + Http::fake(mockDefaultHttpResponse()); + + expect(Celebrity::where('name', 'Dwayne Johnson')->first()->id)->toBe(999) + ->and(Celebrity::where('name', 'The Rock')->first())->toBeNull(); +}); + +it('adds domain to config', function () { + Config::set('remote-models.domain', 'https://yourdomain.com/'); + + Http::fake(mockDefaultHttpResponse()); + + expect(WithDomain::where('name', 'Dwayne Johnson')->first()->id)->toBe(999); +}); + +it('loads user from plain API', function () { + Http::fake([ + 'yourdomain.com/api/celebrities*' => Http::response([ + [ + 'id' => 999, + 'name' => 'Dwayne Johnson', + ] + ]), + ]); + + expect(Celebrity::where('name', 'Dwayne Johnson')->first()->id)->toBe(999) + ->and(Celebrity::where('name', 'The Rock')->first())->toBeNull(); +}); + +it('fails with no endpoint', function () { + expect(NoEndpoint::where('name', 'Dwayne Johnson')->first())->toBeNull(); +})->throws(\Exception::class, 'Remote Model property `$endpoint` cannot be empty.'); + +it('fails on API call', function () { + Http::fake([ + 'yourdomain.com/api/celebrities*' => Http::response(status: 500), + ]); + + expect(Celebrity::where('name', 'Dwayne Johnson')->first())->toBeNull(); +})->throws(\Exception::class, 'Access to Remote Model `$endpoint` failed.'); + +it('fails on empty API data', function () { + Http::fake([ + 'yourdomain.com/api/celebrities*' => Http::response([ + 'total' => 0, + 'per_page' => 15, + 'current_page' => 1, + 'last_page' => 1, + 'data' => [] + ]), + ]); + + expect(Celebrity::where('name', 'Dwayne Johnson')->first())->toBeNull(); +})->throws(\Exception::class, 'No data returned from Remote Model `$endpoint`.'); + +it('uses memory if the cache directory is not writeable or not found', function () { + Http::fake(mockDefaultHttpResponse()); + + config(['remote-models.cache-path' => $path = __DIR__ . '/non-existant-path']); + + $count = Celebrity::count(); + + expect(\file_exists($path))->toBeFalse() + ->and($count)->toBe(1) + ->and((new Celebrity)->getConnection()->getDatabaseName())->toBe(':memory:'); +}); + +it('caches sqlite file if storage cache folder is available', function () { + Http::fake(mockDefaultHttpResponse()); + + $count = Celebrity::count(); + + expect(\file_exists(__DIR__ . '/cache'))->toBeTrue() + ->and($count)->toBe(1); +}); + +it('uses same cache between requests', function () { + // TODO +})->skip(); + + +class Celebrity extends Model { + use RemoteModel; + + protected $endpoint = 'https://yourdomain.com/api/celebrities'; +} + +class WithDomain extends Model { + use RemoteModel; + + protected $endpoint = '/api/celebrities'; +} + +class NoEndpoint extends Model { + use RemoteModel; +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..7ceb5c5 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,54 @@ +set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + } + + protected function defineDatabaseMigrations(): void + { + $this->loadLaravelMigrations(['--database' => 'testbench']); + } + + protected function setUp(): void + { + parent::setUp(); + + config(['remote-models.cache-path' => $this->cachePath = __DIR__ . '/cache']); + + if (! file_exists($this->cachePath)) { + mkdir($this->cachePath, 0777, true); + } + + File::cleanDirectory($this->cachePath); + } + + protected function tearDown(): void + { + File::cleanDirectory($this->cachePath); + + parent::tearDown(); + } + + protected function getPackageProviders($app): array + { + return [ + RemoteModelServiceProvider::class, + ]; + } +}