3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-08-24 22:29:27 +00:00
Files
snipe-it/tests/Feature/Assets/Ui/BulkAuditSelectedAssetsTest.php
2026-07-30 23:04:08 +01:00

144 lines
5.8 KiB
PHP

<?php
namespace Tests\Feature\Assets\Ui;
use App\Models\Asset;
use App\Models\Company;
use App\Models\User;
use PHPUnit\Framework\Attributes\Group;
use Tests\TestCase;
/**
* Form / access surface of the checked-rows bulk-audit flow (Selected
* Actions > Bulk Audit on the assets index). Route pair covered here:
* `hardware.bulk-audit.show` and the dispatcher redirect on
* `hardware.bulkedit.show`. Submission-side (POST /bulk-audit)
* behavior lives in BulkAuditSelectedAssetsSubmissionTest to keep
* either file under Codacy's per-class method-count threshold.
*
* Distinct from the existing BulkAuditAssetsTest which covers
* /hardware/bulkaudit, the barcode-scanner quickscan workflow at
* route `assets.bulkaudit`.
*/
#[Group('auditing')]
class BulkAuditSelectedAssetsTest extends TestCase
{
public function test_permission_required_to_view_form(): void
{
$this->actingAs(User::factory()->create())
->get(route('hardware.bulk-audit.show'))
->assertForbidden();
}
public function test_auditor_can_view_form(): void
{
$this->actingAs(User::factory()->auditAssets()->create())
->get(route('hardware.bulk-audit.show'))
->assertOk()
->assertViewIs('hardware.bulk-audit');
}
public function test_bulk_actions_dispatcher_redirects_to_show_with_selected_assets_flashed(): void
{
// BulkAssetsController::edit gates on view permission before
// dispatching to any specific action, so the auditor also
// needs view to reach the audit branch.
$auditor = User::factory()->viewAssets()->auditAssets()->create();
$assets = Asset::factory()->count(3)->create();
$this->actingAs($auditor)
->post(route('hardware.bulkedit.show'), [
'bulk_actions' => 'audit',
'ids' => $assets->pluck('id')->toArray(),
])
->assertRedirect(route('hardware.bulk-audit.show'));
}
public function test_form_prefills_next_audit_date_from_audit_interval(): void
{
$this->settings->setAuditInterval(6);
$this->actingAs(User::factory()->auditAssets()->create())
->get(route('hardware.bulk-audit.show'))
->assertOk()
->assertViewHas('next_audit_date', \Carbon\Carbon::now()->addMonths(6)->toDateString());
}
public function test_form_leaves_next_audit_date_blank_when_no_audit_interval_configured(): void
{
// With no audit_interval set, "today + 0 months" would prefill
// as today, which reads as "audit again right now" and is
// useless. The form should start empty and let the user pick
// a date (or leave blank to skip updating next_audit_date).
$this->settings->setAuditInterval(null);
$this->actingAs(User::factory()->auditAssets()->create())
->get(route('hardware.bulk-audit.show'))
->assertOk()
->assertViewHas('next_audit_date', null);
}
public function test_location_controls_render_unscoped_when_location_scoping_is_off(): void
{
// FMCS location scoping disabled -> no company-based hiding
// and no picker scoping regardless of selection distribution.
$this->actingAs(User::factory()->auditAssets()->create())
->withSession(['_old_input' => ['selected_assets' => [1, 2, 3]]])
->get(route('hardware.bulk-audit.show'))
->assertOk()
->assertViewHas('hideLocationFields', false)
->assertViewHas('sharedCompanyId', null);
}
public function test_location_controls_scope_to_shared_company_when_selection_is_uniform(): void
{
// FMCS location scoping on + every selected asset in the same
// company -> the picker is scoped so only that company's
// locations are offered. Uses the real dispatch flow so
// `old('selected_assets')` populates from the same session
// mechanism prod uses. Create fixtures BEFORE enabling FMCS
// so the Asset factory's fmcs_company validation rule doesn't
// fail with no authenticated user during setUp.
$company = Company::factory()->create();
$assets = Asset::factory()->count(3)->create(['company_id' => $company->id]);
$actor = User::factory()->viewAssets()->auditAssets()->forCompany($company)->create();
$this->settings->enableScopedLocationsWithFullMultipleCompanySupport();
$response = $this->actingAs($actor)
->post(route('hardware.bulkedit.show'), [
'bulk_actions' => 'audit',
'ids' => $assets->pluck('id')->toArray(),
]);
$this->followRedirects($response)
->assertOk()
->assertViewHas('hideLocationFields', false)
->assertViewHas('sharedCompanyId', $company->id);
}
public function test_location_controls_hide_when_selection_spans_multiple_companies(): void
{
// FMCS location scoping on + selected assets belong to more
// than one company -> the picker is hidden entirely since no
// shared location can legitimately fit all of them.
[$companyA, $companyB] = Company::factory()->count(2)->create();
$assetA = Asset::factory()->create(['company_id' => $companyA->id]);
$assetB = Asset::factory()->create(['company_id' => $companyB->id]);
$actor = User::factory()->superuser()->create();
$this->settings->enableScopedLocationsWithFullMultipleCompanySupport();
$response = $this->actingAs($actor)
->post(route('hardware.bulkedit.show'), [
'bulk_actions' => 'audit',
'ids' => [$assetA->id, $assetB->id],
]);
$this->followRedirects($response)
->assertOk()
->assertViewHas('hideLocationFields', true)
->assertViewHas('sharedCompanyId', null);
}
}