diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
new file mode 100644
index 0000000..89b1735
--- /dev/null
+++ b/.github/workflows/continuous-integration.yml
@@ -0,0 +1,45 @@
+name: "Continuous Integration"
+
+on:
+ push:
+ pull_request:
+ schedule:
+ - cron: '0 0 * * *'
+
+jobs:
+ phpunit:
+
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: true
+ matrix:
+ php: [8.2, 8.3]
+ stability: [prefer-stable]
+
+ name: PHP ${{ matrix.php }} - ${{ matrix.stability }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, memcached
+ tools: composer:v2
+ coverage: none
+
+ - name: Setup Memcached
+ uses: niden/actions-memcached@v7
+
+ - name: Install dependencies
+ uses: nick-invision/retry@v1
+ with:
+ timeout_minutes: 5
+ max_attempts: 5
+ command: COMPOSER_ROOT_VERSION=dev-master composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress
+
+ - name: Execute tests
+ run: vendor/bin/pest
diff --git a/.github/workflows/lock-closed-issues.yml b/.github/workflows/lock-closed-issues.yml
index 6b89427..8c34d1f 100644
--- a/.github/workflows/lock-closed-issues.yml
+++ b/.github/workflows/lock-closed-issues.yml
@@ -18,4 +18,4 @@ jobs:
#issue-comment: |
# This issue has been locked since it has been closed for more than 14 days.
issue-lock-reason: ""
- process-only: "issues"
+ process-only: "issues"
\ No newline at end of file
diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml
new file mode 100644
index 0000000..f078347
--- /dev/null
+++ b/.github/workflows/pint.yml
@@ -0,0 +1,20 @@
+name: PHP Linting
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+jobs:
+ phplint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: "laravel-pint"
+ uses: aglipanci/laravel-pint-action@2.0.0
+ with:
+ preset: laravel
+ verboseMode: true
+ - uses: stefanzweifel/git-auto-commit-action@v5
+ with:
+ commit_message: "fix: pint"
+
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index d5cd3cf..77b9e66 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -1,7 +1,7 @@
name: Close inactive issues
on:
schedule:
- - cron: "30 1 * * *"
+ - cron: "0 0 * * *"
jobs:
close-issues:
@@ -12,11 +12,12 @@ jobs:
steps:
- uses: actions/stale@v5
with:
+ exempt-issue-labels: "bug,security,enhancement,pinned"
days-before-issue-stale: 30
- days-before-issue-close: 14
+ days-before-issue-close: 7
stale-issue-label: "stale"
- stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
- close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
+ stale-issue-message: "This issue is stale because it has been open for 30 days with no activity. Remove stale label or comment or this will be closed in 7 days."
+ close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
new file mode 100644
index 0000000..8e9365d
--- /dev/null
+++ b/.github/workflows/static-analysis.yml
@@ -0,0 +1,54 @@
+name: "Static Analysis"
+
+on:
+ push:
+ paths:
+ - .github/workflows/static-analysis.yml
+ - composer.*
+ - phpstan.neon.dist
+ - src/**
+ - tests/**
+
+ pull_request:
+ paths:
+ - .github/workflows/static-analysis.yml
+ - composer.*
+ - phpstan.neon.dist
+ - src/**
+ - tests/**
+
+ schedule:
+ - cron: '0 0 * * *'
+
+jobs:
+ static-analysis-phpstan:
+
+ name: "Static Analysis with PHPStan"
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: true
+ matrix:
+ php: [8.2, 8.3]
+ stability: [prefer-stable]
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ tools: composer:v2
+ coverage: none
+
+ - name: Install dependencies
+ uses: nick-invision/retry@v1
+ with:
+ timeout_minutes: 5
+ max_attempts: 5
+ command: COMPOSER_ROOT_VERSION=dev-master composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress
+
+ - name: "Run a static analysis with phpstan/phpstan"
+ run: "vendor/bin/phpstan --error-format=table"
diff --git a/.gitignore b/.gitignore
index 85d90cf..70e07f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
-build
+build/
composer.lock
-docs
-vendor
-.idea
+docs/
+vendor/
+.idea/
+.phpunit.cache/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e32720..2ec82f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
All Notable changes to `laravel-auditable` will be documented in this file.
+## [Unreleased]
+
+- Laravel 11 Support
+- Implement static analysis tools
+- Add GitHub Actions for CI/CD
+- Add Pint and Rector
+- Upgrade code to PHP 8.2 coding standards
+- Add tests using PestPHP
+
## v4.6.0 - 2023-04-11
- feat: Add withDefault on deleter #26
diff --git a/README.md b/README.md
index e2dd9e7..c52bc18 100644
--- a/README.md
+++ b/README.md
@@ -2,16 +2,25 @@
[![Latest Version on Packagist][ico-version]][link-packagist]
[![Software License][ico-license]](LICENSE.md)
-[![Build Status][ico-travis]][link-travis]
+
+[![Continuous Integration](https://github.com/yajra/laravel-auditable/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/yajra/laravel-auditable/actions/workflows/continuous-integration.yml)
+[![Static Analysis](https://github.com/yajra/laravel-auditable/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/yajra/laravel-auditable/actions/workflows/static-analysis.yml)
[![Total Downloads][ico-downloads]][link-downloads]
Laravel Auditable is a simple Laravel auditing package for your Eloquent Model.
This package automatically inserts/updates an audit log on your table on who created and last updated the record.
+## Laravel Version Compatibility
+
+| Laravel | Package |
+|:---------|:--------|
+| 5.x-10.x | 4.x |
+| 11.x | 11.x |
+
## Install via Composer
```bash
-composer require yajra/laravel-auditable
+composer require yajra/laravel-auditable:^11
```
## Publish config file
diff --git a/composer.json b/composer.json
index 3afdf79..51c41ad 100644
--- a/composer.json
+++ b/composer.json
@@ -17,12 +17,22 @@
}
],
"require": {
- "php": ">=7.2",
- "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0",
- "illuminate/database": "^6.0|^7.0|^8.0|^9.0|^10.0"
+ "php": "^8.2",
+ "illuminate/support": "^11.0",
+ "illuminate/database": "^11.0"
},
"require-dev": {
- "phpunit/phpunit": "^7.5|^8.4|^9.0|^10.0"
+ "larastan/larastan": "^2.9.1",
+ "laravel/pint": "^1.14",
+ "rector/rector": "^1.0",
+ "orchestra/testbench": "^9.0",
+ "pestphp/pest": "^2.34",
+ "pestphp/pest-plugin-laravel": "^2.3"
+ },
+ "config": {
+ "allow-plugins": {
+ "pestphp/pest-plugin": true
+ }
},
"autoload": {
"psr-4": {
@@ -31,20 +41,35 @@
},
"autoload-dev": {
"psr-4": {
- "Yajra\\Auditable\\Test\\": "tests"
+ "Yajra\\Auditable\\Tests\\": "tests"
}
},
- "scripts": {
- "test": "phpunit"
- },
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "11.x-dev"
},
"laravel": {
"providers": [
"Yajra\\Auditable\\AuditableServiceProvider"
]
}
- }
+ },
+ "scripts": {
+ "test": "./vendor/bin/pest",
+ "pint": "./vendor/bin/pint",
+ "rector": "./vendor/bin/rector",
+ "stan": "./vendor/bin/phpstan analyse --memory-limit=2G --ansi --no-progress --no-interaction --configuration=phpstan.neon.dist",
+ "pr": [
+ "@rector",
+ "@pint",
+ "@stan",
+ "@test"
+ ]
+ },
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/yajra"
+ }
+ ]
}
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..31521e9
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,15 @@
+includes:
+ - ./vendor/larastan/larastan/extension.neon
+
+parameters:
+
+ paths:
+ - src
+
+ level: max
+
+ ignoreErrors:
+
+ excludePaths:
+
+ checkMissingIterableValueType: true
diff --git a/phpunit.xml b/phpunit.xml
deleted file mode 100644
index 422eeac..0000000
--- a/phpunit.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- ./tests/
-
-
-
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..3d6dfa6
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,20 @@
+
+
+
+
+ ./tests/Unit
+
+
+ ./tests/Feature
+
+
+
+
+
+
+
+
+ src/
+
+
+
diff --git a/pint.json b/pint.json
new file mode 100644
index 0000000..93061b6
--- /dev/null
+++ b/pint.json
@@ -0,0 +1,3 @@
+{
+ "preset": "laravel"
+}
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000..ca7ca05
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,22 @@
+paths([
+ __DIR__.'/src',
+ __DIR__.'/tests',
+ ]);
+
+ // register a single rule
+ $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
+
+ // define sets of rules
+ $rectorConfig->sets([
+ LevelSetList::UP_TO_PHP_82,
+ ]);
+};
diff --git a/src/AuditableServiceProvider.php b/src/AuditableServiceProvider.php
index 9a737d3..448545e 100644
--- a/src/AuditableServiceProvider.php
+++ b/src/AuditableServiceProvider.php
@@ -2,46 +2,52 @@
namespace Yajra\Auditable;
-use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\ServiceProvider;
class AuditableServiceProvider extends ServiceProvider
{
/**
* Boot the package.
*/
- public function boot()
+ public function boot(): void
{
- $this->mergeConfigFrom(__DIR__ . '/config/auditable.php', 'auditable');
+ $this->mergeConfigFrom(__DIR__.'/config/auditable.php', 'auditable');
$this->publishes([
- __DIR__ . '/config/auditable.php' => base_path('config/auditable.php'),
+ __DIR__.'/config/auditable.php' => base_path('config/auditable.php'),
], 'auditable');
}
/**
* Register the service provider.
- *
- * @return void
*/
- public function register()
+ public function register(): void
{
Blueprint::macro('auditable', function () {
- $this->unsignedBigInteger('created_by')->nullable()->index();
- $this->unsignedBigInteger('updated_by')->nullable()->index();
+ /** @var Blueprint $blueprint */
+ $blueprint = $this;
+ $blueprint->unsignedBigInteger('created_by')->nullable()->index();
+ $blueprint->unsignedBigInteger('updated_by')->nullable()->index();
});
Blueprint::macro('dropAuditable', function () {
- $this->dropColumn(['created_by', 'updated_by']);
+ /** @var Blueprint $blueprint */
+ $blueprint = $this;
+ $blueprint->dropColumn(['created_by', 'updated_by']);
});
Blueprint::macro('auditableWithDeletes', function () {
- $this->unsignedBigInteger('created_by')->nullable()->index();
- $this->unsignedBigInteger('updated_by')->nullable()->index();
- $this->unsignedBigInteger('deleted_by')->nullable()->index();
+ /** @var Blueprint $blueprint */
+ $blueprint = $this;
+ $blueprint->unsignedBigInteger('created_by')->nullable()->index();
+ $blueprint->unsignedBigInteger('updated_by')->nullable()->index();
+ $blueprint->unsignedBigInteger('deleted_by')->nullable()->index();
});
Blueprint::macro('dropAuditableWithDeletes', function () {
- $this->dropColumn(['created_by', 'updated_by', 'deleted_by']);
+ /** @var Blueprint $blueprint */
+ $blueprint = $this;
+ $blueprint->dropColumn(['created_by', 'updated_by', 'deleted_by']);
});
}
}
diff --git a/src/AuditableTrait.php b/src/AuditableTrait.php
index ce9df67..49cf3aa 100644
--- a/src/AuditableTrait.php
+++ b/src/AuditableTrait.php
@@ -3,40 +3,36 @@
namespace Yajra\Auditable;
use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
- * @property mixed creator
- * @property mixed updater
+ * @property Model $creator
+ * @property Model $updater
*/
trait AuditableTrait
{
/**
* Boot the audit trait for a model.
- *
- * @return void
*/
- public static function bootAuditableTrait()
+ public static function bootAuditableTrait(): void
{
static::observe(new AuditableTraitObserver);
}
/**
* Get user model who created the record.
- *
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
- public function creator()
+ public function creator(): BelongsTo
{
return $this->belongsTo($this->getUserClass(), $this->getCreatedByColumn())
- ->withDefault(config('auditable.defaults.creator'));
+ ->withDefault(config('auditable.defaults.creator'));
}
/**
* Get user class.
- *
- * @return string
*/
- protected function getUserClass()
+ protected function getUserClass(): string
{
if (property_exists($this, 'auditUser')) {
return $this->auditUser;
@@ -47,82 +43,65 @@ protected function getUserClass()
/**
* Get column name for created by.
- *
- * @return string
*/
- public function getCreatedByColumn()
+ public function getCreatedByColumn(): string
{
return defined('static::CREATED_BY') ? static::CREATED_BY : 'created_by';
}
/**
* Get user model who updated the record.
- *
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
- public function updater()
+ public function updater(): BelongsTo
{
return $this->belongsTo($this->getUserClass(), $this->getUpdatedByColumn())
- ->withDefault(config('auditable.defaults.updater'));
+ ->withDefault(config('auditable.defaults.updater'));
}
/**
* Get column name for updated by.
- *
- * @return string
*/
- public function getUpdatedByColumn()
+ public function getUpdatedByColumn(): string
{
return defined('static::UPDATED_BY') ? static::UPDATED_BY : 'updated_by';
}
/**
* Get created by user full name.
- *
- * @return string
*/
- public function getCreatedByNameAttribute()
+ public function getCreatedByNameAttribute(): string
{
return $this->creator->name ?? '';
}
/**
* Get updated by user full name.
- *
- * @return string
*/
- public function getUpdatedByNameAttribute()
+ public function getUpdatedByNameAttribute(): string
{
return $this->updater->name ?? '';
}
/**
* Query scope to limit results to own records.
- *
- * @param \Illuminate\Database\Eloquent\Builder $query
- * @return \Illuminate\Database\Eloquent\Builder
*/
- public function scopeOwned(Builder $query)
+ public function scopeOwned(Builder $query): Builder
{
return $query->where($this->getQualifiedUserIdColumn(), auth()->id());
}
/**
* Get qualified column name for user id.
- *
- * @return string
*/
- public function getQualifiedUserIdColumn()
+ public function getQualifiedUserIdColumn(): string
{
- return $this->getTable() . '.' . $this->getUserInstance()->getKey();
+ return $this->getTable().'.'.$this->getUserInstance()->getKey();
}
/**
* Get Laravel's user class instance.
- *
- * @return \Illuminate\Database\Eloquent\Model
*/
- public function getUserInstance()
+ public function getUserInstance(): Model
{
$class = $this->getUserClass();
diff --git a/src/AuditableTraitObserver.php b/src/AuditableTraitObserver.php
index b9b32aa..b3bd09a 100644
--- a/src/AuditableTraitObserver.php
+++ b/src/AuditableTraitObserver.php
@@ -8,59 +8,60 @@ class AuditableTraitObserver
{
/**
* Model's creating event hook.
- *
- * @param Model $model
*/
- public function creating(Model $model)
+ public function creating(Model $model): void
{
- $createdBy = $model->getCreatedByColumn();
- $updatedBy = $model->getUpdatedByColumn();
+ if (method_exists($model, 'getCreatedByColumn')) {
+ $createdBy = $model->getCreatedByColumn();
- if (! $model->$createdBy) {
- $model->$createdBy = $this->getAuthenticatedUserId();
+ if (! $model->$createdBy) {
+ $model->$createdBy = $this->getAuthenticatedUserId();
+ }
}
- if (! $model->$updatedBy) {
- $model->$updatedBy = $this->getAuthenticatedUserId();
+ if (method_exists($model, 'getUpdatedByColumn')) {
+ $updatedBy = $model->getUpdatedByColumn();
+
+ if (! $model->$updatedBy) {
+ $model->$updatedBy = $this->getAuthenticatedUserId();
+ }
}
}
/**
* Get authenticated user id depending on model's auth guard.
- *
- * @return int
*/
- protected function getAuthenticatedUserId()
+ protected function getAuthenticatedUserId(): int|string|null
{
return auth()->check() ? auth()->id() : null;
}
/**
* Model's updating event hook.
- *
- * @param Model $model
*/
- public function updating(Model $model)
+ public function updating(Model $model): void
{
- $updatedBy = $model->getUpdatedByColumn();
+ if (method_exists($model, 'getUpdatedByColumn')) {
+ $updatedBy = $model->getUpdatedByColumn();
- if (! $model->isDirty($updatedBy)) {
- $model->$updatedBy = $this->getAuthenticatedUserId();
+ if (! $model->isDirty($updatedBy)) {
+ $model->$updatedBy = $this->getAuthenticatedUserId();
+ }
}
}
/**
* Set updatedBy column on save if value is not the same.
- *
- * @param \Illuminate\Database\Eloquent\Model $model
*/
- public function saved(Model $model)
+ public function saved(Model $model): void
{
- $updatedBy = $model->getUpdatedByColumn();
+ if (method_exists($model, 'getUpdatedByColumn')) {
+ $updatedBy = $model->getUpdatedByColumn();
- if ($this->getAuthenticatedUserId() && $model->$updatedBy <> $this->getAuthenticatedUserId()) {
- $model->$updatedBy = $this->getAuthenticatedUserId();
- $model->save();
+ if ($this->getAuthenticatedUserId() && $this->getAuthenticatedUserId() != $model->$updatedBy) {
+ $model->$updatedBy = $this->getAuthenticatedUserId();
+ $model->save();
+ }
}
}
}
diff --git a/src/AuditableWithDeletesTrait.php b/src/AuditableWithDeletesTrait.php
index 86224f5..a945472 100644
--- a/src/AuditableWithDeletesTrait.php
+++ b/src/AuditableWithDeletesTrait.php
@@ -2,8 +2,10 @@
namespace Yajra\Auditable;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
/**
- * @property mixed deleter
+ * @property \Illuminate\Database\Eloquent\Model $deleter
*/
trait AuditableWithDeletesTrait
{
@@ -11,20 +13,16 @@ trait AuditableWithDeletesTrait
/**
* Boot the audit trait for a model.
- *
- * @return void
*/
- public static function bootAuditableWithDeletesTrait()
+ public static function bootAuditableWithDeletesTrait(): void
{
static::observe(new AuditableWithDeletesTraitObserver);
}
/**
* Get user model who deleted the record.
- *
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
- public function deleter()
+ public function deleter(): BelongsTo
{
return $this->belongsTo($this->getUserClass(), $this->getDeletedByColumn())
->withDefault(config('auditable.defaults.deleter'));
@@ -32,20 +30,16 @@ public function deleter()
/**
* Get column name for deleted by.
- *
- * @return string
*/
- public function getDeletedByColumn()
+ public function getDeletedByColumn(): string
{
return defined('static::DELETED_BY') ? static::DELETED_BY : 'deleted_by';
}
/**
* Get deleted by user full name.
- *
- * @return string
*/
- public function getDeletedByNameAttribute()
+ public function getDeletedByNameAttribute(): string
{
return $this->deleter->name ?? '';
}
diff --git a/src/AuditableWithDeletesTraitObserver.php b/src/AuditableWithDeletesTraitObserver.php
index edd1b53..eee478a 100644
--- a/src/AuditableWithDeletesTraitObserver.php
+++ b/src/AuditableWithDeletesTraitObserver.php
@@ -8,36 +8,34 @@ class AuditableWithDeletesTraitObserver
{
/**
* Model's deleting event hook
- *
- * @param Model $model
*/
- public function deleting(Model $model)
+ public function deleting(Model $model): void
{
- $deletedBy = $model->getDeletedByColumn();
+ if (method_exists($model, 'getDeletedByColumn')) {
+ $deletedBy = $model->getDeletedByColumn();
- $model->$deletedBy = $this->getAuthenticatedUserId();
- $model->save();
+ $model->$deletedBy = $this->getAuthenticatedUserId();
+ $model->save();
+ }
}
/**
* Get authenticated user id depending on model's auth guard.
- *
- * @return int
*/
- protected function getAuthenticatedUserId()
+ protected function getAuthenticatedUserId(): int|string|null
{
return auth()->check() ? auth()->id() : null;
}
/**
* Model's restoring event hook
- *
- * @param Model $model
*/
- public function restoring(Model $model)
+ public function restoring(Model $model): void
{
- $deletedBy = $model->getDeletedByColumn();
+ if (method_exists($model, 'getDeletedByColumn')) {
+ $deletedBy = $model->getDeletedByColumn();
- $model->$deletedBy = null;
+ $model->$deletedBy = null;
+ }
}
}
diff --git a/tests/App/Migrations/package_migrations.php b/tests/App/Migrations/package_migrations.php
new file mode 100644
index 0000000..42d8311
--- /dev/null
+++ b/tests/App/Migrations/package_migrations.php
@@ -0,0 +1,33 @@
+id();
+ $table->string('name');
+ $table->string('email');
+ $table->auditable();
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('users');
+ }
+};
diff --git a/tests/App/Models/User.php b/tests/App/Models/User.php
new file mode 100644
index 0000000..96af023
--- /dev/null
+++ b/tests/App/Models/User.php
@@ -0,0 +1,13 @@
+assertTrue(true);
- }
-}
diff --git a/tests/Feature/MacroTest.php b/tests/Feature/MacroTest.php
new file mode 100644
index 0000000..3e0cac1
--- /dev/null
+++ b/tests/Feature/MacroTest.php
@@ -0,0 +1,10 @@
+assertTrue(Blueprint::hasMacro('auditable'));
+ $this->assertTrue(Blueprint::hasMacro('dropAuditable'));
+ $this->assertTrue(Blueprint::hasMacro('auditableWithDeletes'));
+ $this->assertTrue(Blueprint::hasMacro('dropAuditableWithDeletes'));
+});
diff --git a/tests/Feature/TraitTest.php b/tests/Feature/TraitTest.php
new file mode 100644
index 0000000..4e7b4ab
--- /dev/null
+++ b/tests/Feature/TraitTest.php
@@ -0,0 +1,27 @@
+ 'J1',
+ 'email' => 'email1@email.com',
+ ]);
+
+ assertDatabaseCount('users', 1);
+ expect($user->created_by)->toBeNull();
+
+ be($user);
+
+ $user2 = User::forceCreate([
+ 'name' => 'J2',
+ 'email' => 'email2@email.com',
+ ]);
+
+ assertDatabaseCount('users', 2);
+ expect($user2->created_by)->toBe(1);
+ expect($user2->updated_by)->toBe(1);
+});
diff --git a/tests/Pest.php b/tests/Pest.php
new file mode 100644
index 0000000..3d3b50f
--- /dev/null
+++ b/tests/Pest.php
@@ -0,0 +1,46 @@
+in('Feature');
+
+/*
+|--------------------------------------------------------------------------
+| 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.
+|
+*/
+
+expect()->extend('toBeOne', fn () => $this->toBe(1));
+
+/*
+|--------------------------------------------------------------------------
+| 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 something()
+{
+ // ..
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..0018617
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,23 @@
+loadMigrationsFrom(__DIR__.'/App/Migrations');
+ }
+
+ protected function getPackageProviders($app): array
+ {
+ return [
+ \Yajra\Auditable\AuditableServiceProvider::class,
+ ];
+ }
+}
diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php
new file mode 100644
index 0000000..61cd84c
--- /dev/null
+++ b/tests/Unit/ExampleTest.php
@@ -0,0 +1,5 @@
+toBeTrue();
+});