ajout app
This commit is contained in:
22
SNIPE-IT/tests/CreatesApplication.php
Normal file
22
SNIPE-IT/tests/CreatesApplication.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
trait CreatesApplication
|
||||
{
|
||||
/**
|
||||
* Creates the application.
|
||||
*
|
||||
* @return \Illuminate\Foundation\Application
|
||||
*/
|
||||
public function createApplication()
|
||||
{
|
||||
$app = require __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
$app->make(Kernel::class)->bootstrap();
|
||||
|
||||
return $app;
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Accessories;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutAccessoryNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AccessoryCheckoutTest extends TestCase
|
||||
{
|
||||
public function testCheckingOutAccessoryRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->postJson(route('api.accessories.checkout', Accessory::factory()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidationWhenCheckingOutAccessory()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkoutAccessories()->create())
|
||||
->postJson(route('api.accessories.checkout', Accessory::factory()->create()), [
|
||||
// missing assigned_to
|
||||
])
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testAccessoryMustBeAvailableWhenCheckingOut()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkoutAccessories()->create())
|
||||
->postJson(route('api.accessories.checkout', Accessory::factory()->withoutItemsRemaining()->create()), [
|
||||
'assigned_to' => User::factory()->create()->id,
|
||||
])
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testAccessoryCanBeCheckedOut()
|
||||
{
|
||||
$accessory = Accessory::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkoutAccessories()->create())
|
||||
->postJson(route('api.accessories.checkout', $accessory), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
$this->assertTrue($accessory->users->contains($user));
|
||||
}
|
||||
|
||||
public function testUserSentNotificationUponCheckout()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$accessory = Accessory::factory()->requiringAcceptance()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkoutAccessories()->create())
|
||||
->postJson(route('api.accessories.checkout', $accessory), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
Notification::assertSentTo($user, CheckoutAccessoryNotification::class);
|
||||
}
|
||||
|
||||
public function testActionLogCreatedUponCheckout()
|
||||
{
|
||||
$accessory = Accessory::factory()->create();
|
||||
$actor = User::factory()->checkoutAccessories()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi($actor)
|
||||
->postJson(route('api.accessories.checkout', $accessory), [
|
||||
'assigned_to' => $user->id,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertEquals(
|
||||
1,
|
||||
Actionlog::where([
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $user->id,
|
||||
'target_type' => User::class,
|
||||
'item_id' => $accessory->id,
|
||||
'item_type' => Accessory::class,
|
||||
'user_id' => $actor->id,
|
||||
'note' => 'oh hi there',
|
||||
])->count(),
|
||||
'Log entry either does not exist or there are more than expected'
|
||||
);
|
||||
}
|
||||
}
|
162
SNIPE-IT/tests/Feature/Api/Assets/AssetCheckinTest.php
Normal file
162
SNIPE-IT/tests/Feature/Api/Assets/AssetCheckinTest.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Location;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetCheckinTest extends TestCase
|
||||
{
|
||||
public function testCheckingInAssetRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->postJson(route('api.asset.checkin', Asset::factory()->assignedToUser()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testCannotCheckInNonExistentAsset()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', ['id' => 'does-not-exist']))
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testCannotCheckInAssetThatIsNotCheckedOut()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', Asset::factory()->create()->id))
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testAssetCanBeCheckedIn()
|
||||
{
|
||||
Event::fake([CheckoutableCheckedIn::class]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
$location = Location::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser($user)->create([
|
||||
'expected_checkin' => now()->addDay(),
|
||||
'last_checkin' => null,
|
||||
'accepted' => 'accepted',
|
||||
]);
|
||||
|
||||
$this->assertTrue($asset->assignedTo->is($user));
|
||||
|
||||
$currentTimestamp = now();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', $asset), [
|
||||
'name' => 'Changed Name',
|
||||
'status_id' => $status->id,
|
||||
'location_id' => $location->id,
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
$this->assertNull($asset->refresh()->assignedTo);
|
||||
$this->assertNull($asset->expected_checkin);
|
||||
$this->assertNull($asset->assignedTo);
|
||||
$this->assertNull($asset->assigned_type);
|
||||
$this->assertNull($asset->accepted);
|
||||
$this->assertEquals('Changed Name', $asset->name);
|
||||
$this->assertEquals($status->id, $asset->status_id);
|
||||
$this->assertTrue($asset->location()->is($location));
|
||||
|
||||
Event::assertDispatched(function (CheckoutableCheckedIn $event) use ($currentTimestamp) {
|
||||
// this could be better mocked but is ok for now.
|
||||
return Carbon::parse($event->action_date)->diffInSeconds($currentTimestamp) < 2;
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public function testLocationIsSetToRTDLocationByDefaultUponCheckin()
|
||||
{
|
||||
$rtdLocation = Location::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser()->create([
|
||||
'location_id' => Location::factory()->create()->id,
|
||||
'rtd_location_id' => $rtdLocation->id,
|
||||
]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', $asset->id));
|
||||
|
||||
$this->assertTrue($asset->refresh()->location()->is($rtdLocation));
|
||||
}
|
||||
|
||||
public function testDefaultLocationCanBeUpdatedUponCheckin()
|
||||
{
|
||||
$location = Location::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', $asset), [
|
||||
'location_id' => $location->id,
|
||||
'update_default_location' => true,
|
||||
]);
|
||||
|
||||
$this->assertTrue($asset->refresh()->defaultLoc()->is($location));
|
||||
}
|
||||
|
||||
public function testAssetsLicenseSeatsAreClearedUponCheckin()
|
||||
{
|
||||
$asset = Asset::factory()->assignedToUser()->create();
|
||||
LicenseSeat::factory()->assignedToUser()->for($asset)->create();
|
||||
|
||||
$this->assertNotNull($asset->licenseseats->first()->assigned_to);
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', $asset));
|
||||
|
||||
$this->assertNull($asset->refresh()->licenseseats->first()->assigned_to);
|
||||
}
|
||||
|
||||
public function testLegacyLocationValuesSetToZeroAreUpdated()
|
||||
{
|
||||
$asset = Asset::factory()->canBeInvalidUponCreation()->assignedToUser()->create([
|
||||
'rtd_location_id' => 0,
|
||||
'location_id' => 0,
|
||||
]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', $asset));
|
||||
|
||||
$this->assertNull($asset->refresh()->rtd_location_id);
|
||||
$this->assertEquals($asset->location_id, $asset->rtd_location_id);
|
||||
}
|
||||
|
||||
public function testPendingCheckoutAcceptancesAreClearedUponCheckin()
|
||||
{
|
||||
$asset = Asset::factory()->assignedToUser()->create();
|
||||
|
||||
$acceptance = CheckoutAcceptance::factory()->for($asset, 'checkoutable')->pending()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', $asset));
|
||||
|
||||
$this->assertFalse($acceptance->exists(), 'Acceptance was not deleted');
|
||||
}
|
||||
|
||||
public function testCheckinTimeAndActionLogNoteCanBeSet()
|
||||
{
|
||||
Event::fake();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkinAssets()->create())
|
||||
->postJson(route('api.asset.checkin', Asset::factory()->assignedToUser()->create()), [
|
||||
// time is appended to the provided date in controller
|
||||
'checkin_at' => '2023-01-02',
|
||||
'note' => 'hi there',
|
||||
]);
|
||||
|
||||
Event::assertDispatched(function (CheckoutableCheckedIn $event) {
|
||||
return Carbon::parse('2023-01-02')->isSameDay(Carbon::parse($event->action_date))
|
||||
&& $event->note === 'hi there';
|
||||
}, 1);
|
||||
}
|
||||
}
|
78
SNIPE-IT/tests/Feature/Api/Assets/AssetIndexTest.php
Normal file
78
SNIPE-IT/tests/Feature/Api/Assets/AssetIndexTest.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetIndexTest extends TestCase
|
||||
{
|
||||
public function testAssetIndexReturnsExpectedAssets()
|
||||
{
|
||||
Asset::factory()->count(3)->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->getJson(
|
||||
route('api.assets.index', [
|
||||
'sort' => 'name',
|
||||
'order' => 'asc',
|
||||
'offset' => '0',
|
||||
'limit' => '20',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'total',
|
||||
'rows',
|
||||
])
|
||||
->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();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseDoesNotContainInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseDoesNotContainInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
}
|
||||
}
|
482
SNIPE-IT/tests/Feature/Api/Assets/AssetStoreTest.php
Normal file
482
SNIPE-IT/tests/Feature/Api/Assets/AssetStoreTest.php
Normal file
@ -0,0 +1,482 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetStoreTest extends TestCase
|
||||
{
|
||||
public function testRequiresPermissionToCreateAsset()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->postJson(route('api.assets.store'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testAllAssetAttributesAreStored()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->create();
|
||||
$model = AssetModel::factory()->create();
|
||||
$rtdLocation = Location::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$user = User::factory()->createAssets()->create();
|
||||
$userAssigned = User::factory()->create();
|
||||
|
||||
$response = $this->actingAsForApi($user)
|
||||
->postJson(route('api.assets.store'), [
|
||||
'asset_eol_date' => '2024-06-02',
|
||||
'asset_tag' => 'random_string',
|
||||
'assigned_user' => $userAssigned->id,
|
||||
'company_id' => $company->id,
|
||||
'last_audit_date' => '2023-09-03',
|
||||
'location_id' => $location->id,
|
||||
'model_id' => $model->id,
|
||||
'name' => 'A New Asset',
|
||||
'notes' => 'Some notes',
|
||||
'order_number' => '5678',
|
||||
'purchase_cost' => '123.45',
|
||||
'purchase_date' => '2023-09-02',
|
||||
'requestable' => true,
|
||||
'rtd_location_id' => $rtdLocation->id,
|
||||
'serial' => '1234567890',
|
||||
'status_id' => $status->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'warranty_months' => 10,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
|
||||
$this->assertTrue($asset->adminuser->is($user));
|
||||
|
||||
$this->assertEquals('2024-06-02', $asset->asset_eol_date);
|
||||
$this->assertEquals('random_string', $asset->asset_tag);
|
||||
$this->assertEquals($userAssigned->id, $asset->assigned_to);
|
||||
$this->assertTrue($asset->company->is($company));
|
||||
$this->assertEquals('2023-09-03 00:00:00', $asset->last_audit_date->format('Y-m-d H:i:s'));
|
||||
$this->assertTrue($asset->location->is($location));
|
||||
$this->assertTrue($asset->model->is($model));
|
||||
$this->assertEquals('A New Asset', $asset->name);
|
||||
$this->assertEquals('Some notes', $asset->notes);
|
||||
$this->assertEquals('5678', $asset->order_number);
|
||||
$this->assertEquals('123.45', $asset->purchase_cost);
|
||||
$this->assertTrue($asset->purchase_date->is('2023-09-02'));
|
||||
$this->assertEquals('1', $asset->requestable);
|
||||
$this->assertTrue($asset->defaultLoc->is($rtdLocation));
|
||||
$this->assertEquals('1234567890', $asset->serial);
|
||||
$this->assertTrue($asset->assetstatus->is($status));
|
||||
$this->assertTrue($asset->supplier->is($supplier));
|
||||
$this->assertEquals(10, $asset->warranty_months);
|
||||
}
|
||||
|
||||
public function testSetsLastAuditDateToMidnightOfProvidedDate()
|
||||
{
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'last_audit_date' => '2023-09-03 12:23:45',
|
||||
'asset_tag' => '1234',
|
||||
'model_id' => AssetModel::factory()->create()->id,
|
||||
'status_id' => Statuslabel::factory()->create()->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertEquals('00:00:00', $asset->last_audit_date->format('H:i:s'));
|
||||
}
|
||||
|
||||
public function testLastAuditDateCanBeNull()
|
||||
{
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
// 'last_audit_date' => '2023-09-03 12:23:45',
|
||||
'asset_tag' => '1234',
|
||||
'model_id' => AssetModel::factory()->create()->id,
|
||||
'status_id' => Statuslabel::factory()->create()->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertNull($asset->last_audit_date);
|
||||
}
|
||||
|
||||
public function testNonDateUsedForLastAuditDateReturnsValidationError()
|
||||
{
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'last_audit_date' => 'this-is-not-valid',
|
||||
'asset_tag' => '1234',
|
||||
'model_id' => AssetModel::factory()->create()->id,
|
||||
'status_id' => Statuslabel::factory()->create()->id,
|
||||
])
|
||||
->assertStatusMessageIs('error');
|
||||
|
||||
$this->assertNotNull($response->json('messages.last_audit_date'));
|
||||
}
|
||||
|
||||
public function testArchivedDepreciateAndPhysicalCanBeNull()
|
||||
{
|
||||
$model = AssetModel::factory()->ipadModel()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'archive' => null,
|
||||
'depreciate' => null,
|
||||
'physical' => null
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertEquals(0, $asset->archived);
|
||||
$this->assertEquals(1, $asset->physical);
|
||||
$this->assertEquals(0, $asset->depreciate);
|
||||
}
|
||||
|
||||
public function testArchivedDepreciateAndPhysicalCanBeEmpty()
|
||||
{
|
||||
$model = AssetModel::factory()->ipadModel()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'archive' => '',
|
||||
'depreciate' => '',
|
||||
'physical' => ''
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertEquals(0, $asset->archived);
|
||||
$this->assertEquals(1, $asset->physical);
|
||||
$this->assertEquals(0, $asset->depreciate);
|
||||
}
|
||||
|
||||
public function testAssetEolDateIsCalculatedIfPurchaseDateSet()
|
||||
{
|
||||
$model = AssetModel::factory()->mbp13Model()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'purchase_date' => '2021-01-01',
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertEquals('2024-01-01', $asset->asset_eol_date);
|
||||
}
|
||||
|
||||
public function testAssetEolDateIsNotCalculatedIfPurchaseDateNotSet()
|
||||
{
|
||||
$model = AssetModel::factory()->mbp13Model()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertNull($asset->asset_eol_date);
|
||||
}
|
||||
|
||||
public function testAssetEolExplicitIsSetIfAssetEolDateIsExplicitlySet()
|
||||
{
|
||||
$model = AssetModel::factory()->mbp13Model()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'asset_eol_date' => '2025-01-01',
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertEquals('2025-01-01', $asset->asset_eol_date);
|
||||
$this->assertTrue($asset->eol_explicit);
|
||||
}
|
||||
|
||||
public function testAssetGetsAssetTagWithAutoIncrement()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
$this->assertNotNull($asset->asset_tag);
|
||||
}
|
||||
|
||||
public function testAssetCreationFailsWithNoAssetTagOrAutoIncrement()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
|
||||
$this->settings->disableAutoIncrement();
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testUniqueSerialNumbersIsEnforcedWhenEnabled()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$serial = '1234567890';
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
$this->settings->enableUniqueSerialNumbers();
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'serial' => $serial,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'serial' => $serial,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testUniqueSerialNumbersIsNotEnforcedWhenDisabled()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$serial = '1234567890';
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
$this->settings->disableUniqueSerialNumbers();
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'serial' => $serial,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
'serial' => $serial,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
}
|
||||
|
||||
public function testAssetTagsMustBeUniqueWhenUndeleted()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$asset_tag = '1234567890';
|
||||
|
||||
$this->settings->disableAutoIncrement();
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'asset_tag' => $asset_tag,
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'asset_tag' => $asset_tag,
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testAssetTagsCanBeDuplicatedIfDeleted()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$asset_tag = '1234567890';
|
||||
|
||||
$this->settings->disableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'asset_tag' => $asset_tag,
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
Asset::find($response['payload']['id'])->delete();
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'asset_tag' => $asset_tag,
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
}
|
||||
|
||||
public function testAnAssetCanBeCheckedOutToUserOnStore()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$user = User::factory()->createAssets()->create();
|
||||
$userAssigned = User::factory()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi($user)
|
||||
->postJson(route('api.assets.store'), [
|
||||
'assigned_user' => $userAssigned->id,
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
|
||||
$this->assertTrue($asset->adminuser->is($user));
|
||||
$this->assertTrue($asset->checkedOutToUser());
|
||||
$this->assertTrue($asset->assignedTo->is($userAssigned));
|
||||
}
|
||||
|
||||
public function testAnAssetCanBeCheckedOutToLocationOnStore()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$location = Location::factory()->create();
|
||||
$user = User::factory()->createAssets()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi($user)
|
||||
->postJson(route('api.assets.store'), [
|
||||
'assigned_location' => $location->id,
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$asset = Asset::find($response['payload']['id']);
|
||||
|
||||
$this->assertTrue($asset->adminuser->is($user));
|
||||
$this->assertTrue($asset->checkedOutToLocation());
|
||||
$this->assertTrue($asset->location->is($location));
|
||||
}
|
||||
|
||||
public function testAnAssetCanBeCheckedOutToAssetOnStore()
|
||||
{
|
||||
$model = AssetModel::factory()->create();
|
||||
$status = Statuslabel::factory()->create();
|
||||
$asset = Asset::factory()->create();
|
||||
$user = User::factory()->createAssets()->create();
|
||||
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$response = $this->actingAsForApi($user)
|
||||
->postJson(route('api.assets.store'), [
|
||||
'assigned_asset' => $asset->id,
|
||||
'model_id' => $model->id,
|
||||
'status_id' => $status->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success')
|
||||
->json();
|
||||
|
||||
$apiAsset = Asset::find($response['payload']['id']);
|
||||
|
||||
$this->assertTrue($apiAsset->adminuser->is($user));
|
||||
$this->assertTrue($apiAsset->checkedOutToAsset());
|
||||
// I think this makes sense, but open to a sanity check
|
||||
$this->assertTrue($asset->assignedAssets()->find($response['payload']['id'])->is($apiAsset));
|
||||
}
|
||||
|
||||
public function testCompanyIdNeedsToBeInteger()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->createAssets()->create())
|
||||
->postJson(route('api.assets.store'), [
|
||||
'company_id' => [1],
|
||||
])
|
||||
->assertStatusMessageIs('error')
|
||||
->assertJson(function (AssertableJson $json) {
|
||||
$json->has('messages.company_id')->etc();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetsForSelectListTest extends TestCase
|
||||
{
|
||||
public function testAssetsCanBeSearchedForByAssetTag()
|
||||
{
|
||||
Asset::factory()->create(['asset_tag' => '0001']);
|
||||
Asset::factory()->create(['asset_tag' => '0002']);
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->create())
|
||||
->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()
|
||||
{
|
||||
[$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();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseDoesNotContainInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseDoesNotContainInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
}
|
||||
}
|
76
SNIPE-IT/tests/Feature/Api/Assets/RequestableAssetsTest.php
Normal file
76
SNIPE-IT/tests/Feature/Api/Assets/RequestableAssetsTest.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RequestableAssetsTest extends TestCase
|
||||
{
|
||||
public function testViewingRequestableAssetsRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->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']);
|
||||
|
||||
$this->actingAsForApi(User::factory()->viewRequestableAssets()->create())
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertOk()
|
||||
->assertResponseContainsInRows($requestableAsset, 'asset_tag')
|
||||
->assertResponseDoesNotContainInRows($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();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseDoesNotContainInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseDoesNotContainInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
}
|
||||
}
|
57
SNIPE-IT/tests/Feature/Api/Components/ComponentIndexTest.php
Normal file
57
SNIPE-IT/tests/Feature/Api/Components/ComponentIndexTest.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Components;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Component;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ComponentIndexTest extends TestCase
|
||||
{
|
||||
public function testComponentIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->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();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseDoesNotContainInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseDoesNotContainInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Consumables;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ConsumableCheckoutTest extends TestCase
|
||||
{
|
||||
public function testCheckingOutConsumableRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->postJson(route('api.consumables.checkout', Consumable::factory()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidationWhenCheckingOutConsumable()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', Consumable::factory()->create()), [
|
||||
// missing assigned_to
|
||||
])
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testConsumableMustBeAvailableWhenCheckingOut()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', Consumable::factory()->withoutItemsRemaining()->create()), [
|
||||
'assigned_to' => User::factory()->create()->id,
|
||||
])
|
||||
->assertStatusMessageIs('error');
|
||||
}
|
||||
|
||||
public function testConsumableCanBeCheckedOut()
|
||||
{
|
||||
$consumable = Consumable::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
$this->assertTrue($user->consumables->contains($consumable));
|
||||
}
|
||||
|
||||
public function testUserSentNotificationUponCheckout()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$consumable = Consumable::factory()->requiringAcceptance()->create();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->checkoutConsumables()->create())
|
||||
->postJson(route('api.consumables.checkout', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
Notification::assertSentTo($user, CheckoutConsumableNotification::class);
|
||||
}
|
||||
|
||||
public function testActionLogCreatedUponCheckout()
|
||||
{$consumable = Consumable::factory()->create();
|
||||
$actor = User::factory()->checkoutConsumables()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAsForApi($actor)
|
||||
->postJson(route('api.consumables.checkout', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertEquals(
|
||||
1,
|
||||
Actionlog::where([
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $user->id,
|
||||
'target_type' => User::class,
|
||||
'item_id' => $consumable->id,
|
||||
'item_type' => Consumable::class,
|
||||
'user_id' => $actor->id,
|
||||
'note' => 'oh hi there',
|
||||
])->count(),
|
||||
'Log entry either does not exist or there are more than expected'
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Consumables;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ConsumablesIndexTest extends TestCase
|
||||
{
|
||||
public function testConsumableIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->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();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseDoesNotContainInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseDoesNotContainInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Departments;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Department;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DepartmentIndexTest extends TestCase
|
||||
{
|
||||
public function testViewingDepartmentIndexRequiresAuthentication()
|
||||
{
|
||||
$this->getJson(route('api.departments.index'))->assertRedirect();
|
||||
}
|
||||
|
||||
public function testViewingDepartmentIndexRequiresPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->getJson(route('api.departments.index'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testDepartmentIndexReturnsExpectedDepartments()
|
||||
{
|
||||
Department::factory()->count(3)->create();
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->getJson(
|
||||
route('api.departments.index', [
|
||||
'sort' => 'name',
|
||||
'order' => 'asc',
|
||||
'offset' => '0',
|
||||
'limit' => '20',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'total',
|
||||
'rows',
|
||||
])
|
||||
->assertJson(fn(AssertableJson $json) => $json->has('rows', 3)->etc());
|
||||
}
|
||||
|
||||
public function testDepartmentIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$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);
|
||||
}
|
||||
}
|
38
SNIPE-IT/tests/Feature/Api/Groups/GroupStoreTest.php
Normal file
38
SNIPE-IT/tests/Feature/Api/Groups/GroupStoreTest.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Groups;
|
||||
|
||||
use App\Models\Group;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class GroupStoreTest extends TestCase
|
||||
{
|
||||
public function testStoringGroupRequiresSuperAdminPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->postJson(route('api.groups.store'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testCanStoreGroup()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.groups.store'), [
|
||||
'name' => 'My Awesome Group',
|
||||
'permissions' => [
|
||||
'admin' => '1',
|
||||
'import' => '1',
|
||||
'reports.view' => '0',
|
||||
],
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
$group = Group::where('name', 'My Awesome Group')->first();
|
||||
|
||||
$this->assertNotNull($group);
|
||||
$this->assertEquals('1', $group->decodePermissions()['admin']);
|
||||
$this->assertEquals('1', $group->decodePermissions()['import']);
|
||||
$this->assertEquals('0', $group->decodePermissions()['reports.view']);
|
||||
}
|
||||
}
|
57
SNIPE-IT/tests/Feature/Api/Licenses/LicensesIndexTest.php
Normal file
57
SNIPE-IT/tests/Feature/Api/Licenses/LicensesIndexTest.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Licenses;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LicensesIndexTest extends TestCase
|
||||
{
|
||||
public function testLicensesIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->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();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseDoesNotContainInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseDoesNotContainInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Locations;
|
||||
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LocationsForSelectListTest extends TestCase
|
||||
{
|
||||
public function testGettingLocationListRequiresProperPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->getJson(route('api.locations.selectlist'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testLocationsReturned()
|
||||
{
|
||||
Location::factory()->create();
|
||||
|
||||
// see the where the "view.selectlists" is defined in the AuthServiceProvider
|
||||
// for info on why "createUsers()" is used here.
|
||||
$this->actingAsForApi(User::factory()->createUsers()->create())
|
||||
->getJson(route('api.locations.selectlist'))
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'results',
|
||||
'pagination',
|
||||
'total_count',
|
||||
'page',
|
||||
'page_count',
|
||||
])
|
||||
->assertJson(fn(AssertableJson $json) => $json->has('results', 1)->etc());
|
||||
}
|
||||
|
||||
public function testLocationsAreReturnedWhenUserIsUpdatingTheirProfileAndHasPermissionToUpdateLocation()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->canEditOwnLocation()->create())
|
||||
->withHeader('referer', route('profile'))
|
||||
->getJson(route('api.locations.selectlist'))
|
||||
->assertOk();
|
||||
}
|
||||
}
|
61
SNIPE-IT/tests/Feature/Api/Users/UpdateUserApiTest.php
Normal file
61
SNIPE-IT/tests/Feature/Api/Users/UpdateUserApiTest.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UpdateUserApiTest extends TestCase
|
||||
{
|
||||
public function testApiUsersCanBeActivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => 0]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
->patch(route('api.users.update', $user), [
|
||||
'activated' => 1,
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testApiUsersCanBeActivatedWithBooleanTrue()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => false]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
->patch(route('api.users.update', $user), [
|
||||
'activated' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testApiUsersCanBeDeactivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
->patch(route('api.users.update', $user), [
|
||||
'activated' => 0,
|
||||
]);
|
||||
|
||||
$this->assertEquals(0, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testApiUsersCanBeDeactivatedWithBooleanFalse()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
->patch(route('api.users.update', $user), [
|
||||
'activated' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals(0, $user->refresh()->activated);
|
||||
}
|
||||
}
|
97
SNIPE-IT/tests/Feature/Api/Users/UsersForSelectListTest.php
Normal file
97
SNIPE-IT/tests/Feature/Api/Users/UsersForSelectListTest.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Laravel\Passport\Passport;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UsersForSelectListTest extends TestCase
|
||||
{
|
||||
public function testUsersAreReturned()
|
||||
{
|
||||
$users = User::factory()->superuser()->count(3)->create();
|
||||
|
||||
Passport::actingAs($users->first());
|
||||
$this->getJson(route('api.users.selectlist'))
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'results',
|
||||
'pagination',
|
||||
'total_count',
|
||||
'page',
|
||||
'page_count',
|
||||
])
|
||||
->assertJson(fn(AssertableJson $json) => $json->has('results', 3)->etc());
|
||||
}
|
||||
|
||||
public function testUsersCanBeSearchedByFirstAndLastName()
|
||||
{
|
||||
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();
|
||||
|
||||
$results = collect($response->json('results'));
|
||||
|
||||
$this->assertEquals(1, $results->count());
|
||||
$this->assertTrue($results->pluck('text')->contains(fn($text) => str_contains($text, 'Luke')));
|
||||
}
|
||||
|
||||
public function testUsersScopedToCompanyWhenMultipleFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$jedi = Company::factory()->has(User::factory()->count(3)->sequence(
|
||||
['first_name' => 'Luke', 'last_name' => 'Skywalker', 'username' => 'lskywalker'],
|
||||
['first_name' => 'Obi-Wan', 'last_name' => 'Kenobi', 'username' => 'okenobi'],
|
||||
['first_name' => 'Anakin', 'last_name' => 'Skywalker', 'username' => 'askywalker'],
|
||||
))->create();
|
||||
|
||||
$sith = Company::factory()
|
||||
->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();
|
||||
|
||||
$results = collect($response->json('results'));
|
||||
|
||||
$this->assertEquals(3, $results->count());
|
||||
$this->assertTrue(
|
||||
$results->pluck('text')->contains(fn($text) => str_contains($text, 'Luke'))
|
||||
);
|
||||
$this->assertFalse(
|
||||
$results->pluck('text')->contains(fn($text) => str_contains($text, 'Darth'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testUsersScopedToCompanyDuringSearchWhenMultipleFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$jedi = Company::factory()->has(User::factory()->count(3)->sequence(
|
||||
['first_name' => 'Luke', 'last_name' => 'Skywalker', 'username' => 'lskywalker'],
|
||||
['first_name' => 'Obi-Wan', 'last_name' => 'Kenobi', 'username' => 'okenobi'],
|
||||
['first_name' => 'Anakin', 'last_name' => 'Skywalker', 'username' => 'askywalker'],
|
||||
))->create();
|
||||
|
||||
Company::factory()
|
||||
->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();
|
||||
|
||||
$results = collect($response->json('results'));
|
||||
|
||||
$this->assertEquals(3, $results->count());
|
||||
$this->assertTrue($results->pluck('text')->contains(fn($text) => str_contains($text, 'Luke')));
|
||||
$this->assertTrue($results->pluck('text')->contains(fn($text) => str_contains($text, 'Anakin')));
|
||||
|
||||
$response = $this->getJson(route('api.users.selectlist', ['search' => 'v']))->assertOk();
|
||||
$this->assertEquals(0, collect($response->json('results'))->count());
|
||||
}
|
||||
}
|
147
SNIPE-IT/tests/Feature/Api/Users/UsersSearchTest.php
Normal file
147
SNIPE-IT/tests/Feature/Api/Users/UsersSearchTest.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Laravel\Passport\Passport;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UsersSearchTest extends TestCase
|
||||
{
|
||||
public function testCanSearchByUserFirstAndLastName()
|
||||
{
|
||||
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();
|
||||
|
||||
$results = collect($response->json('rows'));
|
||||
|
||||
$this->assertEquals(1, $results->count());
|
||||
$this->assertTrue($results->pluck('name')->contains(fn($text) => str_contains($text, 'Luke')));
|
||||
$this->assertFalse($results->pluck('name')->contains(fn($text) => str_contains($text, 'Darth')));
|
||||
}
|
||||
|
||||
public function testResultsWhenSearchingForActiveUsers()
|
||||
{
|
||||
User::factory()->create(['first_name' => 'Active', 'last_name' => 'User']);
|
||||
User::factory()->create(['first_name' => 'Deleted', 'last_name' => 'User'])->delete();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->viewUsers()->create())
|
||||
->getJson(route('api.users.index', [
|
||||
'deleted' => 'false',
|
||||
'company_id' => '',
|
||||
'search' => 'user',
|
||||
'order' => 'asc',
|
||||
'offset' => '0',
|
||||
'limit' => '20',
|
||||
]))
|
||||
->assertOk();
|
||||
|
||||
$firstNames = collect($response->json('rows'))->pluck('first_name');
|
||||
|
||||
$this->assertTrue(
|
||||
$firstNames->contains('Active'),
|
||||
'Expected user does not appear in results'
|
||||
);
|
||||
|
||||
$this->assertFalse(
|
||||
$firstNames->contains('Deleted'),
|
||||
'Unexpected deleted user appears in results'
|
||||
);
|
||||
}
|
||||
|
||||
public function testResultsWhenSearchingForDeletedUsers()
|
||||
{
|
||||
User::factory()->create(['first_name' => 'Active', 'last_name' => 'User']);
|
||||
User::factory()->create(['first_name' => 'Deleted', 'last_name' => 'User'])->delete();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->viewUsers()->create())
|
||||
->getJson(route('api.users.index', [
|
||||
'deleted' => 'true',
|
||||
'company_id' => '',
|
||||
'search' => 'user',
|
||||
'order' => 'asc',
|
||||
'offset' => '0',
|
||||
'limit' => '20',
|
||||
]))
|
||||
->assertOk();
|
||||
|
||||
$firstNames = collect($response->json('rows'))->pluck('first_name');
|
||||
|
||||
$this->assertFalse(
|
||||
$firstNames->contains('Active'),
|
||||
'Unexpected active user appears in results'
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$firstNames->contains('Deleted'),
|
||||
'Expected deleted user does not appear in results'
|
||||
);
|
||||
}
|
||||
|
||||
public function testUsersScopedToCompanyWhenMultipleFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$companyA = Company::factory()
|
||||
->has(User::factory(['first_name' => 'Company A', 'last_name' => 'User']))
|
||||
->create();
|
||||
|
||||
Company::factory()
|
||||
->has(User::factory(['first_name' => 'Company B', 'last_name' => 'User']))
|
||||
->create();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->for($companyA)->viewUsers()->create())
|
||||
->getJson(route('api.users.index'))
|
||||
->assertOk();
|
||||
|
||||
$results = collect($response->json('rows'));
|
||||
|
||||
$this->assertTrue(
|
||||
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company A')),
|
||||
'User index does not contain expected user'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company B')),
|
||||
'User index contains unexpected user from another company'
|
||||
);
|
||||
}
|
||||
|
||||
public function testUsersScopedToCompanyDuringSearchWhenMultipleFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$companyA = Company::factory()
|
||||
->has(User::factory(['first_name' => 'Company A', 'last_name' => 'User']))
|
||||
->create();
|
||||
|
||||
Company::factory()
|
||||
->has(User::factory(['first_name' => 'Company B', 'last_name' => 'User']))
|
||||
->create();
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->for($companyA)->viewUsers()->create())
|
||||
->getJson(route('api.users.index', [
|
||||
'deleted' => 'false',
|
||||
'company_id' => null,
|
||||
'search' => 'user',
|
||||
'order' => 'asc',
|
||||
'offset' => '0',
|
||||
'limit' => '20',
|
||||
]))
|
||||
->assertOk();
|
||||
|
||||
$results = collect($response->json('rows'));
|
||||
|
||||
$this->assertTrue(
|
||||
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company A')),
|
||||
'User index does not contain expected user'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company B')),
|
||||
'User index contains unexpected user from another company'
|
||||
);
|
||||
}
|
||||
}
|
84
SNIPE-IT/tests/Feature/Api/Users/UsersUpdateTest.php
Normal file
84
SNIPE-IT/tests/Feature/Api/Users/UsersUpdateTest.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Department;
|
||||
use App\Models\Group;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UsersUpdateTest extends TestCase
|
||||
{
|
||||
public function testCanUpdateUserViaPatch()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$manager = User::factory()->create();
|
||||
$company = Company::factory()->create();
|
||||
$department = Department::factory()->create();
|
||||
$location = Location::factory()->create();
|
||||
[$groupA, $groupB] = Group::factory()->count(2)->create();
|
||||
|
||||
$user = User::factory()->create([
|
||||
'activated' => false,
|
||||
'remote' => false,
|
||||
'vip' => false,
|
||||
]);
|
||||
|
||||
$this->actingAsForApi($admin)
|
||||
->patchJson(route('api.users.update', $user), [
|
||||
'first_name' => 'Mabel',
|
||||
'last_name' => 'Mora',
|
||||
'username' => 'mabel',
|
||||
'password' => 'super-secret',
|
||||
'email' => 'mabel@onlymurderspod.com',
|
||||
'permissions' => '{"a.new.permission":"1"}',
|
||||
'activated' => true,
|
||||
'phone' => '619-555-5555',
|
||||
'jobtitle' => 'Host',
|
||||
'manager_id' => $manager->id,
|
||||
'employee_num' => '1111',
|
||||
'notes' => 'Pretty good artist',
|
||||
'company_id' => $company->id,
|
||||
'department_id' => $department->id,
|
||||
'location_id' => $location->id,
|
||||
'remote' => true,
|
||||
'groups' => $groupA->id,
|
||||
'vip' => true,
|
||||
'start_date' => '2021-08-01',
|
||||
'end_date' => '2025-12-31',
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
$user->refresh();
|
||||
$this->assertEquals('Mabel', $user->first_name, 'First name was not updated');
|
||||
$this->assertEquals('Mora', $user->last_name, 'Last name was not updated');
|
||||
$this->assertEquals('mabel', $user->username, 'Username was not updated');
|
||||
$this->assertTrue(Hash::check('super-secret', $user->password), 'Password was not updated');
|
||||
$this->assertEquals('mabel@onlymurderspod.com', $user->email, 'Email was not updated');
|
||||
$this->assertArrayHasKey('a.new.permission', $user->decodePermissions(), 'Permissions were not updated');
|
||||
$this->assertTrue((bool)$user->activated, 'User not marked as activated');
|
||||
$this->assertEquals('619-555-5555', $user->phone, 'Phone was not updated');
|
||||
$this->assertEquals('Host', $user->jobtitle, 'Job title was not updated');
|
||||
$this->assertTrue($user->manager->is($manager), 'Manager was not updated');
|
||||
$this->assertEquals('1111', $user->employee_num, 'Employee number was not updated');
|
||||
$this->assertEquals('Pretty good artist', $user->notes, 'Notes was not updated');
|
||||
$this->assertTrue($user->company->is($company), 'Company was not updated');
|
||||
$this->assertTrue($user->department->is($department), 'Department was not updated');
|
||||
$this->assertTrue($user->location->is($location), 'Location was not updated');
|
||||
$this->assertEquals(1, $user->remote, 'Remote was not updated');
|
||||
$this->assertTrue($user->groups->contains($groupA), 'Groups were not updated');
|
||||
$this->assertEquals(1, $user->vip, 'VIP was not updated');
|
||||
$this->assertEquals('2021-08-01', $user->start_date, 'Start date was not updated');
|
||||
$this->assertEquals('2025-12-31', $user->end_date, 'End date was not updated');
|
||||
|
||||
// `groups` can be an id or array or ids
|
||||
$this->patch(route('api.users.update', $user), ['groups' => [$groupA->id, $groupB->id]]);
|
||||
|
||||
$user->refresh();
|
||||
$this->assertTrue($user->groups->contains($groupA), 'Not part of expected group');
|
||||
$this->assertTrue($user->groups->contains($groupB), 'Not part of expected group');
|
||||
}
|
||||
}
|
88
SNIPE-IT/tests/Feature/Checkins/AccessoryCheckinTest.php
Normal file
88
SNIPE-IT/tests/Feature/Checkins/AccessoryCheckinTest.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Checkins;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckinAccessoryNotification;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AccessoryCheckinTest extends TestCase
|
||||
{
|
||||
public function testCheckingInAccessoryRequiresCorrectPermission()
|
||||
{
|
||||
$accessory = Accessory::factory()->checkedOutToUser()->create();
|
||||
|
||||
$this->actingAs(User::factory()->create())
|
||||
->post(route('accessories.checkin.store', $accessory->users->first()->pivot->id))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testAccessoryCanBeCheckedIn()
|
||||
{
|
||||
Event::fake([CheckoutableCheckedIn::class]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
$accessory = Accessory::factory()->checkedOutToUser($user)->create();
|
||||
|
||||
$this->assertTrue($accessory->users->contains($user));
|
||||
|
||||
$this->actingAs(User::factory()->checkinAccessories()->create())
|
||||
->post(route('accessories.checkin.store', $accessory->users->first()->pivot->id));
|
||||
|
||||
$this->assertFalse($accessory->fresh()->users->contains($user));
|
||||
|
||||
Event::assertDispatched(CheckoutableCheckedIn::class, 1);
|
||||
}
|
||||
|
||||
public function testEmailSentToUserIfSettingEnabled()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
$accessory = Accessory::factory()->checkedOutToUser($user)->create();
|
||||
|
||||
$accessory->category->update(['checkin_email' => true]);
|
||||
|
||||
event(new CheckoutableCheckedIn(
|
||||
$accessory,
|
||||
$user,
|
||||
User::factory()->checkinAccessories()->create(),
|
||||
'',
|
||||
));
|
||||
|
||||
Notification::assertSentTo(
|
||||
[$user],
|
||||
function (CheckinAccessoryNotification $notification, $channels) {
|
||||
return in_array('mail', $channels);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailNotSentToUserIfSettingDisabled()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
$accessory = Accessory::factory()->checkedOutToUser($user)->create();
|
||||
|
||||
$accessory->category->update(['checkin_email' => false]);
|
||||
|
||||
event(new CheckoutableCheckedIn(
|
||||
$accessory,
|
||||
$user,
|
||||
User::factory()->checkinAccessories()->create(),
|
||||
'',
|
||||
));
|
||||
|
||||
Notification::assertNotSentTo(
|
||||
[$user],
|
||||
function (CheckinAccessoryNotification $notification, $channels) {
|
||||
return in_array('mail', $channels);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
163
SNIPE-IT/tests/Feature/Checkins/AssetCheckinTest.php
Normal file
163
SNIPE-IT/tests/Feature/Checkins/AssetCheckinTest.php
Normal file
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Checkins;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Location;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetCheckinTest extends TestCase
|
||||
{
|
||||
public function testCheckingInAssetRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->post(route('hardware.checkin.store', [
|
||||
'assetId' => Asset::factory()->assignedToUser()->create()->id,
|
||||
]))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testCannotCheckInAssetThatIsNotCheckedOut()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(route('hardware.checkin.store', ['assetId' => Asset::factory()->create()->id]))
|
||||
->assertSessionHas('error')
|
||||
->assertRedirect(route('hardware.index'));
|
||||
}
|
||||
|
||||
public function testAssetCanBeCheckedIn()
|
||||
{
|
||||
Event::fake([CheckoutableCheckedIn::class]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
$location = Location::factory()->create();
|
||||
$status = Statuslabel::first() ?? Statuslabel::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser($user)->create([
|
||||
'expected_checkin' => now()->addDay(),
|
||||
'last_checkin' => null,
|
||||
'accepted' => 'accepted',
|
||||
]);
|
||||
|
||||
$this->assertTrue($asset->assignedTo->is($user));
|
||||
|
||||
$currentTimestamp = now();
|
||||
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(
|
||||
route('hardware.checkin.store', ['assetId' => $asset->id, 'backto' => 'user']),
|
||||
[
|
||||
'name' => 'Changed Name',
|
||||
'status_id' => $status->id,
|
||||
'location_id' => $location->id,
|
||||
],
|
||||
)
|
||||
->assertRedirect(route('users.show', $user));
|
||||
|
||||
$this->assertNull($asset->refresh()->assignedTo);
|
||||
$this->assertNull($asset->expected_checkin);
|
||||
$this->assertNotNull($asset->last_checkin);
|
||||
$this->assertNull($asset->assignedTo);
|
||||
$this->assertNull($asset->assigned_type);
|
||||
$this->assertNull($asset->accepted);
|
||||
$this->assertEquals('Changed Name', $asset->name);
|
||||
$this->assertEquals($status->id, $asset->status_id);
|
||||
$this->assertTrue($asset->location()->is($location));
|
||||
|
||||
Event::assertDispatched(function (CheckoutableCheckedIn $event) use ($currentTimestamp) {
|
||||
// this could be better mocked but is ok for now.
|
||||
return Carbon::parse($event->action_date)->diffInSeconds($currentTimestamp) < 2;
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public function testLocationIsSetToRTDLocationByDefaultUponCheckin()
|
||||
{
|
||||
$rtdLocation = Location::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser()->create([
|
||||
'location_id' => Location::factory()->create()->id,
|
||||
'rtd_location_id' => $rtdLocation->id,
|
||||
]);
|
||||
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(route('hardware.checkin.store', ['assetId' => $asset->id]));
|
||||
|
||||
$this->assertTrue($asset->refresh()->location()->is($rtdLocation));
|
||||
}
|
||||
|
||||
public function testDefaultLocationCanBeUpdatedUponCheckin()
|
||||
{
|
||||
$location = Location::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(route('hardware.checkin.store', ['assetId' => $asset->id]), [
|
||||
'location_id' => $location->id,
|
||||
'update_default_location' => 0
|
||||
]);
|
||||
|
||||
$this->assertTrue($asset->refresh()->defaultLoc()->is($location));
|
||||
}
|
||||
|
||||
public function testAssetsLicenseSeatsAreClearedUponCheckin()
|
||||
{
|
||||
$asset = Asset::factory()->assignedToUser()->create();
|
||||
LicenseSeat::factory()->assignedToUser()->for($asset)->create();
|
||||
|
||||
$this->assertNotNull($asset->licenseseats->first()->assigned_to);
|
||||
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(route('hardware.checkin.store', ['assetId' => $asset->id]));
|
||||
|
||||
$this->assertNull($asset->refresh()->licenseseats->first()->assigned_to);
|
||||
}
|
||||
|
||||
public function testLegacyLocationValuesSetToZeroAreUpdated()
|
||||
{
|
||||
$asset = Asset::factory()->canBeInvalidUponCreation()->assignedToUser()->create([
|
||||
'rtd_location_id' => 0,
|
||||
'location_id' => 0,
|
||||
]);
|
||||
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(route('hardware.checkin.store', ['assetId' => $asset->id]));
|
||||
|
||||
$this->assertNull($asset->refresh()->rtd_location_id);
|
||||
$this->assertEquals($asset->location_id, $asset->rtd_location_id);
|
||||
}
|
||||
|
||||
public function testPendingCheckoutAcceptancesAreClearedUponCheckin()
|
||||
{
|
||||
$asset = Asset::factory()->assignedToUser()->create();
|
||||
|
||||
$acceptance = CheckoutAcceptance::factory()->for($asset, 'checkoutable')->pending()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(route('hardware.checkin.store', ['assetId' => $asset->id]));
|
||||
|
||||
$this->assertFalse($acceptance->exists(), 'Acceptance was not deleted');
|
||||
}
|
||||
|
||||
public function testCheckinTimeAndActionLogNoteCanBeSet()
|
||||
{
|
||||
Event::fake([CheckoutableCheckedIn::class]);
|
||||
|
||||
$this->actingAs(User::factory()->checkinAssets()->create())
|
||||
->post(route(
|
||||
'hardware.checkin.store',
|
||||
['assetId' => Asset::factory()->assignedToUser()->create()->id]
|
||||
), [
|
||||
'checkin_at' => '2023-01-02',
|
||||
'note' => 'hello'
|
||||
]);
|
||||
|
||||
Event::assertDispatched(function (CheckoutableCheckedIn $event) {
|
||||
return $event->action_date === '2023-01-02' && $event->note === 'hello';
|
||||
}, 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\CheckoutAcceptances;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Notifications\AcceptanceAssetAcceptedNotification;
|
||||
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
||||
use Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AccessoryAcceptanceTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* This can be absorbed into a bigger test
|
||||
*/
|
||||
public function testUsersNameIsIncludedInAccessoryAcceptedNotification()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$this->settings->enableAlertEmail();
|
||||
|
||||
$acceptance = CheckoutAcceptance::factory()
|
||||
->pending()
|
||||
->for(Accessory::factory()->appleMouse(), 'checkoutable')
|
||||
->create();
|
||||
|
||||
$this->actingAs($acceptance->assignedTo)
|
||||
->post(route('account.store-acceptance', $acceptance), ['asset_acceptance' => 'accepted'])
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$this->assertNotNull($acceptance->fresh()->accepted_at);
|
||||
|
||||
Notification::assertSentTo(
|
||||
$acceptance,
|
||||
function (AcceptanceAssetAcceptedNotification $notification) use ($acceptance) {
|
||||
$this->assertStringContainsString(
|
||||
$acceptance->assignedTo->present()->fullName,
|
||||
$notification->toMail()->render()
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This can be absorbed into a bigger test
|
||||
*/
|
||||
public function testUsersNameIsIncludedInAccessoryDeclinedNotification()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$this->settings->enableAlertEmail();
|
||||
|
||||
$acceptance = CheckoutAcceptance::factory()
|
||||
->pending()
|
||||
->for(Accessory::factory()->appleMouse(), 'checkoutable')
|
||||
->create();
|
||||
|
||||
$this->actingAs($acceptance->assignedTo)
|
||||
->post(route('account.store-acceptance', $acceptance), ['asset_acceptance' => 'declined'])
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$this->assertNotNull($acceptance->fresh()->declined_at);
|
||||
|
||||
Notification::assertSentTo(
|
||||
$acceptance,
|
||||
function (AcceptanceAssetDeclinedNotification $notification) use ($acceptance) {
|
||||
$this->assertStringContainsString(
|
||||
$acceptance->assignedTo->present()->fullName,
|
||||
$notification->toMail($acceptance)->render()
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
93
SNIPE-IT/tests/Feature/Checkouts/AccessoryCheckoutTest.php
Normal file
93
SNIPE-IT/tests/Feature/Checkouts/AccessoryCheckoutTest.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Checkouts;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutAccessoryNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AccessoryCheckoutTest extends TestCase
|
||||
{
|
||||
public function testCheckingOutAccessoryRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->post(route('accessories.checkout.store', Accessory::factory()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidationWhenCheckingOutAccessory()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkoutAccessories()->create())
|
||||
->post(route('accessories.checkout.store', Accessory::factory()->create()), [
|
||||
// missing assigned_to
|
||||
])
|
||||
->assertSessionHas('error');
|
||||
}
|
||||
|
||||
public function testAccessoryMustBeAvailableWhenCheckingOut()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkoutAccessories()->create())
|
||||
->post(route('accessories.checkout.store', Accessory::factory()->withoutItemsRemaining()->create()), [
|
||||
'assigned_to' => User::factory()->create()->id,
|
||||
])
|
||||
->assertSessionHas('error');
|
||||
}
|
||||
|
||||
public function testAccessoryCanBeCheckedOut()
|
||||
{
|
||||
$accessory = Accessory::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutAccessories()->create())
|
||||
->post(route('accessories.checkout.store', $accessory), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
$this->assertTrue($accessory->users->contains($user));
|
||||
}
|
||||
|
||||
public function testUserSentNotificationUponCheckout()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$accessory = Accessory::factory()->requiringAcceptance()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutAccessories()->create())
|
||||
->post(route('accessories.checkout.store', $accessory), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
Notification::assertSentTo($user, CheckoutAccessoryNotification::class);
|
||||
}
|
||||
|
||||
public function testActionLogCreatedUponCheckout()
|
||||
{
|
||||
$accessory = Accessory::factory()->create();
|
||||
$actor = User::factory()->checkoutAccessories()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('accessories.checkout.store', $accessory), [
|
||||
'assigned_to' => $user->id,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertEquals(
|
||||
1,
|
||||
Actionlog::where([
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $user->id,
|
||||
'target_type' => User::class,
|
||||
'item_id' => $accessory->id,
|
||||
'item_type' => Accessory::class,
|
||||
'user_id' => $actor->id,
|
||||
'note' => 'oh hi there',
|
||||
])->count(),
|
||||
'Log entry either does not exist or there are more than expected'
|
||||
);
|
||||
}
|
||||
}
|
93
SNIPE-IT/tests/Feature/Checkouts/ConsumableCheckoutTest.php
Normal file
93
SNIPE-IT/tests/Feature/Checkouts/ConsumableCheckoutTest.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Checkouts;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ConsumableCheckoutTest extends TestCase
|
||||
{
|
||||
public function testCheckingOutConsumableRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->post(route('consumables.checkout.store', Consumable::factory()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testValidationWhenCheckingOutConsumable()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', Consumable::factory()->create()), [
|
||||
// missing assigned_to
|
||||
])
|
||||
->assertSessionHas('error');
|
||||
}
|
||||
|
||||
public function testConsumableMustBeAvailableWhenCheckingOut()
|
||||
{
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', Consumable::factory()->withoutItemsRemaining()->create()), [
|
||||
'assigned_to' => User::factory()->create()->id,
|
||||
])
|
||||
->assertSessionHas('error');
|
||||
}
|
||||
|
||||
public function testConsumableCanBeCheckedOut()
|
||||
{
|
||||
$consumable = Consumable::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
$this->assertTrue($user->consumables->contains($consumable));
|
||||
}
|
||||
|
||||
public function testUserSentNotificationUponCheckout()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$consumable = Consumable::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutConsumables()->create())
|
||||
->post(route('consumables.checkout.store', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
|
||||
Notification::assertSentTo($user, CheckoutConsumableNotification::class);
|
||||
}
|
||||
|
||||
public function testActionLogCreatedUponCheckout()
|
||||
{
|
||||
$consumable = Consumable::factory()->create();
|
||||
$actor = User::factory()->checkoutConsumables()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('consumables.checkout.store', $consumable), [
|
||||
'assigned_to' => $user->id,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertEquals(
|
||||
1,
|
||||
Actionlog::where([
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $user->id,
|
||||
'target_type' => User::class,
|
||||
'item_id' => $consumable->id,
|
||||
'item_type' => Consumable::class,
|
||||
'user_id' => $actor->id,
|
||||
'note' => 'oh hi there',
|
||||
])->count(),
|
||||
'Log entry either does not exist or there are more than expected'
|
||||
);
|
||||
}
|
||||
}
|
59
SNIPE-IT/tests/Feature/Checkouts/LicenseCheckoutTest.php
Normal file
59
SNIPE-IT/tests/Feature/Checkouts/LicenseCheckoutTest.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Checkouts;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LicenseCheckoutTest extends TestCase
|
||||
{
|
||||
public function testNotesAreStoredInActionLogOnCheckoutToAsset()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$asset = Asset::factory()->create();
|
||||
$licenseSeat = LicenseSeat::factory()->create();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->post("/licenses/{$licenseSeat->license->id}/checkout", [
|
||||
'checkout_to_type' => 'asset',
|
||||
'assigned_to' => null,
|
||||
'asset_id' => $asset->id,
|
||||
'notes' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('action_logs', [
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $asset->id,
|
||||
'target_type' => Asset::class,
|
||||
'item_id' => $licenseSeat->license->id,
|
||||
'item_type' => License::class,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testNotesAreStoredInActionLogOnCheckoutToUser()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$licenseSeat = LicenseSeat::factory()->create();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->post("/licenses/{$licenseSeat->license->id}/checkout", [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_to' => $admin->id,
|
||||
'asset_id' => null,
|
||||
'notes' => 'oh hi there',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('action_logs', [
|
||||
'action_type' => 'checkout',
|
||||
'target_id' => $admin->id,
|
||||
'target_type' => User::class,
|
||||
'item_id' => $licenseSeat->license->id,
|
||||
'item_type' => License::class,
|
||||
'note' => 'oh hi there',
|
||||
]);
|
||||
}
|
||||
}
|
16
SNIPE-IT/tests/Feature/DashboardTest.php
Normal file
16
SNIPE-IT/tests/Feature/DashboardTest.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DashboardTest extends TestCase
|
||||
{
|
||||
public function testUsersWithoutAdminAccessAreRedirected()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->get(route('home'))
|
||||
->assertRedirect(route('view-assets'));
|
||||
}
|
||||
}
|
105
SNIPE-IT/tests/Feature/Livewire/CategoryEditFormTest.php
Normal file
105
SNIPE-IT/tests/Feature/Livewire/CategoryEditFormTest.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Livewire;
|
||||
|
||||
use App\Http\Livewire\CategoryEditForm;
|
||||
use Livewire\Livewire;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CategoryEditFormTest extends TestCase
|
||||
{
|
||||
public function testTheComponentCanRender()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class)->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testSendEmailCheckboxIsCheckedOnLoadWhenSendEmailIsExistingSetting()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'sendCheckInEmail' => true,
|
||||
'eulaText' => '',
|
||||
'useDefaultEula' => false,
|
||||
])->assertSet('sendCheckInEmail', true);
|
||||
}
|
||||
|
||||
public function testSendEmailCheckboxIsCheckedOnLoadWhenCategoryEulaSet()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'sendCheckInEmail' => false,
|
||||
'eulaText' => 'Some Content',
|
||||
'useDefaultEula' => false,
|
||||
])->assertSet('sendCheckInEmail', true);
|
||||
}
|
||||
|
||||
public function testSendEmailCheckboxIsCheckedOnLoadWhenUsingDefaultEula()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'sendCheckInEmail' => false,
|
||||
'eulaText' => '',
|
||||
'useDefaultEula' => true,
|
||||
])->assertSet('sendCheckInEmail', true);
|
||||
}
|
||||
|
||||
public function testSendEmailCheckBoxIsUncheckedOnLoadWhenSendEmailIsFalseNoCategoryEulaSetAndNotUsingDefaultEula()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'sendCheckInEmail' => false,
|
||||
'eulaText' => '',
|
||||
'useDefaultEula' => false,
|
||||
])->assertSet('sendCheckInEmail', false);
|
||||
}
|
||||
|
||||
public function testSendEmailCheckboxIsCheckedWhenCategoryEulaEntered()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'sendCheckInEmail' => false,
|
||||
'useDefaultEula' => false,
|
||||
])->assertSet('sendCheckInEmail', false)
|
||||
->set('eulaText', 'Some Content')
|
||||
->assertSet('sendCheckInEmail', true);
|
||||
}
|
||||
|
||||
public function testSendEmailCheckboxCheckedAndDisabledAndEulaTextDisabledWhenUseDefaultEulaSelected()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'sendCheckInEmail' => false,
|
||||
'useDefaultEula' => false,
|
||||
])->assertSet('sendCheckInEmail', false)
|
||||
->set('useDefaultEula', true)
|
||||
->assertSet('sendCheckInEmail', true)
|
||||
->assertSet('eulaTextDisabled', true)
|
||||
->assertSet('sendCheckInEmailDisabled', true);
|
||||
}
|
||||
|
||||
public function testSendEmailCheckboxEnabledAndSetToOriginalValueWhenNoCategoryEulaAndNotUsingGlobalEula()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'eulaText' => 'Some Content',
|
||||
'sendCheckInEmail' => false,
|
||||
'useDefaultEula' => true,
|
||||
])
|
||||
->set('useDefaultEula', false)
|
||||
->set('eulaText', '')
|
||||
->assertSet('sendCheckInEmail', false)
|
||||
->assertSet('sendCheckInEmailDisabled', false);
|
||||
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'eulaText' => 'Some Content',
|
||||
'sendCheckInEmail' => true,
|
||||
'useDefaultEula' => true,
|
||||
])
|
||||
->set('useDefaultEula', false)
|
||||
->set('eulaText', '')
|
||||
->assertSet('sendCheckInEmail', true)
|
||||
->assertSet('sendCheckInEmailDisabled', false);
|
||||
}
|
||||
|
||||
public function testEulaFieldEnabledOnLoadWhenNotUsingDefaultEula()
|
||||
{
|
||||
Livewire::test(CategoryEditForm::class, [
|
||||
'sendCheckInEmail' => false,
|
||||
'eulaText' => '',
|
||||
'useDefaultEula' => false,
|
||||
])->assertSet('eulaTextDisabled', false);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Notifications\Email;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Asset;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckinAssetNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @group notifications
|
||||
*/
|
||||
class EmailNotificationsUponCheckinTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Notification::fake();
|
||||
}
|
||||
|
||||
public function testCheckInEmailSentToUserIfSettingEnabled()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser($user)->create();
|
||||
|
||||
$asset->model->category->update(['checkin_email' => true]);
|
||||
|
||||
$this->fireCheckInEvent($asset, $user);
|
||||
|
||||
Notification::assertSentTo(
|
||||
$user,
|
||||
function (CheckinAssetNotification $notification, $channels) {
|
||||
return in_array('mail', $channels);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public function testCheckInEmailNotSentToUserIfSettingDisabled()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$asset = Asset::factory()->assignedToUser($user)->create();
|
||||
|
||||
$asset->model->category->update(['checkin_email' => false]);
|
||||
|
||||
$this->fireCheckInEvent($asset, $user);
|
||||
|
||||
Notification::assertNotSentTo(
|
||||
$user,
|
||||
function (CheckinAssetNotification $notification, $channels) {
|
||||
return in_array('mail', $channels);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function fireCheckInEvent($asset, $user): void
|
||||
{
|
||||
event(new CheckoutableCheckedIn(
|
||||
$asset,
|
||||
$user,
|
||||
User::factory()->checkinAssets()->create(),
|
||||
''
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Notifications\Webhooks;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Component;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckinAccessoryNotification;
|
||||
use App\Notifications\CheckinAssetNotification;
|
||||
use App\Notifications\CheckinLicenseSeatNotification;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @group notifications
|
||||
*/
|
||||
class SlackNotificationsUponCheckinTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Notification::fake();
|
||||
}
|
||||
|
||||
public function assetCheckInTargets(): array
|
||||
{
|
||||
return [
|
||||
'Asset checked out to user' => [fn() => User::factory()->create()],
|
||||
'Asset checked out to asset' => [fn() => Asset::factory()->laptopMbp()->create()],
|
||||
'Asset checked out to location' => [fn() => Location::factory()->create()],
|
||||
];
|
||||
}
|
||||
|
||||
public function licenseCheckInTargets(): array
|
||||
{
|
||||
return [
|
||||
'License checked out to user' => [fn() => User::factory()->create()],
|
||||
'License checked out to asset' => [fn() => Asset::factory()->laptopMbp()->create()],
|
||||
];
|
||||
}
|
||||
|
||||
public function testAccessoryCheckinSendsSlackNotificationWhenSettingEnabled()
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckInEvent(
|
||||
Accessory::factory()->create(),
|
||||
User::factory()->create(),
|
||||
);
|
||||
|
||||
$this->assertSlackNotificationSent(CheckinAccessoryNotification::class);
|
||||
}
|
||||
|
||||
public function testAccessoryCheckinDoesNotSendSlackNotificationWhenSettingDisabled()
|
||||
{
|
||||
$this->settings->disableSlackWebhook();
|
||||
|
||||
$this->fireCheckInEvent(
|
||||
Accessory::factory()->create(),
|
||||
User::factory()->create(),
|
||||
);
|
||||
|
||||
$this->assertNoSlackNotificationSent(CheckinAccessoryNotification::class);
|
||||
}
|
||||
|
||||
/** @dataProvider assetCheckInTargets */
|
||||
public function testAssetCheckinSendsSlackNotificationWhenSettingEnabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckInEvent(
|
||||
Asset::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertSlackNotificationSent(CheckinAssetNotification::class);
|
||||
}
|
||||
|
||||
/** @dataProvider assetCheckInTargets */
|
||||
public function testAssetCheckinDoesNotSendSlackNotificationWhenSettingDisabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->disableSlackWebhook();
|
||||
|
||||
$this->fireCheckInEvent(
|
||||
Asset::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertNoSlackNotificationSent(CheckinAssetNotification::class);
|
||||
}
|
||||
|
||||
public function testComponentCheckinDoesNotSendSlackNotification()
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckInEvent(
|
||||
Component::factory()->create(),
|
||||
Asset::factory()->laptopMbp()->create(),
|
||||
);
|
||||
|
||||
Notification::assertNothingSent();
|
||||
}
|
||||
|
||||
/** @dataProvider licenseCheckInTargets */
|
||||
public function testLicenseCheckinSendsSlackNotificationWhenSettingEnabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckInEvent(
|
||||
LicenseSeat::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertSlackNotificationSent(CheckinLicenseSeatNotification::class);
|
||||
}
|
||||
|
||||
/** @dataProvider licenseCheckInTargets */
|
||||
public function testLicenseCheckinDoesNotSendSlackNotificationWhenSettingDisabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->disableSlackWebhook();
|
||||
|
||||
$this->fireCheckInEvent(
|
||||
LicenseSeat::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertNoSlackNotificationSent(CheckinLicenseSeatNotification::class);
|
||||
}
|
||||
|
||||
private function fireCheckInEvent(Model $checkoutable, Model $target)
|
||||
{
|
||||
event(new CheckoutableCheckedIn(
|
||||
$checkoutable,
|
||||
$target,
|
||||
User::factory()->superuser()->create(),
|
||||
''
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Notifications\Webhooks;
|
||||
|
||||
use App\Events\CheckoutableCheckedOut;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckoutAccessoryNotification;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use App\Notifications\CheckoutConsumableNotification;
|
||||
use App\Notifications\CheckoutLicenseSeatNotification;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @group notifications
|
||||
*/
|
||||
class SlackNotificationsUponCheckoutTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Notification::fake();
|
||||
}
|
||||
|
||||
public function assetCheckoutTargets(): array
|
||||
{
|
||||
return [
|
||||
'Asset checked out to user' => [fn() => User::factory()->create()],
|
||||
'Asset checked out to asset' => [fn() => Asset::factory()->laptopMbp()->create()],
|
||||
'Asset checked out to location' => [fn() => Location::factory()->create()],
|
||||
];
|
||||
}
|
||||
|
||||
public function licenseCheckoutTargets(): array
|
||||
{
|
||||
return [
|
||||
'License checked out to user' => [fn() => User::factory()->create()],
|
||||
'License checked out to asset' => [fn() => Asset::factory()->laptopMbp()->create()],
|
||||
];
|
||||
}
|
||||
|
||||
public function testAccessoryCheckoutSendsSlackNotificationWhenSettingEnabled()
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
Accessory::factory()->create(),
|
||||
User::factory()->create(),
|
||||
);
|
||||
|
||||
$this->assertSlackNotificationSent(CheckoutAccessoryNotification::class);
|
||||
}
|
||||
|
||||
public function testAccessoryCheckoutDoesNotSendSlackNotificationWhenSettingDisabled()
|
||||
{
|
||||
$this->settings->disableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
Accessory::factory()->create(),
|
||||
User::factory()->create(),
|
||||
);
|
||||
|
||||
$this->assertNoSlackNotificationSent(CheckoutAccessoryNotification::class);
|
||||
}
|
||||
|
||||
/** @dataProvider assetCheckoutTargets */
|
||||
public function testAssetCheckoutSendsSlackNotificationWhenSettingEnabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
Asset::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertSlackNotificationSent(CheckoutAssetNotification::class);
|
||||
}
|
||||
|
||||
/** @dataProvider assetCheckoutTargets */
|
||||
public function testAssetCheckoutDoesNotSendSlackNotificationWhenSettingDisabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->disableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
Asset::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertNoSlackNotificationSent(CheckoutAssetNotification::class);
|
||||
}
|
||||
|
||||
public function testComponentCheckoutDoesNotSendSlackNotification()
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
Component::factory()->create(),
|
||||
Asset::factory()->laptopMbp()->create(),
|
||||
);
|
||||
|
||||
Notification::assertNothingSent();
|
||||
}
|
||||
|
||||
public function testConsumableCheckoutSendsSlackNotificationWhenSettingEnabled()
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
Consumable::factory()->create(),
|
||||
User::factory()->create(),
|
||||
);
|
||||
|
||||
$this->assertSlackNotificationSent(CheckoutConsumableNotification::class);
|
||||
}
|
||||
|
||||
public function testConsumableCheckoutDoesNotSendSlackNotificationWhenSettingDisabled()
|
||||
{
|
||||
$this->settings->disableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
Consumable::factory()->create(),
|
||||
User::factory()->create(),
|
||||
);
|
||||
|
||||
$this->assertNoSlackNotificationSent(CheckoutConsumableNotification::class);
|
||||
}
|
||||
|
||||
/** @dataProvider licenseCheckoutTargets */
|
||||
public function testLicenseCheckoutSendsSlackNotificationWhenSettingEnabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->enableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
LicenseSeat::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertSlackNotificationSent(CheckoutLicenseSeatNotification::class);
|
||||
}
|
||||
|
||||
/** @dataProvider licenseCheckoutTargets */
|
||||
public function testLicenseCheckoutDoesNotSendSlackNotificationWhenSettingDisabled($checkoutTarget)
|
||||
{
|
||||
$this->settings->disableSlackWebhook();
|
||||
|
||||
$this->fireCheckOutEvent(
|
||||
LicenseSeat::factory()->create(),
|
||||
$checkoutTarget(),
|
||||
);
|
||||
|
||||
$this->assertNoSlackNotificationSent(CheckoutLicenseSeatNotification::class);
|
||||
}
|
||||
|
||||
private function fireCheckOutEvent(Model $checkoutable, Model $target)
|
||||
{
|
||||
event(new CheckoutableCheckedOut(
|
||||
$checkoutable,
|
||||
$target,
|
||||
User::factory()->superuser()->create(),
|
||||
'',
|
||||
));
|
||||
}
|
||||
}
|
132
SNIPE-IT/tests/Feature/Reports/CustomReportTest.php
Normal file
132
SNIPE-IT/tests/Feature/Reports/CustomReportTest.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Reports;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\TestResponse;
|
||||
use League\Csv\Reader;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CustomReportTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
TestResponse::macro(
|
||||
'assertSeeTextInStreamedResponse',
|
||||
function (string $needle) {
|
||||
Assert::assertTrue(
|
||||
collect(Reader::createFromString($this->streamedContent())->getRecords())
|
||||
->pluck(0)
|
||||
->contains($needle)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
|
||||
TestResponse::macro(
|
||||
'assertDontSeeTextInStreamedResponse',
|
||||
function (string $needle) {
|
||||
Assert::assertFalse(
|
||||
collect(Reader::createFromString($this->streamedContent())->getRecords())
|
||||
->pluck(0)
|
||||
->contains($needle)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function testCustomAssetReport()
|
||||
{
|
||||
Asset::factory()->create(['name' => 'Asset A']);
|
||||
Asset::factory()->create(['name' => 'Asset B']);
|
||||
|
||||
$this->actingAs(User::factory()->canViewReports()->create())
|
||||
->post('reports/custom', [
|
||||
'asset_name' => '1',
|
||||
'asset_tag' => '1',
|
||||
'serial' => '1',
|
||||
])->assertOk()
|
||||
->assertHeader('content-type', 'text/csv; charset=UTF-8')
|
||||
->assertSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B');
|
||||
}
|
||||
|
||||
public function testCustomAssetReportAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
Asset::factory()->for($companyA)->create(['name' => 'Asset A']);
|
||||
Asset::factory()->for($companyB)->create(['name' => 'Asset B']);
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->canViewReports()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->canViewReports()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser)
|
||||
->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1'])
|
||||
->assertSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B');
|
||||
|
||||
$this->actingAs($userInCompanyA)
|
||||
->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1'])
|
||||
->assertSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B');
|
||||
|
||||
$this->actingAs($userInCompanyB)
|
||||
->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1'])
|
||||
->assertSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B');
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser)
|
||||
->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1'])
|
||||
->assertSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B');
|
||||
|
||||
$this->actingAs($userInCompanyA)
|
||||
->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1'])
|
||||
->assertSeeTextInStreamedResponse('Asset A')
|
||||
->assertDontSeeTextInStreamedResponse('Asset B');
|
||||
|
||||
$this->actingAs($userInCompanyB)
|
||||
->post('reports/custom', ['asset_name' => '1', 'asset_tag' => '1', 'serial' => '1'])
|
||||
->assertDontSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B');
|
||||
}
|
||||
|
||||
public function testCanLimitAssetsByLastCheckIn()
|
||||
{
|
||||
Asset::factory()->create(['name' => 'Asset A', 'last_checkin' => '2023-08-01']);
|
||||
Asset::factory()->create(['name' => 'Asset B', 'last_checkin' => '2023-08-02']);
|
||||
Asset::factory()->create(['name' => 'Asset C', 'last_checkin' => '2023-08-03']);
|
||||
Asset::factory()->create(['name' => 'Asset D', 'last_checkin' => '2023-08-04']);
|
||||
Asset::factory()->create(['name' => 'Asset E', 'last_checkin' => '2023-08-05']);
|
||||
|
||||
$this->actingAs(User::factory()->canViewReports()->create())
|
||||
->post('reports/custom', [
|
||||
'asset_name' => '1',
|
||||
'asset_tag' => '1',
|
||||
'serial' => '1',
|
||||
'checkin_date' => '1',
|
||||
'checkin_date_start' => '2023-08-02',
|
||||
'checkin_date_end' => '2023-08-04',
|
||||
])->assertOk()
|
||||
->assertHeader('content-type', 'text/csv; charset=UTF-8')
|
||||
->assertDontSeeTextInStreamedResponse('Asset A')
|
||||
->assertSeeTextInStreamedResponse('Asset B')
|
||||
->assertSeeTextInStreamedResponse('Asset C')
|
||||
->assertSeeTextInStreamedResponse('Asset D')
|
||||
->assertDontSeeTextInStreamedResponse('Asset E');
|
||||
}
|
||||
}
|
82
SNIPE-IT/tests/Feature/Users/UpdateUserTest.php
Normal file
82
SNIPE-IT/tests/Feature/Users/UpdateUserTest.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Users;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UpdateUserTest extends TestCase
|
||||
{
|
||||
public function testUsersCanBeActivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => 0]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $user), [
|
||||
'first_name' => $user->first_name,
|
||||
'username' => $user->username,
|
||||
'activated' => 1,
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testUsersCanBeActivatedWithBooleanTrue()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => false]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $user), [
|
||||
'first_name' => $user->first_name,
|
||||
'username' => $user->username,
|
||||
'activated' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testUsersCanBeDeactivatedWithNumber()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $user), [
|
||||
'first_name' => $user->first_name,
|
||||
'username' => $user->username,
|
||||
'activated' => 0,
|
||||
]);
|
||||
|
||||
$this->assertEquals(0, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testUsersCanBeDeactivatedWithBooleanFalse()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create(['activated' => true]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $user), [
|
||||
'first_name' => $user->first_name,
|
||||
'username' => $user->username,
|
||||
'activated' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals(0, $user->refresh()->activated);
|
||||
}
|
||||
|
||||
public function testUsersUpdatingThemselvesDoNotDeactivateTheirAccount()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create(['activated' => true]);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put(route('users.update', $admin), [
|
||||
'first_name' => $admin->first_name,
|
||||
'username' => $admin->username,
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $admin->refresh()->activated);
|
||||
}
|
||||
}
|
26
SNIPE-IT/tests/Support/AssertsAgainstSlackNotifications.php
Normal file
26
SNIPE-IT/tests/Support/AssertsAgainstSlackNotifications.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Notifications\AnonymousNotifiable;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
trait AssertsAgainstSlackNotifications
|
||||
{
|
||||
public function assertSlackNotificationSent(string $notificationClass)
|
||||
{
|
||||
Notification::assertSentTo(
|
||||
new AnonymousNotifiable,
|
||||
$notificationClass,
|
||||
function ($notification, $channels, $notifiable) {
|
||||
return $notifiable->routes['slack'] === Setting::getSettings()->webhook_endpoint;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function assertNoSlackNotificationSent(string $notificationClass)
|
||||
{
|
||||
Notification::assertNotSentTo(new AnonymousNotifiable, $notificationClass);
|
||||
}
|
||||
}
|
91
SNIPE-IT/tests/Support/CustomTestMacros.php
Normal file
91
SNIPE-IT/tests/Support/CustomTestMacros.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Testing\TestResponse;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use RuntimeException;
|
||||
|
||||
trait CustomTestMacros
|
||||
{
|
||||
protected function registerCustomMacros()
|
||||
{
|
||||
$guardAgainstNullProperty = function (Model $model, string $property) {
|
||||
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."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TestResponse::macro(
|
||||
'assertResponseContainsInRows',
|
||||
function (Model $model, string $property = 'name') use ($guardAgainstNullProperty) {
|
||||
$guardAgainstNullProperty($model, $property);
|
||||
|
||||
Assert::assertTrue(
|
||||
collect($this['rows'])->pluck($property)->contains(e($model->{$property})),
|
||||
"Response did not contain the expected value: {$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(e($model->{$property})),
|
||||
"Response contained unexpected value: {$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(e($model->{$property})),
|
||||
"Response did not contain the expected value: {$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(e($model->{$property})),
|
||||
"Response contained unexpected value: {$model->{$property}}"
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
|
||||
TestResponse::macro(
|
||||
'assertStatusMessageIs',
|
||||
function (string $message) {
|
||||
Assert::assertEquals(
|
||||
$message,
|
||||
$this['status'],
|
||||
"Response status message was not {$message}"
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
17
SNIPE-IT/tests/Support/InitializesSettings.php
Normal file
17
SNIPE-IT/tests/Support/InitializesSettings.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use App\Models\Setting;
|
||||
|
||||
trait InitializesSettings
|
||||
{
|
||||
protected Settings $settings;
|
||||
|
||||
public function initializeSettings()
|
||||
{
|
||||
$this->settings = Settings::initialize();
|
||||
|
||||
$this->beforeApplicationDestroyed(fn() => Setting::$_cache = null);
|
||||
}
|
||||
}
|
16
SNIPE-IT/tests/Support/InteractsWithAuthentication.php
Normal file
16
SNIPE-IT/tests/Support/InteractsWithAuthentication.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
trait InteractsWithAuthentication
|
||||
{
|
||||
protected function actingAsForApi(Authenticatable $user)
|
||||
{
|
||||
Passport::actingAs($user);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
140
SNIPE-IT/tests/Support/Settings.php
Normal file
140
SNIPE-IT/tests/Support/Settings.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class Settings
|
||||
{
|
||||
private Setting $setting;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->setting = Setting::factory()->create();
|
||||
}
|
||||
|
||||
public static function initialize(): Settings
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function enableAlertEmail(string $email = 'notifications@afcrichmond.com'): Settings
|
||||
{
|
||||
return $this->update(['alert_email' => $email]);
|
||||
}
|
||||
|
||||
public function disableAlertEmail(): Settings
|
||||
{
|
||||
return $this->update(['alert_email' => null]);
|
||||
}
|
||||
|
||||
public function enableMultipleFullCompanySupport(): Settings
|
||||
{
|
||||
return $this->update(['full_multiple_companies_support' => 1]);
|
||||
}
|
||||
|
||||
public function disableMultipleFullCompanySupport(): Settings
|
||||
{
|
||||
return $this->update(['full_multiple_companies_support' => 0]);
|
||||
}
|
||||
|
||||
public function enableSlackWebhook(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'webhook_selected' => 'slack',
|
||||
'webhook_botname' => 'SnipeBot5000',
|
||||
'webhook_endpoint' => 'https://hooks.slack.com/services/NZ59/Q446/672N',
|
||||
'webhook_channel' => '#it',
|
||||
]);
|
||||
}
|
||||
|
||||
public function disableSlackWebhook(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'webhook_selected' => '',
|
||||
'webhook_botname' => '',
|
||||
'webhook_endpoint' => '',
|
||||
'webhook_channel' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
public function enableAutoIncrement(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'auto_increment_assets' => 1,
|
||||
'auto_increment_prefix' => 'ABCD',
|
||||
'next_auto_tag_base' => 123,
|
||||
'zerofill_count' => 5
|
||||
]);
|
||||
}
|
||||
|
||||
public function disableAutoIncrement(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'auto_increment_assets' => 0,
|
||||
'auto_increment_prefix' => 0,
|
||||
'next_auto_tag_base' => 0,
|
||||
'zerofill_count' => 0
|
||||
]);
|
||||
}
|
||||
|
||||
public function enableUniqueSerialNumbers(): Settings
|
||||
{
|
||||
return $this->update(['unique_serial' => 1]);
|
||||
}
|
||||
|
||||
public function disableUniqueSerialNumbers(): Settings
|
||||
{
|
||||
return $this->update(['unique_serial' => 0]);
|
||||
}
|
||||
|
||||
public function enableLdap(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'ldap_enabled' => 1,
|
||||
'ldap_server' => 'ldaps://ldap.example.com',
|
||||
'ldap_uname' => 'fake_username',
|
||||
'ldap_pword' => Crypt::encrypt("fake_password"),
|
||||
'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
|
||||
]);
|
||||
}
|
||||
|
||||
public function enableAnonymousLdap(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'ldap_enabled' => 1,
|
||||
'ldap_server' => 'ldaps://ldap.example.com',
|
||||
// 'ldap_uname' => 'fake_username',
|
||||
'ldap_pword' => Crypt::encrypt("fake_password"),
|
||||
'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
|
||||
]);
|
||||
}
|
||||
|
||||
public function enableBadPasswordLdap(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'ldap_enabled' => 1,
|
||||
'ldap_server' => 'ldaps://ldap.example.com',
|
||||
'ldap_uname' => 'fake_username',
|
||||
'ldap_pword' => "badly_encrypted_password!",
|
||||
'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $attributes Attributes to modify in the application's settings.
|
||||
*/
|
||||
public function set(array $attributes): Settings
|
||||
{
|
||||
return $this->update($attributes);
|
||||
}
|
||||
|
||||
private function update(array $attributes): Settings
|
||||
{
|
||||
Setting::unguarded(fn() => $this->setting->update($attributes));
|
||||
Setting::$_cache = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
48
SNIPE-IT/tests/TestCase.php
Normal file
48
SNIPE-IT/tests/TestCase.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\Http\Middleware\SecurityHeaders;
|
||||
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use RuntimeException;
|
||||
use Tests\Support\AssertsAgainstSlackNotifications;
|
||||
use Tests\Support\CustomTestMacros;
|
||||
use Tests\Support\InteractsWithAuthentication;
|
||||
use Tests\Support\InitializesSettings;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
use AssertsAgainstSlackNotifications;
|
||||
use CreatesApplication;
|
||||
use CustomTestMacros;
|
||||
use InteractsWithAuthentication;
|
||||
use InitializesSettings;
|
||||
use LazilyRefreshDatabase;
|
||||
|
||||
private array $globallyDisabledMiddleware = [
|
||||
SecurityHeaders::class,
|
||||
];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->guardAgainstMissingEnv();
|
||||
|
||||
parent::setUp();
|
||||
|
||||
$this->registerCustomMacros();
|
||||
|
||||
$this->withoutMiddleware($this->globallyDisabledMiddleware);
|
||||
|
||||
$this->initializeSettings();
|
||||
}
|
||||
|
||||
private function guardAgainstMissingEnv(): void
|
||||
{
|
||||
if (!file_exists(realpath(__DIR__ . '/../') . '/.env.testing')) {
|
||||
throw new RuntimeException(
|
||||
'.env.testing file does not exist. Aborting to avoid wiping your local database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
57
SNIPE-IT/tests/Unit/AccessoryTest.php
Normal file
57
SNIPE-IT/tests/Unit/AccessoryTest.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Manufacturer;
|
||||
use App\Models\Location;
|
||||
use App\Models\Category;
|
||||
use App\Models\Company;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AccessoryTest extends TestCase
|
||||
{
|
||||
public function testAnAccessoryBelongsToACompany()
|
||||
{
|
||||
$accessory = Accessory::factory()
|
||||
->create(
|
||||
[
|
||||
'company_id' =>
|
||||
Company::factory()->create()->id]);
|
||||
$this->assertInstanceOf(Company::class, $accessory->company);
|
||||
}
|
||||
|
||||
public function testAnAccessoryHasALocation()
|
||||
{
|
||||
$accessory = Accessory::factory()
|
||||
->create(
|
||||
[
|
||||
'location_id' => Location::factory()->create()->id
|
||||
]);
|
||||
$this->assertInstanceOf(Location::class, $accessory->location);
|
||||
}
|
||||
|
||||
public function testAnAccessoryBelongsToACategory()
|
||||
{
|
||||
$accessory = Accessory::factory()->appleBtKeyboard()
|
||||
->create(
|
||||
[
|
||||
'category_id' =>
|
||||
Category::factory()->create(
|
||||
[
|
||||
'category_type' => 'accessory'
|
||||
]
|
||||
)->id]);
|
||||
$this->assertInstanceOf(Category::class, $accessory->category);
|
||||
$this->assertEquals('accessory', $accessory->category->category_type);
|
||||
}
|
||||
|
||||
public function testAnAccessoryHasAManufacturer()
|
||||
{
|
||||
$accessory = Accessory::factory()->appleBtKeyboard()->create(
|
||||
[
|
||||
'category_id' => Category::factory()->create(),
|
||||
'manufacturer_id' => Manufacturer::factory()->apple()->create()
|
||||
]);
|
||||
$this->assertInstanceOf(Manufacturer::class, $accessory->manufacturer);
|
||||
}
|
||||
}
|
46
SNIPE-IT/tests/Unit/AssetMaintenanceTest.php
Normal file
46
SNIPE-IT/tests/Unit/AssetMaintenanceTest.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\AssetMaintenance;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetMaintenanceTest extends TestCase
|
||||
{
|
||||
public function testZerosOutWarrantyIfBlank()
|
||||
{
|
||||
$c = new AssetMaintenance;
|
||||
$c->is_warranty = '';
|
||||
$this->assertTrue($c->is_warranty === 0);
|
||||
$c->is_warranty = '4';
|
||||
$this->assertTrue($c->is_warranty == 4);
|
||||
}
|
||||
|
||||
public function testSetsCostsAppropriately()
|
||||
{
|
||||
$c = new AssetMaintenance();
|
||||
$c->cost = '0.00';
|
||||
$this->assertTrue($c->cost === null);
|
||||
$c->cost = '9.54';
|
||||
$this->assertTrue($c->cost === 9.54);
|
||||
$c->cost = '9.50';
|
||||
$this->assertTrue($c->cost === 9.5);
|
||||
}
|
||||
|
||||
public function testNullsOutNotesIfBlank()
|
||||
{
|
||||
$c = new AssetMaintenance;
|
||||
$c->notes = '';
|
||||
$this->assertTrue($c->notes === null);
|
||||
$c->notes = 'This is a long note';
|
||||
$this->assertTrue($c->notes === 'This is a long note');
|
||||
}
|
||||
|
||||
public function testNullsOutCompletionDateIfBlankOrInvalid()
|
||||
{
|
||||
$c = new AssetMaintenance;
|
||||
$c->completion_date = '';
|
||||
$this->assertTrue($c->completion_date === null);
|
||||
$c->completion_date = '0000-00-00';
|
||||
$this->assertTrue($c->completion_date === null);
|
||||
}
|
||||
}
|
25
SNIPE-IT/tests/Unit/AssetModelTest.php
Normal file
25
SNIPE-IT/tests/Unit/AssetModelTest.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Category;
|
||||
use App\Models\AssetModel;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetModelTest extends TestCase
|
||||
{
|
||||
public function testAnAssetModelContainsAssets()
|
||||
{
|
||||
$category = Category::factory()->create([
|
||||
'category_type' => 'asset'
|
||||
]);
|
||||
$model = AssetModel::factory()->create([
|
||||
'category_id' => $category->id,
|
||||
]);
|
||||
|
||||
$asset = Asset::factory()->create([
|
||||
'model_id' => $model->id
|
||||
]);
|
||||
$this->assertEquals(1, $model->assets()->count());
|
||||
}
|
||||
}
|
159
SNIPE-IT/tests/Unit/AssetTest.php
Normal file
159
SNIPE-IT/tests/Unit/AssetTest.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use Carbon\Carbon;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetTest extends TestCase
|
||||
{
|
||||
public function testAutoIncrement()
|
||||
{
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$a = Asset::factory()->create(['asset_tag' => Asset::autoincrement_asset() ]);
|
||||
$b = Asset::factory()->create(['asset_tag' => Asset::autoincrement_asset() ]);
|
||||
|
||||
$this->assertModelExists($a);
|
||||
$this->assertModelExists($b);
|
||||
|
||||
}
|
||||
|
||||
public function testAutoIncrementCollision()
|
||||
{
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
// we have to do this by hand to 'simulate' two web pages being open at the same time
|
||||
$a = Asset::factory()->make(['asset_tag' => Asset::autoincrement_asset() ]);
|
||||
$b = Asset::factory()->make(['asset_tag' => Asset::autoincrement_asset() ]);
|
||||
|
||||
$this->assertTrue($a->save());
|
||||
$this->assertFalse($b->save());
|
||||
}
|
||||
|
||||
public function testAutoIncrementDouble()
|
||||
{
|
||||
// make one asset with the autoincrement *ONE* higher than the next auto-increment
|
||||
// make sure you can then still make another
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$gap_number = Asset::autoincrement_asset(1);
|
||||
$final_number = Asset::autoincrement_asset(2);
|
||||
$a = Asset::factory()->make(['asset_tag' => $gap_number]); //make an asset with an ID that is one *over* the next increment
|
||||
$b = Asset::factory()->make(['asset_tag' => Asset::autoincrement_asset()]); //but also make one with one that is *at* the next increment
|
||||
$this->assertTrue($a->save());
|
||||
$this->assertTrue($b->save());
|
||||
|
||||
//and ensure a final asset ends up at *two* over what would've been the next increment at the start
|
||||
$c = Asset::factory()->make(['asset_tag' => Asset::autoincrement_asset()]);
|
||||
$this->assertTrue($c->save());
|
||||
$this->assertEquals($c->asset_tag, $final_number);
|
||||
}
|
||||
|
||||
public function testAutoIncrementGapAndBackfill()
|
||||
{
|
||||
// make one asset 3 higher than the next auto-increment
|
||||
// manually make one that's 1 lower than that
|
||||
// make sure the next one is one higher than the 3 higher one.
|
||||
$this->settings->enableAutoIncrement();
|
||||
|
||||
$big_gap = Asset::autoincrement_asset(3);
|
||||
$final_result = Asset::autoincrement_asset(4);
|
||||
$backfill_one = Asset::autoincrement_asset(0);
|
||||
$backfill_two = Asset::autoincrement_asset(1);
|
||||
$backfill_three = Asset::autoincrement_asset(2);
|
||||
$a = Asset::factory()->create(['asset_tag' => $big_gap]);
|
||||
$this->assertModelExists($a);
|
||||
|
||||
$b = Asset::factory()->create(['asset_tag' => $backfill_one]);
|
||||
$this->assertModelExists($b);
|
||||
|
||||
$c = Asset::factory()->create(['asset_tag' => $backfill_two]);
|
||||
$this->assertModelExists($c);
|
||||
|
||||
$d = Asset::factory()->create(['asset_tag' => $backfill_three]);
|
||||
$this->assertModelExists($d);
|
||||
|
||||
$final = Asset::factory()->create(['asset_tag' => Asset::autoincrement_asset()]);
|
||||
$this->assertModelExists($final);
|
||||
$this->assertEquals($final->asset_tag, $final_result);
|
||||
}
|
||||
|
||||
public function testPrefixlessAutoincrementBackfill()
|
||||
{
|
||||
// TODO: COPYPASTA FROM above, is there a way to still run this test but not have it be so duplicative?
|
||||
$this->settings->enableAutoIncrement()->set(['auto_increment_prefix' => '']);
|
||||
|
||||
$big_gap = Asset::autoincrement_asset(3);
|
||||
$final_result = Asset::autoincrement_asset(4);
|
||||
$backfill_one = Asset::autoincrement_asset(0);
|
||||
$backfill_two = Asset::autoincrement_asset(1);
|
||||
$backfill_three = Asset::autoincrement_asset(2);
|
||||
$a = Asset::factory()->create(['asset_tag' => $big_gap]);
|
||||
$this->assertModelExists($a);
|
||||
|
||||
$b = Asset::factory()->create(['asset_tag' => $backfill_one]);
|
||||
$this->assertModelExists($b);
|
||||
|
||||
$c = Asset::factory()->create(['asset_tag' => $backfill_two]);
|
||||
$this->assertModelExists($c);
|
||||
|
||||
$d = Asset::factory()->create(['asset_tag' => $backfill_three]);
|
||||
$this->assertModelExists($d);
|
||||
|
||||
$final = Asset::factory()->create(['asset_tag' => Asset::autoincrement_asset()]);
|
||||
$this->assertModelExists($final);
|
||||
$this->assertEquals($final->asset_tag, $final_result);
|
||||
}
|
||||
|
||||
public function testUnzerofilledPrefixlessAutoincrementBackfill()
|
||||
{
|
||||
// TODO: COPYPASTA FROM above (AGAIN), is there a way to still run this test but not have it be so duplicative?
|
||||
$this->settings->enableAutoIncrement()->set(['auto_increment_prefix' => '','zerofill_count' => 0]);
|
||||
|
||||
$big_gap = Asset::autoincrement_asset(3);
|
||||
$final_result = Asset::autoincrement_asset(4);
|
||||
$backfill_one = Asset::autoincrement_asset(0);
|
||||
$backfill_two = Asset::autoincrement_asset(1);
|
||||
$backfill_three = Asset::autoincrement_asset(2);
|
||||
$a = Asset::factory()->create(['asset_tag' => $big_gap]);
|
||||
$this->assertModelExists($a);
|
||||
|
||||
$b = Asset::factory()->create(['asset_tag' => $backfill_one]);
|
||||
$this->assertModelExists($b);
|
||||
|
||||
$c = Asset::factory()->create(['asset_tag' => $backfill_two]);
|
||||
$this->assertModelExists($c);
|
||||
|
||||
$d = Asset::factory()->create(['asset_tag' => $backfill_three]);
|
||||
$this->assertModelExists($d);
|
||||
|
||||
$final = Asset::factory()->create(['asset_tag' => Asset::autoincrement_asset()]);
|
||||
$this->assertModelExists($final);
|
||||
$this->assertEquals($final->asset_tag, $final_result);
|
||||
}
|
||||
|
||||
public function testWarrantyExpiresAttribute()
|
||||
{
|
||||
|
||||
$asset = Asset::factory()
|
||||
->create(
|
||||
[
|
||||
'model_id' => AssetModel::factory()
|
||||
->create(
|
||||
[
|
||||
'category_id' => Category::factory()->assetLaptopCategory()->create()->id
|
||||
]
|
||||
)->id,
|
||||
'warranty_months' => 24,
|
||||
'purchase_date' => Carbon::createFromDate(2017, 1, 1)->hour(0)->minute(0)->second(0)
|
||||
]);
|
||||
|
||||
|
||||
$this->assertEquals(Carbon::createFromDate(2017, 1, 1)->format('Y-m-d'), $asset->purchase_date->format('Y-m-d'));
|
||||
$this->assertEquals(Carbon::createFromDate(2019, 1, 1)->format('Y-m-d'), $asset->warranty_expires->format('Y-m-d'));
|
||||
|
||||
}
|
||||
}
|
60
SNIPE-IT/tests/Unit/CategoryTest.php
Normal file
60
SNIPE-IT/tests/Unit/CategoryTest.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Asset;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CategoryTest extends TestCase
|
||||
{
|
||||
public function testFailsEmptyValidation()
|
||||
{
|
||||
// An Asset requires a name, a qty, and a category_id.
|
||||
$a = Category::create();
|
||||
$this->assertFalse($a->isValid());
|
||||
|
||||
$fields = [
|
||||
'name' => 'name',
|
||||
'category_type' => 'category type',
|
||||
];
|
||||
$errors = $a->getErrors();
|
||||
foreach ($fields as $field => $fieldTitle) {
|
||||
$this->assertEquals($errors->get($field)[0], "The ${fieldTitle} field is required.");
|
||||
}
|
||||
}
|
||||
|
||||
public function testACategoryCanHaveAssets()
|
||||
{
|
||||
$category = Category::factory()->assetDesktopCategory()->create();
|
||||
|
||||
// Generate 5 models via factory
|
||||
$models = AssetModel::factory()
|
||||
->mbp13Model()
|
||||
->count(5)
|
||||
->create(
|
||||
[
|
||||
'category_id' => $category->id
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Loop through the models and create 2 assets in each model
|
||||
$models->each(function ($model) {
|
||||
//dd($model);
|
||||
$asset = Asset::factory()
|
||||
->count(2)
|
||||
->create(
|
||||
[
|
||||
'model_id' => $model->id,
|
||||
]
|
||||
);
|
||||
//dd($asset);
|
||||
});
|
||||
|
||||
$this->assertCount(5, $category->models);
|
||||
$this->assertCount(5, $category->models);
|
||||
$this->assertEquals(10, $category->itemCount());
|
||||
}
|
||||
}
|
166
SNIPE-IT/tests/Unit/CompanyScopingTest.php
Normal file
166
SNIPE-IT/tests/Unit/CompanyScopingTest.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\Company;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CompanyScopingTest extends TestCase
|
||||
{
|
||||
public function models(): array
|
||||
{
|
||||
return [
|
||||
'Accessories' => [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'
|
||||
);
|
||||
}
|
||||
}
|
44
SNIPE-IT/tests/Unit/ComponentTest.php
Normal file
44
SNIPE-IT/tests/Unit/ComponentTest.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\Company;
|
||||
use App\Models\Component;
|
||||
use App\Models\Location;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ComponentTest extends TestCase
|
||||
{
|
||||
public function testAComponentBelongsToACompany()
|
||||
{
|
||||
$component = Component::factory()
|
||||
->create(
|
||||
[
|
||||
'company_id' => Company::factory()->create()->id
|
||||
]
|
||||
);
|
||||
$this->assertInstanceOf(Company::class, $component->company);
|
||||
}
|
||||
|
||||
public function testAComponentHasALocation()
|
||||
{
|
||||
$component = Component::factory()
|
||||
->create(['location_id' => Location::factory()->create()->id]);
|
||||
$this->assertInstanceOf(Location::class, $component->location);
|
||||
}
|
||||
|
||||
public function testAComponentBelongsToACategory()
|
||||
{
|
||||
$component = Component::factory()->ramCrucial4()
|
||||
->create(
|
||||
[
|
||||
'category_id' =>
|
||||
Category::factory()->create(
|
||||
[
|
||||
'category_type' => 'component'
|
||||
]
|
||||
)->id]);
|
||||
$this->assertInstanceOf(Category::class, $component->category);
|
||||
$this->assertEquals('component', $component->category->category_type);
|
||||
}
|
||||
}
|
111
SNIPE-IT/tests/Unit/CustomFieldTest.php
Normal file
111
SNIPE-IT/tests/Unit/CustomFieldTest.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use Tests\TestCase;
|
||||
|
||||
/*
|
||||
* Test strings for db column names gathered from
|
||||
* http://www.omniglot.com/language/phrases/hovercraft.htm
|
||||
*/
|
||||
class CustomFieldTest extends TestCase
|
||||
{
|
||||
public function testFormat()
|
||||
{
|
||||
$customfield = CustomField::factory()->make(['format' => 'IP']);
|
||||
$this->assertEquals($customfield->getAttributes()['format'], CustomField::PREDEFINED_FORMATS['IP']); //this seems undocumented...
|
||||
$this->assertEquals($customfield->format, 'IP');
|
||||
}
|
||||
|
||||
public function testDbNameAscii()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = 'My hovercraft is full of eels';
|
||||
$customfield->id = 1337;
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_my_hovercraft_is_full_of_eels_1337');
|
||||
}
|
||||
|
||||
// Western Europe
|
||||
public function testDbNameLatin()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = 'My hovercraft is full of eels';
|
||||
$customfield->id = 1337;
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_my_hovercraft_is_full_of_eels_1337');
|
||||
}
|
||||
|
||||
// Asian
|
||||
public function testDbNameChinese()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = '我的氣墊船裝滿了鱔魚';
|
||||
$customfield->id = 1337;
|
||||
if (function_exists('transliterator_transliterate')) {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_wo_de_qi_dian_chuan_zhuang_man_le_shan_yu_1337');
|
||||
} else {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_aecsae0ase1eaeaeoees_1337');
|
||||
}
|
||||
}
|
||||
|
||||
public function testDbNameJapanese()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = '私のホバークラフトは鰻でいっぱいです';
|
||||
$customfield->id = 1337;
|
||||
if (function_exists('transliterator_transliterate')) {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_sinohohakurafutoha_manteihhaitesu_1337');
|
||||
} else {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_caafafafaafcafafae0aaaaaaa_1337');
|
||||
}
|
||||
}
|
||||
|
||||
public function testDbNameKorean()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = '내 호버크라프트는 장어로 가득 차 있어요';
|
||||
$customfield->id = 1337;
|
||||
if (function_exists('transliterator_transliterate')) {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_nae_hobeokeulapeuteuneun_jang_eolo_gadeug_1337');
|
||||
} else {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_e_ie2ieiises_izieoe_e0e_i0_iziis_1337');
|
||||
}
|
||||
}
|
||||
|
||||
// Nordic languages
|
||||
public function testDbNameNonLatinEuro()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = 'Mój poduszkowiec jest pełen węgorzy';
|
||||
$customfield->id = 1337;
|
||||
if (function_exists('transliterator_transliterate')) {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_moj_poduszkowiec_jest_pelen_wegorzy_1337');
|
||||
} else {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_ma3j_poduszkowiec_jest_peaen_waegorzy_1337');
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
public function testDbNameTurkish()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = 'Hoverkraftım yılan balığı dolu';
|
||||
$customfield->id = 1337;
|
||||
if (function_exists('transliterator_transliterate')) {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_hoverkraftim_yilan_baligi_dolu_1337');
|
||||
} else {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_hoverkraftaem_yaelan_balaeaeyae_dolu_1337');
|
||||
}
|
||||
}
|
||||
|
||||
public function testDbNameArabic()
|
||||
{
|
||||
$customfield = new CustomField();
|
||||
$customfield->name = 'حَوّامتي مُمْتِلئة بِأَنْقَلَيْسون';
|
||||
$customfield->id = 1337;
|
||||
if (function_exists('transliterator_transliterate')) {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_hwamty_mmtlyt_banqlyswn_1337');
|
||||
} else {
|
||||
$this->assertEquals($customfield->convertUnicodeDbSlug(), '_snipeit_ouzuuouoaus_uuuuoauuooc_ououzuuuuzuuzusuo_1337');
|
||||
}
|
||||
}
|
||||
}
|
44
SNIPE-IT/tests/Unit/DepreciationTest.php
Normal file
44
SNIPE-IT/tests/Unit/DepreciationTest.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Depreciation;
|
||||
use App\Models\Category;
|
||||
use App\Models\License;
|
||||
use App\Models\AssetModel;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DepreciationTest extends TestCase
|
||||
{
|
||||
public function testADepreciationHasModels()
|
||||
{
|
||||
$depreciation = Depreciation::factory()->create();
|
||||
|
||||
AssetModel::factory()
|
||||
->mbp13Model()
|
||||
->count(5)
|
||||
->create(
|
||||
[
|
||||
'category_id' => Category::factory()->assetLaptopCategory()->create(),
|
||||
'depreciation_id' => $depreciation->id
|
||||
]);
|
||||
|
||||
|
||||
$this->assertEquals(5, $depreciation->models->count());
|
||||
}
|
||||
|
||||
public function testADepreciationHasLicenses()
|
||||
{
|
||||
|
||||
$depreciation = Depreciation::factory()->create();
|
||||
License::factory()
|
||||
->count(5)
|
||||
->photoshop()
|
||||
->create(
|
||||
[
|
||||
'category_id' => Category::factory()->licenseGraphicsCategory()->create(),
|
||||
'depreciation_id' => $depreciation->id
|
||||
]);
|
||||
|
||||
$this->assertEquals(5, $depreciation->licenses()->count());
|
||||
}
|
||||
}
|
19
SNIPE-IT/tests/Unit/Helpers/HelperTest.php
Normal file
19
SNIPE-IT/tests/Unit/Helpers/HelperTest.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Helpers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use Tests\TestCase;
|
||||
|
||||
class HelperTest extends TestCase
|
||||
{
|
||||
public function testDefaultChartColorsMethodHandlesHighValues()
|
||||
{
|
||||
$this->assertIsString(Helper::defaultChartColors(1000));
|
||||
}
|
||||
|
||||
public function testDefaultChartColorsMethodHandlesNegativeNumbers()
|
||||
{
|
||||
$this->assertIsString(Helper::defaultChartColors(-1));
|
||||
}
|
||||
}
|
210
SNIPE-IT/tests/Unit/LdapTest.php
Normal file
210
SNIPE-IT/tests/Unit/LdapTest.php
Normal file
@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Ldap;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @group ldap
|
||||
*/
|
||||
class LdapTest extends TestCase
|
||||
{
|
||||
use \phpmock\phpunit\PHPMock;
|
||||
|
||||
public function testConnect()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
|
||||
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||
|
||||
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||
$ldap_set_option->expects($this->exactly(3));
|
||||
|
||||
|
||||
$blah = Ldap::connectToLdap();
|
||||
$this->assertEquals('hello',$blah,"LDAP_connect should return 'hello'");
|
||||
}
|
||||
|
||||
// other test cases - with/without client-side certs?
|
||||
// with/without LDAP version 3?
|
||||
// with/without ignore cert validation?
|
||||
// test (and mock) ldap_start_tls() ?
|
||||
|
||||
public function testBindAdmin()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||
}
|
||||
|
||||
public function testBindBad()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false);
|
||||
$this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
|
||||
$this->expectExceptionMessage("Could not bind to LDAP:");
|
||||
|
||||
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||
}
|
||||
// other test cases - test donked password?
|
||||
|
||||
public function testAnonymousBind()
|
||||
{
|
||||
//todo - would be nice to introspect somehow to make sure the right parameters were passed?
|
||||
$this->settings->enableAnonymousLdap();
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||
}
|
||||
|
||||
public function testBadAnonymousBind()
|
||||
{
|
||||
$this->settings->enableAnonymousLdap();
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false);
|
||||
$this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
|
||||
$this->expectExceptionMessage("Could not bind to LDAP:");
|
||||
|
||||
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||
}
|
||||
|
||||
public function testBadEncryptedPassword()
|
||||
{
|
||||
$this->settings->enableBadPasswordLdap();
|
||||
|
||||
$this->expectExceptionMessage("Your app key has changed");
|
||||
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||
}
|
||||
|
||||
public function testFindAndBind()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
|
||||
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||
|
||||
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||
$ldap_set_option->expects($this->exactly(3));
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(true);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_first_entry")->expects($this->once())->willReturn(true);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_get_attributes")->expects($this->once())->willReturn(
|
||||
[
|
||||
"count" => 1,
|
||||
0 => [
|
||||
'sn' => 'Surname',
|
||||
'firstName' => 'FirstName'
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
$results = Ldap::findAndBindUserLdap("username","password");
|
||||
$this->assertEqualsCanonicalizing(["count" =>1,0 =>['sn' => 'Surname','firstname' => 'FirstName']],$results);
|
||||
}
|
||||
|
||||
public function testFindAndBindBadPassword()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
|
||||
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||
|
||||
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||
$ldap_set_option->expects($this->exactly(3));
|
||||
|
||||
// note - we return FALSE first, to simulate a bad-bind, then TRUE the second time to simulate a successful admin bind
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->exactly(2))->willReturn(false, true);
|
||||
|
||||
// $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
|
||||
|
||||
|
||||
// $this->expectExceptionMessage("exception");
|
||||
$results = Ldap::findAndBindUserLdap("username","password");
|
||||
$this->assertFalse($results);
|
||||
}
|
||||
|
||||
public function testFindAndBindCannotFindSelf()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
|
||||
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||
|
||||
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||
$ldap_set_option->expects($this->exactly(3));
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(false);
|
||||
|
||||
$this->expectExceptionMessage("Could not search LDAP:");
|
||||
$results = Ldap::findAndBindUserLdap("username","password");
|
||||
$this->assertFalse($results);
|
||||
}
|
||||
|
||||
//maybe should do an AD test as well?
|
||||
|
||||
public function testFindLdapUsers()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
|
||||
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||
|
||||
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||
$ldap_set_option->expects($this->exactly(3));
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(["stuff"]);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->once())->willReturn(true);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->once())->willReturn(["count" => 1]);
|
||||
|
||||
$results = Ldap::findLdapUsers();
|
||||
|
||||
$this->assertEqualsCanonicalizing(["count" => 1], $results);
|
||||
}
|
||||
|
||||
public function testFindLdapUsersPaginated()
|
||||
{
|
||||
$this->settings->enableLdap();
|
||||
|
||||
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||
|
||||
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||
$ldap_set_option->expects($this->exactly(3));
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->exactly(2))->willReturn(["stuff"]);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->exactly(2))->willReturnCallback(
|
||||
function ($ldapconn, $search_results, $errcode , $matcheddn , $errmsg , $referrals, &$controls) {
|
||||
static $count = 0;
|
||||
if($count == 0) {
|
||||
$count++;
|
||||
$controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] = "cookie";
|
||||
return ["count" => 1];
|
||||
} else {
|
||||
$controls = [];
|
||||
return ["count" => 1];
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
$this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->exactly(2))->willReturn(["count" => 1]);
|
||||
|
||||
$results = Ldap::findLdapUsers();
|
||||
|
||||
$this->assertEqualsCanonicalizing(["count" => 2], $results);
|
||||
}
|
||||
|
||||
}
|
31
SNIPE-IT/tests/Unit/LocationTest.php
Normal file
31
SNIPE-IT/tests/Unit/LocationTest.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Location;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LocationTest extends TestCase
|
||||
{
|
||||
public function testPassesIfNotSelfParent()
|
||||
{
|
||||
$a = Location::factory()->make([
|
||||
'name' => 'Test Location',
|
||||
'id' => 1,
|
||||
'parent_id' => Location::factory()->create(['id' => 10])->id,
|
||||
]);
|
||||
|
||||
$this->assertTrue($a->isValid());
|
||||
}
|
||||
|
||||
public function testFailsIfSelfParent()
|
||||
{
|
||||
$a = Location::factory()->make([
|
||||
'name' => 'Test Location',
|
||||
'id' => 1,
|
||||
'parent_id' => 1,
|
||||
]);
|
||||
|
||||
$this->assertFalse($a->isValid());
|
||||
$this->assertStringContainsString(trans('validation.non_circular', ['attribute' => 'parent id']), $a->getErrors());
|
||||
}
|
||||
}
|
22
SNIPE-IT/tests/Unit/Models/Company/CompanyTest.php
Normal file
22
SNIPE-IT/tests/Unit/Models/Company/CompanyTest.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Models\Company;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CompanyTest extends TestCase
|
||||
{
|
||||
public function testACompanyCanHaveUsers()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$user = User::factory()
|
||||
->create(
|
||||
[
|
||||
'company_id'=> $company->id
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertCount(1, $company->users);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Models\Company;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class GetIdForCurrentUserTest extends TestCase
|
||||
{
|
||||
public function testReturnsProvidedValueWhenFullCompanySupportDisabled()
|
||||
{
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs(User::factory()->create());
|
||||
$this->assertEquals(1000, Company::getIdForCurrentUser(1000));
|
||||
}
|
||||
|
||||
public function testReturnsProvidedValueForSuperUsersWhenFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create());
|
||||
$this->assertEquals(2000, Company::getIdForCurrentUser(2000));
|
||||
}
|
||||
|
||||
public function testReturnsNonSuperUsersCompanyIdWhenFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs(User::factory()->forCompany(['id' => 2000])->create());
|
||||
$this->assertEquals(2000, Company::getIdForCurrentUser(1000));
|
||||
}
|
||||
|
||||
public function testReturnsProvidedValueForNonSuperUserWithoutCompanyIdWhenFullCompanySupportEnabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs(User::factory()->create(['company_id' => null]));
|
||||
$this->assertEquals(1000, Company::getIdForCurrentUser(1000));
|
||||
}
|
||||
}
|
26
SNIPE-IT/tests/Unit/Models/Labels/FieldOptionTest.php
Normal file
26
SNIPE-IT/tests/Unit/Models/Labels/FieldOptionTest.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Models\Labels;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Labels\FieldOption;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FieldOptionTest extends TestCase
|
||||
{
|
||||
public function testItDisplaysAssignedToProperly()
|
||||
{
|
||||
// "assignedTo" is a "special" value that can be used in the new label engine
|
||||
$fieldOption = FieldOption::fromString('Assigned To=assignedTo');
|
||||
|
||||
$asset = Asset::factory()
|
||||
->assignedToUser(User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']))
|
||||
->create();
|
||||
|
||||
$this->assertEquals('Luke Skywalker', $fieldOption->getValue($asset));
|
||||
// If the "assignedTo" relationship was eager loaded then the way to get the
|
||||
// relationship changes from $asset->assignedTo to $asset->assigned.
|
||||
$this->assertEquals('Luke Skywalker', $fieldOption->getValue(Asset::with('assignedTo')->find($asset->id)));
|
||||
}
|
||||
}
|
36
SNIPE-IT/tests/Unit/NotificationTest.php
Normal file
36
SNIPE-IT/tests/Unit/NotificationTest.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use Carbon\Carbon;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationTest extends TestCase
|
||||
{
|
||||
public function testAUserIsEmailedIfTheyCheckoutAnAssetWithEULA()
|
||||
{
|
||||
$admin = User::factory()->superuser()->create();
|
||||
$user = User::factory()->create();
|
||||
$asset = Asset::factory()
|
||||
->create(
|
||||
[
|
||||
'model_id' => AssetModel::factory()
|
||||
->create(
|
||||
[
|
||||
'category_id' => Category::factory()->assetLaptopCategory()->create()->id
|
||||
]
|
||||
)->id,
|
||||
'warranty_months' => 24,
|
||||
'purchase_date' => Carbon::createFromDate(2017, 1, 1)->hour(0)->minute(0)->second(0)->format('Y-m-d')
|
||||
]);
|
||||
|
||||
Notification::fake();
|
||||
$asset->checkOut($user, $admin->id);
|
||||
Notification::assertSentTo($user, CheckoutAssetNotification::class);
|
||||
}
|
||||
}
|
73
SNIPE-IT/tests/Unit/SnipeModelTest.php
Normal file
73
SNIPE-IT/tests/Unit/SnipeModelTest.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\SnipeModel;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SnipeModelTest extends TestCase
|
||||
{
|
||||
public function testSetsPurchaseDatesAppropriately()
|
||||
{
|
||||
$c = new SnipeModel;
|
||||
$c->purchase_date = '';
|
||||
$this->assertTrue($c->purchase_date === null);
|
||||
$c->purchase_date = '2016-03-25 12:35:50';
|
||||
$this->assertTrue($c->purchase_date === '2016-03-25 12:35:50');
|
||||
}
|
||||
|
||||
public function testSetsPurchaseCostsAppropriately()
|
||||
{
|
||||
$c = new SnipeModel;
|
||||
$c->purchase_cost = '0.00';
|
||||
$this->assertTrue($c->purchase_cost === null);
|
||||
$c->purchase_cost = '9.54';
|
||||
$this->assertTrue($c->purchase_cost === 9.54);
|
||||
$c->purchase_cost = '9.50';
|
||||
$this->assertTrue($c->purchase_cost === 9.5);
|
||||
}
|
||||
|
||||
public function testNullsBlankLocationIdsButNotOthers()
|
||||
{
|
||||
$c = new SnipeModel;
|
||||
$c->location_id = '';
|
||||
$this->assertTrue($c->location_id === null);
|
||||
$c->location_id = '5';
|
||||
$this->assertTrue($c->location_id == 5);
|
||||
}
|
||||
|
||||
public function testNullsBlankCategoriesButNotOthers()
|
||||
{
|
||||
$c = new SnipeModel;
|
||||
$c->category_id = '';
|
||||
$this->assertTrue($c->category_id === null);
|
||||
$c->category_id = '1';
|
||||
$this->assertTrue($c->category_id == 1);
|
||||
}
|
||||
|
||||
public function testNullsBlankSuppliersButNotOthers()
|
||||
{
|
||||
$c = new SnipeModel;
|
||||
$c->supplier_id = '';
|
||||
$this->assertTrue($c->supplier_id === null);
|
||||
$c->supplier_id = '4';
|
||||
$this->assertTrue($c->supplier_id == 4);
|
||||
}
|
||||
|
||||
public function testNullsBlankDepreciationsButNotOthers()
|
||||
{
|
||||
$c = new SnipeModel;
|
||||
$c->depreciation_id = '';
|
||||
$this->assertTrue($c->depreciation_id === null);
|
||||
$c->depreciation_id = '4';
|
||||
$this->assertTrue($c->depreciation_id == 4);
|
||||
}
|
||||
|
||||
public function testNullsBlankManufacturersButNotOthers()
|
||||
{
|
||||
$c = new SnipeModel;
|
||||
$c->manufacturer_id = '';
|
||||
$this->assertTrue($c->manufacturer_id === null);
|
||||
$c->manufacturer_id = '4';
|
||||
$this->assertTrue($c->manufacturer_id == 4);
|
||||
}
|
||||
}
|
44
SNIPE-IT/tests/Unit/StatuslabelTest.php
Normal file
44
SNIPE-IT/tests/Unit/StatuslabelTest.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Statuslabel;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StatuslabelTest extends TestCase
|
||||
{
|
||||
public function testRTDStatuslabelAdd()
|
||||
{
|
||||
$statuslabel = Statuslabel::factory()->rtd()->create();
|
||||
$this->assertModelExists($statuslabel);
|
||||
}
|
||||
|
||||
public function testPendingStatuslabelAdd()
|
||||
{
|
||||
$statuslabel = Statuslabel::factory()->pending()->create();
|
||||
$this->assertModelExists($statuslabel);
|
||||
}
|
||||
|
||||
public function testArchivedStatuslabelAdd()
|
||||
{
|
||||
$statuslabel = Statuslabel::factory()->archived()->create();
|
||||
$this->assertModelExists($statuslabel);
|
||||
}
|
||||
|
||||
public function testOutForRepairStatuslabelAdd()
|
||||
{
|
||||
$statuslabel = Statuslabel::factory()->outForRepair()->create();
|
||||
$this->assertModelExists($statuslabel);
|
||||
}
|
||||
|
||||
public function testBrokenStatuslabelAdd()
|
||||
{
|
||||
$statuslabel = Statuslabel::factory()->broken()->create();
|
||||
$this->assertModelExists($statuslabel);
|
||||
}
|
||||
|
||||
public function testLostStatuslabelAdd()
|
||||
{
|
||||
$statuslabel = Statuslabel::factory()->lost()->create();
|
||||
$this->assertModelExists($statuslabel);
|
||||
}
|
||||
}
|
98
SNIPE-IT/tests/Unit/UserTest.php
Normal file
98
SNIPE-IT/tests/Unit/UserTest.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserTest extends TestCase
|
||||
{
|
||||
public function testFirstNameSplit()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_firstname = 'Natalia';
|
||||
$expected_lastname = "Allanovna Romanova-O'Shostakova";
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstname');
|
||||
$this->assertEquals($expected_firstname, $user['first_name']);
|
||||
$this->assertEquals($expected_lastname, $user['last_name']);
|
||||
}
|
||||
|
||||
public function testFirstName()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'natalia';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstname');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function testFirstNameDotLastName()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'natalia.allanovna-romanova-oshostakova';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstname.lastname');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function testLastNameFirstInitial()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'allanovna-romanova-oshostakovan';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'lastnamefirstinitial');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function testFirstInitialLastName()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'nallanovna-romanova-oshostakova';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'filastname');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function testFirstInitialUnderscoreLastName()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'nallanovna-romanova-oshostakova';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstinitial_lastname');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function testSingleName()
|
||||
{
|
||||
$fullname = 'Natalia';
|
||||
$expected_username = 'natalia';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstname_lastname',);
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function firstInitialDotLastname()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'n.allanovnaromanovaoshostakova';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstinitial.lastname');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function lastNameUnderscoreFirstInitial()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'allanovnaromanovaoshostakova_n';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'lastname_firstinitial');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function firstNameLastName()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'nataliaallanovnaromanovaoshostakova';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstnamelastname');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
public function firstNameLastInitial()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'nataliaa';
|
||||
$user = User::generateFormattedNameFromFullName($fullname, 'firstnamelastinitial');
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user