Skip to content
This repository was archived by the owner on Feb 14, 2023. It is now read-only.

Commit 8ef2db7

Browse files
committed
Add testing utilities
1 parent 3c0d680 commit 8ef2db7

File tree

10 files changed

+415
-3
lines changed

10 files changed

+415
-3
lines changed

src/JsonApiServiceProvider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
namespace SkoreLabs\JsonApi;
44

55
use Illuminate\Database\Query\Builder;
6+
use Illuminate\Foundation\Testing\TestResponse;
67
use Illuminate\Support\ServiceProvider;
78
use SkoreLabs\JsonApi\Builder as JsonApiBuilder;
9+
use SkoreLabs\JsonApi\Testing\TestResponseMacros;
810

911
class JsonApiServiceProvider extends ServiceProvider
1012
{
@@ -32,5 +34,9 @@ public function boot()
3234
public function register()
3335
{
3436
$this->mergeConfigFrom(__DIR__.'/../config/json-api.php', 'json-api');
37+
38+
if (class_exists(TestResponse::class)) {
39+
TestResponse::mixin(new TestResponseMacros());
40+
}
3541
}
3642
}

src/Testing/Assert.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace SkoreLabs\JsonApi\Testing;
4+
5+
use Illuminate\Contracts\Support\Arrayable;
6+
use Illuminate\Support\Traits\Macroable;
7+
use PHPUnit\Framework\Assert as PHPUnit;
8+
use PHPUnit\Framework\AssertionFailedError;
9+
use SkoreLabs\JsonApi\Testing\Concerns\HasRelationships;
10+
use SkoreLabs\JsonApi\Testing\Concerns\HasAttributes;
11+
use SkoreLabs\JsonApi\Testing\Concerns\HasCollections;
12+
use SkoreLabs\JsonApi\Testing\Concerns\HasIdentifications;
13+
14+
class Assert implements Arrayable
15+
{
16+
use HasIdentifications,
17+
HasAttributes,
18+
HasRelationships,
19+
HasCollections,
20+
Macroable;
21+
22+
/**
23+
* @var string
24+
*/
25+
protected $id;
26+
27+
/**
28+
* @var string
29+
*/
30+
protected $type;
31+
32+
/**
33+
* @var array
34+
*/
35+
protected $attributes;
36+
37+
/**
38+
* @var array
39+
*/
40+
protected $relationships;
41+
42+
/**
43+
* @var array
44+
*/
45+
protected $includeds;
46+
47+
/**
48+
* @var array
49+
*/
50+
protected $collection;
51+
52+
protected function __construct($id = '', $type = '', array $attributes = [], array $relationships = [], array $includeds = [], array $collection = [])
53+
{
54+
$this->id = $id;
55+
$this->type = $type;
56+
57+
$this->attributes = $attributes;
58+
$this->relationships = $relationships;
59+
$this->includeds = $includeds;
60+
61+
$this->collection = $collection;
62+
}
63+
64+
public static function fromTestResponse($response)
65+
{
66+
try {
67+
$content = json_decode($response->getContent(), true);
68+
$data = $content['data'];
69+
$collection = [];
70+
71+
if (static::isCollection($data)) {
72+
$collection = $data;
73+
$data = head($data);
74+
}
75+
76+
PHPUnit::assertIsArray($data);
77+
PHPUnit::assertArrayHasKey('id', $data);
78+
PHPUnit::assertArrayHasKey('type', $data);
79+
PHPUnit::assertArrayHasKey('attributes', $data);
80+
PHPUnit::assertIsArray($data['attributes']);
81+
} catch (AssertionFailedError $e) {
82+
PHPUnit::fail('Not a valid JSON:API response.');
83+
}
84+
85+
return new self($data['id'], $data['type'], $data['attributes'], $data['relationships'] ?? [], $content['included'] ?? [], $collection);
86+
}
87+
88+
public function toArray(): array
89+
{
90+
return $this->attributes;
91+
}
92+
93+
public static function isCollection(array $data = [])
94+
{
95+
return !array_key_exists('attributes', $data);
96+
}
97+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace SkoreLabs\JsonApi\Testing\Concerns;
4+
5+
use PHPUnit\Framework\Assert as PHPUnit;
6+
7+
/**
8+
* @mixin \SkoreLabs\JsonApi\Testing\Assert
9+
*/
10+
trait HasAttributes
11+
{
12+
public function hasAttribute($name, $value = null)
13+
{
14+
PHPUnit::assertArrayHasKey($name, $this->attributes, sprintf('JSON:API response does not have an attribute named "%s"', $name));
15+
16+
if ($value) {
17+
PHPUnit::assertContains($value, $this->attributes, sprintf('JSON:API response does not have an attribute named "%s" with value "%s"', $name, $value));
18+
}
19+
20+
return $this;
21+
}
22+
23+
public function hasAttributes($attributes)
24+
{
25+
foreach ($attributes as $name => $value) {
26+
$this->hasAttribute($name, $value);
27+
}
28+
29+
return $this;
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace SkoreLabs\JsonApi\Testing\Concerns;
4+
5+
use PHPUnit\Framework\Assert as PHPUnit;
6+
7+
/**
8+
* @mixin \SkoreLabs\JsonApi\Testing\Assert
9+
*/
10+
trait HasCollections
11+
{
12+
public function at($position)
13+
{
14+
if (!array_key_exists($position, $this->collection)) {
15+
PHPUnit::fail(sprintf('There is no item at position "%d" on the collection response.', $position));
16+
17+
return $this;
18+
}
19+
20+
$data = $this->collection[$position];
21+
22+
return new self($data['id'], $data['type'], $data['attributes']);
23+
}
24+
25+
public function hasSize(int $value)
26+
{
27+
PHPUnit::assertCount($value, $this->collection, sprintf('The collection size is not same as "%d"', $value));
28+
29+
return $this;
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace SkoreLabs\JsonApi\Testing\Concerns;
4+
5+
use PHPUnit\Framework\Assert as PHPUnit;
6+
7+
/**
8+
* @mixin \SkoreLabs\JsonApi\Testing\Assert
9+
*/
10+
trait HasIdentifications
11+
{
12+
public function hasId($value)
13+
{
14+
$value .= '';
15+
16+
PHPUnit::assertTrue($this->id === $value, sprintf('JSON:API response does not have id "%s"', $value));
17+
18+
return $this;
19+
}
20+
21+
public function hasType($value)
22+
{
23+
PHPUnit::assertSame($this->type, $value, sprintf('JSON:API response does not have type "%s"', $value));
24+
25+
return $this;
26+
}
27+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace SkoreLabs\JsonApi\Testing\Concerns;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use PHPUnit\Framework\Assert as PHPUnit;
7+
use SkoreLabs\JsonApi\Support\JsonApi;
8+
9+
/**
10+
* @mixin \SkoreLabs\JsonApi\Testing\Assert
11+
*/
12+
trait HasRelationships
13+
{
14+
public function atRelation(Model $model)
15+
{
16+
$item = head(array_filter($this->includeds, function ($included) use ($model) {
17+
return $included['type'] === JsonApi::getResourceType($model) && $included['id'] == $model->getKey();
18+
}));
19+
20+
return new self($item['id'], $item['type'], $item['attributes'], $item['relationships'] ?? [], $this->includeds);
21+
}
22+
23+
public function hasAnyRelationships($name, $withIncluded = false)
24+
{
25+
$type = JsonApi::getResourceType($name);
26+
27+
PHPUnit::assertTrue(count(array_filter($this->relationships, function ($relation) use ($type) {
28+
return $relation['data']['type'] === $type;
29+
})) > 0);
30+
31+
if ($withIncluded) {
32+
PHPUnit::assertTrue(count(array_filter($this->includeds, function ($included) use ($type) {
33+
return $included['type'] === $type;
34+
})) > 0);
35+
}
36+
37+
return $this;
38+
}
39+
40+
public function hasRelationshipWith(Model $model, $withIncluded = false)
41+
{
42+
$type = JsonApi::getResourceType($model);
43+
44+
PHPUnit::assertTrue(count(array_filter($this->relationships, function ($relation) use ($type, $model) {
45+
return $relation['data']['type'] === $type && $relation['data']['id'] == $model->getKey();
46+
})) > 0);
47+
48+
if ($withIncluded) {
49+
PHPUnit::assertTrue(count(array_filter($this->includeds, function ($included) use ($type, $model) {
50+
return $included['type'] === $type && $included['id'] == $model->getKey();
51+
})) > 0);
52+
}
53+
54+
return $this;
55+
}
56+
}

src/Testing/TestResponseMacros.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace SkoreLabs\JsonApi\Testing;
4+
5+
use Closure;
6+
7+
class TestResponseMacros
8+
{
9+
public function assertJsonApi()
10+
{
11+
return function (Closure $callback = null) {
12+
$assert = Assert::fromTestResponse($this);
13+
14+
if (is_null($callback)) {
15+
return $this;
16+
}
17+
18+
$callback($assert);
19+
20+
return $this;
21+
};
22+
}
23+
}

tests/JsonApiCollectionTest.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
namespace SkoreLabs\JsonApi\Tests;
44

55
use Illuminate\Support\Facades\Route;
6-
use Orchestra\Testbench\TestCase;
76
use SkoreLabs\JsonApi\Http\Resources\JsonApiCollection;
7+
use SkoreLabs\JsonApi\Testing\Assert;
88
use SkoreLabs\JsonApi\Tests\Fixtures\Post;
99

1010
class JsonApiCollectionTest extends TestCase
1111
{
12-
public function testCollectionsMayBeConvertedToJsonApi()
12+
public function setUp(): void
1313
{
14+
parent::setUp();
15+
1416
Route::get('/', function () {
1517
return new JsonApiCollection(collect([
1618
new Post([
@@ -24,7 +26,10 @@ public function testCollectionsMayBeConvertedToJsonApi()
2426
]),
2527
]), true);
2628
});
29+
}
2730

31+
public function testCollectionsMayBeConvertedToJsonApi()
32+
{
2833
$response = $this->get('/', ['Accept' => 'application/json']);
2934

3035
$response->assertStatus(200);
@@ -49,4 +54,26 @@ public function testCollectionsMayBeConvertedToJsonApi()
4954
],
5055
], true);
5156
}
57+
58+
public function testCollectionsAtHasAttribute()
59+
{
60+
$this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $json) {
61+
$json->at(0)->hasAttribute('title', 'Test Title');
62+
$json->at(1)->hasAttribute('title', 'Test Title 2');
63+
});
64+
}
65+
66+
public function testCollectionsTakeByDefaultFirstItem()
67+
{
68+
$this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $json) {
69+
$json->hasAttribute('title', 'Test Title');
70+
});
71+
}
72+
73+
public function testCollectionsHasSize()
74+
{
75+
$this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $json) {
76+
$json->hasSize(2);
77+
});
78+
}
5279
}

0 commit comments

Comments
 (0)