seedRolesAndPermissions(); $this->admin = $this->createAdmin(); } /** * Test issue due date today */ public function test_issue_due_date_today(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, 'due_date' => now()->endOfDay(), ]); $this->assertTrue($issue->due_date->isToday()); } /** * Test issue due date in past */ public function test_issue_due_date_in_past(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, 'due_date' => now()->subDay(), 'status' => Issue::STATUS_IN_PROGRESS, ]); // Issue with past due date and not closed is overdue $this->assertTrue($issue->due_date->isPast()); $this->assertNotEquals(Issue::STATUS_CLOSED, $issue->status); } /** * Test issue with no assignee */ public function test_issue_with_no_assignee(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, 'assigned_to_user_id' => null, ]); $this->assertNull($issue->assigned_to_user_id); $this->assertNull($issue->assignee); } /** * Test issue with circular parent reference prevention */ public function test_issue_with_circular_parent_reference(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, ]); // Try to set parent to self via update $response = $this->withoutMiddleware(VerifyCsrfToken::class) ->actingAs($this->admin) ->patch( route('admin.issues.update', $issue), [ 'title' => $issue->title, 'parent_issue_id' => $issue->id, ] ); // Should either have errors or redirect with preserved state $issue->refresh(); $this->assertNotEquals($issue->id, $issue->parent_issue_id); } /** * Test issue with many subtasks */ public function test_issue_with_many_subtasks(): void { $parentIssue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, ]); // Create 10 subtasks for ($i = 0; $i < 10; $i++) { Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, 'parent_issue_id' => $parentIssue->id, ]); } $this->assertCount(10, $parentIssue->subTasks); } /** * Test issue with many comments */ public function test_issue_with_many_comments(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, ]); // Create 50 comments for ($i = 0; $i < 50; $i++) { IssueComment::factory()->create([ 'issue_id' => $issue->id, 'user_id' => $this->admin->id, ]); } $this->assertCount(50, $issue->comments); } /** * Test issue time log with positive hours */ public function test_issue_time_log_positive_hours(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, ]); // Create time log directly via model $timeLog = \App\Models\IssueTimeLog::create([ 'issue_id' => $issue->id, 'user_id' => $this->admin->id, 'hours' => 2.5, 'description' => 'Work done', 'logged_at' => now(), ]); $this->assertDatabaseHas('issue_time_logs', [ 'issue_id' => $issue->id, 'hours' => 2.5, ]); $this->assertEquals(2.5, $timeLog->hours); } /** * Test issue status transition from closed */ public function test_issue_status_transition_from_closed(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, 'status' => Issue::STATUS_CLOSED, ]); // Reopen the issue $response = $this->withoutMiddleware(VerifyCsrfToken::class) ->actingAs($this->admin) ->patch( route('admin.issues.update-status', $issue), ['status' => Issue::STATUS_IN_PROGRESS] ); $issue->refresh(); // Depending on business rules, reopening might be allowed $this->assertTrue( $issue->status === Issue::STATUS_CLOSED || $issue->status === Issue::STATUS_IN_PROGRESS ); } /** * Test issue with maximum labels */ public function test_issue_with_maximum_labels(): void { $issue = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, ]); // Create and attach many labels $labels = IssueLabel::factory()->count(20)->create(); $issue->labels()->attach($labels->pluck('id')); $this->assertCount(20, $issue->labels); } /** * Test issue number generation across years */ public function test_issue_number_generation_across_years(): void { // Create issue in current year $issue1 = Issue::factory()->create([ 'created_by_user_id' => $this->admin->id, ]); $currentYear = now()->year; // Issue number should contain year $this->assertStringContainsString((string) $currentYear, $issue1->issue_number); } }