Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[8.x] feat: improve tests suite#2166

Merged
nabeelio merged 13 commits into
phpvms:mainfrom
arthurpar06:tests
Mar 18, 2026
Merged

[8.x] feat: improve tests suite#2166
nabeelio merged 13 commits into
phpvms:mainfrom
arthurpar06:tests

Conversation

@arthurpar06

@arthurpar06 arthurpar06 commented Mar 18, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Security

    • Strengthened cryptographic randomness across the app (IDs, API keys, random sampling).
  • Bug Fixes

    • Improved cron error logging with structured context.
    • Fixed reference resolution in the expense importer.
    • Removed stray debug output from live flight command.
  • Tests

    • Reorganized test suite to Pest with multiple suites; large-scale test additions, removals, and architectural tests introduced.
  • Chores

    • Removed a development Pest plugin from dependencies.
    • CI and DB config tweaks for compatibility and test bootstrap.

@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@arthurpar06 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 46 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 081ca5ac-42fc-4941-afff-9eca3eded832

📥 Commits

Reviewing files that changed from the base of the PR and between 0982df2 and 1535edd.

📒 Files selected for processing (5)
  • .github/scripts/phpunit.xml
  • .github/workflows/build.yml
  • app/Services/GeoService.php
  • app/Support/GeoJson.php
  • tests/Feature/PIREPTest.php

Walkthrough

Replaces many PHPUnit tests with Pest-style tests and helpers, adds factories and HasFactory traits to models, hardens randomness/ID generation using cryptographic functions, tweaks a few services/logging/importer behaviors, and updates CI/test configuration and composer dev deps.

Changes

Cohort / File(s) Summary
Test infra & suites
tests/Pest.php, phpunit.xml, tests/TestCase.php, tests/... (many removed), tests/Feature/..., tests/Arch/..., tests/Unit/...
Introduce Pest bootstrap, reorganize PHPUnit suites, drastically change TestCase (strip helpers), add many Pest-style feature/arch/unit tests, and remove numerous legacy PHPUnit test files and helper traits. Review CI/test runner and references to removed helpers.
New test helpers & fixtures
tests/Helpers/DatabaseHelpers.php, tests/Helpers/HttpHelpers.php, tests/data/base.yml
Add test helper functions for YAML seeding, HTTP mocking, data transforms, and add pilot_id to base fixture. Verify helper interfaces and fixture expectations.
Model factories & HasFactory
app/Models/...
database/factories/...
Add HasFactory trait to several models and introduce multiple new model factories (Bid, Event, File, FlightField, FlightFieldValue, Airport updates). Check factory wiring and model relations.
Randomness / ID / key hardening
app/Http/Controllers/Frontend/SimBriefController.php, app/Services/Installer/ConfigService.php, app/Services/ModuleService.php, app/Support/Utils.php
Replace non-crypto RNGs/uniqid/mt_rand with random_int() / random_bytes() / bin2hex() for load sampling, cache-prefix, directory names, ID/hash seeding, and API key generation. Validate any tests or code depending on deterministic values.
Service & minor logic tweaks
app/Console/Commands/DevCommands.php, app/Services/CronService.php, app/Services/ImportExport/ExpenseImporter.php, app/Services/GeoService.php
Remove debug dump in DevCommands, change CronService logging to structured context, refine ExpenseImporter ref_model_type namespace handling, and add GeoJson import. Confirm importer type resolution and logging consumers.
Composer / CI adjustments
composer.json, .github/workflows/build.yml
Removed pestphp/pest-plugin-drift dev dependency and altered CI steps (optimized composer autoload, removed some DB setup steps). Ensure CI reflects plugin removal and updated steps.
Database factory change
database/factories/UserFactory.php
UserFactory now creates a Rank via Rank::factory()->create()->id instead of hardcoded rank_id. Confirm seed/test expectations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐇 I hopped through test files, nibbling old wheat,

Planted small factories, made randomness neat.
Pest hops along as the night sky grows bright,
Logs tidy and keys sparkle in moonlight.
A rabbit’s soft cheer for the code taking flight.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[8.x] feat: improve tests suite' accurately reflects the primary change—a comprehensive overhaul of the test suite from unit tests to feature tests (Pest-style), addition of multiple new test files, test helpers, and architectural tests.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
app/Services/ModuleService.php (1)

169-174: ⚠️ Potential issue | 🟡 Minor

Consider using only positive random values for directory names.

Using random_int(PHP_INT_MIN, PHP_INT_MAX) can produce negative integers, creating directory names like -1234567890. While this works on most filesystems, it's unconventional and could cause parsing issues with certain tools.

Suggested fix to ensure positive values
-        $new_dir = random_int(PHP_INT_MIN, PHP_INT_MAX);
+        $new_dir = random_int(0, PHP_INT_MAX);

Alternatively, consider using bin2hex(random_bytes(8)) for consistency with other changes in this PR (e.g., ConfigService.php).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/Services/ModuleService.php` around lines 169 - 174, The directory name
generator uses random_int(PHP_INT_MIN, PHP_INT_MAX) which can produce negative
names; update the code that sets $new_dir (and the subsequent
File::makeDirectory call) to use only positive/filesystem-friendly values —
e.g., replace random_int(PHP_INT_MIN, PHP_INT_MAX) with random_int(0,
PHP_INT_MAX) or, for consistency with ConfigService.php, use a hex token
generated from random_bytes like bin2hex(random_bytes(8)) so the created storage
path contains a non-negative alphanumeric directory name.
app/Support/Utils.php (1)

31-36: ⚠️ Potential issue | 🟡 Minor

PHPDoc comment is incorrect: function returns 20 characters, not 40.

The comment states "Returns a 40 character API key" but the code returns substr(..., 0, 20), producing a 20-character key. The security improvement using random_int() is good, but the documentation should be corrected.

Suggested fix
     /**
-     * Returns a 40 character API key that a user can use
+     * Returns a 20 character API key that a user can use
      */
     public static function generateApiKey(): string
     {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/Support/Utils.php` around lines 31 - 36, The PHPDoc for generateApiKey()
is wrong: the function currently returns 20 characters (substr(..., 0, 20)).
Update the doc comment to state "Returns a 20 character API key" to match the
implementation, or if you intended a 40-character key, change the substr call to
use 40 (or return the full sha1() result) — adjust either the PHPDoc or the
substr length in generateApiKey() so the comment and the implementation match.
app/Http/Controllers/Frontend/SimBriefController.php (1)

231-237: ⚠️ Potential issue | 🟠 Major

Clamp remaining cargo capacity before applying the load factor.

Line 236 can produce a negative cargo count when baggage already exceeds a fare's capacity. That reduces $tcargoload and understates the final payload instead of bottoming out at zero.

🐛 Proposed fix
-            $count = ceil((($fare->capacity - $tbagload) * random_int($cgoloadmin, $cgoloadmax)) / 100);
+            $availableCargoCapacity = max(0, $fare->capacity - $tbagload);
+            $count = (int) ceil(($availableCargoCapacity * random_int($cgoloadmin, $cgoloadmax)) / 100);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/Http/Controllers/Frontend/SimBriefController.php` around lines 231 - 237,
In the foreach over $all_fares in SimBriefController (the cargo-processing loop
checking FareType::CARGO) clamp the remaining capacity before applying the
random load factor: compute a $remainingCapacity = max(0, $fare->capacity -
$tbagload) and use that value in the subsequent calculation instead of
($fare->capacity - $tbagload) so the computed $count (which is added to
$tcargoload) never becomes negative; if $remainingCapacity is zero you can skip
the random/ceil step or let it produce zero.
🧹 Nitpick comments (20)
tests/Unit/AirlineTest.php (1)

9-31: Consider splitting this test or completing the second scenario verification.

This test combines two scenarios: (1) creating an airline and verifying its journal, and (2) creating a second airline with an empty IATA. However, the journal verification is only performed for the first airline. Either:

  • Split into two separate tests (it('can add an airline') and it('can add multiple airlines with empty IATA')) for better isolation.
  • Or complete the second scenario by also verifying the journal for the second airline.
♻️ Proposed refactor: split into focused tests
 it('can add an airline', function () {
     $attrs = Airline::factory()->make([
         'iata' => '',
     ])->toArray();

     $airline = app(AirlineService::class)->createAirline($attrs);
     expect($airline)->not->toBeNull();

     // Ensure only a single journal is created
     $journals = Journal::where([
         'morphed_type' => Airline::class,
         'morphed_id'   => $airline->id,
     ])->get();

     expect($journals)->toHaveCount(1);
+});

-    // Add another airline, also blank IATA
-    $attrs = Airline::factory()->make([
+it('can add multiple airlines with empty IATA', function () {
+    $attrs = Airline::factory()->make([
+        'iata' => '',
+    ])->toArray();
+    $firstAirline = app(AirlineService::class)->createAirline($attrs);
+    expect($firstAirline)->not->toBeNull();
+
+    $attrs = Airline::factory()->make([
         'iata' => '',
     ])->toArray();
-    $airline = app(AirlineService::class)->createAirline($attrs);
-    expect($airline)->not->toBeNull();
+    $secondAirline = app(AirlineService::class)->createAirline($attrs);
+    expect($secondAirline)->not->toBeNull();
+    expect($secondAirline->id)->not->toBe($firstAirline->id);
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Unit/AirlineTest.php` around lines 9 - 31, The test mixes two
scenarios; split them or add assertions for the second airline: create a new
separate test (e.g., it('can add multiple airlines with empty IATA')) or keep
the current test but after creating the second airline call
Journal::where(['morphed_type' => Airline::class, 'morphed_id' =>
$airline->id])->get() and assert expect($journals)->toHaveCount(1); reference
the Airline::factory()->make([...]), AirlineService::createAirline, and Journal
to locate the code to change and ensure each test only verifies the journals for
the airline instance it just created.
tests/Feature/OAuthTest.php (1)

53-56: Prefer factories/custom states + Faker over repeated hard-coded fixtures.

There’s repeated manual setup for users/tokens and hard-coded identity strings. Consolidate with factories/states and Faker to reduce duplication and align test conventions.

Refactor direction
-    $user = User::factory()->create([
-        'name'  => 'OAuth user',
-        'email' => '[email protected]',
-    ]);
+    $user = User::factory()->create([
+        'name'  => fake()->name(),
+        'email' => fake()->safeEmail(),
+    ]);
...
-        UserOAuthToken::create([
-            'user_id'       => $user->id,
-            'provider'      => $driver,
-            'token'         => 'token',
-            'refresh_token' => 'refresh_token',
-        ]);
+        UserOAuthToken::factory()->for($user)->create([
+            'provider'      => $driver,
+            'token'         => 'token',
+            'refresh_token' => 'refresh_token',
+        ]);

Based on learnings: "When creating models for tests, use factories for the models and check for custom states before manually setting up the model" and "Use Faker methods such as $this->faker->word() or fake()->randomDigit(), following existing conventions."

Also applies to: 78-81, 105-108, 115-120, 142-146, 166-169, 207-210, 217-226

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/OAuthTest.php` around lines 53 - 56, Replace the repeated
hard-coded user/token fixtures and identity strings in OAuthTest with factory
states and Faker: create/extend UserFactory and any Token/Identity factories
with custom states (e.g., ->state(['name' => fn() => $this->faker->name(),
'email' => fn() => $this->faker->unique()->safeEmail()])) and then use those in
the test instead of literal values (replace direct
User::factory()->create([...]) and manual token setup with
User::factory()->verified()->create() or
Token::factory()->for($user)->createOne(), and use $this->faker or fake()->...
for random identity strings), ensuring tests reference the factory state names
(e.g., verified) and generated faker values rather than hard-coded strings.
tests/Feature/CronTest.php (1)

67-67: Remove or rewrite the inline comments; two are also inaccurate.

The repeated “Make sure the state is accepted” comment is incorrect in rejected/cancelled tests, and these comments are unnecessary noise here.

As per coding guidelines "**/*.php: Prefer PHPDoc blocks over inline comments; never use comments within the code itself unless the logic is exceptionally complex".

Also applies to: 83-83, 99-99

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/CronTest.php` at line 67, In CronTest.php remove the inline
comment string "Make sure the state is accepted" (and its duplicates in the
other tests) from the test methods that assert rejected/cancelled states and
either delete the comment entirely or replace it with a short PHPDoc above the
test method (e.g., /** Asserts job transitions to rejected/cancelled/accepted
*/) so the inaccurate inline comments are not left in the body; locate
occurrences by searching for that exact comment text inside the test methods and
update the tests accordingly (preserve assertions and test logic in methods like
the cron-related test functions).
tests/Feature/GeoTest.php (2)

4-6: WithoutMiddleware appears unnecessary for service-level tests.

These tests resolve GeoService from the container and call methods directly without making HTTP requests. The WithoutMiddleware trait only affects HTTP test requests, so it has no effect here.

♻️ Suggested cleanup
 <?php

 use App\Models\Navdata;
-use Illuminate\Foundation\Testing\WithoutMiddleware;
-
-uses(WithoutMiddleware::class);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/GeoTest.php` around lines 4 - 6, Remove the unnecessary
WithoutMiddleware import and the uses(WithoutMiddleware::class) call from
GeoTest; since the tests resolve GeoService from the container and call its
methods directly (no HTTP requests), delete the line importing
Illuminate\Foundation\Testing\WithoutMiddleware and the uses(...) invocation so
the test class no longer references the trait (verify no other tests in this
file rely on middleware disabling before pushing).

8-32: LGTM! Minor style suggestion.

The test correctly validates the getClosestCoords method with well-documented test coordinates. Consider using ::class syntax for better IDE support and refactoring safety:

-    $geoSvc = app('\App\Services\GeoService');
+    $geoSvc = app(\App\Services\GeoService::class);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/GeoTest.php` around lines 8 - 32, Replace the hard-coded
service string in the test with class-constant syntax to improve
IDE/refactorability: change the app('\App\Services\GeoService') call used to get
$geoSvc in the test to use \App\Services\GeoService::class (or import the class
and call app(GeoService::class)); keep the rest of the test and the
getClosestCoords assertions unchanged.
tests/Feature/SubfleetTest.php (1)

7-37: Split this lifecycle check into focused tests.

This single example covers attach, override, and delete behavior, so the current name is misleading and failures are harder to localize. Separate these into dedicated Pest tests and drop the inline // narration.

As per coding guidelines, "Prefer PHPDoc blocks over inline comments; never use comments within the code itself unless the logic is exceptionally complex."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/SubfleetTest.php` around lines 7 - 37, Split the single Pest
test named test('subfleet fares no override', ...) into three focused tests in
SubfleetTest.php: one that verifies attaching a fare using
FareService::setForSubfleet and reading it with FareService::getForSubfleet
(assert count and original price/capacity), one that verifies overriding a fare
by calling FareService::setForSubfleet with override attributes and asserting
the updated price/capacity via getForSubfleet, and one that verifies deletion
using FareService::delFareFromSubfleet and asserting getForSubfleet returns an
empty collection; remove the inline // comments and narration and give each new
test a descriptive name reflecting the single behavior it verifies.
tests/Feature/AwardsTest.php (1)

16-19: Assertion expects count but compares collection directly.

$classes is likely an array or collection returned by findAllAwardClasses(), but toBeGreaterThanOrEqual(2) performs a numeric comparison. This may work if the collection implements Countable and Pest handles it, but the intent is clearer with an explicit count assertion.

♻️ Clearer assertion
 test('get awards classes', function () {
     $classes = app(AwardService::class)->findAllAwardClasses();
-    expect($classes)->toBeGreaterThanOrEqual(2);
+    expect($classes)->toHaveCountGreaterThanOrEqual(2);
 });

Or if that method isn't available:

-    expect($classes)->toBeGreaterThanOrEqual(2);
+    expect(count($classes))->toBeGreaterThanOrEqual(2);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/AwardsTest.php` around lines 16 - 19, The test "get awards
classes" is comparing the collection directly with toBeGreaterThanOrEqual;
change the assertion to check the actual count of the result from
AwardService::findAllAwardClasses() (use count($classes) or $classes->count()
depending on the return type) and assert that the count is >= 2 so the intent is
explicit and correct.
tests/Pest.php (1)

39-40: Remove commented-out dead code.

Line 40 is a duplicate of the RefreshDatabase usage on line 25. Remove to avoid confusion.

🧹 Remove dead code
     ->in('Unit', 'Feature', 'Arch', '../resources/views');
-// ->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Pest.php` around lines 39 - 40, Remove the commented-out duplicate of
the RefreshDatabase usage (the line starting with "//
->use(Illuminate\Foundation\Testing\RefreshDatabase::class)") from tests' Pest
bootstrap so only the intended single use(...) call remains; locate the
commented line near the existing ->use(RefreshDatabase::class) invocation and
delete that dead/commented code to avoid confusion.
tests/Helpers/DatabaseHelpers.php (1)

27-30: Add type hint for $value parameter.

Per coding guidelines, use appropriate PHP type hints for method parameters. The $value parameter lacks a type hint.

♻️ Add type hint
-function updateSetting(string $key, $value): void
+function updateSetting(string $key, mixed $value): void
 {
     app(SettingRepository::class)->store($key, $value);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Helpers/DatabaseHelpers.php` around lines 27 - 30, The updateSetting
function lacks a type hint for its $value parameter; update the signature of
updateSetting to include an appropriate PHP type (e.g., mixed if settings can be
different types or string/int/float/bool if known) and ensure the call to
SettingRepository::store($key, $value) remains compatible; update any related
usages/tests if necessary to satisfy the new type hint and keep the function
signature consistent with SettingRepository::store's parameter type.
tests/Feature/DatabaseTest.php (1)

7-10: Remove unused $dbSvc variable declaration.

The PHPDoc @var DatabaseService $dbSvc appears in all three tests but the variable is never used. This appears to be a copy-paste artifact.

🧹 Remove unused declarations
 test('seeder', function () {
-    /** `@var` DatabaseService $dbSvc */
     $file = file_get_contents(base_path('tests/data/seed.yml'));

Apply similar changes to tests at lines 31-34 and 49-52.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/DatabaseTest.php` around lines 7 - 10, Remove the unused
PHPDoc/variable declaration "@var DatabaseService $dbSvc" from the tests (it’s a
copy‑paste artifact) — delete the line that declares $dbSvc in the 'seeder' test
and the same declaration in the two other tests so no unused $dbSvc remains;
ensure no remaining references to DatabaseService $dbSvc are left in those test
functions.
tests/Feature/AcarsTest.php (2)

593-593: Fix typo in test name.

"instantitaion" should be "instantiation".

✏️ Proposed fix
-test('acars data instantitaion', function () {
+test('acars data instantiation', function () {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/AcarsTest.php` at line 593, Rename the test description string
in the test declaration that currently reads "acars data instantitaion" to the
correct spelling "acars data instantiation" (the test call starting with
test('acars data instantitaion', function () { in AcarsTest.php); update only
the human-readable test name—leave the test body and function unchanged.

21-26: Remove redundant conditional assignment.

Lines 23-25 are redundant: if $addtl_fields === [] is true, assigning $addtl_fields = [] does nothing.

🔧 Proposed fix
 function allPointsInRoute(array $route, array $points, array $addtl_fields = []): void
 {
-    if ($addtl_fields === []) {
-        $addtl_fields = [];
-    }
-
     $fields = array_merge(
         [
             'name',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/AcarsTest.php` around lines 21 - 26, The conditional inside the
allPointsInRoute function that checks if $addtl_fields === [] and then assigns
$addtl_fields = [] is redundant; remove that if-block entirely and rely on the
default parameter declaration (array $addtl_fields = []) so the parameter is
already an empty array when not provided, leaving the rest of allPointsInRoute
unchanged.
tests/Arch/ProvidersTest.php (1)

3-4: Minor: Add blank line after declare statement.

PSR-12 recommends a blank line after declare(strict_types=1) before the use statements.

✏️ Proposed fix
 declare(strict_types=1);
+
 use Illuminate\Support\ServiceProvider;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Arch/ProvidersTest.php` around lines 3 - 4, Add a blank line after the
file-level declare statement so PSR-12 spacing is respected: insert an empty
line between the existing declare(strict_types=1); statement and the following
use Illuminate\Support\ServiceProvider; line in Tests/Arch/ProvidersTest.php
(i.e., separate the declare(...) from the use statements).
tests/Feature/VersionTest.php (1)

26-36: Inconsistent setting helper usage.

Line 27 uses setting() while lines 39, 51, and 69 use updateSetting(). Consider using a consistent helper for test clarity.

✏️ Proposed fix
 test('get latest version', function () {
-    setting('general.check_prerelease_version', false);
+    updateSetting('general.check_prerelease_version', false);

     mockGuzzleResponse('releases.json', 'application/json; charset=utf-8');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/VersionTest.php` around lines 26 - 36, In the "get latest
version" test, replace the inconsistent helper call
setting('general.check_prerelease_version', false) with the same helper used
elsewhere (updateSetting) so the test consistently uses
updateSetting('general.check_prerelease_version', false); locate the call in the
test function (test('get latest version', ...)) and update it accordingly so
VersionService::getLatestVersion() and the subsequent assertion against
KvpRepository::get('latest_version_tag') run under the same setting helper
convention.
tests/Arch/ModelsTest.php (1)

44-68: Malformed PHPDoc annotations in commented code.

Lines 48 and 58 have malformed PHPDoc comments (missing * before @var). If you plan to re-enable these tests in the future, fix the annotations.

✏️ Proposed fix (for when uncommenting)
-         `@var` \Illuminate\Database\Eloquent\Factories\HasFactory $model
+        /** `@var` \Illuminate\Database\Eloquent\Factories\HasFactory $model */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Arch/ModelsTest.php` around lines 44 - 68, Fix the malformed PHPDoc
annotations inside the commented tests for arch('ensure factories') and
arch('ensure datetime casts') by replacing the lines that read " `@var`
\Illuminate\Database\Eloquent\Factories\HasFactory $model" with a valid inline
PHPDoc such as "/** `@var` \\Illuminate\\Database\\Eloquent\\Factories\\HasFactory
$model */" (or a single-line comment "/* `@var`
\\Illuminate\\Database\\Eloquent\\Factories\\HasFactory $model */") so the
annotation is syntactically correct and will parse if these tests are
uncommented; update the annotation occurrences adjacent to getModels(), $model
and $instance usages accordingly.
tests/Feature/ApiTest.php (3)

319-320: Clarify or remove commented-out assertions.

Multiple commented-out assertions exist throughout this test (lines 319-320, 327-328, 338-339). If these are temporarily disabled due to a known issue, add a TODO comment explaining why. Otherwise, remove them to keep the test clean.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/ApiTest.php` around lines 319 - 320, The commented-out
assertions ($this->assertEquals calls comparing $body['mtow'] to
$aircraft->mtow->local(0) and $body['zfw'] to $aircraft->zfw->local(0), and the
similar pairs elsewhere) should either be removed or annotated with a TODO
explaining why they're disabled; update tests/Feature/ApiTest.php by either
deleting those commented assertions or replacing each comment with a one-line
TODO that states the known issue or ticket (e.g., "TODO: disabled due to
<issue-id> - re-enable when <condition>") so future readers know whether they
are intentionally skipped or can be safely removed.

352-360: Consider using assertStringContainsString for clarity.

Using strpos() !== -1 is less readable than Laravel's built-in assertion methods.

Proposed fix
-    $this->assertNotSame(-1, strpos($user['avatar'], 'http'));
+    $this->assertStringContainsString('http', $user['avatar']);

     // Should go to gravatar
     $user = User::factory()->create();

     $res = $this->get('/api/user')->assertStatus(200);
     $user = $res->json('data');
     expect($user)->not->toBeNull();
-    $this->assertNotSame(-1, strpos($user['avatar'], 'gravatar'));
+    $this->assertStringContainsString('gravatar', $user['avatar']);

Or using Pest's expect() style for consistency with the rest of the file:

expect($user['avatar'])->toContain('http');
// ...
expect($user['avatar'])->toContain('gravatar');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/ApiTest.php` around lines 352 - 360, Replace the manual strpos
comparisons used in the assertions with clearer, built-in string assertions:
change calls like $this->assertNotSame(-1, strpos($user['avatar'], 'http')) and
$this->assertNotSame(-1, strpos($user['avatar'], 'gravatar')) to use PHPUnit's
assertStringContainsString('http', $user['avatar']) /
assertStringContainsString('gravatar', $user['avatar']) or, to match the file's
Pest style, use expect($user['avatar'])->toContain('http') and
expect($user['avatar'])->toContain('gravatar'); update the assertions around the
get('/api/user')->assertStatus(200) block and the User::factory()->create()
section accordingly so the tests remain equivalent but more readable.

3-3: Remove commented-out import.

Dead code should be cleaned up. This commented import is unused.

Proposed fix
 <?php
 
-// use Swagger\Serializer;
 use App\Models\Aircraft;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/ApiTest.php` at line 3, Remove the dead commented import in
tests/Feature/ApiTest.php by deleting the commented line "// use
Swagger\Serializer;"; ensure no other commented-out unused imports remain in the
ApiTest class or file so the file only contains active, necessary use
statements.
tests/Feature/MetarTest.php (1)

121-127: Variable shadowing reduces readability.

The variable $metar is used for both the input string and the parsed result in multiple tests (lines 123, 130, 139, 148, 156, 164). While not incorrect, this shadowing can be confusing during debugging.

Consider using distinct variable names like $metarString and $parsed for clarity.

Example fix for one occurrence
 test('metar trends3', function () {
-    $metar = 'EHAM 041455Z 13012KT 9999 FEW034CB BKN040 05/01 Q1007 TEMPO 14017G28K 4000 SHRA =';
-    $metar = Metar::parse($metar);
+    $metarString = 'EHAM 041455Z 13012KT 9999 FEW034CB BKN040 05/01 Q1007 TEMPO 14017G28K 4000 SHRA =';
+    $parsed = Metar::parse($metarString);
 
-    expect($metar['category'])->toEqual('VFR');
+    expect($parsed['category'])->toEqual('VFR');
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/MetarTest.php` around lines 121 - 127, Replace the shadowed
$metar variable in the test blocks by giving the raw METAR string and the parsed
result distinct names (e.g., rename the input $metar string to $metarString and
the parsed output from Metar::parse(...) to $parsed or $metarParsed) in the
test('metar trends3', function () { ... }) and the other affected tests (the
functions that call Metar::parse); update all subsequent assertions and
references to use the new parsed variable name (e.g.,
expect($metarParsed['category'])->toEqual('VFR')) so the input and parsed values
are not shadowing each other.
tests/Feature/RegistrationTest.php (1)

87-105: Consider faking notifications for invite registration test.

This test also POSTs to /register, which may trigger notification/email sending. For consistency and to prevent potential pipeline failures, consider adding Notification::fake() here as well.

Proposed fix
 test('access with valid invite', function () {
+    Notification::fake();
+
     updateSetting('general.disable_registrations', false);
     updateSetting('general.invite_only_registrations', true);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/RegistrationTest.php` around lines 87 - 105, Add a
Notification::fake() call in the "access with valid invite" test before the POST
to /register to prevent real emails/notifications from being sent; update the
test closure that creates the Invite (the test named "access with valid invite")
to call Notification::fake() (or
\Illuminate\Support\Facades\Notification::fake() if not imported) just before
$this->post('/register', $userData) so the Invite::create and
$this->post('/register', $userData) flow uses the fake notifications.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@database/factories/EventFactory.php`:
- Around line 18-25: The EventFactory's definition() currently generates
'start_date' and 'end_date' independently which can produce end_date <=
start_date; to fix it, generate a start date first (in definition()) and then
derive end_date from it using faker's between/after helpers so end_date is
always after start_date (e.g. use fake()->dateTimeBetween/start and then
fake()->dateTimeBetween(start, '+N days') or equivalent), updating the
'start_date' and 'end_date' entries in EventFactory::definition() accordingly.

In `@database/factories/FlightFieldFactory.php`:
- Around line 18-22: The FlightFieldFactory definition() currently returns an
empty array causing required fields (like name) to be missing; update the
FlightFieldFactory::definition() to return a minimal valid attribute set (at
least provide 'name' with a faker or unique string and other required attributes
such as 'type' and any non-nullable columns like 'label' or 'required') so
FlightField::factory()->create() produces a valid model; locate the definition()
method in FlightFieldFactory and add those default keys using faker helpers
consistent with other factories.

In `@tests/Arch/ModelsTest.php`:
- Around line 75-81: The getModels() function assumes glob() returns an array
but glob() can return false; update getModels to handle that by checking if
$models === false and assigning an empty array (or casting (array)$models)
before passing to collect(), so the subsequent map using
'App\Models\\'.basename(... ) won't receive a boolean; reference getModels(),
the $models variable and the glob(...) call when making the fix.

In `@tests/Feature/CronTest.php`:
- Around line 79-93: The assertions in the "delete rejected pireps" (and the
corresponding accepted deletion test) are inverted: after running
DeletePireps->handle(new CronHourly()) the created PireP record should be
deleted, so replace the expect($found_pirep)->not->toBeNull() with
expect($found_pirep)->toBeNull() in both tests; locate the tests by the test
names and references to Pirep, PirepState::REJECTED/ACCEPTED, DeletePireps, and
CronHourly and update the final expectation to assert null.

In `@tests/Feature/ImporterTest.php`:
- Line 61: The test name string in the call test('convert stringto objects',
function () { contains a typo; update that literal to include a space (e.g.,
change 'convert stringto objects' to 'convert string to objects') so the test
description reads correctly and matches expected naming; locate the test call
with the exact string 'convert stringto objects' and edit the first argument
accordingly.

In `@tests/Feature/MoneyTest.php`:
- Line 5: The Pest test closure in the call to test in MoneyTest (the anonymous
function starting with function ()) lacks an explicit return type; update the
closure signature to declare a return type of void (i.e., change the anonymous
function to function(): void) so the test complies with the repository PHP
typing rules and the /**/*.php guideline requiring explicit return type
declarations.

In `@tests/Feature/NewsTest.php`:
- Line 21: Add a negative assertion to ensure opt-out users are not notified:
after the existing Notification::assertSentTo($users_opt_in, NewsAdded::class)
call, add Notification::assertNotSentTo($users_opt_out, NewsAdded::class) (or
the test framework's equivalent) so the test verifies both the opt-in and
opt-out branches using the $users_opt_out variable and the NewsAdded
notification class.

In `@tests/Feature/OAuthTest.php`:
- Line 91: The time-window assertions using
$user->lastlogin_at->diffInSeconds(now()) <= 2 are CI-flaky; update the
OAuthTest to freeze time before the action (use Carbon::setTestNow() or
travelTo()) so now() is deterministic, then assert an exact expected difference
(or compare against the frozen timestamp) instead of a <= 2 tolerance; locate
and change the assertions around the $user->lastlogin_at usage in the OAuthTest
test method(s) to use the frozen time helpers and exact expectation.
- Line 14: Remove the inline comment "Create a default user to prevent
redirection to the installer" from the OAuthTest class (tests/Feature OAuthTest)
— locate the comment within the test setup or method and delete it; if the
rationale must be preserved, convert it into a PHPDoc block placed above the
setup/test method (e.g., above setUp() or the specific test method) rather than
leaving an inline comment in the code.

In `@tests/Feature/RegistrationTest.php`:
- Around line 55-64: The test "access to registration when registration enabled"
is failing because it sends real emails during the POST /register; add
Notification::fake() (or Mail::fake()) at the start of that test to prevent
actual mail delivery, e.g., call Notification::fake() before updateSetting(...)
inside the test that calls $this->post('/register', getUserData()) so the
registration email is mocked and assertions can run without relay errors.

In `@tests/Feature/SimBriefTest.php`:
- Line 138: The test uses $this->get('/api/flights/'.$briefing->id.'/briefing',
[], $user) which passes an invalid third argument and does not authenticate;
replace this call by authenticating the user first with $this->actingAs($user)
and then calling ->get('/api/flights/'.$briefing->id.'/briefing') so the request
is made as the specified user (update the call in SimBriefTest where the get
request is made).
- Around line 219-225: Replace the incorrect use of $this->put(..., $user) and
$this->get(..., $user) by authenticating the request with actingAs before
calling the HTTP method: call $this->actingAs($user2)->put($uri, $data) and
$this->actingAs($user)->put($uri, $data) for the two put assertions, and
$this->actingAs($user)->get('/api/user/bids') for the final get; ensure you keep
the same variables ($user, $user2, $uri, $data) and assertions
(expect(...)->not->toBeEmpty()) but remove the extra user argument passed to
put/get.

In `@tests/Feature/UserTest.php`:
- Around line 395-408: The test "event called when profile updated" uses a
hardcoded airline_id (1) which can break in isolation; replace the literal with
a created or associated airline id by creating an Airline via its factory (e.g.,
$airline = Airline::factory()->create()) or using the user's existing relation
and set 'airline_id' => $airline->id (or $user->airline_id) in the $body array,
so update the $body construction in the test to use the dynamic id and then run
the same actingAs/put and Event::assertDispatched(ProfileUpdated::class).

In `@tests/Helpers/DatabaseHelpers.php`:
- Around line 18-22: The catch block in DatabaseHelpers:: (around the call to
app(DatabaseService::class)->seed_from_yaml_file($file_path)) silently swallows
exceptions; change it to either re-throw with context or log the exception
before swallowing: capture the Exception $e in the catch, then call a logger (or
process/test framework logger) with a descriptive message including $file_path
and $e->getMessage()/stack, or re-throw a new RuntimeException that includes
$file_path and the original exception as previous so test setup failures surface
clearly.

In `@tests/Helpers/HttpHelpers.php`:
- Around line 1-9: The transformData function in tests/Helpers/HttpHelpers.php
uses Carbon but there's no import; add the Carbon import (use Carbon\Carbon;) at
the top of the file with the other use statements so transformData can correctly
detect/handle Carbon instances and avoid the runtime error.
- Around line 56-77: In transformData, remove the redundant
is_subclass_of($value, Unit::class) branch and rely on the instanceof Unit
branch to handle Unit objects consistently; locate the is_subclass_of check and
delete those lines so Unit instances are processed only by the instanceof Unit
case (adjust behavior there if you prefer string output via __toString() instead
of the current (float) $value->internal(2)).

In `@tests/Pest.php`:
- Around line 24-38: The static $initialized guard prevents reseeding after
RefreshDatabase resets the DB; either remove the guard so the beforeEach
callback always runs the seeds, or enable automatic seeding via RefreshDatabase
by setting RefreshDatabase::$seed = true and implementing a seeder that runs
app(SeederService::class)->syncAllSeeds(),
app(DatabaseService::class)->seed_from_yaml_file(...), and
seed(ShieldSeeder::class). Update the beforeEach closure (the one passed to
pest()->extend(...)->beforeEach(...)) to either drop the static $initialized
check so seeding runs every test, or instead configure RefreshDatabase to use
your central seeder that runs those same calls.

In `@tests/TestCase.php`:
- Around line 19-33: Remove the debug dump and restore or gate the commented
setup logic in setUp(): delete the dump('Boot: ...') call and either uncomment
and re-enable the critical initialization calls
(Filament::setCurrentPanel('admin'), $this->seed(ShieldSeeder::class),
app(SeederService)->syncAllSeeds(),
app(DatabaseService)->seed_from_yaml_file(...)) or wrap them behind a clear
configuration check (e.g., an env flag or a TestCase property like
$runFullSetup) so tests can opt into the full seed/panel setup instead of
leaving logic commented out.

---

Outside diff comments:
In `@app/Http/Controllers/Frontend/SimBriefController.php`:
- Around line 231-237: In the foreach over $all_fares in SimBriefController (the
cargo-processing loop checking FareType::CARGO) clamp the remaining capacity
before applying the random load factor: compute a $remainingCapacity = max(0,
$fare->capacity - $tbagload) and use that value in the subsequent calculation
instead of ($fare->capacity - $tbagload) so the computed $count (which is added
to $tcargoload) never becomes negative; if $remainingCapacity is zero you can
skip the random/ceil step or let it produce zero.

In `@app/Services/ModuleService.php`:
- Around line 169-174: The directory name generator uses random_int(PHP_INT_MIN,
PHP_INT_MAX) which can produce negative names; update the code that sets
$new_dir (and the subsequent File::makeDirectory call) to use only
positive/filesystem-friendly values — e.g., replace random_int(PHP_INT_MIN,
PHP_INT_MAX) with random_int(0, PHP_INT_MAX) or, for consistency with
ConfigService.php, use a hex token generated from random_bytes like
bin2hex(random_bytes(8)) so the created storage path contains a non-negative
alphanumeric directory name.

In `@app/Support/Utils.php`:
- Around line 31-36: The PHPDoc for generateApiKey() is wrong: the function
currently returns 20 characters (substr(..., 0, 20)). Update the doc comment to
state "Returns a 20 character API key" to match the implementation, or if you
intended a 40-character key, change the substr call to use 40 (or return the
full sha1() result) — adjust either the PHPDoc or the substr length in
generateApiKey() so the comment and the implementation match.

---

Nitpick comments:
In `@tests/Arch/ModelsTest.php`:
- Around line 44-68: Fix the malformed PHPDoc annotations inside the commented
tests for arch('ensure factories') and arch('ensure datetime casts') by
replacing the lines that read " `@var`
\Illuminate\Database\Eloquent\Factories\HasFactory $model" with a valid inline
PHPDoc such as "/** `@var` \\Illuminate\\Database\\Eloquent\\Factories\\HasFactory
$model */" (or a single-line comment "/* `@var`
\\Illuminate\\Database\\Eloquent\\Factories\\HasFactory $model */") so the
annotation is syntactically correct and will parse if these tests are
uncommented; update the annotation occurrences adjacent to getModels(), $model
and $instance usages accordingly.

In `@tests/Arch/ProvidersTest.php`:
- Around line 3-4: Add a blank line after the file-level declare statement so
PSR-12 spacing is respected: insert an empty line between the existing
declare(strict_types=1); statement and the following use
Illuminate\Support\ServiceProvider; line in Tests/Arch/ProvidersTest.php (i.e.,
separate the declare(...) from the use statements).

In `@tests/Feature/AcarsTest.php`:
- Line 593: Rename the test description string in the test declaration that
currently reads "acars data instantitaion" to the correct spelling "acars data
instantiation" (the test call starting with test('acars data instantitaion',
function () { in AcarsTest.php); update only the human-readable test name—leave
the test body and function unchanged.
- Around line 21-26: The conditional inside the allPointsInRoute function that
checks if $addtl_fields === [] and then assigns $addtl_fields = [] is redundant;
remove that if-block entirely and rely on the default parameter declaration
(array $addtl_fields = []) so the parameter is already an empty array when not
provided, leaving the rest of allPointsInRoute unchanged.

In `@tests/Feature/ApiTest.php`:
- Around line 319-320: The commented-out assertions ($this->assertEquals calls
comparing $body['mtow'] to $aircraft->mtow->local(0) and $body['zfw'] to
$aircraft->zfw->local(0), and the similar pairs elsewhere) should either be
removed or annotated with a TODO explaining why they're disabled; update
tests/Feature/ApiTest.php by either deleting those commented assertions or
replacing each comment with a one-line TODO that states the known issue or
ticket (e.g., "TODO: disabled due to <issue-id> - re-enable when <condition>")
so future readers know whether they are intentionally skipped or can be safely
removed.
- Around line 352-360: Replace the manual strpos comparisons used in the
assertions with clearer, built-in string assertions: change calls like
$this->assertNotSame(-1, strpos($user['avatar'], 'http')) and
$this->assertNotSame(-1, strpos($user['avatar'], 'gravatar')) to use PHPUnit's
assertStringContainsString('http', $user['avatar']) /
assertStringContainsString('gravatar', $user['avatar']) or, to match the file's
Pest style, use expect($user['avatar'])->toContain('http') and
expect($user['avatar'])->toContain('gravatar'); update the assertions around the
get('/api/user')->assertStatus(200) block and the User::factory()->create()
section accordingly so the tests remain equivalent but more readable.
- Line 3: Remove the dead commented import in tests/Feature/ApiTest.php by
deleting the commented line "// use Swagger\Serializer;"; ensure no other
commented-out unused imports remain in the ApiTest class or file so the file
only contains active, necessary use statements.

In `@tests/Feature/AwardsTest.php`:
- Around line 16-19: The test "get awards classes" is comparing the collection
directly with toBeGreaterThanOrEqual; change the assertion to check the actual
count of the result from AwardService::findAllAwardClasses() (use
count($classes) or $classes->count() depending on the return type) and assert
that the count is >= 2 so the intent is explicit and correct.

In `@tests/Feature/CronTest.php`:
- Line 67: In CronTest.php remove the inline comment string "Make sure the state
is accepted" (and its duplicates in the other tests) from the test methods that
assert rejected/cancelled states and either delete the comment entirely or
replace it with a short PHPDoc above the test method (e.g., /** Asserts job
transitions to rejected/cancelled/accepted */) so the inaccurate inline comments
are not left in the body; locate occurrences by searching for that exact comment
text inside the test methods and update the tests accordingly (preserve
assertions and test logic in methods like the cron-related test functions).

In `@tests/Feature/DatabaseTest.php`:
- Around line 7-10: Remove the unused PHPDoc/variable declaration "@var
DatabaseService $dbSvc" from the tests (it’s a copy‑paste artifact) — delete the
line that declares $dbSvc in the 'seeder' test and the same declaration in the
two other tests so no unused $dbSvc remains; ensure no remaining references to
DatabaseService $dbSvc are left in those test functions.

In `@tests/Feature/GeoTest.php`:
- Around line 4-6: Remove the unnecessary WithoutMiddleware import and the
uses(WithoutMiddleware::class) call from GeoTest; since the tests resolve
GeoService from the container and call its methods directly (no HTTP requests),
delete the line importing Illuminate\Foundation\Testing\WithoutMiddleware and
the uses(...) invocation so the test class no longer references the trait
(verify no other tests in this file rely on middleware disabling before
pushing).
- Around line 8-32: Replace the hard-coded service string in the test with
class-constant syntax to improve IDE/refactorability: change the
app('\App\Services\GeoService') call used to get $geoSvc in the test to use
\App\Services\GeoService::class (or import the class and call
app(GeoService::class)); keep the rest of the test and the getClosestCoords
assertions unchanged.

In `@tests/Feature/MetarTest.php`:
- Around line 121-127: Replace the shadowed $metar variable in the test blocks
by giving the raw METAR string and the parsed result distinct names (e.g.,
rename the input $metar string to $metarString and the parsed output from
Metar::parse(...) to $parsed or $metarParsed) in the test('metar trends3',
function () { ... }) and the other affected tests (the functions that call
Metar::parse); update all subsequent assertions and references to use the new
parsed variable name (e.g., expect($metarParsed['category'])->toEqual('VFR')) so
the input and parsed values are not shadowing each other.

In `@tests/Feature/OAuthTest.php`:
- Around line 53-56: Replace the repeated hard-coded user/token fixtures and
identity strings in OAuthTest with factory states and Faker: create/extend
UserFactory and any Token/Identity factories with custom states (e.g.,
->state(['name' => fn() => $this->faker->name(), 'email' => fn() =>
$this->faker->unique()->safeEmail()])) and then use those in the test instead of
literal values (replace direct User::factory()->create([...]) and manual token
setup with User::factory()->verified()->create() or
Token::factory()->for($user)->createOne(), and use $this->faker or fake()->...
for random identity strings), ensuring tests reference the factory state names
(e.g., verified) and generated faker values rather than hard-coded strings.

In `@tests/Feature/RegistrationTest.php`:
- Around line 87-105: Add a Notification::fake() call in the "access with valid
invite" test before the POST to /register to prevent real emails/notifications
from being sent; update the test closure that creates the Invite (the test named
"access with valid invite") to call Notification::fake() (or
\Illuminate\Support\Facades\Notification::fake() if not imported) just before
$this->post('/register', $userData) so the Invite::create and
$this->post('/register', $userData) flow uses the fake notifications.

In `@tests/Feature/SubfleetTest.php`:
- Around line 7-37: Split the single Pest test named test('subfleet fares no
override', ...) into three focused tests in SubfleetTest.php: one that verifies
attaching a fare using FareService::setForSubfleet and reading it with
FareService::getForSubfleet (assert count and original price/capacity), one that
verifies overriding a fare by calling FareService::setForSubfleet with override
attributes and asserting the updated price/capacity via getForSubfleet, and one
that verifies deletion using FareService::delFareFromSubfleet and asserting
getForSubfleet returns an empty collection; remove the inline // comments and
narration and give each new test a descriptive name reflecting the single
behavior it verifies.

In `@tests/Feature/VersionTest.php`:
- Around line 26-36: In the "get latest version" test, replace the inconsistent
helper call setting('general.check_prerelease_version', false) with the same
helper used elsewhere (updateSetting) so the test consistently uses
updateSetting('general.check_prerelease_version', false); locate the call in the
test function (test('get latest version', ...)) and update it accordingly so
VersionService::getLatestVersion() and the subsequent assertion against
KvpRepository::get('latest_version_tag') run under the same setting helper
convention.

In `@tests/Helpers/DatabaseHelpers.php`:
- Around line 27-30: The updateSetting function lacks a type hint for its $value
parameter; update the signature of updateSetting to include an appropriate PHP
type (e.g., mixed if settings can be different types or string/int/float/bool if
known) and ensure the call to SettingRepository::store($key, $value) remains
compatible; update any related usages/tests if necessary to satisfy the new type
hint and keep the function signature consistent with SettingRepository::store's
parameter type.

In `@tests/Pest.php`:
- Around line 39-40: Remove the commented-out duplicate of the RefreshDatabase
usage (the line starting with "//
->use(Illuminate\Foundation\Testing\RefreshDatabase::class)") from tests' Pest
bootstrap so only the intended single use(...) call remains; locate the
commented line near the existing ->use(RefreshDatabase::class) invocation and
delete that dead/commented code to avoid confusion.

In `@tests/Unit/AirlineTest.php`:
- Around line 9-31: The test mixes two scenarios; split them or add assertions
for the second airline: create a new separate test (e.g., it('can add multiple
airlines with empty IATA')) or keep the current test but after creating the
second airline call Journal::where(['morphed_type' => Airline::class,
'morphed_id' => $airline->id])->get() and assert
expect($journals)->toHaveCount(1); reference the
Airline::factory()->make([...]), AirlineService::createAirline, and Journal to
locate the code to change and ensure each test only verifies the journals for
the airline instance it just created.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0ebe5e53-9159-4ac0-b9b4-1eec2b267b1c

📥 Commits

Reviewing files that changed from the base of the PR and between 5623f7e and ee8e816.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (82)
  • app/Console/Commands/DevCommands.php
  • app/Http/Controllers/Frontend/SimBriefController.php
  • app/Models/Bid.php
  • app/Models/Event.php
  • app/Models/File.php
  • app/Models/FlightField.php
  • app/Models/FlightFieldValue.php
  • app/Services/CronService.php
  • app/Services/GeoService.php
  • app/Services/ImportExport/ExpenseImporter.php
  • app/Services/Installer/ConfigService.php
  • app/Services/ModuleService.php
  • app/Support/Utils.php
  • composer.json
  • database/factories/AirportFactory.php
  • database/factories/BidFactory.php
  • database/factories/EventFactory.php
  • database/factories/FileFactory.php
  • database/factories/FlightFieldFactory.php
  • database/factories/FlightFieldValueFactory.php
  • phpunit.xml
  • tests/AcarsTest.php
  • tests/AdminControllerTests.php
  • tests/AirlineTest.php
  • tests/AirportTest.php
  • tests/ApiTest.php
  • tests/ApiTestTrait.php
  • tests/Arch/GlobalTest.php
  • tests/Arch/ModelsTest.php
  • tests/Arch/ProvidersTest.php
  • tests/ArchTest.php
  • tests/AwardsTest.php
  • tests/BidTest.php
  • tests/CreatesApplication.php
  • tests/CronTest.php
  • tests/DatabaseTest.php
  • tests/Feature/AcarsTest.php
  • tests/Feature/AirportTest.php
  • tests/Feature/ApiTest.php
  • tests/Feature/AwardsTest.php
  • tests/Feature/BidTest.php
  • tests/Feature/CronTest.php
  • tests/Feature/DatabaseTest.php
  • tests/Feature/FinanceTest.php
  • tests/Feature/FlightTest.php
  • tests/Feature/GeoTest.php
  • tests/Feature/ImporterTest.php
  • tests/Feature/MathTest.php
  • tests/Feature/MetarTest.php
  • tests/Feature/MoneyTest.php
  • tests/Feature/NewsTest.php
  • tests/Feature/OAuthTest.php
  • tests/Feature/PIREPTest.php
  • tests/Feature/RegistrationTest.php
  • tests/Feature/SimBriefTest.php
  • tests/Feature/SubfleetTest.php
  • tests/Feature/UserTest.php
  • tests/Feature/UtilsTest.php
  • tests/Feature/VersionTest.php
  • tests/FinanceTest.php
  • tests/FlightTest.php
  • tests/GeoTest.php
  • tests/Helpers/DatabaseHelpers.php
  • tests/Helpers/HttpHelpers.php
  • tests/ImporterTest.php
  • tests/MathTest.php
  • tests/MetarTest.php
  • tests/MoneyTest.php
  • tests/NewsTest.php
  • tests/OAuthTest.php
  • tests/PIREPTest.php
  • tests/Pest.php
  • tests/RegistrationTest.php
  • tests/SimBriefTest.php
  • tests/SubfleetTest.php
  • tests/TestCase.php
  • tests/TestData.php
  • tests/Unit/AirlineTest.php
  • tests/UserTest.php
  • tests/UtilsTest.php
  • tests/VersionTest.php
  • tests/data/base.yml
💤 Files with no reviewable changes (30)
  • tests/UtilsTest.php
  • tests/DatabaseTest.php
  • tests/AdminControllerTests.php
  • app/Console/Commands/DevCommands.php
  • tests/ApiTestTrait.php
  • tests/ImporterTest.php
  • tests/OAuthTest.php
  • tests/AwardsTest.php
  • tests/AcarsTest.php
  • tests/SimBriefTest.php
  • tests/TestData.php
  • composer.json
  • tests/CronTest.php
  • tests/AirlineTest.php
  • tests/AirportTest.php
  • tests/MetarTest.php
  • tests/MoneyTest.php
  • tests/RegistrationTest.php
  • tests/NewsTest.php
  • tests/GeoTest.php
  • tests/ApiTest.php
  • tests/FinanceTest.php
  • tests/CreatesApplication.php
  • tests/FlightTest.php
  • tests/VersionTest.php
  • tests/SubfleetTest.php
  • tests/BidTest.php
  • tests/PIREPTest.php
  • tests/MathTest.php
  • tests/UserTest.php

Comment thread database/factories/EventFactory.php Outdated
Comment thread database/factories/FlightFieldFactory.php
Comment thread tests/Arch/ModelsTest.php
Comment thread tests/Feature/CronTest.php
Comment thread tests/Feature/ImporterTest.php Outdated
Comment thread tests/Helpers/DatabaseHelpers.php Outdated
Comment thread tests/Helpers/HttpHelpers.php
Comment thread tests/Helpers/HttpHelpers.php
Comment thread tests/Pest.php Outdated
Comment thread tests/TestCase.php Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (6)
tests/Helpers/DatabaseHelpers.php (3)

23-25: Type-hint $value explicitly in updateSetting.

$value is currently untyped. Use mixed so the signature stays explicit and consistent with the project rules.

Suggested change
-function updateSetting(string $key, $value): void
+function updateSetting(string $key, mixed $value): void
 {
     app(SettingRepository::class)->store($key, $value);
 }

As per coding guidelines: "Use appropriate PHP type hints for method parameters".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Helpers/DatabaseHelpers.php` around lines 23 - 25, The updateSetting
helper currently leaves $value untyped; update the function signature for
updateSetting to explicitly type-hint the second parameter as mixed (e.g.,
change to function updateSetting(string $key, mixed $value): void) and ensure
any calls to updateSetting still pass compatible values; this aligns with the
project's typing rules and matches the SettingRepository::store usage.

54-54: Remove inline comment in helper body.

The inline comment is unnecessary here and can be dropped.

As per coding guidelines: "Prefer PHPDoc blocks over inline comments; never use comments within the code itself unless the logic is exceptionally complex".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Helpers/DatabaseHelpers.php` at line 54, Remove the inline comment "//
Return a Pirep model" from the helper body in tests/Helpers/DatabaseHelpers.php;
locate the helper function that returns the Pirep model (the method containing
that inline comment) and delete that comment, keeping the function body
unchanged, or if documentation is needed, move the text into the function's
PHPDoc block above the method instead.

45-59: createPirep() name implies persistence, but it returns an unsaved model.

This helper uses make(), so callers can easily forget to persist the model. Consider renaming to makePirep() or persisting before returning to avoid test setup mistakes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Helpers/DatabaseHelpers.php` around lines 45 - 59, The helper
createPirep() currently calls Pirep::factory()->make() and returns an unsaved
model which contradicts its name; either rename the function to makePirep() to
reflect that it returns an unsaved instance, or persist the Pirep before
returning by replacing Pirep::factory()->make(...) with
Pirep::factory()->create(...) (ensure related callers expect a saved model when
changing behavior); update references to createPirep() accordingly if you rename
it so tests remain correct.
tests/Feature/SimBriefTest.php (3)

64-71: Add concrete parameter types to downloadOfp().

$user, $flight, $aircraft, and $fares should be type-hinted for consistency and safer test helpers.

Suggested change
-function downloadOfp($user, $flight, $aircraft, $fares): ?SimBrief
+function downloadOfp(User $user, Flight $flight, Aircraft $aircraft, array $fares): ?SimBrief
 {

As per coding guidelines: "Use appropriate PHP type hints for method parameters".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/SimBriefTest.php` around lines 64 - 71, Update the test helper
function signature for downloadOfp to add concrete PHP type hints for
parameters: type-hint $user as the User model (e.g., User), $flight as Flight,
$aircraft as Aircraft, and $fares as the correct collection/array type (e.g.,
array or Collection) while keeping the existing ?SimBrief return type; also
import or fully-qualify these classes at the top of the test file so the
downloadOfp function and its calls compile and follow the project's typing
guidelines.

175-177: Remove duplicated assertion in the expectation chain.

The same non-null simbrief.id assertion is repeated twice; keeping one is enough and improves readability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/SimBriefTest.php` around lines 175 - 177, The expectation chain
in the test duplicates the same assertion for
expect($body['flight']['simbrief']['id']) twice; edit the test (SimBriefTest) to
remove the duplicated ->and($body['flight']['simbrief']['id'])->not->toBeNull()
so the chain only asserts simbrief.id once and still includes the subsequent
->and($body['flight']['simbrief']['subfleet']['fares'])->not->toBeNull().

131-134: Remove commented-out assertion block.

Keeping disabled assertions in-place makes maintenance harder and obscures the real checks.

As per coding guidelines: "Prefer PHPDoc blocks over inline comments; never use comments within the code itself unless the logic is exceptionally complex".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Feature/SimBriefTest.php` around lines 131 - 134, In the SimBriefTest
test, remove the commented-out assertion block containing
$this->assertEquals('https://localhost/api/flights/'.$briefing->id.'/briefing',
$url); — delete those commented lines (the disabled $this->assertEquals
reference to $briefing->id and $url) so the test contains only active assertions
or, if an assertion is still required, replace the commented block with an
active $this->assertEquals(...) using $briefing->id and $url in the appropriate
test method.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@database/factories/UserFactory.php`:
- Around line 46-47: The factory currently evaluates
Rank::factory()->create()->id immediately for the 'rank_id' attribute which
causes a DB write on User::factory()->make(); change the 'rank_id' entry to a
lazy callback like the 'airline_id' one (i.e., 'rank_id' => fn () =>
Rank::factory()->create()->id) inside the UserFactory class so related Rank
records are only created when the factory is persisted.

In `@tests/Feature/OAuthTest.php`:
- Around line 3-12: Add an explicit import "use Carbon\Carbon;" at the top of
the OAuthTest class and ensure the test clock is reset after each test to avoid
leakage: in the OAuthTest class (e.g., add or update a tearDown() or afterEach()
method) call Carbon::setTestNow(null) and then call parent::tearDown() (or the
framework equivalent) so any frozen time set by Carbon::setTestNow() in tests
(lines around 79,109) is cleared for subsequent tests.

In `@tests/Feature/PIREPTest.php`:
- Around line 110-117: The failing calls to put() include an unsupported 4th
argument ($user); remove the extra argument from both put() invocations so they
use the signature put($uri, array $data = [], array $headers = []), relying on
the existing apiAs($user) authentication already set in the test; update the two
put() calls around the PIREP update (the initial $response = $this->put($uri,
[], [], $user); and the subsequent $response = $this->put($uri, ['state' =>
'FIL'], [], $user);) to omit the trailing $user parameter.

---

Nitpick comments:
In `@tests/Feature/SimBriefTest.php`:
- Around line 64-71: Update the test helper function signature for downloadOfp
to add concrete PHP type hints for parameters: type-hint $user as the User model
(e.g., User), $flight as Flight, $aircraft as Aircraft, and $fares as the
correct collection/array type (e.g., array or Collection) while keeping the
existing ?SimBrief return type; also import or fully-qualify these classes at
the top of the test file so the downloadOfp function and its calls compile and
follow the project's typing guidelines.
- Around line 175-177: The expectation chain in the test duplicates the same
assertion for expect($body['flight']['simbrief']['id']) twice; edit the test
(SimBriefTest) to remove the duplicated
->and($body['flight']['simbrief']['id'])->not->toBeNull() so the chain only
asserts simbrief.id once and still includes the subsequent
->and($body['flight']['simbrief']['subfleet']['fares'])->not->toBeNull().
- Around line 131-134: In the SimBriefTest test, remove the commented-out
assertion block containing
$this->assertEquals('https://localhost/api/flights/'.$briefing->id.'/briefing',
$url); — delete those commented lines (the disabled $this->assertEquals
reference to $briefing->id and $url) so the test contains only active assertions
or, if an assertion is still required, replace the commented block with an
active $this->assertEquals(...) using $briefing->id and $url in the appropriate
test method.

In `@tests/Helpers/DatabaseHelpers.php`:
- Around line 23-25: The updateSetting helper currently leaves $value untyped;
update the function signature for updateSetting to explicitly type-hint the
second parameter as mixed (e.g., change to function updateSetting(string $key,
mixed $value): void) and ensure any calls to updateSetting still pass compatible
values; this aligns with the project's typing rules and matches the
SettingRepository::store usage.
- Line 54: Remove the inline comment "// Return a Pirep model" from the helper
body in tests/Helpers/DatabaseHelpers.php; locate the helper function that
returns the Pirep model (the method containing that inline comment) and delete
that comment, keeping the function body unchanged, or if documentation is
needed, move the text into the function's PHPDoc block above the method instead.
- Around line 45-59: The helper createPirep() currently calls
Pirep::factory()->make() and returns an unsaved model which contradicts its
name; either rename the function to makePirep() to reflect that it returns an
unsaved instance, or persist the Pirep before returning by replacing
Pirep::factory()->make(...) with Pirep::factory()->create(...) (ensure related
callers expect a saved model when changing behavior); update references to
createPirep() accordingly if you rename it so tests remain correct.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f96cb14b-5bf5-4fd9-a9d5-d46058c7c026

📥 Commits

Reviewing files that changed from the base of the PR and between ee8e816 and 19b26a7.

📒 Files selected for processing (15)
  • database/factories/EventFactory.php
  • database/factories/FlightFieldFactory.php
  • database/factories/UserFactory.php
  • phpunit.xml
  • tests/Arch/ModelsTest.php
  • tests/Feature/ImporterTest.php
  • tests/Feature/NewsTest.php
  • tests/Feature/OAuthTest.php
  • tests/Feature/PIREPTest.php
  • tests/Feature/RegistrationTest.php
  • tests/Feature/SimBriefTest.php
  • tests/Helpers/DatabaseHelpers.php
  • tests/Helpers/HttpHelpers.php
  • tests/Pest.php
  • tests/TestCase.php
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/Feature/RegistrationTest.php
  • tests/Helpers/HttpHelpers.php
  • tests/Arch/ModelsTest.php

Comment thread database/factories/UserFactory.php
Comment thread tests/Feature/OAuthTest.php
Comment thread tests/Feature/PIREPTest.php Outdated
@nabeelio nabeelio merged commit 379a9b3 into phpvms:main Mar 18, 2026
6 checks passed
@arthurpar06 arthurpar06 deleted the tests branch May 3, 2026 12:04
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.

2 participants