Skip to content

fix(test): seed finance_reports.view permission for policy tests#3839

Merged
rathorevaibhav merged 2 commits intodevelopfrom
bugfix/seed-finance-reports-permission-in-tests
May 8, 2026
Merged

fix(test): seed finance_reports.view permission for policy tests#3839
rathorevaibhav merged 2 commits intodevelopfrom
bugfix/seed-finance-reports-permission-in-tests

Conversation

@rathorevaibhav
Copy link
Copy Markdown
Member

@rathorevaibhav rathorevaibhav commented May 8, 2026

Summary

Wires ReportDatabaseSeeder into the central DatabaseSeeder so the finance_reports.view permission is registered when tests run db:seed. Fixes the 24 failing tests across Modules/Project/Tests/{Feature,Unit} and Modules/Client/Tests/{Feature,Unit}.

Root cause

Both Modules/Project/Policies/ProjectInvoiceTermPolicy::view() and Modules/Client/Policies/ClientContractPolicy::view() call:

if ($user->hasPermissionTo('finance_reports.view')) {
    return true;
}

Spatie's hasPermissionTo() throws PermissionDoesNotExist if the permission name isn't registered in the permissions table. The permission is defined in Modules/Report/Database/Seeders/ReportDatabaseSeeder.php:22, but that seeder was never called from database/seeders/DatabaseSeeder.php.

The four failing test classes all use the standard test bootstrap:

$this->setUpRolesAndPermissions();  // → $this->artisan('db:seed') → DatabaseSeeder
$this->artisan('db:seed', ['--class' => ProjectPermissionsTableSeeder::class]);

db:seed runs the central DatabaseSeeder, which seeds roles, HR domains, users, and book permissions — but not finance-report permissions. So when a non-super-admin test user hit a route that invoked ProjectInvoiceTermPolicy/ClientContractPolicy, the policy threw PermissionDoesNotExist before reaching any of the actual authorization logic, and the request 500'd.

That's why the test counts (Tests: 106, Assertions: 140, Errors: 13, Failures: 11.) have stayed identical across recent develop runs — a single configuration gap is producing all 24 failures.

The one test in each class that does pass — test_user_with_finance_reports_view_permission_can_download — explicitly calls Permission::findOrCreate('finance_reports.view') inline as a workaround, which confirms the original author was aware of the gap but only patched the local case.

The fix

Add $this->call(ReportDatabaseSeeder::class) to DatabaseSeeder::run() alongside the already-present BooksPermissionsSeeder — there's clear precedent for wiring module-level permission seeders into the central seeder.

+use Modules\Report\Database\Seeders\ReportDatabaseSeeder;
 ...
         $this->call(BooksPermissionsSeeder::class);
         $this->call(BookCategoriesTableSeeder::class);
+        $this->call(ReportDatabaseSeeder::class);

Permission::updateOrCreate and givePermissionTo are idempotent, so re-running is safe. RolesTableSeeder (already called first in DatabaseSeeder) creates the admin and finance-manager roles that ReportDatabaseSeeder assigns permissions to, so dependency order is satisfied.

Why this won't change production behavior

DatabaseSeeder::run() is gated by app()->environment(['local', 'staging', 'UAT', 'testing']), so this seeder will only run in those environments. Production seeding behavior is unchanged. (Production presumably already has finance_reports.view registered — the policy code that uses it has been live and the affected views/routes work for real users — but how it's seeded in production is out of scope for this PR.)

Test plan

  • CI green on unit-testing.yml
  • Specifically check that the previously-failing tests now pass:
    • Modules\Client\Tests\Feature\ClientContractPdfAccessTest (5 tests)
    • Modules\Client\Tests\Unit\ClientContractPolicyTest (5+ tests)
    • Modules\Project\Tests\Feature\DeliveryReportAccessTest (4 tests)
    • Modules\Project\Tests\Unit\ProjectInvoiceTermPolicyTest (5 tests)
  • Tests that previously passed continue to pass

Note on local verification

I couldn't run PHPUnit locally to verify (no MySQL on this machine), so CI is the source of truth here. The change is small, follows clear precedent, and the reasoning is grounded in reading the failing test code, the policy code, and the existing seeder wiring — but if CI surfaces something unexpected I'll iterate.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Contract file paths are now optional when creating or updating contracts.
  • Chores

    • Report data is now seeded during database initialization.

The ProjectInvoiceTerm and ClientContract policies call
$user->hasPermissionTo('finance_reports.view'), which Spatie throws
PermissionDoesNotExist on if the permission is not registered. The
permission is defined in ReportDatabaseSeeder, but that seeder was
never wired into the central DatabaseSeeder, so neither tests
(via setUpRolesAndPermissions -> db:seed) nor non-prod environments
were registering it. As a result, every policy test that exercises
a non-super-admin user path errored before reaching the actual
authorization logic — the only passing tests were ones that called
Permission::findOrCreate('finance_reports.view') inline as a
workaround.

Wiring ReportDatabaseSeeder into DatabaseSeeder follows the existing
precedent of BooksPermissionsSeeder being seeded the same way, and
unblocks the 24 failing tests in the Project and Client modules
without changing any policy or production code paths. The seeder is
gated by app()->environment(['local','staging','UAT','testing']) so
production seeding behavior is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack

Walkthrough

This PR introduces two database setup changes: a migration making the contract_file_path column nullable on the client_contracts table, and integration of ReportDatabaseSeeder into the main database seeding workflow. Both changes modify the database initialization pipeline.

Changes

Database Setup

Layer / File(s) Summary
Schema Migration
Modules/Client/Database/Migrations/2026_05_08_190600_make_contract_file_path_nullable_on_client_contracts_table.php
Migration class alters client_contracts.contract_file_path to nullable via change() with reversible down() method.
Seeder Integration
database/Seeders/DatabaseSeeder.php
Imports ReportDatabaseSeeder and adds its invocation to the seeding sequence after BookCategoriesTableSeeder.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🗃️ A column softens its stance today,
nullable now, come what may,
Reports seed themselves with grace,
Database setup finds its place. 📊

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title references seeding a permission for policy tests, but the changeset also includes a schema migration making contract_file_path nullable—a significant structural change not mentioned in the title. Update the title to reflect both main changes, e.g., 'fix(test): seed finance_reports.view permission and make contract_file_path nullable' or split into two focused PRs.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/seed-finance-reports-permission-in-tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.1.54)

PHPStan was skipped because the config uses disallowed bootstrapFiles, bootstrapFile, or includes directives.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rathorevaibhav rathorevaibhav self-assigned this May 8, 2026
@cypress
Copy link
Copy Markdown

cypress Bot commented May 8, 2026

Employee portal    Run #9048

Run Properties:  status check passed Passed #9048  •  git commit 1317dbd5ca ℹ️: Merge f5a5774529bccbaa665855ab39a0ed387d629e1f into 1936836b842752462940eb5a02b3...
Project Employee portal
Branch Review refs/pull/3839/merge
Run status status check passed Passed #9048
Run duration 00m 23s
Commit git commit 1317dbd5ca ℹ️: Merge f5a5774529bccbaa665855ab39a0ed387d629e1f into 1936836b842752462940eb5a02b3...
Committer Vaibhav Rathore
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 4
View all changes introduced in this branch ↗︎

ClientController::showPdf() defensively handles a null contract_file_path
by logging a warning and returning 404, and the matching feature test
test_null_file_path_returns_404_and_logs_warning exercises that exact
branch — but the original create_client_contracts_table migration
declared the column NOT NULL, so the test errored at factory setup
with an integrity-constraint violation before reaching the assertion.

The analogous project_invoice_terms.delivery_report column is nullable
and its equivalent null-path test passes; the column nullability here
was simply a missed ->nullable() in the original migration. Aligning
the schema with the existing controller behavior and test intent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Modules/Client/Database/Migrations/2026_05_08_190600_make_contract_file_path_nullable_on_client_contracts_table.php`:
- Around line 16-20: The down() migration currently changes contract_file_path
to NOT NULL but doesn't handle existing NULLs; update any rows with NULL
contract_file_path to a non-null default (e.g., empty string or a sensible
placeholder) before calling Schema::table so the alter won't fail. In other
words, in the down() method, run a DB update targeting the client_contracts
table to backfill NULL contract_file_path values, then proceed with the existing
Schema::table('client_contracts', function (Blueprint $table) {
$table->string('contract_file_path')->nullable(false)->change(); }); to enforce
NOT NULL.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bb2cb74f-34cf-43b8-974b-111b95ba7a79

📥 Commits

Reviewing files that changed from the base of the PR and between 1936836 and f5a5774.

📒 Files selected for processing (2)
  • Modules/Client/Database/Migrations/2026_05_08_190600_make_contract_file_path_nullable_on_client_contracts_table.php
  • database/Seeders/DatabaseSeeder.php

Comment on lines +16 to +20
public function down()
{
Schema::table('client_contracts', function (Blueprint $table) {
$table->string('contract_file_path')->nullable(false)->change();
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rollback can fail if existing rows contain NULL contract_file_path

On Line 19, reverting to NOT NULL will error if any row has contract_file_path = NULL (which up() explicitly permits). Backfill nulls before altering the constraint.

Suggested fix
 use Illuminate\Database\Migrations\Migration;
 use Illuminate\Database\Schema\Blueprint;
 use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\DB;
@@
     public function down()
     {
+        DB::table('client_contracts')
+            ->whereNull('contract_file_path')
+            ->update(['contract_file_path' => '']);
+
         Schema::table('client_contracts', function (Blueprint $table) {
             $table->string('contract_file_path')->nullable(false)->change();
         });
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Modules/Client/Database/Migrations/2026_05_08_190600_make_contract_file_path_nullable_on_client_contracts_table.php`
around lines 16 - 20, The down() migration currently changes contract_file_path
to NOT NULL but doesn't handle existing NULLs; update any rows with NULL
contract_file_path to a non-null default (e.g., empty string or a sensible
placeholder) before calling Schema::table so the alter won't fail. In other
words, in the down() method, run a DB update targeting the client_contracts
table to backfill NULL contract_file_path values, then proceed with the existing
Schema::table('client_contracts', function (Blueprint $table) {
$table->string('contract_file_path')->nullable(false)->change(); }); to enforce
NOT NULL.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Coverage report for commit: f5a5774
File: coverage.xml

Cover ┌─────────────────────────┐ Freq.
   0% │ ███████████████████████ │ 73.1%
  10% │ █░░░░░░░░░░░░░░░░░░░░░░ │  1.5%
  20% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.6%
  30% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.3%
  40% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.6%
  50% │ ██░░░░░░░░░░░░░░░░░░░░░ │  4.6%
  60% │ █░░░░░░░░░░░░░░░░░░░░░░ │  1.2%
  70% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.9%
  80% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.9%
  90% │ █░░░░░░░░░░░░░░░░░░░░░░ │  3.1%
 100% │ █████░░░░░░░░░░░░░░░░░░ │ 13.0%
      └─────────────────────────┘
 *Legend:* █ = Current Distribution 
Summary - Lines: 10.48% | Methods: 11.13%
FilesLinesMethodsBranches
Modules/HR/Console
   JobExpiredEmailToHr.php--100.00%
   QuarterlyReviewSystemForEmployee.php--100.00%
Modules/HR/Console/Recruitment
   ApplicationNoShow.php--100.00%
   DailyMessage.php--100.00%
   MappingOfJobsAndHrRounds.php--100.00%
   MarkApplicationForFollowUp.php--100.00%
   MoveFilesToWordPress.php--100.00%
   ResetIsLatestApplicationRound.php45.45%66.67%100.00%
   SendFollowUpThresholdMail.php--100.00%
   SendInterviewReminders.php--100.00%
Modules/HR/Contracts
   ApplicationServiceContract.php100.00%100.00%100.00%
   EvaluationServiceContract.php100.00%100.00%100.00%
   UniversityServiceContract.php100.00%100.00%100.00%
Modules/HR/Database/Factories
   HrApplicantsFactory.php100.00%100.00%100.00%
   HrApplicationEvaluationFactory.php--100.00%
   HrApplicationMetaFactory.php--100.00%
   HrApplicationRejectionFactory.php--100.00%
   HrApplicationRoundReviewFactory.php--100.00%
   HrApplicationSegmentFactory.php--100.00%
   HrApplicationsFactory.php--100.00%
   HrEmployeeFactory.php--100.00%
   HrFollowUpFactory.php--100.00%
   HrJobsFactory.php100.00%100.00%100.00%
   HrResourcesCategoriesFactory.php--100.00%
   HrResourcesFactory.php--100.00%
   HrUniversitiesContactsFactory.php100.00%100.00%100.00%
   HrUniversitiesFactory.php100.00%100.00%100.00%
   HrUniversityAliasesFactory.php100.00%100.00%100.00%
Modules/HR/Database/Migrations
   2020_07_15_110611_create_hr_application_segments_table.php91.67%50.00%100.00%
   2020_07_15_142215_rename_next_interview_comments_column.php50.00%50.00%100.00%
   2020_07_25_202622_update_segment_table_with_segment_parent.php61.54%50.00%100.00%
   2020_09_04_234639_update_application_round_with_calendar_meeting_id.php66.67%50.00%100.00%
   2020_09_06_234443_update_hr_application_round_table_with_is_latest.php50.00%50.00%100.00%
   2020_09_07_171154_create_hr_follow_ups_table.php92.31%50.00%100.00%
   2020_09_08_073438_create_hr_universities_table.php87.50%50.00%100.00%
   2020_09_08_073538_create_hr_universities_contacts_table.php90.00%50.00%100.00%
   2020_09_08_073651_add_hr_university_id_to_hr_applicants_table.php42.86%50.00%100.00%
   2020_11_24_141131_create_hr_university_aliases_table.php85.71%50.00%100.00%
   2020_12_31_112259_alter_posted_by_in_hr_jobs_table.php50.00%50.00%100.00%
   2021_01_01_113149_add_status_to_hr_jobs_table.php50.00%50.00%100.00%
   2021_01_01_123714_add_soft_deletes_to_hr_jobs_table.php50.00%50.00%100.00%
   2022_03_08_064931_update_hr_jobs_table.php50.00%50.00%100.00%
   2022_06_15_141424_add_parameter_slug_column_in_evaluation_parameter_table.php50.00%50.00%100.00%
   2022_07_04_165601_add_verification_status_to_application.php50.00%50.00%100.00%
   2022_07_07_075310_create_hr_job_domains_table.php85.71%50.00%100.00%
   2022_07_15_115016_create_hr_channels_table.php85.71%50.00%100.00%
   2022_07_15_115134_update_hr_applications_with_hr_channels_table.php50.00%50.00%100.00%
   2022_09_01_230847_create_job_requisition_table.php57.14%50.00%100.00%
   2022_09_06_232653_add_status_to_job_requisition.php50.00%50.00%100.00%
   2022_09_12_140344_create_hr_applicant_meta_table.php76.92%50.00%100.00%
   2022_09_19_160414_create_hr_job_designation_table.php85.71%50.00%100.00%
   2022_09_21_145858_create_batch_members_table.php57.14%50.00%100.00%
   2022_09_21_151304_create_batches_table.php83.33%50.00%100.00%
   2022_09_26_134702_alter_column_for_application_meta_value.php50.00%50.00%100.00%
   2024_03_20_161855_add_commencement_date_column_to_employee_salary_table.php50.00%50.00%100.00%
Modules/HR/Database/Seeders
   AddPreparatoryRoundsSeeder.php--100.00%
   ApplicationEvaluationTableSeeder.php--100.00%
   DomainTableSeeder.php--100.00%
   HRDatabaseSeeder.php--100.00%
   HRJobsSeederTableSeeder.php--100.00%
   HRPermissionsTableSeeder.php--100.00%
   HRRoundsTableSeeder.php--100.00%
   HrApplicantsTableSeeder.php--100.00%
   HrApplicationEvaluationSegmentTableSeeder.php--100.00%
   HrApplicationMetaTableSeeder.php--100.00%
   HrApplicationRejectionReasonTableSeeder.php--100.00%
   HrApplicationRoundReviewTableSeeder.php--100.00%
   HrApplicationRoundTableSeeder.php--100.00%
   HrApplicationSegmentTableSeeder.php--100.00%
   HrApplicationsTableSeeder.php--100.00%
   HrChannelsTableSeeder.php--100.00%
   HrDesignationTableSeeder.php100.00%100.00%100.00%
   HrDomainTableSeeder.php100.00%100.00%100.00%
   HrFollowUpTableSeeder.php--100.00%
   HrResourcesCategoriesTableSeeder.php--100.00%
   HrResourcesTableSeeder.php--100.00%
   HrUniversitiesContactsTableSeeder.php--100.00%
   HrUniversitiesTableSeeder.php--100.00%
   HrUniversityAliasesTableSeeder.php--100.00%
   ResumeScreeningEvaluationSeeder.php--100.00%
   SettingsTableSeeder.php--100.00%
   TagTableSeeder.php--100.00%
Modules/HR/Emails
   AppointmentSlotSelectionMail.php--100.00%
   SendHiringMail.php--100.00%
   SendJobExpiredMail.php--100.00%
   SendPayrollListMail.php--100.00%
   SendThreshholdFollowUp.php--100.00%
Modules/HR/Emails/Recruitment/Applicant
   ApplicantCreateAutoResponder.php--100.00%
   NoShow.php--100.00%
   OnHold.php--100.00%
   RoundReviewed.php--100.00%
   ScheduledInterviewReminder.php--100.00%
Modules/HR/Emails/Recruitment/Application
   ApplicationHandover.php--100.00%
   CustomApplicationMail.php--100.00%
   JobChanged.php--100.00%
   RoundNotConducted.php--100.00%
Modules/HR/Emails/Recruitment
   InterviewerScheduledRoundsReminder.php--100.00%
   SendForApproval.php--100.00%
   SendOfferLetter.php--100.00%
Modules/HR/Entities
   Applicant.php1.69%10.00%100.00%
   ApplicantMeta.php--100.00%
   Application.php13.52%10.42%100.00%
   ApplicationEvaluationSegment.php--100.00%
   ApplicationMeta.php--100.00%
   ApplicationRound.php0.36%4.00%100.00%
   ApplicationRoundReview.php--100.00%
   Assessment.php--100.00%
   Employee.php1.39%4.35%100.00%
   FollowUp.php--100.00%
   HRJobsRounds.php100.00%100.00%100.00%
   HRRejectionReason.php--100.00%
   HRRequisitionHiredBatch.php--100.00%
   HRRequisitionHiredBatchMembers.php--100.00%
   HrChannel.php100.00%100.00%100.00%
   HrJobDesignation.php--100.00%
   HrJobDomain.php--100.00%
   IndividualAssessment.php--100.00%
   Job.php50.00%38.89%100.00%
   JobRequisition.php--100.00%
   Round.php--100.00%
   University.php33.33%33.33%100.00%
   UniversityAlias.php100.00%100.00%100.00%
   UniversityContact.php100.00%100.00%100.00%
Modules/HR/Entities/Evaluation
   ApplicationEvaluation.php--100.00%
   Parameter.php--100.00%
   ParameterOption.php--100.00%
   Segment.php--100.00%
Modules/HR/Events
   ApplicationMovedToNewRound.php--100.00%
   CustomMailTriggeredForApplication.php--100.00%
   FollowUpEvent.php--100.00%
   InterviewCommunicationEmailSent.php--100.00%
Modules/HR/Events/Recruitment
   ApplicantEmailVerified.php--100.00%
   ApplicationCreated.php--100.00%
   JobUpdated.php66.67%50.00%100.00%
Modules/HR/Exports
   ContractorFeeExport.php--100.00%
   EmployeePayrollExport.php--100.00%
Modules/HR/Helpers
   TemplateHelper.php--100.00%
Modules/HR/Http/Controllers
   EmployeeController.php--100.00%
   EvaluationController.php--100.00%
   HiringController.php--100.00%
   HrChannelController.php--100.00%
   HrJobDesignationController.php--100.00%
   RequisitionController.php--100.00%
   ResourcesController.php--100.00%
   TagsController.php--100.00%
Modules/HR/Http/Controllers/Recruitment
   ApplicantController.php--100.00%
   ApplicationController.php38.22%7.14%100.00%
   ApplicationRoundController.php--100.00%
   CampaignsController.php--100.00%
   InternshipApplicationController.php--100.00%
   JobApplicationController.php100.00%100.00%100.00%
   JobController.php13.13%25.00%100.00%
Table truncated to fit comment

🤖 comment via lucassabreu/comment-coverage-clover

@rathorevaibhav rathorevaibhav merged commit 4c91a3d into develop May 8, 2026
7 checks passed
@rathorevaibhav rathorevaibhav deleted the bugfix/seed-finance-reports-permission-in-tests branch May 8, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant