From deca80ba71e6846c9fbb04afb4bb95acad417c68 Mon Sep 17 00:00:00 2001 From: akemidx Date: Wed, 17 May 2023 13:17:48 -0400 Subject: [PATCH 01/31] checkin/out info on side bar --- resources/lang/en/admin/hardware/general.php | 2 +- resources/views/hardware/view.blade.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/resources/lang/en/admin/hardware/general.php b/resources/lang/en/admin/hardware/general.php index b0a48f2ce4..7201d37053 100644 --- a/resources/lang/en/admin/hardware/general.php +++ b/resources/lang/en/admin/hardware/general.php @@ -19,7 +19,7 @@ return [ 'requestable' => 'Requestable', 'requested' => 'Requested', 'not_requestable' => 'Not Requestable', - 'requestable_status_warning' => 'Do not change requestable status', + 'requestable_status_warning' => 'Do not change requestable status', 'restore' => 'Restore Asset', 'pending' => 'Pending', 'undeployable' => 'Undeployable', diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index 50b80de0f2..207f18e680 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -934,6 +934,14 @@ {{ $asset->location->state }} {{ $asset->location->zip }} @endif +
  • + {{ trans('admin/hardware/form.checkout_date') }}: {{ Helper::getFormattedDateObject($asset->last_checkout, 'date', false) }} +
  • + @if (isset($asset->expected_checkin)) +
  • + {{ trans('admin/hardware/form.expected_checkin') }}: {{ Helper::getFormattedDateObject($asset->expected_checkin, 'date', false) }} +
  • + @endif @endif From 6585aa0cf071b5ce40900f7b87c816608cca3da2 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 6 Jun 2023 16:31:14 -0700 Subject: [PATCH 02/31] Add unit tests for company scoping --- tests/Support/Settings.php | 5 + tests/Unit/CompanyScopingTest.php | 169 ++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 tests/Unit/CompanyScopingTest.php diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 70022e53c3..fa8886b751 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -33,6 +33,11 @@ class Settings return $this->update(['full_multiple_companies_support' => 1]); } + public function disableMultipleFullCompanySupport(): Settings + { + return $this->update(['full_multiple_companies_support' => 0]); + } + public function enableWebhook(): Settings { return $this->update([ diff --git a/tests/Unit/CompanyScopingTest.php b/tests/Unit/CompanyScopingTest.php new file mode 100644 index 0000000000..669dd5ed41 --- /dev/null +++ b/tests/Unit/CompanyScopingTest.php @@ -0,0 +1,169 @@ + [Accessory::class], + 'Assets' => [Asset::class], + 'Components' => [Component::class], + 'Consumables' => [Consumable::class], + 'Licenses' => [License::class], + ]; + } + + /** @dataProvider models */ + public function testCompanyScoping($model) + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $modelA = $model::factory()->for($companyA)->create(); + $modelB = $model::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + $this->actingAs($superUser); + $this->assertCanSee($modelA); + $this->assertCanSee($modelB); + + $this->actingAs($userInCompanyA); + $this->assertCanSee($modelA); + $this->assertCanSee($modelB); + + $this->actingAs($userInCompanyB); + $this->assertCanSee($modelA); + $this->assertCanSee($modelB); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAs($superUser); + $this->assertCanSee($modelA); + $this->assertCanSee($modelB); + + $this->actingAs($userInCompanyA); + $this->assertCanSee($modelA); + $this->assertCannotSee($modelB); + + $this->actingAs($userInCompanyB); + $this->assertCannotSee($modelA); + $this->assertCanSee($modelB); + } + + public function testAssetMaintenanceCompanyScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $assetMaintenanceForCompanyA = AssetMaintenance::factory()->for(Asset::factory()->for($companyA))->create(); + $assetMaintenanceForCompanyB = AssetMaintenance::factory()->for(Asset::factory()->for($companyB))->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + $this->actingAs($superUser); + $this->assertCanSee($assetMaintenanceForCompanyA); + $this->assertCanSee($assetMaintenanceForCompanyB); + + $this->actingAs($userInCompanyA); + $this->assertCanSee($assetMaintenanceForCompanyA); + $this->assertCanSee($assetMaintenanceForCompanyB); + + $this->actingAs($userInCompanyB); + $this->assertCanSee($assetMaintenanceForCompanyA); + $this->assertCanSee($assetMaintenanceForCompanyB); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAs($superUser); + $this->assertCanSee($assetMaintenanceForCompanyA); + $this->assertCanSee($assetMaintenanceForCompanyB); + + $this->actingAs($userInCompanyA); + $this->assertCanSee($assetMaintenanceForCompanyA); + $this->assertCannotSee($assetMaintenanceForCompanyB); + + $this->actingAs($userInCompanyB); + $this->assertCannotSee($assetMaintenanceForCompanyA); + $this->assertCanSee($assetMaintenanceForCompanyB); + } + + public function testLicenseSeatCompanyScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $licenseSeatA = LicenseSeat::factory()->for(Asset::factory()->for($companyA))->create(); + $licenseSeatB = LicenseSeat::factory()->for(Asset::factory()->for($companyB))->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + $this->actingAs($superUser); + $this->assertCanSee($licenseSeatA); + $this->assertCanSee($licenseSeatB); + + $this->actingAs($userInCompanyA); + $this->assertCanSee($licenseSeatA); + $this->assertCanSee($licenseSeatB); + + $this->actingAs($userInCompanyB); + $this->assertCanSee($licenseSeatA); + $this->assertCanSee($licenseSeatB); + + $this->settings->enableMultipleFullCompanySupport(); + + $this->actingAs($superUser); + $this->assertCanSee($licenseSeatA); + $this->assertCanSee($licenseSeatB); + + $this->actingAs($userInCompanyA); + $this->assertCanSee($licenseSeatA); + $this->assertCannotSee($licenseSeatB); + + $this->actingAs($userInCompanyB); + $this->assertCannotSee($licenseSeatA); + $this->assertCanSee($licenseSeatB); + } + + private function assertCanSee(Model $model) + { + $this->assertTrue( + get_class($model)::all()->contains($model), + 'User was not able to see expected model' + ); + } + + private function assertCannotSee(Model $model) + { + $this->assertFalse( + get_class($model)::all()->contains($model), + 'User was able to see model from a different company' + ); + } +} From 42a4941ad2ea75e868f76bb8b7a2e08bca5c7559 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 5 Jun 2023 12:17:44 -0700 Subject: [PATCH 03/31] Ensure consumable name is valid in factory --- database/factories/ConsumableFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/factories/ConsumableFactory.php b/database/factories/ConsumableFactory.php index 5444999711..ea303eccae 100644 --- a/database/factories/ConsumableFactory.php +++ b/database/factories/ConsumableFactory.php @@ -27,7 +27,7 @@ class ConsumableFactory extends Factory public function definition() { return [ - 'name' => $this->faker->word(), + 'name' => $this->faker->words(), 'category_id' => Category::factory(), 'user_id' => User::factory()->superuser(), 'item_no' => $this->faker->numberBetween(1000000, 50000000), From 4fb86ad2fbb66d0cf6da66e5a61cf5b30d9fedbe Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 5 Jun 2023 12:57:09 -0700 Subject: [PATCH 04/31] Get name as a string and not an array --- database/factories/ConsumableFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/factories/ConsumableFactory.php b/database/factories/ConsumableFactory.php index ea303eccae..18a116418b 100644 --- a/database/factories/ConsumableFactory.php +++ b/database/factories/ConsumableFactory.php @@ -27,7 +27,7 @@ class ConsumableFactory extends Factory public function definition() { return [ - 'name' => $this->faker->words(), + 'name' => $this->faker->words(3, true), 'category_id' => Category::factory(), 'user_id' => User::factory()->superuser(), 'item_no' => $this->faker->numberBetween(1000000, 50000000), From 48850f35971fb142207eb9c8f77cb9335fe5130f Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 6 Jun 2023 18:02:18 -0700 Subject: [PATCH 05/31] Remove scopeCompanyables call from ComponentsController --- .../Controllers/Api/ComponentsController.php | 4 +- .../Api/Components/ComponentIndexTest.php | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 tests/Feature/Api/Components/ComponentIndexTest.php diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 24eb1044b8..59d12c920e 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -44,9 +44,7 @@ class ComponentsController extends Controller 'notes', ]; - - $components = Company::scopeCompanyables(Component::select('components.*') - ->with('company', 'location', 'category', 'assets', 'supplier')); + $components = Component::with('company', 'location', 'category', 'assets', 'supplier'); if ($request->filled('search')) { $components = $components->TextSearch($request->input('search')); diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php new file mode 100644 index 0000000000..e459e9f8f6 --- /dev/null +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -0,0 +1,77 @@ +count(2)->create(); + + $componentA = Component::factory()->for($companyA)->create(); + $componentB = Component::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewComponents()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewComponents()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + Passport::actingAs($userInCompanyA); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + Passport::actingAs($userInCompanyB); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + Passport::actingAs($userInCompanyA); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseDoesNotContain($response, $componentB); + + Passport::actingAs($userInCompanyB); + $response = $this->sendRequest(); + $this->assertResponseDoesNotContain($response, $componentA); + $this->assertResponseContains($response, $componentB); + } + + private function sendRequest(): TestResponse + { + return $this->getJson(route('api.components.index')); + } + + private function assertResponseContains(TestResponse $response, Component $component) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($component->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, Component $component) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($component->name)); + } +} From a18f5e7fc0c2ce339b2c6247e239820a57c67622 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 14:22:22 -0700 Subject: [PATCH 06/31] Remove scopeCompanyables call from ConsumablesController --- .../Controllers/Api/ConsumablesController.php | 6 +- .../Api/Consumables/ConsumablesIndexTest.php | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 tests/Feature/Api/Consumables/ConsumablesIndexTest.php diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index bac9440dca..385f306c25 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -45,11 +45,7 @@ class ConsumablesController extends Controller 'notes', ]; - - $consumables = Company::scopeCompanyables( - Consumable::select('consumables.*') - ->with('company', 'location', 'category', 'users', 'manufacturer') - ); + $consumables = Consumable::with('company', 'location', 'category', 'users', 'manufacturer'); if ($request->filled('search')) { $consumables = $consumables->TextSearch(e($request->input('search'))); diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php new file mode 100644 index 0000000000..1d1a627c65 --- /dev/null +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -0,0 +1,72 @@ +count(2)->create(); + + $consumableA = Consumable::factory()->for($companyA)->create(); + $consumableB = Consumable::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewConsumables()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewConsumables()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseDoesNotContain($response, $consumableB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseDoesNotContain($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + } + + private function assertResponseContains(TestResponse $response, Consumable $consumable) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($consumable->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, Consumable $consumable) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($consumable->name)); + } +} From 8e6e525b47bdd5cbb0f9d81bdafc614bd532a663 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:09:45 -0700 Subject: [PATCH 07/31] Remove scopeCompanyables call from LicensesController --- .../Controllers/Api/LicensesController.php | 2 +- .../Api/Licenses/LicensesIndexTest.php | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/Api/Licenses/LicensesIndexTest.php diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index df74b60895..e021fc3d3e 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -26,8 +26,8 @@ class LicensesController extends Controller public function index(Request $request) { $this->authorize('view', License::class); - $licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count')); + $licenses = License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count'); if ($request->filled('company_id')) { $licenses->where('company_id', '=', $request->input('company_id')); diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php new file mode 100644 index 0000000000..4deb6bbcbe --- /dev/null +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -0,0 +1,72 @@ +count(2)->create(); + + $licenseA = License::factory()->for($companyA)->create(); + $licenseB = License::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewLicenses()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewLicenses()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseDoesNotContain($response, $licenseB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseDoesNotContain($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + } + + private function assertResponseContains(TestResponse $response, License $license) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($license->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, License $license) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($license->name)); + } +} From 27d4d107bb3a142793b871859f4866c2f23da531 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:10:29 -0700 Subject: [PATCH 08/31] Scaffold test before removing scopeCompanyables call from DepartmentsController --- database/factories/UserFactory.php | 9 +++ .../Api/Departments/DepartmentsIndexTest.php | 74 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/Feature/Api/Departments/DepartmentsIndexTest.php diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 8aa38d2325..586cb7186b 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -271,6 +271,15 @@ class UserFactory extends Factory }); } + public function viewDepartments() + { + return $this->state(function () { + return [ + 'permissions' => '{"departments.view":"1"}', + ]; + }); + } + public function viewLicenses() { return $this->state(function () { diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php new file mode 100644 index 0000000000..a79a4f89ef --- /dev/null +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -0,0 +1,74 @@ +markTestIncomplete(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $departmentA = Department::factory()->for($companyA)->create(); + $departmentB = Department::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewDepartments()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewDepartments()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseDoesNotContain($response, $departmentB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseDoesNotContain($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + } + + private function assertResponseContains(TestResponse $response, Department $department) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($department->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, Department $department) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($department->name)); + } +} From abaf59c9902a54515212f29f370e2d58b77e5d68 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:16:30 -0700 Subject: [PATCH 09/31] Extract and use helper methods --- .../Api/Components/ComponentIndexTest.php | 36 +++++++----------- .../Api/Consumables/ConsumablesIndexTest.php | 37 +++++++------------ .../Api/Departments/DepartmentsIndexTest.php | 37 +++++++------------ .../Api/Licenses/LicensesIndexTest.php | 37 +++++++------------ tests/Support/InteractsWithResponses.php | 19 ++++++++++ 5 files changed, 75 insertions(+), 91 deletions(-) create mode 100644 tests/Support/InteractsWithResponses.php diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index e459e9f8f6..978d4be10b 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -7,11 +7,13 @@ use App\Models\Component; use App\Models\User; use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ComponentIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testComponentIndexAdheresToCompanyScoping() @@ -29,49 +31,39 @@ class ComponentIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyB); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseDoesNotContain($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseDoesNotContainInRows($response, $componentB); Passport::actingAs($userInCompanyB); $response = $this->sendRequest(); - $this->assertResponseDoesNotContain($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseDoesNotContainInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); } private function sendRequest(): TestResponse { return $this->getJson(route('api.components.index')); } - - private function assertResponseContains(TestResponse $response, Component $component) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($component->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, Component $component) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($component->name)); - } } diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php index 1d1a627c65..11a4d79afa 100644 --- a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -5,13 +5,14 @@ namespace Tests\Feature\Api\Consumables; use App\Models\Company; use App\Models\Consumable; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ConsumablesIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testConsumableIndexAdheresToCompanyScoping() @@ -29,44 +30,34 @@ class ConsumablesIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseDoesNotContain($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseDoesNotContainInRows($response, $consumableB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseDoesNotContain($response, $consumableA); - $this->assertResponseContains($response, $consumableB); - } - - private function assertResponseContains(TestResponse $response, Consumable $consumable) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($consumable->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, Consumable $consumable) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($consumable->name)); + $this->assertResponseDoesNotContainInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); } } diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index a79a4f89ef..d791c79e93 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -5,13 +5,14 @@ namespace Tests\Feature\Api\Departments; use App\Models\Company; use App\Models\Department; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class DepartmentsIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testDepartmentsIndexAdheresToCompanyScoping() @@ -31,44 +32,34 @@ class DepartmentsIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseDoesNotContain($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseDoesNotContainInRows($response, $departmentB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseDoesNotContain($response, $departmentA); - $this->assertResponseContains($response, $departmentB); - } - - private function assertResponseContains(TestResponse $response, Department $department) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($department->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, Department $department) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($department->name)); + $this->assertResponseDoesNotContainInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); } } diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php index 4deb6bbcbe..404eb31238 100644 --- a/tests/Feature/Api/Licenses/LicensesIndexTest.php +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -5,13 +5,14 @@ namespace Tests\Feature\Api\Licenses; use App\Models\Company; use App\Models\License; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class LicensesIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testLicensesIndexAdheresToCompanyScoping() @@ -29,44 +30,34 @@ class LicensesIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseDoesNotContain($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseDoesNotContainInRows($response, $licenseB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseDoesNotContain($response, $licenseA); - $this->assertResponseContains($response, $licenseB); - } - - private function assertResponseContains(TestResponse $response, License $license) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($license->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, License $license) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($license->name)); + $this->assertResponseDoesNotContainInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); } } diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php new file mode 100644 index 0000000000..3206aaea9d --- /dev/null +++ b/tests/Support/InteractsWithResponses.php @@ -0,0 +1,19 @@ +assertTrue(collect($response['rows'])->pluck($field)->contains($model->{$field})); + } + + private function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $field = 'name') + { + $this->assertFalse(collect($response['rows'])->pluck($field)->contains($model->{$field})); + } +} From 0f6051bbe574c923be5953d1074d7d776f4e825b Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:18:02 -0700 Subject: [PATCH 10/31] Inline method call --- .../Api/Components/ComponentIndexTest.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index 978d4be10b..845ce29b99 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Components; use App\Models\Company; use App\Models\Component; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; @@ -30,40 +29,35 @@ class ComponentIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyB); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseDoesNotContainInRows($response, $componentB); Passport::actingAs($userInCompanyB); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseDoesNotContainInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); } - - private function sendRequest(): TestResponse - { - return $this->getJson(route('api.components.index')); - } } From 6f5252449e4e5dad664c77ff4e73da4cd518fc7e Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:25:18 -0700 Subject: [PATCH 11/31] Scaffold test before removing scopeCompanyables call from UsersController --- tests/Feature/Api/Users/UsersIndexTest.php | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/Feature/Api/Users/UsersIndexTest.php diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php new file mode 100644 index 0000000000..16893cd174 --- /dev/null +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -0,0 +1,64 @@ +markTestIncomplete(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $userA = User::factory()->for($companyA)->create(); + $userB = User::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewUsers()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewUsers()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseDoesNotContainInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseDoesNotContainInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + } +} From 7672861b96ac5ba1487d99153cc6ce1a6b0c344d Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 17:38:23 -0700 Subject: [PATCH 12/31] Scaffold test before removing scopeCompanyables call from DashboardController --- tests/Feature/DashboardTest.php | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/Feature/DashboardTest.php diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php new file mode 100644 index 0000000000..c5c41d268e --- /dev/null +++ b/tests/Feature/DashboardTest.php @@ -0,0 +1,38 @@ +actingAs(User::factory()->create()) + ->get(route('home')) + ->assertRedirect(route('view-assets')); + } + + public function testUserCountIsScopedByCompany() + { + $this->markTestIncomplete(); + + $this->settings->enableMultipleFullCompanySupport(); + + $companyA = Company::factory()->has(User::factory()->count(1))->create(); + Company::factory()->has(User::factory()->count(3))->create(); + + $adminForCompanyA = $companyA->users()->save(User::factory()->admin()->make()); + + $this->actingAs($adminForCompanyA) + ->get(route('home')) + ->assertOk() + ->assertViewIs('dashboard') + ->assertViewHas('counts', fn($counts) => $counts['user'] === $companyA->users->count()); + } +} From 65e8e4e1632cc009ff54b13b1d359f5a50595ca3 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 16:18:09 -0700 Subject: [PATCH 13/31] Guard against attempting to use invalid property --- tests/Support/InteractsWithResponses.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php index 3206aaea9d..9a1965eefe 100644 --- a/tests/Support/InteractsWithResponses.php +++ b/tests/Support/InteractsWithResponses.php @@ -4,16 +4,30 @@ namespace Tests\Support; use Illuminate\Database\Eloquent\Model; use Illuminate\Testing\TestResponse; +use RuntimeException; trait InteractsWithResponses { - private function assertResponseContainsInRows(TestResponse $response, Model $model, string $field = 'name') + protected function assertResponseContainsInRows(TestResponse $response, Model $model, string $property = 'name') { - $this->assertTrue(collect($response['rows'])->pluck($field)->contains($model->{$field})); + $this->guardAgainstNullProperty($model, $property); + + $this->assertTrue(collect($response['rows'])->pluck($property)->contains($model->{$property})); } - private function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $field = 'name') + protected function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $property = 'name') { - $this->assertFalse(collect($response['rows'])->pluck($field)->contains($model->{$field})); + $this->guardAgainstNullProperty($model, $property); + + $this->assertFalse(collect($response['rows'])->pluck($property)->contains($model->{$property})); + } + + private function guardAgainstNullProperty(Model $model, string $property): void + { + if (is_null($model->{$property})) { + throw new RuntimeException( + "The property ({$property}) is null on the model which isn't helpful for comparison." + ); + } } } From af77fefc61f09fe420a65f6232eefcdb408514b1 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 16:19:56 -0700 Subject: [PATCH 14/31] Scaffold test before removing scopeCompanyables call from AssetsController --- tests/Feature/Api/Assets/AssetIndexTest.php | 49 +++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/Feature/Api/Assets/AssetIndexTest.php b/tests/Feature/Api/Assets/AssetIndexTest.php index 3618c6e01e..9ca415c74d 100644 --- a/tests/Feature/Api/Assets/AssetIndexTest.php +++ b/tests/Feature/Api/Assets/AssetIndexTest.php @@ -3,14 +3,17 @@ namespace Tests\Feature\Api\Assets; use App\Models\Asset; +use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testAssetIndexReturnsExpectedAssets() @@ -32,4 +35,50 @@ class AssetIndexTest extends TestCase ]) ->assertJson(fn(AssertableJson $json) => $json->has('rows', 3)->etc()); } + + public function testAssetIndexAdheresToCompanyScoping() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $assetA = Asset::factory()->for($companyA)->create(); + $assetB = Asset::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewAssets()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewAssets()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + } } From fd55c99b87c5e68d524940a2fbfcad155cf0a8dc Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 16:29:44 -0700 Subject: [PATCH 15/31] Remove scopeCompanyables call from AssetsController@index --- app/Http/Controllers/Api/AssetsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index ced1f013c6..1169f652f2 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -115,7 +115,7 @@ class AssetsController extends Controller $allowed_columns[] = $field->db_column_name(); } - $assets = Company::scopeCompanyables(Asset::select('assets.*'), 'company_id', 'assets') + $assets = Asset::select('assets.*') ->with('location', 'assetstatus', 'company', 'defaultLoc','assignedTo', 'model.category', 'model.manufacturer', 'model.fieldset','supplier'); //it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users. From effd96928485cd342608d419e90dcaa2501e8dc3 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 17:15:02 -0700 Subject: [PATCH 16/31] Scaffold test before removing scopeCompanyables call from AssetsController@selectlist --- .../Api/Assets/AssetsForSelectListTest.php | 81 +++++++++++++++++++ tests/Support/InteractsWithResponses.php | 14 ++++ 2 files changed, 95 insertions(+) create mode 100644 tests/Feature/Api/Assets/AssetsForSelectListTest.php diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php new file mode 100644 index 0000000000..625d623b76 --- /dev/null +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -0,0 +1,81 @@ +create(['asset_tag' => '0001']); + Asset::factory()->create(['asset_tag' => '0002']); + + Passport::actingAs(User::factory()->create()); + + $response = $this->getJson(route('assets.selectlist', ['search' => '000']))->assertOk(); + + $results = collect($response->json('results')); + + $this->assertEquals(2, $results->count()); + $this->assertTrue($results->pluck('text')->contains(fn($text) => str_contains($text, '0001'))); + $this->assertTrue($results->pluck('text')->contains(fn($text) => str_contains($text, '0002'))); + } + + public function testAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled() + { + $this->markTestIncomplete(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $assetA = Asset::factory()->for($companyA)->create(['asset_tag' => '0001']); + $assetB = Asset::factory()->for($companyB)->create(['asset_tag' => '0002']); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewAssets()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewAssets()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseDoesNotContainInResults($response, $assetB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseDoesNotContainInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + } +} diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php index 9a1965eefe..1fb6f311be 100644 --- a/tests/Support/InteractsWithResponses.php +++ b/tests/Support/InteractsWithResponses.php @@ -22,6 +22,20 @@ trait InteractsWithResponses $this->assertFalse(collect($response['rows'])->pluck($property)->contains($model->{$property})); } + protected function assertResponseContainsInResults(TestResponse $response, Model $model, string $property = 'id') + { + $this->guardAgainstNullProperty($model, $property); + + $this->assertTrue(collect($response->json('results'))->pluck('id')->contains($model->{$property})); + } + + protected function assertResponseDoesNotContainInResults(TestResponse $response, Model $model, string $property = 'id') + { + $this->guardAgainstNullProperty($model, $property); + + $this->assertFalse(collect($response->json('results'))->pluck('id')->contains($model->{$property})); + } + private function guardAgainstNullProperty(Model $model, string $property): void { if (is_null($model->{$property})) { From 0a5e1e31904f37c953ce75dfde23ac978c323f90 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 17:21:36 -0700 Subject: [PATCH 17/31] Remove scopeCompanyables call from AssetsController@selectlist --- app/Http/Controllers/Api/AssetsController.php | 4 ++-- tests/Feature/Api/Assets/AssetsForSelectListTest.php | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 1169f652f2..e22a037a89 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -477,7 +477,7 @@ class AssetsController extends Controller public function selectlist(Request $request) { - $assets = Company::scopeCompanyables(Asset::select([ + $assets = Asset::select([ 'assets.id', 'assets.name', 'assets.asset_tag', @@ -485,7 +485,7 @@ class AssetsController extends Controller 'assets.assigned_to', 'assets.assigned_type', 'assets.status_id', - ])->with('model', 'assetstatus', 'assignedTo')->NotArchived(), 'company_id', 'assets'); + ])->with('model', 'assetstatus', 'assignedTo')->NotArchived(); if ($request->filled('assetStatusType') && $request->input('assetStatusType') === 'RTD') { $assets = $assets->RTD(); diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php index 625d623b76..fbc5a1e332 100644 --- a/tests/Feature/Api/Assets/AssetsForSelectListTest.php +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -33,8 +33,6 @@ class AssetsForSelectListTest extends TestCase public function testAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled() { - $this->markTestIncomplete(); - [$companyA, $companyB] = Company::factory()->count(2)->create(); $assetA = Asset::factory()->for($companyA)->create(['asset_tag' => '0001']); From 74b072f1b5d68a0fa2289f0b7854926e17ea227e Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 12:36:30 -0700 Subject: [PATCH 18/31] Improve messaging in testing helper --- tests/Support/InteractsWithResponses.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php index 1fb6f311be..03faf0ef22 100644 --- a/tests/Support/InteractsWithResponses.php +++ b/tests/Support/InteractsWithResponses.php @@ -40,7 +40,7 @@ trait InteractsWithResponses { if (is_null($model->{$property})) { throw new RuntimeException( - "The property ({$property}) is null on the model which isn't helpful for comparison." + "The property ({$property}) either does not exist or is null on the model which isn't helpful for comparison." ); } } From ab5fed09dbe74263ffb92726772463278d0dfa84 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 12:36:43 -0700 Subject: [PATCH 19/31] Remove scopeCompanyables call from AssetsController@requestable --- app/Http/Controllers/Api/AssetsController.php | 5 +- database/factories/AssetFactory.php | 10 +++ .../Api/Assets/RequestableAssetsTest.php | 81 +++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 tests/Feature/Api/Assets/RequestableAssetsTest.php diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index e22a037a89..e3ae9e3445 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -1030,9 +1030,10 @@ class AssetsController extends Controller { $this->authorize('viewRequestable', Asset::class); - $assets = Company::scopeCompanyables(Asset::select('assets.*'), 'company_id', 'assets') + $assets = Asset::select('assets.*') ->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo', - 'model.category', 'model.manufacturer', 'model.fieldset', 'supplier')->requestableAssets(); + 'model.category', 'model.manufacturer', 'model.fieldset', 'supplier') + ->requestableAssets(); $offset = request('offset', 0); $limit = $request->input('limit', 50); diff --git a/database/factories/AssetFactory.php b/database/factories/AssetFactory.php index cd3e0f8391..0e0c3931d8 100644 --- a/database/factories/AssetFactory.php +++ b/database/factories/AssetFactory.php @@ -328,4 +328,14 @@ class AssetFactory extends Factory ]; }); } + + public function requestable() + { + return $this->state(['requestable' => true]); + } + + public function nonrequestable() + { + return $this->state(['requestable' => false]); + } } diff --git a/tests/Feature/Api/Assets/RequestableAssetsTest.php b/tests/Feature/Api/Assets/RequestableAssetsTest.php new file mode 100644 index 0000000000..7c9b4e1204 --- /dev/null +++ b/tests/Feature/Api/Assets/RequestableAssetsTest.php @@ -0,0 +1,81 @@ +create()); + $this->getJson(route('api.assets.requestable'))->assertForbidden(); + } + + public function testReturnsRequestableAssets() + { + $requestableAsset = Asset::factory()->requestable()->create(['asset_tag' => 'requestable']); + $nonRequestableAsset = Asset::factory()->nonrequestable()->create(['asset_tag' => 'non-requestable']); + + Passport::actingAs(User::factory()->viewRequestableAssets()->create()); + $response = $this->getJson(route('api.assets.requestable'))->assertOk(); + + $this->assertResponseContainsInRows($response, $requestableAsset, 'asset_tag'); + $this->assertResponseDoesNotContainInRows($response, $nonRequestableAsset, 'asset_tag'); + } + + public function testRequestableAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled() + { + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $assetA = Asset::factory()->requestable()->for($companyA)->create(['asset_tag' => '0001']); + $assetB = Asset::factory()->requestable()->for($companyB)->create(['asset_tag' => '0002']); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewRequestableAssets()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewRequestableAssets()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + } +} From a333d7b72fbaa56005316642fce584eda9eeb9a2 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 12:48:09 -0700 Subject: [PATCH 20/31] Add context to incomplete tests --- tests/Feature/Api/Departments/DepartmentsIndexTest.php | 4 +++- tests/Feature/Api/Users/UsersIndexTest.php | 4 +++- tests/Feature/DashboardTest.php | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index d791c79e93..7e813ad9cb 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -17,7 +17,9 @@ class DepartmentsIndexTest extends TestCase public function testDepartmentsIndexAdheresToCompanyScoping() { - $this->markTestIncomplete(); + $this->markTestIncomplete( + 'Waiting for removal of Company::scopeCompanyables in DepartmentsController@index' + ); [$companyA, $companyB] = Company::factory()->count(2)->create(); diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php index 16893cd174..b48da4483d 100644 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -16,7 +16,9 @@ class UsersIndexTest extends TestCase public function testUsersIndexAdheresToCompanyScoping() { - $this->markTestIncomplete(); + $this->markTestIncomplete( + 'Waiting for removal of Company::scopeCompanyables in UsersController@index' + ); [$companyA, $companyB] = Company::factory()->count(2)->create(); diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index c5c41d268e..1772eac316 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -20,7 +20,9 @@ class DashboardTest extends TestCase public function testUserCountIsScopedByCompany() { - $this->markTestIncomplete(); + $this->markTestIncomplete( + 'Waiting for removal of Company::scopeCompanyables in DashboardController@index' + ); $this->settings->enableMultipleFullCompanySupport(); From a8133f62e81cc3bdd3aebb177515053c3d7e6e52 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 13:07:49 -0700 Subject: [PATCH 21/31] Add explicit select back to query --- app/Http/Controllers/Api/ConsumablesController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index 385f306c25..ba7e6fb302 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -45,7 +45,8 @@ class ConsumablesController extends Controller 'notes', ]; - $consumables = Consumable::with('company', 'location', 'category', 'users', 'manufacturer'); + $consumables = Consumable::select('consumables.*') + ->with('company', 'location', 'category', 'users', 'manufacturer'); if ($request->filled('search')) { $consumables = $consumables->TextSearch(e($request->input('search'))); From 8aae5beabafb6f58995bad31aa34359605ad1cfc Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 13:09:08 -0700 Subject: [PATCH 22/31] Add explicit select back to query --- app/Http/Controllers/Api/ComponentsController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 59d12c920e..8b51344424 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -44,7 +44,8 @@ class ComponentsController extends Controller 'notes', ]; - $components = Component::with('company', 'location', 'category', 'assets', 'supplier'); + $components = Component::select('components.*') + ->with('company', 'location', 'category', 'assets', 'supplier'); if ($request->filled('search')) { $components = $components->TextSearch($request->input('search')); From a35d83d14a07d3bc1e7044be36c2e4af25f32c79 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 14:41:56 -0700 Subject: [PATCH 23/31] Migrate to response macros for readability --- tests/Feature/Api/Assets/AssetIndexTest.php | 38 +++++------ .../Api/Assets/AssetsForSelectListTest.php | 38 +++++------ .../Api/Assets/RequestableAssetsTest.php | 46 +++++++------ .../Api/Components/ComponentIndexTest.php | 38 +++++------ .../Api/Consumables/ConsumablesIndexTest.php | 38 +++++------ .../Api/Departments/DepartmentsIndexTest.php | 38 +++++------ .../Api/Licenses/LicensesIndexTest.php | 38 +++++------ tests/Feature/Api/Users/UsersIndexTest.php | 38 +++++------ tests/Support/CustomTestMacros.php | 66 +++++++++++++++++++ tests/Support/InteractsWithResponses.php | 47 ------------- tests/TestCase.php | 4 ++ 11 files changed, 218 insertions(+), 211 deletions(-) create mode 100644 tests/Support/CustomTestMacros.php delete mode 100644 tests/Support/InteractsWithResponses.php diff --git a/tests/Feature/Api/Assets/AssetIndexTest.php b/tests/Feature/Api/Assets/AssetIndexTest.php index 9ca415c74d..0fe3a4d306 100644 --- a/tests/Feature/Api/Assets/AssetIndexTest.php +++ b/tests/Feature/Api/Assets/AssetIndexTest.php @@ -7,13 +7,11 @@ use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testAssetIndexReturnsExpectedAssets() @@ -50,35 +48,35 @@ class AssetIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); } } diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php index fbc5a1e332..a3210b9886 100644 --- a/tests/Feature/Api/Assets/AssetsForSelectListTest.php +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -6,13 +6,11 @@ use App\Models\Asset; use App\Models\Company; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetsForSelectListTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testAssetsCanBeSearchedForByAssetTag() @@ -45,35 +43,35 @@ class AssetsForSelectListTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseDoesNotContainInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseDoesNotContainInResults($assetB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseDoesNotContainInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseDoesNotContainInResults($assetA) + ->assertResponseContainsInResults($assetB); } } diff --git a/tests/Feature/Api/Assets/RequestableAssetsTest.php b/tests/Feature/Api/Assets/RequestableAssetsTest.php index 7c9b4e1204..7ecddeaa02 100644 --- a/tests/Feature/Api/Assets/RequestableAssetsTest.php +++ b/tests/Feature/Api/Assets/RequestableAssetsTest.php @@ -6,13 +6,11 @@ use App\Models\Asset; use App\Models\Company; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class RequestableAssetsTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testViewingRequestableAssetsRequiresCorrectPermission() @@ -27,10 +25,10 @@ class RequestableAssetsTest extends TestCase $nonRequestableAsset = Asset::factory()->nonrequestable()->create(['asset_tag' => 'non-requestable']); Passport::actingAs(User::factory()->viewRequestableAssets()->create()); - $response = $this->getJson(route('api.assets.requestable'))->assertOk(); - - $this->assertResponseContainsInRows($response, $requestableAsset, 'asset_tag'); - $this->assertResponseDoesNotContainInRows($response, $nonRequestableAsset, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertOk() + ->assertResponseContainsInRows($requestableAsset, 'asset_tag') + ->assertResponseDoesNotContainInRows($nonRequestableAsset, 'asset_tag'); } public function testRequestableAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled() @@ -47,35 +45,35 @@ class RequestableAssetsTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); } } diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index 845ce29b99..276f22e6f1 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\Component; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ComponentIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testComponentIndexAdheresToCompanyScoping() @@ -29,35 +27,35 @@ class ComponentIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseDoesNotContainInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseDoesNotContainInRows($componentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseDoesNotContainInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseDoesNotContainInRows($componentA) + ->assertResponseContainsInRows($componentB); } } diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php index 11a4d79afa..6e6e809c6c 100644 --- a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\Consumable; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ConsumablesIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testConsumableIndexAdheresToCompanyScoping() @@ -29,35 +27,35 @@ class ConsumablesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseDoesNotContainInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseDoesNotContainInRows($consumableB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseDoesNotContainInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseDoesNotContainInRows($consumableA) + ->assertResponseContainsInRows($consumableB); } } diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index 7e813ad9cb..9570e85307 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\Department; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class DepartmentsIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testDepartmentsIndexAdheresToCompanyScoping() @@ -33,35 +31,35 @@ class DepartmentsIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseDoesNotContainInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseDoesNotContainInRows($departmentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseDoesNotContainInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseDoesNotContainInRows($departmentA) + ->assertResponseContainsInRows($departmentB); } } diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php index 404eb31238..fd85239928 100644 --- a/tests/Feature/Api/Licenses/LicensesIndexTest.php +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\License; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class LicensesIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testLicensesIndexAdheresToCompanyScoping() @@ -29,35 +27,35 @@ class LicensesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseDoesNotContainInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseDoesNotContainInRows($licenseB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseDoesNotContainInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseDoesNotContainInRows($licenseA) + ->assertResponseContainsInRows($licenseB); } } diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php index b48da4483d..ed91976ccb 100644 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -5,13 +5,11 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class UsersIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testUsersIndexAdheresToCompanyScoping() @@ -32,35 +30,35 @@ class UsersIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseDoesNotContainInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseDoesNotContainInRows($userB, 'first_name'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseDoesNotContainInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseDoesNotContainInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); } } diff --git a/tests/Support/CustomTestMacros.php b/tests/Support/CustomTestMacros.php new file mode 100644 index 0000000000..0a30d7c243 --- /dev/null +++ b/tests/Support/CustomTestMacros.php @@ -0,0 +1,66 @@ +{$property})) { + throw new RuntimeException( + "The property ({$property}) either does not exist or is null on the model which isn't helpful for comparison." + ); + } + }; + + TestResponse::macro( + 'assertResponseContainsInRows', + function (Model $model, string $property = 'name') use ($guardAgainstNullProperty) { + $guardAgainstNullProperty($model, $property); + + Assert::assertTrue(collect($this['rows'])->pluck($property)->contains($model->{$property})); + + return $this; + } + ); + + TestResponse::macro( + 'assertResponseDoesNotContainInRows', + function (Model $model, string $property = 'name') use ($guardAgainstNullProperty) { + $guardAgainstNullProperty($model, $property); + + Assert::assertFalse(collect($this['rows'])->pluck($property)->contains($model->{$property})); + + return $this; + } + ); + + TestResponse::macro( + 'assertResponseContainsInResults', + function (Model $model, string $property = 'id') use ($guardAgainstNullProperty) { + $guardAgainstNullProperty($model, $property); + + Assert::assertTrue(collect($this->json('results'))->pluck('id')->contains($model->{$property})); + + return $this; + } + ); + + TestResponse::macro( + 'assertResponseDoesNotContainInResults', + function (Model $model, string $property = 'id') use ($guardAgainstNullProperty) { + $guardAgainstNullProperty($model, $property); + + Assert::assertFalse(collect($this->json('results'))->pluck('id')->contains($model->{$property})); + + return $this; + } + ); + } +} diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php deleted file mode 100644 index 03faf0ef22..0000000000 --- a/tests/Support/InteractsWithResponses.php +++ /dev/null @@ -1,47 +0,0 @@ -guardAgainstNullProperty($model, $property); - - $this->assertTrue(collect($response['rows'])->pluck($property)->contains($model->{$property})); - } - - protected function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $property = 'name') - { - $this->guardAgainstNullProperty($model, $property); - - $this->assertFalse(collect($response['rows'])->pluck($property)->contains($model->{$property})); - } - - protected function assertResponseContainsInResults(TestResponse $response, Model $model, string $property = 'id') - { - $this->guardAgainstNullProperty($model, $property); - - $this->assertTrue(collect($response->json('results'))->pluck('id')->contains($model->{$property})); - } - - protected function assertResponseDoesNotContainInResults(TestResponse $response, Model $model, string $property = 'id') - { - $this->guardAgainstNullProperty($model, $property); - - $this->assertFalse(collect($response->json('results'))->pluck('id')->contains($model->{$property})); - } - - private function guardAgainstNullProperty(Model $model, string $property): void - { - if (is_null($model->{$property})) { - throw new RuntimeException( - "The property ({$property}) either does not exist or is null on the model which isn't helpful for comparison." - ); - } - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php index 28051c7c7f..4a5c3da692 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -5,11 +5,13 @@ namespace Tests; use App\Http\Middleware\SecurityHeaders; use Illuminate\Foundation\Testing\LazilyRefreshDatabase; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; +use Tests\Support\CustomTestMacros; use Tests\Support\InteractsWithSettings; abstract class TestCase extends BaseTestCase { use CreatesApplication; + use CustomTestMacros; use LazilyRefreshDatabase; private array $globallyDisabledMiddleware = [ @@ -25,5 +27,7 @@ abstract class TestCase extends BaseTestCase if (collect(class_uses_recursive($this))->contains(InteractsWithSettings::class)) { $this->initializeSettings(); } + + $this->registerCustomMacros(); } } From acd06927ac09c32dd88773ec1bc9ca9782c5acf5 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 17:37:30 -0700 Subject: [PATCH 24/31] Add helper method for authenticating with passport --- tests/Feature/Api/Assets/AssetIndexTest.php | 41 ++++++++-------- .../Api/Assets/AssetsForSelectListTest.php | 31 ++++++------ .../Api/Assets/RequestableAssetsTest.php | 34 ++++++------- .../Api/Components/ComponentIndexTest.php | 25 +++++----- .../Api/Consumables/ConsumablesIndexTest.php | 25 +++++----- .../Api/Departments/DepartmentsIndexTest.php | 25 +++++----- .../Api/Licenses/LicensesIndexTest.php | 25 +++++----- .../Api/Users/UsersForSelectListTest.php | 20 ++++---- tests/Feature/Api/Users/UsersIndexTest.php | 49 +++++++++---------- tests/Feature/Api/Users/UsersSearchTest.php | 6 +-- tests/Support/InteractsWithAuthentication.php | 16 ++++++ tests/TestCase.php | 2 + 12 files changed, 156 insertions(+), 143 deletions(-) create mode 100644 tests/Support/InteractsWithAuthentication.php diff --git a/tests/Feature/Api/Assets/AssetIndexTest.php b/tests/Feature/Api/Assets/AssetIndexTest.php index 0fe3a4d306..778483c1c9 100644 --- a/tests/Feature/Api/Assets/AssetIndexTest.php +++ b/tests/Feature/Api/Assets/AssetIndexTest.php @@ -6,7 +6,6 @@ use App\Models\Asset; use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -18,14 +17,14 @@ class AssetIndexTest extends TestCase { Asset::factory()->count(3)->create(); - Passport::actingAs(User::factory()->superuser()->create()); - $this->getJson( - route('api.assets.index', [ - 'sort' => 'name', - 'order' => 'asc', - 'offset' => '0', - 'limit' => '20', - ])) + $this->actingAsForApi(User::factory()->superuser()->create()) + ->getJson( + route('api.assets.index', [ + 'sort' => 'name', + 'order' => 'asc', + 'offset' => '0', + 'limit' => '20', + ])) ->assertOk() ->assertJsonStructure([ 'total', @@ -47,35 +46,35 @@ class AssetIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.index')) ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); } diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php index a3210b9886..cccae38d38 100644 --- a/tests/Feature/Api/Assets/AssetsForSelectListTest.php +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Assets; use App\Models\Asset; use App\Models\Company; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -18,9 +17,9 @@ class AssetsForSelectListTest extends TestCase Asset::factory()->create(['asset_tag' => '0001']); Asset::factory()->create(['asset_tag' => '0002']); - Passport::actingAs(User::factory()->create()); - - $response = $this->getJson(route('assets.selectlist', ['search' => '000']))->assertOk(); + $response = $this->actingAsForApi(User::factory()->create()) + ->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertOk(); $results = collect($response->json('results')); @@ -42,35 +41,35 @@ class AssetsForSelectListTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($superUser) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($superUser) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseDoesNotContainInResults($assetB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseDoesNotContainInResults($assetA) ->assertResponseContainsInResults($assetB); } diff --git a/tests/Feature/Api/Assets/RequestableAssetsTest.php b/tests/Feature/Api/Assets/RequestableAssetsTest.php index 7ecddeaa02..8649b1b00b 100644 --- a/tests/Feature/Api/Assets/RequestableAssetsTest.php +++ b/tests/Feature/Api/Assets/RequestableAssetsTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Assets; use App\Models\Asset; use App\Models\Company; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -15,8 +14,9 @@ class RequestableAssetsTest extends TestCase public function testViewingRequestableAssetsRequiresCorrectPermission() { - Passport::actingAs(User::factory()->create()); - $this->getJson(route('api.assets.requestable'))->assertForbidden(); + $this->actingAsForApi(User::factory()->create()) + ->getJson(route('api.assets.requestable')) + ->assertForbidden(); } public function testReturnsRequestableAssets() @@ -24,8 +24,8 @@ class RequestableAssetsTest extends TestCase $requestableAsset = Asset::factory()->requestable()->create(['asset_tag' => 'requestable']); $nonRequestableAsset = Asset::factory()->nonrequestable()->create(['asset_tag' => 'non-requestable']); - Passport::actingAs(User::factory()->viewRequestableAssets()->create()); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi(User::factory()->viewRequestableAssets()->create()) + ->getJson(route('api.assets.requestable')) ->assertOk() ->assertResponseContainsInRows($requestableAsset, 'asset_tag') ->assertResponseDoesNotContainInRows($nonRequestableAsset, 'asset_tag'); @@ -44,35 +44,35 @@ class RequestableAssetsTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.requestable')) ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); } diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index 276f22e6f1..ee83b7a46d 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Components; use App\Models\Company; use App\Models\Component; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -26,35 +25,35 @@ class ComponentIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseDoesNotContainInRows($componentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.components.index')) ->assertResponseDoesNotContainInRows($componentA) ->assertResponseContainsInRows($componentB); } diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php index 6e6e809c6c..33c10ed078 100644 --- a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Consumables; use App\Models\Company; use App\Models\Consumable; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -26,35 +25,35 @@ class ConsumablesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseDoesNotContainInRows($consumableB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.consumables.index')) ->assertResponseDoesNotContainInRows($consumableA) ->assertResponseContainsInRows($consumableB); } diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index 9570e85307..1067ec74c7 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Departments; use App\Models\Company; use App\Models\Department; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -30,35 +29,35 @@ class DepartmentsIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseDoesNotContainInRows($departmentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.departments.index')) ->assertResponseDoesNotContainInRows($departmentA) ->assertResponseContainsInRows($departmentB); } diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php index fd85239928..a21a27da73 100644 --- a/tests/Feature/Api/Licenses/LicensesIndexTest.php +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Licenses; use App\Models\Company; use App\Models\License; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -26,35 +25,35 @@ class LicensesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseDoesNotContainInRows($licenseB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.licenses.index')) ->assertResponseDoesNotContainInRows($licenseA) ->assertResponseContainsInRows($licenseB); } diff --git a/tests/Feature/Api/Users/UsersForSelectListTest.php b/tests/Feature/Api/Users/UsersForSelectListTest.php index 8cdf700f04..ba4beb211b 100644 --- a/tests/Feature/Api/Users/UsersForSelectListTest.php +++ b/tests/Feature/Api/Users/UsersForSelectListTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -17,8 +16,8 @@ class UsersForSelectListTest extends TestCase { $users = User::factory()->superuser()->count(3)->create(); - Passport::actingAs($users->first()); - $this->getJson(route('api.users.selectlist')) + $this->actingAsForApi($users->first()) + ->getJson(route('api.users.selectlist')) ->assertOk() ->assertJsonStructure([ 'results', @@ -34,8 +33,9 @@ class UsersForSelectListTest extends TestCase { User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); - Passport::actingAs(User::factory()->create()); - $response = $this->getJson(route('api.users.selectlist', ['search' => 'luke sky']))->assertOk(); + $response = $this->actingAsForApi(User::factory()->create()) + ->getJson(route('api.users.selectlist', ['search' => 'luke sky'])) + ->assertOk(); $results = collect($response->json('results')); @@ -57,8 +57,9 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - Passport::actingAs($jedi->users->first()); - $response = $this->getJson(route('api.users.selectlist'))->assertOk(); + $response = $this->actingAsForApi($jedi->users->first()) + ->getJson(route('api.users.selectlist')) + ->assertOk(); $results = collect($response->json('results')); @@ -85,8 +86,9 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - Passport::actingAs($jedi->users->first()); - $response = $this->getJson(route('api.users.selectlist', ['search' => 'a']))->assertOk(); + $response = $this->actingAsForApi($jedi->users->first()) + ->getJson(route('api.users.selectlist', ['search' => 'a'])) + ->assertOk(); $results = collect($response->json('results')); diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php index ed91976ccb..644c5e9e0d 100644 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -4,7 +4,6 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -29,36 +28,36 @@ class UsersIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($superUser) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($superUser) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseDoesNotContainInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseDoesNotContainInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.users.index')) - ->assertResponseDoesNotContainInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.users.index')) + ->assertResponseDoesNotContainInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); } } diff --git a/tests/Feature/Api/Users/UsersSearchTest.php b/tests/Feature/Api/Users/UsersSearchTest.php index 33f77196f3..349cd1e85c 100644 --- a/tests/Feature/Api/Users/UsersSearchTest.php +++ b/tests/Feature/Api/Users/UsersSearchTest.php @@ -3,7 +3,6 @@ namespace Tests\Feature\Api\Users; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -16,8 +15,9 @@ class UsersSearchTest extends TestCase User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); User::factory()->create(['first_name' => 'Darth', 'last_name' => 'Vader']); - Passport::actingAs(User::factory()->viewUsers()->create()); - $response = $this->getJson(route('api.users.index', ['search' => 'luke sky']))->assertOk(); + $response = $this->actingAsForApi(User::factory()->viewUsers()->create()) + ->getJson(route('api.users.index', ['search' => 'luke sky'])) + ->assertOk(); $results = collect($response->json('rows')); diff --git a/tests/Support/InteractsWithAuthentication.php b/tests/Support/InteractsWithAuthentication.php new file mode 100644 index 0000000000..27b20e382b --- /dev/null +++ b/tests/Support/InteractsWithAuthentication.php @@ -0,0 +1,16 @@ + Date: Mon, 26 Jun 2023 11:26:46 -0700 Subject: [PATCH 25/31] adds half_year fix from jdickerson71388 --- app/Models/Depreciable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Depreciable.php b/app/Models/Depreciable.php index 250894820c..9bbf4fcbf8 100644 --- a/app/Models/Depreciable.php +++ b/app/Models/Depreciable.php @@ -127,7 +127,7 @@ class Depreciable extends SnipeModel $yearsPast = 0; } - return round($yearsPast / $deprecationYears * $this->purchase_cost, 2); + return $this->purchase_cost - round($yearsPast / $deprecationYears * $this->purchase_cost, 2); } /** From 7cb22d3d49b1b8707f8f44f09e39c4aba28d2670 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 26 Jun 2023 14:00:53 -0700 Subject: [PATCH 26/31] Remove incomplete tests --- .../Api/Departments/DepartmentsIndexTest.php | 64 ------------------- tests/Feature/Api/Users/UsersIndexTest.php | 63 ------------------ tests/Feature/DashboardTest.php | 21 ------ 3 files changed, 148 deletions(-) delete mode 100644 tests/Feature/Api/Departments/DepartmentsIndexTest.php delete mode 100644 tests/Feature/Api/Users/UsersIndexTest.php diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php deleted file mode 100644 index 1067ec74c7..0000000000 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ /dev/null @@ -1,64 +0,0 @@ -markTestIncomplete( - 'Waiting for removal of Company::scopeCompanyables in DepartmentsController@index' - ); - - [$companyA, $companyB] = Company::factory()->count(2)->create(); - - $departmentA = Department::factory()->for($companyA)->create(); - $departmentB = Department::factory()->for($companyB)->create(); - - $superUser = $companyA->users()->save(User::factory()->superuser()->make()); - $userInCompanyA = $companyA->users()->save(User::factory()->viewDepartments()->make()); - $userInCompanyB = $companyB->users()->save(User::factory()->viewDepartments()->make()); - - $this->settings->disableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->settings->enableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseDoesNotContainInRows($departmentB); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.departments.index')) - ->assertResponseDoesNotContainInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - } -} diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php deleted file mode 100644 index 644c5e9e0d..0000000000 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ /dev/null @@ -1,63 +0,0 @@ -markTestIncomplete( - 'Waiting for removal of Company::scopeCompanyables in UsersController@index' - ); - - [$companyA, $companyB] = Company::factory()->count(2)->create(); - - $userA = User::factory()->for($companyA)->create(); - $userB = User::factory()->for($companyB)->create(); - - $superUser = $companyA->users()->save(User::factory()->superuser()->make()); - $userInCompanyA = $companyA->users()->save(User::factory()->viewUsers()->make()); - $userInCompanyB = $companyB->users()->save(User::factory()->viewUsers()->make()); - - $this->settings->disableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->settings->enableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseDoesNotContainInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.users.index')) - ->assertResponseDoesNotContainInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - } -} diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index 1772eac316..4e9459fb06 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -2,7 +2,6 @@ namespace Tests\Feature; -use App\Models\Company; use App\Models\User; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -17,24 +16,4 @@ class DashboardTest extends TestCase ->get(route('home')) ->assertRedirect(route('view-assets')); } - - public function testUserCountIsScopedByCompany() - { - $this->markTestIncomplete( - 'Waiting for removal of Company::scopeCompanyables in DashboardController@index' - ); - - $this->settings->enableMultipleFullCompanySupport(); - - $companyA = Company::factory()->has(User::factory()->count(1))->create(); - Company::factory()->has(User::factory()->count(3))->create(); - - $adminForCompanyA = $companyA->users()->save(User::factory()->admin()->make()); - - $this->actingAs($adminForCompanyA) - ->get(route('home')) - ->assertOk() - ->assertViewIs('dashboard') - ->assertViewHas('counts', fn($counts) => $counts['user'] === $companyA->users->count()); - } } From 2abdb8a5fd02ab2c5dff8e6e3dd22f5a1c9d5751 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 26 Jun 2023 14:01:09 -0700 Subject: [PATCH 27/31] Revert unneeded changes --- .../Api/Users/UsersForSelectListTest.php | 20 +++++++++---------- tests/Feature/Api/Users/UsersSearchTest.php | 6 +++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/tests/Feature/Api/Users/UsersForSelectListTest.php b/tests/Feature/Api/Users/UsersForSelectListTest.php index ba4beb211b..8cdf700f04 100644 --- a/tests/Feature/Api/Users/UsersForSelectListTest.php +++ b/tests/Feature/Api/Users/UsersForSelectListTest.php @@ -5,6 +5,7 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; +use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -16,8 +17,8 @@ class UsersForSelectListTest extends TestCase { $users = User::factory()->superuser()->count(3)->create(); - $this->actingAsForApi($users->first()) - ->getJson(route('api.users.selectlist')) + Passport::actingAs($users->first()); + $this->getJson(route('api.users.selectlist')) ->assertOk() ->assertJsonStructure([ 'results', @@ -33,9 +34,8 @@ class UsersForSelectListTest extends TestCase { User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); - $response = $this->actingAsForApi(User::factory()->create()) - ->getJson(route('api.users.selectlist', ['search' => 'luke sky'])) - ->assertOk(); + Passport::actingAs(User::factory()->create()); + $response = $this->getJson(route('api.users.selectlist', ['search' => 'luke sky']))->assertOk(); $results = collect($response->json('results')); @@ -57,9 +57,8 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - $response = $this->actingAsForApi($jedi->users->first()) - ->getJson(route('api.users.selectlist')) - ->assertOk(); + Passport::actingAs($jedi->users->first()); + $response = $this->getJson(route('api.users.selectlist'))->assertOk(); $results = collect($response->json('results')); @@ -86,9 +85,8 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - $response = $this->actingAsForApi($jedi->users->first()) - ->getJson(route('api.users.selectlist', ['search' => 'a'])) - ->assertOk(); + Passport::actingAs($jedi->users->first()); + $response = $this->getJson(route('api.users.selectlist', ['search' => 'a']))->assertOk(); $results = collect($response->json('results')); diff --git a/tests/Feature/Api/Users/UsersSearchTest.php b/tests/Feature/Api/Users/UsersSearchTest.php index 349cd1e85c..33f77196f3 100644 --- a/tests/Feature/Api/Users/UsersSearchTest.php +++ b/tests/Feature/Api/Users/UsersSearchTest.php @@ -3,6 +3,7 @@ namespace Tests\Feature\Api\Users; use App\Models\User; +use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -15,9 +16,8 @@ class UsersSearchTest extends TestCase User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); User::factory()->create(['first_name' => 'Darth', 'last_name' => 'Vader']); - $response = $this->actingAsForApi(User::factory()->viewUsers()->create()) - ->getJson(route('api.users.index', ['search' => 'luke sky'])) - ->assertOk(); + Passport::actingAs(User::factory()->viewUsers()->create()); + $response = $this->getJson(route('api.users.index', ['search' => 'luke sky']))->assertOk(); $results = collect($response->json('rows')); From 3f09e6017b444f4c0578b83c16f1226d37f1787c Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 26 Jun 2023 16:22:28 -0700 Subject: [PATCH 28/31] Install paratest to allow for parallel test running --- composer.json | 1 + composer.lock | 156 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 165a4a08f6..cf4a524376 100644 --- a/composer.json +++ b/composer.json @@ -74,6 +74,7 @@ "watson/validating": "^6.1" }, "require-dev": { + "brianium/paratest": "^6.6", "fakerphp/faker": "^1.16", "laravel/dusk": "^6.25", "mockery/mockery": "^1.4", diff --git a/composer.lock b/composer.lock index 1ef75690aa..4e522d8a99 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4c82b2e171fb02a3ef024906db5d74c9", + "content-hash": "217a3619f0f4eebdb280299efdd7297e", "packages": [ { "name": "alek13/slack", @@ -12122,6 +12122,99 @@ ], "time": "2021-03-30T17:13:30+00:00" }, + { + "name": "brianium/paratest", + "version": "v6.6.2", + "source": { + "type": "git", + "url": "https://github.com/paratestphp/paratest.git", + "reference": "5249af4e25e79da66d1ec3b54b474047999c10b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/5249af4e25e79da66d1ec3b54b474047999c10b8", + "reference": "5249af4e25e79da66d1ec3b54b474047999c10b8", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-simplexml": "*", + "jean85/pretty-package-versions": "^2.0.5", + "php": "^7.3 || ^8.0", + "phpunit/php-code-coverage": "^9.2.15", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-timer": "^5.0.3", + "phpunit/phpunit": "^9.5.21", + "sebastian/environment": "^5.1.4", + "symfony/console": "^5.4.9 || ^6.1.2", + "symfony/polyfill-php80": "^v1.26.0", + "symfony/process": "^5.4.8 || ^6.1.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0.0", + "ext-pcov": "*", + "ext-posix": "*", + "infection/infection": "^0.26.13", + "malukenho/mcbumpface": "^1.1.5", + "squizlabs/php_codesniffer": "^3.7.1", + "symfony/filesystem": "^5.4.9 || ^6.1.0", + "vimeo/psalm": "^4.26.0" + }, + "bin": [ + "bin/paratest", + "bin/paratest.bat", + "bin/paratest_for_phpstorm" + ], + "type": "library", + "autoload": { + "psr-4": { + "ParaTest\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Scaturro", + "email": "scaturrob@gmail.com", + "role": "Developer" + }, + { + "name": "Filippo Tessarotto", + "email": "zoeslam@gmail.com", + "role": "Developer" + } + ], + "description": "Parallel testing for PHP", + "homepage": "https://github.com/paratestphp/paratest", + "keywords": [ + "concurrent", + "parallel", + "phpunit", + "testing" + ], + "support": { + "issues": "https://github.com/paratestphp/paratest/issues", + "source": "https://github.com/paratestphp/paratest/tree/v6.6.2" + }, + "funding": [ + { + "url": "https://github.com/sponsors/Slamdunk", + "type": "github" + }, + { + "url": "https://paypal.me/filippotessarotto", + "type": "paypal" + } + ], + "time": "2022-08-22T10:45:51+00:00" + }, { "name": "composer/ca-bundle", "version": "1.3.5", @@ -13232,6 +13325,65 @@ }, "time": "2020-07-09T08:09:16+00:00" }, + { + "name": "jean85/pretty-package-versions", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + }, + "time": "2021-10-08T21:21:46+00:00" + }, { "name": "justinrainbow/json-schema", "version": "5.2.12", @@ -16570,5 +16722,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.3.0" } From b0177d513ab46c9d436652591c4bb97c8022bec9 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 27 Jun 2023 12:37:19 -0700 Subject: [PATCH 29/31] Fix translation --- resources/lang/en/general.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 28f9fd82ba..f515325b1c 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -459,7 +459,7 @@ return [ 'checked_out_to_email' => 'Checked Out to: Email', 'checked_out_to_tag' => 'Checked Out to: Asset Tag', 'manager_first_name' => 'Manager First Name', - 'manager_last_name' => 'Manager First Name', + 'manager_last_name' => 'Manager Last Name', 'manager_full_name' => 'Manager Full Name', 'manager_username' => 'Manager Username', 'checkout_type' => 'Checkout Type', From 6df7be8c13eabbd50096c446bef2d942b27ae675 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 27 Jun 2023 16:55:20 -0700 Subject: [PATCH 30/31] Have ChipperCI run on each PR --- .chipperci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.chipperci.yml b/.chipperci.yml index 663a06350a..c45d4ddedc 100644 --- a/.chipperci.yml +++ b/.chipperci.yml @@ -14,6 +14,11 @@ on: - master - develop + pull_request: + branches: + - master + - develop + pipeline: - name: Setup cmd: | From ab518578544db09aa45c0f984432ae0a1cef7614 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 27 Jun 2023 19:35:55 -0700 Subject: [PATCH 31/31] Check to see if model relationship exists before using it --- app/Http/Transformers/AssetsTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Transformers/AssetsTransformer.php b/app/Http/Transformers/AssetsTransformer.php index d431ec890d..85f5f9294d 100644 --- a/app/Http/Transformers/AssetsTransformer.php +++ b/app/Http/Transformers/AssetsTransformer.php @@ -38,7 +38,7 @@ class AssetsTransformer 'byod' => ($asset->byod ? true : false), 'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null, - 'eol' => ($asset->model->eol != '') ? $asset->model->eol : null, + 'eol' => (($asset->model) && ($asset->model->eol != '')) ? $asset->model->eol : null, 'asset_eol_date' => ($asset->asset_eol_date != '') ? Helper::getFormattedDateObject($asset->asset_eol_date, 'date') : null, 'status_label' => ($asset->assetstatus) ? [ 'id' => (int) $asset->assetstatus->id,