Files
compras/tests/Feature/AuditMetadataBlockTest.php
nala 63d20b10fc
tests / ci (push) Canceled after 0s
commit de armazens
2026-11-04 09:40:26 +02:00

79 lines
5.3 KiB
PHP

<?php
use App\Services\OrganizationAccess;
use Illuminate\Support\Facades\DB;
use Inertia\Testing\AssertableInertia as Assert;
require_once __DIR__.'/../Support/ReceiptFixture.php';
require_once __DIR__.'/../Support/SupplyFixture.php';
beforeEach(function () {
$this->withoutVite();
$this->f = receiptFixture();
supplyGrant($this->f['receiver'], ['audit_metadata_read']);
$this->actingAs($this->f['receiver']);
$this->ids = [];
foreach (range(1, 30) as $index) {
$this->ids[] = DB::table('audit_logs')->insertGetId(['tenant_id' => $this->f['tenant']->id, 'user_id' => $this->f['receiver']->id,
'action' => $index % 3 === 0 ? 'people.selected' : 'receipt.confirmed', 'created_at' => '2026-11-01 12:00:00',
'before' => json_encode(['bank' => 'PRIVATE-BEFORE']), 'after' => json_encode(['secret' => 'PRIVATE-AFTER'])]);
}
});
test('audit metadata block paginates oldest events and exposes only the four allowed metadata fields', function () {
$before = DB::table('audit_logs')->orderBy('id')->get()->toArray();
$this->get('/auditoria/eventos')->assertOk()->assertHeader('Cache-Control', 'max-age=0, no-store, private')
->assertDontSee('PRIVATE-BEFORE')->assertDontSee('PRIVATE-AFTER')
->assertInertia(fn (Assert $p) => $p->component('audit/metadata')->where('events.total', 30)->has('events.data', 25)
->where('events.data.0.id', $this->ids[0])->where('events.data.24.id', $this->ids[24])
->missing('events.data.0.before')->missing('events.data.0.after')->missing('events.data.0.tenant_id'));
$this->get('/auditoria/eventos?page=2')->assertOk()->assertInertia(fn (Assert $p) => $p->has('events.data', 5)->where('events.data.0.id', $this->ids[25]));
expect(DB::table('audit_logs')->orderBy('id')->get()->toArray())->toEqual($before);
});
test('audit metadata block exports the complete filtered scope independently of the screen page and protects spreadsheet cells', function () {
$query = '?action=people.selected&actor_id='.$this->f['receiver']->id.'&from=2026-11-01&to=2026-11-01';
$this->get('/auditoria/eventos'.$query)->assertOk()->assertInertia(fn (Assert $p) => $p->where('events.total', 10));
$csv = $this->get('/auditoria/eventos.csv'.$query.'&page=2')->assertOk()->streamedContent();
expect(substr_count($csv, 'people.selected'))->toBe(10)->and($csv)->not->toContain('receipt.confirmed', 'PRIVATE-BEFORE', 'PRIVATE-AFTER');
$this->get('/auditoria/eventos?to=2026-11-01')->assertOk();
$this->getJson('/auditoria/eventos?from=2026-11-02&to=2026-11-01')->assertUnprocessable();
DB::table('audit_logs')->insert(['tenant_id' => $this->f['tenant']->id, 'user_id' => $this->f['receiver']->id, 'action' => '=1+1', 'created_at' => now(), 'after' => '{}']);
$formula = $this->get('/auditoria/eventos.csv?action='.urlencode('=1+1'))->assertOk()->streamedContent();
expect($formula)->toContain("'=1+1");
$all = $this->get('/auditoria/eventos.csv')->assertOk()->streamedContent();
expect(substr_count($all, 'receipt.confirmed'))->toBe(20)->and(substr_count($all, 'people.selected'))->toBe(10);
});
test('audit metadata block requires an explicit current nonmaintenance grant even for administrators', function (string $mode) {
if ($mode === 'administrator') {
supplyGrant($this->f['issuer'], ['admin']);
$this->actingAs($this->f['issuer']);
} elseif ($mode === 'expired') {
DB::table('organization_memberships')->where('user_id', $this->f['receiver']->id)->update(['expires_at' => now()->subMinute()]);
} elseif ($mode === 'maintenance') {
DB::table('organization_memberships')->where('user_id', $this->f['receiver']->id)->update(['maintenance' => true]);
} else {
DB::table('organization_profiles')->where('tenant_id', $this->f['tenant']->id)->update(['permissions' => '[]']);
}
$this->get('/auditoria/eventos')->assertForbidden();
$this->get('/auditoria/eventos.csv')->assertForbidden();
})->with(['administrator', 'expired', 'maintenance', 'revoked']);
test('audit metadata block isolates companies and adds no grants or audit events during consultation', function () {
$foreign = receiptFixture();
supplyGrant($foreign['receiver'], ['audit_metadata_read']);
DB::table('audit_logs')->insert(['tenant_id' => $foreign['tenant']->id, 'user_id' => $foreign['receiver']->id, 'action' => 'FOREIGN-ONLY', 'created_at' => now(), 'after' => '{}']);
$before = [];
foreach (['audit_logs', 'users', 'organization_profiles', 'organization_memberships', 'approval_steps', 'stock_movements'] as $table) {
$before[$table] = DB::table($table)->orderBy('id')->get()->toArray();
}
$this->actingAs($this->f['receiver'])->get('/auditoria/eventos')->assertOk()->assertDontSee('FOREIGN-ONLY');
$this->actingAs($foreign['receiver'])->get('/auditoria/eventos')->assertOk()->assertInertia(fn (Assert $p) => $p->where('events.total', 1)->where('events.data.0.action', 'FOREIGN-ONLY'));
expect($this->get('/auditoria/eventos.csv')->assertOk()->streamedContent())->toContain('FOREIGN-ONLY')->not->toContain('people.selected');
foreach ($before as $table => $rows) {
expect(DB::table($table)->orderBy('id')->get()->toArray())->toEqual($rows);
}
expect(array_key_exists('audit_metadata_read', OrganizationAccess::PERMISSIONS))->toBeTrue();
});