mirror of
https://github.com/archtechx/airwire.git
synced 2025-12-12 02:34:04 +00:00
initial
This commit is contained in:
commit
d26fa93f1e
35 changed files with 2388 additions and 0 deletions
203
tests/Airwire/TypehintsTest.php
Normal file
203
tests/Airwire/TypehintsTest.php
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
use Airwire\Airwire;
|
||||
use Airwire\Attributes\Encode;
|
||||
use Airwire\Component;
|
||||
use Airwire\Attributes\Wired;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
beforeEach(function () {
|
||||
Schema::create('products', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('description');
|
||||
$table->unsignedInteger('price');
|
||||
$table->string('secret')->nullable();
|
||||
$table->json('variants')->default('[]');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Airwire::component('typehint-component', TypehintComponent::class);
|
||||
|
||||
Airwire::typeTransformer(
|
||||
type: MyDTO::class,
|
||||
decode: fn (array $data) => new MyDTO($data['foo'], $data['abc']),
|
||||
encode: fn (MyDTO $dto) => ['foo' => $dto->foo, 'abc' => $dto->abc],
|
||||
);
|
||||
});
|
||||
|
||||
// beforeEach(fn () => DB::table('products')->truncate());
|
||||
|
||||
afterEach(fn () => Schema::dropIfExists('products'));
|
||||
|
||||
test('untyped properties are set directly from the json data', function () {
|
||||
foreach ([1, 'foo', ['a' => 'b']] as $value) {
|
||||
expect(Airwire::test(TypehintComponent::class)
|
||||
->state(['notype' => $value])
|
||||
->send()->data('notype')
|
||||
)->toBe($value);
|
||||
}
|
||||
});
|
||||
|
||||
test('strings and numbers are cast to the required type', function () {
|
||||
expect(Airwire::test(TypehintComponent::class)
|
||||
->state(['price' => '1'])
|
||||
->send()->data('price')
|
||||
)->toBe(1);
|
||||
|
||||
expect(Airwire::test(TypehintComponent::class)
|
||||
->state(['name' => 123])
|
||||
->send()->data('name')
|
||||
)->toBe('123');
|
||||
});
|
||||
|
||||
test('received model attributes are converted to unsaved model instances', function () {
|
||||
$model = Airwire::test(TypehintComponent::class)
|
||||
->state(['model' => ['name' => 'foo', 'price' => '100', 'variants' => [
|
||||
['price' => 200, 'color' => 'black']
|
||||
]]])
|
||||
->hydrate()->model;
|
||||
|
||||
expect($model)->toBeInstanceOf(Product::class);
|
||||
expect($model->name)->toBe('foo');
|
||||
expect($model->price)->toBe(100); // Types are converted per the casts
|
||||
expect($model->variants)->toBe([['price' => 200, 'color' => 'black']]); // Array casts are supported
|
||||
});
|
||||
|
||||
test('received model attributes must be fillable', function () {
|
||||
$model = Airwire::test(TypehintComponent::class)
|
||||
->state(['model' => ['name' => 'foo', 'price' => '100', 'secret' => 'bar']])
|
||||
->hydrate()->model;
|
||||
|
||||
expect($model)->toBeInstanceOf(Product::class);
|
||||
expect($model->name)->toBe('foo');
|
||||
expect($model->bar)->toBe(null); // Not fillable
|
||||
});
|
||||
|
||||
test('model properties can be hidden', function () {
|
||||
Product::create(['id' => 1, 'name' => 'foo', 'price' => 10, 'description' => 'bar']);
|
||||
|
||||
expect(Airwire::test(TypehintComponent::class)
|
||||
->call('first')
|
||||
->send()->call('first')
|
||||
)->toBeArray()->toHaveKey('created_at')->not()->toHaveKey('updated_at');
|
||||
});
|
||||
|
||||
test('received model ids are converted to model instances', function () {
|
||||
Product::create(['id' => 1, 'name' => 'foo', 'price' => 10, 'description' => 'bar']);
|
||||
|
||||
$model = Airwire::test(TypehintComponent::class)
|
||||
->state(['model' => 1])
|
||||
->hydrate()->model;
|
||||
|
||||
expect($model)->toBeInstanceOf(Product::class);
|
||||
expect($model->id)->toBe(1);
|
||||
expect($model->exists())->toBe(true);
|
||||
});
|
||||
|
||||
test('sent models are converted to arrays', function () {
|
||||
Product::create(['id' => 1, 'name' => 'foo', 'price' => 10, 'description' => 'bar']);
|
||||
|
||||
expect(Airwire::test(TypehintComponent::class)
|
||||
->call('first')
|
||||
->send()->call('first')
|
||||
)->toBeArray()->toHaveKey('id', 1);
|
||||
});
|
||||
|
||||
test('custom DTOs can be used', function () {
|
||||
// Sending
|
||||
expect(Airwire::test(TypehintComponent::class)
|
||||
->state(['dto' => [
|
||||
'foo' => 'bar',
|
||||
'abc' => 123,
|
||||
]])
|
||||
->hydrate()
|
||||
->dto
|
||||
)->toBeInstanceOf(MyDTO::class)->toHaveKey('foo', 'bar')->toHaveKey('abc', 123);
|
||||
|
||||
// Receiving
|
||||
expect(Airwire::test(TypehintComponent::class)
|
||||
->state(['dto' => [
|
||||
'foo' => 'bar',
|
||||
'abc' => 123,
|
||||
]])
|
||||
->send()
|
||||
->data('dto')
|
||||
)->toBe(['foo' => 'bar', 'abc' => 123]);
|
||||
});
|
||||
|
||||
test('model can be passed to a method', function () {
|
||||
expect(TypehintComponent::test()
|
||||
->call('save', ['name' => 'foo', 'price' => 10, 'description' => 'bar'])
|
||||
->send()
|
||||
->call('save')
|
||||
)->toBe('1');
|
||||
|
||||
expect(Product::count())->toBe(1);
|
||||
});
|
||||
|
||||
test('models can be encoded back to the id', function () {
|
||||
Product::create(['id' => 1, 'name' => 'foo', 'price' => 10, 'description' => 'bar']);
|
||||
|
||||
expect(TypehintComponent::test()
|
||||
->state(['model2' => 1])
|
||||
->send()->data('model2')
|
||||
)->toBe(1);
|
||||
});
|
||||
|
||||
class TypehintComponent extends Component
|
||||
{
|
||||
#[Wired]
|
||||
public $notype;
|
||||
|
||||
#[Wired]
|
||||
public string $name;
|
||||
|
||||
#[Wired]
|
||||
public int $price;
|
||||
|
||||
#[Wired]
|
||||
public Product $model;
|
||||
|
||||
#[Wired] #[Encode(method: 'getKey')] // todo add the same feature for Decode
|
||||
public Product $model2;
|
||||
|
||||
#[Wired]
|
||||
public MyDTO $dto;
|
||||
|
||||
#[Wired]
|
||||
public function first(): Product
|
||||
{
|
||||
return Product::first();
|
||||
}
|
||||
|
||||
#[Wired]
|
||||
public function save(Product $model): string
|
||||
{
|
||||
$model->save();
|
||||
|
||||
return $model->id;
|
||||
}
|
||||
}
|
||||
|
||||
class Product extends Model
|
||||
{
|
||||
public $fillable = ['id', 'name', 'price', 'description', 'variants'];
|
||||
public $hidden = ['updated_at'];
|
||||
|
||||
public $casts = [
|
||||
'price' => 'int',
|
||||
'variants' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
class MyDTO
|
||||
{
|
||||
public function __construct(
|
||||
public string $foo,
|
||||
public int $abc,
|
||||
) {}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue