This commit is contained in:
2026-11-02 08:06:45 +02:00
parent e4f520092e
commit 2a4169162b
108 changed files with 3793 additions and 88 deletions
+4 -4
View File
@@ -8,7 +8,7 @@ use Illuminate\Support\Facades\DB;
final class IdentityFixture
{
public static function create(): array
public static function create(string $emailSuffix = ''): array
{
\App\Shared\Testing\TestingDatabaseGuard::assertSafe();
$now = now();
@@ -21,9 +21,9 @@ final class IdentityFixture
$hidden = DB::table('units')->insertGetId(['tenant_id' => $tenant, 'company_id' => $company, 'name' => 'Unidade Reservada', 'created_at' => $now, 'updated_at' => $now]);
$siblingUnit = DB::table('units')->insertGetId(['tenant_id' => $tenant, 'company_id' => $sibling, 'name' => 'Unidade Maré', 'created_at' => $now, 'updated_at' => $now]);
$password = bin2hex(random_bytes(20));
$manager = User::create(['name' => 'Gestor de Demonstração', 'email' => 'gestor@example.test', 'password' => $password]);
$reader = User::create(['name' => 'Consulta de Demonstração', 'email' => 'consulta@example.test', 'password' => $password]);
$limited = User::create(['name' => 'Gestor Limitado', 'email' => 'limitado@example.test', 'password' => $password]);
$manager = User::create(['name' => 'Gestor de Demonstração', 'email' => 'gestor'.$emailSuffix.'@example.test', 'password' => $password]);
$reader = User::create(['name' => 'Consulta de Demonstração', 'email' => 'consulta'.$emailSuffix.'@example.test', 'password' => $password]);
$limited = User::create(['name' => 'Gestor Limitado', 'email' => 'limitado'.$emailSuffix.'@example.test', 'password' => $password]);
foreach ([$manager, $reader, $limited] as $user) {
DB::table('company_memberships')->insert(['user_id' => $user->id, 'tenant_id' => $tenant, 'company_id' => $company]);
self::grant($user->id, $tenant, $company, 'company.view');
+52
View File
@@ -0,0 +1,52 @@
<?php
namespace Tests\Support;
use App\Shared\Context\ModuleRecords;
use Illuminate\Support\Facades\{Auth,DB};
/** Explicit suite fixture metadata, never a production compatibility bypass.
* These suites recreate their database; only the disposable regression runner
* may seed their synthetic associations and discovery profiles.
*/
trait UsesModuleFixture
{
protected function moduleFixture(): string { return 'commercial'; }
public function postJson($uri, array $data = [], array $headers = [], $options = 0)
{
if ($uri === '/api/context' && !array_key_exists('module_id',$data)) {
if (!getenv('SGF_ISOLATED_REGRESSION_RUN')) throw new \RuntimeException('Use the disposable modular regression runner.');
$actor=Auth::user();
$permitted=$actor && isset($data['tenant_id'],$data['company_id'])
&& DB::table('company_memberships')->where('user_id',$actor->id)->where('tenant_id',$data['tenant_id'])->where('company_id',$data['company_id'])->exists()
&& app(\App\Modules\Identity\Services\Permissions::class)->has($actor->id,(int)$data['tenant_id'],(int)$data['company_id'],'company.view');
if($permitted) {
$module=$this->moduleFixture();
$profile=$actor->id.':'.$data['tenant_id'].':'.$data['company_id'];
config(['modules.development_profiles'=>array_values(array_unique([...config('modules.development_profiles',[]),$profile]))]);
// The suite's freshly created fixture has this explicitly declared purpose.
// This does not run on existing/demo data, or in application middleware.
foreach(ModuleRecords::AREAS as $area) {
$scope=['tenant_id'=>$data['tenant_id'],'company_id'=>$data['company_id'],'unit_id'=>str_ends_with($area,'_drafts')?($data['unit_id']??null):null];
foreach(DB::table('a_'.$area)->where($scope)->get(['id','version']) as $row) {
$exists=DB::table('identity_audit')->where('action','module.record.associated')->where('tenant_id',$scope['tenant_id'])->where('company_id',$scope['company_id'])
->whereRaw("details::jsonb->>'area' = ?",[$area])->whereRaw("details::jsonb->>'record_id' = ?",[(string)$row->id])->whereRaw("details::jsonb->>'module_id' = ?",[$module])->exists();
if(!$exists)ModuleRecords::associate($area,$row->id,$actor->id,$scope,$module,'Explicit newly-created regression fixture: '.static::class,false,(int)$row->version);
}
}
$data['module_id']=$module;
}
}
return parent::postJson($uri,$data,$headers,$options);
}
public function getJson($uri, array $headers = [], $options = 0)
{
// Historical read assertions previously had no generation header. Writes
// retain their explicitly supplied tokens, including intentional stale ones.
$token=app('session.store')->get('company_context.token');
if($token && !array_key_exists('X-SGF-Context',$headers))$headers['X-SGF-Context']=$token;
return parent::getJson($uri,$headers,$options);
}
}