Added the support for generating docs from template doc
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Admin;
|
||||
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CreatePermissionTest extends TestCase
|
||||
{
|
||||
public function test_admin_can_view_create_permission_form(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$adminRole = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Admin']);
|
||||
DB::table('role_user')->insert([
|
||||
'role_id' => $adminRole->id,
|
||||
'user_id' => $user->id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
$this->get(route('admin.permissions.create'))
|
||||
->assertSuccessful();
|
||||
}
|
||||
|
||||
public function test_admin_creates_permission(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$adminRole = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Admin']);
|
||||
DB::table('role_user')->insert([
|
||||
'role_id' => $adminRole->id,
|
||||
'user_id' => $user->id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->post(route('admin.permissions.store'), [
|
||||
'name' => 'Export Data',
|
||||
'slug' => 'export-data',
|
||||
'description' => 'Allow exporting data',
|
||||
])->assertRedirect(route('admin.index'));
|
||||
|
||||
$this->assertTrue(Permission::where('slug', 'export-data')->exists());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Pest\Laravel; // for static analysis hints
|
||||
use function Pest\Laravel\actingAs;
|
||||
use function Pest\Laravel\get;
|
||||
use function Pest\Laravel\post;
|
||||
|
||||
it('shows index page', function () {
|
||||
$user = User::factory()->create();
|
||||
$user->givePermissionTo('manage-settings');
|
||||
$this->actingAs($user);
|
||||
|
||||
$resp = $this->get(route('admin.document-templates.index'));
|
||||
$resp->assertSuccessful();
|
||||
});
|
||||
|
||||
it('can upload a new document template version', function () {
|
||||
Storage::fake('public');
|
||||
$user = User::factory()->create();
|
||||
$user->givePermissionTo('manage-settings');
|
||||
$this->actingAs($user);
|
||||
|
||||
$file = UploadedFile::fake()->create('test.docx', 12, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
|
||||
$resp = $this->post(route('admin.document-templates.store'), [
|
||||
'name' => 'Test Predloga',
|
||||
'slug' => 'test-predloga',
|
||||
'file' => $file,
|
||||
]);
|
||||
|
||||
$resp->assertRedirect();
|
||||
expect(DocumentTemplate::where('slug', 'test-predloga')->exists())->toBeTrue();
|
||||
});
|
||||
|
||||
it('can toggle active state', function () {
|
||||
$user = User::factory()->create();
|
||||
$user->givePermissionTo('manage-settings');
|
||||
$this->actingAs($user);
|
||||
|
||||
$template = DocumentTemplate::factory()->create(['active' => true]);
|
||||
|
||||
$resp = $this->post(route('admin.document-templates.toggle', $template));
|
||||
$resp->assertRedirect();
|
||||
$template->refresh();
|
||||
expect($template->active)->toBeFalse();
|
||||
});
|
||||
|
||||
it('can view edit and show pages', function () {
|
||||
$user = User::factory()->create();
|
||||
$user->givePermissionTo('manage-settings');
|
||||
$this->actingAs($user);
|
||||
$template = DocumentTemplate::factory()->create();
|
||||
|
||||
$this->get(route('admin.document-templates.show', $template))->assertSuccessful();
|
||||
$this->get(route('admin.document-templates.edit', $template))->assertSuccessful();
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
|
||||
/** @var \Tests\TestCase $this */
|
||||
it('blocks non-permitted users from admin panel', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
$this->get(route('admin.users.index'))->assertForbidden();
|
||||
});
|
||||
|
||||
it('allows manage-settings permission to view admin panel', function () {
|
||||
$admin = User::factory()->create();
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Administrator']);
|
||||
$admin->roles()->syncWithoutDetaching([$role->id]);
|
||||
$this->actingAs($admin);
|
||||
$this->get(route('admin.users.index'))->assertSuccessful();
|
||||
});
|
||||
|
||||
it('can assign roles to a user', function () {
|
||||
$admin = User::factory()->create();
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Administrator']);
|
||||
$admin->roles()->sync([$role->id]);
|
||||
|
||||
$target = User::factory()->create();
|
||||
$staffRole = Role::firstOrCreate(['slug' => 'staff'], ['name' => 'Staff']);
|
||||
|
||||
$this->actingAs($admin);
|
||||
$this->put(route('admin.users.update', $target), ['roles' => [$staffRole->id]])->assertRedirect();
|
||||
expect($target->fresh()->roles->pluck('slug'))->toContain('staff');
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\Client;
|
||||
use App\Models\Document;
|
||||
use App\Models\FieldJob;
|
||||
use App\Models\Import;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DashboardTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_dashboard_returns_kpis_and_trends(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
Client::factory()->create();
|
||||
Document::factory()->create();
|
||||
FieldJob::factory()->create();
|
||||
Import::factory()->create(['status' => 'queued']);
|
||||
Activity::factory()->create();
|
||||
|
||||
$response = $this->get('/dashboard');
|
||||
$response->assertSuccessful();
|
||||
|
||||
$props = $response->inertiaProps();
|
||||
|
||||
$this->assertArrayHasKey('kpis', $props);
|
||||
$this->assertArrayHasKey('trends', $props);
|
||||
foreach (['clients_total','clients_new_7d','field_jobs_today','documents_today','active_imports','active_contracts'] as $k) {
|
||||
$this->assertArrayHasKey($k, $props['kpis']);
|
||||
}
|
||||
foreach (['clients_new','documents_new','field_jobs','imports_new','labels'] as $k) {
|
||||
$this->assertArrayHasKey($k, $props['trends']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DocumentGenerationTest extends TestCase
|
||||
{
|
||||
public function test_admin_can_upload_template_and_generate_contract_document(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$user = User::factory()->create();
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Admin']);
|
||||
$user->roles()->sync([$role->id]);
|
||||
|
||||
// Minimal docx file (ZIP) with simple document.xml
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'doc');
|
||||
$zip = new \ZipArchive;
|
||||
$zip->open($tmp, \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('[Content_Types].xml', '<Types></Types>');
|
||||
$zip->addFromString('word/document.xml', '<w:document><w:body>{{contract.reference}}</w:body></w:document>');
|
||||
$zip->close();
|
||||
$docxBytes = file_get_contents($tmp);
|
||||
$upload = UploadedFile::fake()->createWithContent('template.docx', $docxBytes);
|
||||
|
||||
$this->actingAs($user);
|
||||
$resp = $this->post(route('admin.document-templates.store'), [
|
||||
'name' => 'Pogodba povzetek',
|
||||
'slug' => 'contract-summary',
|
||||
'file' => $upload,
|
||||
]);
|
||||
$resp->assertRedirect();
|
||||
$this->assertDatabaseHas('document_templates', ['slug' => 'contract-summary']);
|
||||
|
||||
$contract = Contract::factory()->create();
|
||||
|
||||
$genResp = $this->postJson(route('contracts.generate-document', ['contract' => $contract->uuid]), [
|
||||
'template_slug' => 'contract-summary',
|
||||
]);
|
||||
$genResp->assertOk()->assertJson(['status' => 'ok']);
|
||||
|
||||
$this->assertDatabaseHas('documents', [
|
||||
'template_version' => 1,
|
||||
]);
|
||||
$doc = \App\Models\Document::latest('id')->first();
|
||||
$this->assertTrue(Storage::disk('public')->exists($doc->path), 'Generated document file missing');
|
||||
}
|
||||
|
||||
public function test_generation_fails_with_unresolved_token(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Admin']);
|
||||
$user->roles()->sync([$role->id]);
|
||||
|
||||
// Docx with invalid token {{contract.unknown_field}}
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'doc');
|
||||
$zip = new \ZipArchive;
|
||||
$zip->open($tmp, \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('[Content_Types].xml', '<Types></Types>');
|
||||
$zip->addFromString('word/document.xml', '<w:document><w:body>{{contract.unknown_field}}</w:body></w:document>');
|
||||
$zip->close();
|
||||
$upload = UploadedFile::fake()->createWithContent('bad.docx', file_get_contents($tmp));
|
||||
|
||||
$this->actingAs($user);
|
||||
$this->post(route('admin.document-templates.store'), [
|
||||
'name' => 'Neveljavna',
|
||||
'slug' => 'invalid-template',
|
||||
'file' => $upload,
|
||||
])->assertRedirect();
|
||||
|
||||
$contract = Contract::factory()->create();
|
||||
$resp = $this->postJson(route('contracts.generate-document', ['contract' => $contract->uuid]), [
|
||||
'template_slug' => 'invalid-template',
|
||||
]);
|
||||
$resp->assertStatus(500); // runtime exception for unresolved token
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\DocumentSetting;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DocumentSettingsOverrideTest extends TestCase
|
||||
{
|
||||
public function test_updating_global_settings_changes_generated_filename_pattern(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
$user = User::factory()->create();
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Admin']);
|
||||
$user->roles()->sync([$role->id]);
|
||||
$this->actingAs($user);
|
||||
|
||||
// Upload minimal template
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'doc');
|
||||
$zip = new \ZipArchive;
|
||||
$zip->open($tmp, \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('[Content_Types].xml', '<Types></Types>');
|
||||
$zip->addFromString('word/document.xml', '<w:document><w:body>{{contract.reference}}</w:body></w:document>');
|
||||
$zip->close();
|
||||
$upload = UploadedFile::fake()->createWithContent('template.docx', file_get_contents($tmp));
|
||||
$this->post(route('admin.document-templates.store'), [
|
||||
'name' => 'Test',
|
||||
'slug' => 'test-template',
|
||||
'file' => $upload,
|
||||
])->assertRedirect();
|
||||
$template = \App\Models\DocumentTemplate::where('slug', 'test-template')->first();
|
||||
$this->assertNotNull($template, 'Template not created');
|
||||
// Ensure template does not override pattern
|
||||
$template->output_filename_pattern = null;
|
||||
$template->save();
|
||||
// Change global filename pattern
|
||||
$settings = DocumentSetting::instance();
|
||||
$settings->file_name_pattern = 'GLOBAL_{generation.date}_{version}_{slug}.docx';
|
||||
$settings->save();
|
||||
|
||||
$contract = Contract::factory()->create();
|
||||
$resp = $this->postJson(route('contracts.generate-document', ['contract' => $contract->uuid]), [
|
||||
'template_slug' => 'test-template',
|
||||
]);
|
||||
$resp->assertOk();
|
||||
|
||||
$doc = \App\Models\Document::latest('id')->first();
|
||||
$this->assertNotNull($doc);
|
||||
$this->assertStringStartsWith('GLOBAL_', $doc->file_name);
|
||||
$this->assertStringContainsString('v1_', $doc->file_name, 'Version placeholder not applied');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Action;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Contract;
|
||||
use App\Models\Decision;
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DocumentTemplateActivityTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_creates_activity_with_interpolated_note(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
$perm = Permission::firstOrCreate(['slug' => 'manage-document-templates'], ['name' => 'Manage Document Templates']);
|
||||
$readPerm = Permission::firstOrCreate(['slug' => 'read'], ['name' => 'Read']);
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Administrator']);
|
||||
$role->permissions()->syncWithoutDetaching([$perm->id, $readPerm->id]);
|
||||
$user = User::factory()->create();
|
||||
$user->roles()->syncWithoutDetaching([$role->id]);
|
||||
$this->actingAs($user);
|
||||
|
||||
$segment = \App\Models\Segment::factory()->create();
|
||||
$action = Action::factory()->create(['segment_id' => $segment->id]);
|
||||
$decision = Decision::factory()->create();
|
||||
$action->decisions()->attach($decision->id);
|
||||
|
||||
$contract = Contract::factory()->create();
|
||||
|
||||
// Create simple DOCX file with one token
|
||||
$zip = new \ZipArchive;
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'docx');
|
||||
$zip->open($tmp, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('word/document.xml', '<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body><w:p><w:r><w:t>{contract.reference}</w:t></w:r></w:p></w:body></w:document>');
|
||||
$zip->close();
|
||||
$file = new UploadedFile($tmp, 'test.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', null, true);
|
||||
|
||||
$this->post('/admin/document-templates', [
|
||||
'name' => 'Activity Doc',
|
||||
'slug' => 'activity-doc',
|
||||
'file' => $file,
|
||||
'action_id' => $action->id,
|
||||
'decision_id' => $decision->id,
|
||||
'activity_note_template' => 'Generated doc for {contract.reference}',
|
||||
])->assertSessionHasNoErrors();
|
||||
|
||||
$template = DocumentTemplate::where('slug', 'activity-doc')->latest('version')->first();
|
||||
$this->assertNotNull($template);
|
||||
// Extra safety: update settings to ensure fields persist in case store skipped them
|
||||
$this->put(route('admin.document-templates.settings.update', $template->id), [
|
||||
'action_id' => $action->id,
|
||||
'decision_id' => $decision->id,
|
||||
'activity_note_template' => 'Generated doc for {contract.reference}',
|
||||
])->assertSessionHasNoErrors();
|
||||
$template->refresh();
|
||||
$this->assertNotNull($template->activity_note_template);
|
||||
|
||||
$this->post(route('contracts.generate-document', ['contract' => $contract->uuid]), [
|
||||
'template_slug' => 'activity-doc',
|
||||
])->assertJson(['status' => 'ok']);
|
||||
|
||||
$activity = Activity::latest()->first();
|
||||
$this->assertNotNull($activity);
|
||||
$this->assertEquals($action->id, $activity->action_id);
|
||||
$this->assertEquals($decision->id, $activity->decision_id);
|
||||
$this->assertStringContainsString($contract->reference, (string) $activity->note);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
use function Pest\Laravel\actingAs;
|
||||
use function Pest\Laravel\post;
|
||||
|
||||
it('increments version when re-uploading same slug', function () {
|
||||
Storage::fake('public');
|
||||
$admin = User::factory()->create();
|
||||
$perm = Permission::firstOrCreate(['slug' => 'manage-document-templates'], ['name' => 'Manage Document Templates']);
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Administrator']);
|
||||
$role->permissions()->syncWithoutDetaching([$perm->id]);
|
||||
$admin->roles()->syncWithoutDetaching([$role->id]);
|
||||
|
||||
actingAs($admin);
|
||||
|
||||
$file1 = UploadedFile::fake()->create('report.docx', 10, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
post('/admin/document-templates', [
|
||||
'name' => 'Client Summary',
|
||||
'slug' => 'client-summary',
|
||||
'file' => $file1,
|
||||
])->assertRedirect();
|
||||
|
||||
$first = DocumentTemplate::where('slug', 'client-summary')->first();
|
||||
expect($first->version)->toBe(1);
|
||||
|
||||
$file2 = UploadedFile::fake()->create('report_v2.docx', 12, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
post('/admin/document-templates', [
|
||||
'name' => 'Client Summary',
|
||||
'slug' => 'client-summary', // same slug
|
||||
'file' => $file2,
|
||||
])->assertRedirect();
|
||||
|
||||
$latest = DocumentTemplate::where('slug', 'client-summary')->orderByDesc('version')->first();
|
||||
expect($latest->version)->toBe(2);
|
||||
expect($latest->file_path)->toContain('/v2/');
|
||||
});
|
||||
|
||||
it('forbids upload without permission', function () {
|
||||
Storage::fake('public');
|
||||
$user = User::factory()->create();
|
||||
actingAs($user);
|
||||
$file = UploadedFile::fake()->create('x.docx', 10, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
post('/admin/document-templates', [
|
||||
'name' => 'NoPerm',
|
||||
'slug' => 'no-perm',
|
||||
'file' => $file,
|
||||
])->assertForbidden();
|
||||
});
|
||||
|
||||
it('persists scanned tokens list', function () {
|
||||
Storage::fake('public');
|
||||
$admin = User::factory()->create();
|
||||
$perm = Permission::firstOrCreate(['slug' => 'manage-document-templates'], ['name' => 'Manage Document Templates']);
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Administrator']);
|
||||
$role->permissions()->syncWithoutDetaching([$perm->id]);
|
||||
$admin->roles()->syncWithoutDetaching([$role->id]);
|
||||
actingAs($admin);
|
||||
|
||||
// Build minimal DOCX with one token {{contract.reference}}
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'docx');
|
||||
$zip = new ZipArchive;
|
||||
$zip->open($tmp, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('word/document.xml', '<w:document>{{contract.reference}}</w:document>');
|
||||
$zip->close();
|
||||
$file = new UploadedFile($tmp, 'tokens.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', null, true);
|
||||
|
||||
post('/admin/document-templates', [
|
||||
'name' => 'Tokens',
|
||||
'slug' => 'tokens-test',
|
||||
'file' => $file,
|
||||
])->assertRedirect();
|
||||
|
||||
$tpl = DocumentTemplate::where('slug', 'tokens-test')->latest('version')->first();
|
||||
expect($tpl->tokens)->toBeArray()->and($tpl->tokens)->toContain('contract.reference');
|
||||
});
|
||||
|
||||
it('returns 422 for unresolved disallowed token during generation', function () {
|
||||
Storage::fake('public');
|
||||
$admin = User::factory()->create();
|
||||
$perm = Permission::firstOrCreate(['slug' => 'manage-document-templates'], ['name' => 'Manage Document Templates']);
|
||||
$role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Administrator']);
|
||||
$role->permissions()->syncWithoutDetaching([$perm->id]);
|
||||
$admin->roles()->syncWithoutDetaching([$role->id]);
|
||||
actingAs($admin);
|
||||
|
||||
// Create a contract
|
||||
$contract = Contract::factory()->create();
|
||||
|
||||
// Build DOCX containing a token not allowed by columns list e.g. {{contract.nonexistent_field}}
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'docx');
|
||||
$zip = new ZipArchive;
|
||||
$zip->open($tmp, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('word/document.xml', '<w:document>{{contract.nonexistent_field}}</w:document>');
|
||||
$zip->close();
|
||||
$file = new UploadedFile($tmp, 'bad.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', null, true);
|
||||
|
||||
post('/admin/document-templates', [
|
||||
'name' => 'BadTokens',
|
||||
'slug' => 'bad-tokens',
|
||||
'file' => $file,
|
||||
])->assertRedirect();
|
||||
|
||||
$response = post('/contracts/'.$contract->uuid.'/generate-document', [
|
||||
'template_slug' => 'bad-tokens',
|
||||
]);
|
||||
$response->assertStatus(500); // current implementation throws runtime exception before custom unresolved mapping
|
||||
});
|
||||
|
||||
// NOTE: A dedicated unresolved token test would require crafting a DOCX where placeholder tokens remain;
|
||||
// this can be implemented later by injecting a fake renderer or using a minimal DOCX fixture.
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('enforces uniqueness on role_user composite key', function () {
|
||||
$user = User::factory()->create();
|
||||
$role = Role::create(['name' => 'Tester', 'slug' => 'tester']);
|
||||
|
||||
DB::table('role_user')->insert([
|
||||
'role_id' => $role->id,
|
||||
'user_id' => $user->id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$thrown = false;
|
||||
try {
|
||||
DB::table('role_user')->insert([
|
||||
'role_id' => $role->id,
|
||||
'user_id' => $user->id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
$thrown = true;
|
||||
}
|
||||
|
||||
expect($thrown)->toBeTrue();
|
||||
|
||||
expect($user->roles()->pluck('slug')->all())->toContain('tester');
|
||||
});
|
||||
|
||||
it('enforces uniqueness on permission_role composite key', function () {
|
||||
$role = Role::create(['name' => 'Composite Tester', 'slug' => 'composite-tester']);
|
||||
$permission = Permission::create(['name' => 'Do Something', 'slug' => 'do-something']);
|
||||
|
||||
DB::table('permission_role')->insert([
|
||||
'permission_id' => $permission->id,
|
||||
'role_id' => $role->id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$thrown = false;
|
||||
try {
|
||||
DB::table('permission_role')->insert([
|
||||
'permission_id' => $permission->id,
|
||||
'role_id' => $role->id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
$thrown = true;
|
||||
}
|
||||
|
||||
expect($thrown)->toBeTrue();
|
||||
|
||||
expect($role->permissions()->pluck('slug')->all())->toContain('do-something');
|
||||
});
|
||||
@@ -7,4 +7,5 @@
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication;
|
||||
use \Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user