phpvms/vitest.config.ts
Nabeel Shahzad 1f9f5cc32a
test(routeforge): pest + vitest coverage + service fixes
Add 27 PHP test files + 6 TS test files + Vitest setup, surfacing
and fixing 4 production bugs in the process.

Test counts (all green):
- PHP: 545 tests / 2341 assertions / 25.25s
  - 12 lint rule tests (L1, L2, L2b, L3, L4, L5, L6, L7, L8, L9, L10, L11)
  - LintRunner dispatch + LintReport bucket aggregation
  - DuplicateChecker bulk-query + N+1 protection
  - RouteForgeService full commit pipeline (happy path, lint rollback,
    attach-existing branch, fare multiplier, withoutEvents suppression)
  - 6 endpoint feature tests (PreviewAirports, Subfleets, AirlineStats,
    CheckDuplicates, Lint, Commit)
- TS: 46 tests / 6 files / 280ms via Vitest 4.1.7 + happy-dom
  - geo, timezone, flightNumber, timeStrategy, generator, lint

In-scope production fixes discovered by writing the tests:

1. DuplicateChecker eager-load was 'airline:id,code' but 'code' is an
   accessor over iata/icao columns. Loaded airline came back with
   NEITHER backing column populated and Flight::ident dropped the
   airline prefix in the duplicates response. Changed to
   'airline:id,iata,icao'.

2. LintRunner constructor takes 'array $rules' with no container-
   resolvable shape. Both /lint and /commit endpoints would have
   failed at runtime with 'Unresolvable dependency'. Registered as
   singleton in AppServiceProvider::register() binding to
   LintRunner::defaults().

3. BaseRouteForgeBatchRequest's 'subfleet_ids' rule was
   ['required', 'array', 'min:0']. 'required' rejects empty arrays
   in Laravel, contradicting 'min:0'. Relaxed to ['present', 'array'];
   L3 lint catches the empty case as a warning downstream.

4. RouteForgeService::commit() called auth()->user() directly,
   violating tests/Arch/GlobalTest's http-helpers rule (auth/session/
   request only allowed in App\Http / App\Filament / App\Livewire /
   App\Providers\Filament). Added $causerId field to CommitInput;
   controller stamps it from auth()->id(); service resolves User by id.

Infrastructure:
- tests/Support/RouteForgeTestHelpers.php — shared LintContext + row +
  airport + batchPayload builders. PSR-4 autoloaded via Tests\ namespace;
  static class avoids global-function name collisions across the 15+
  RouteForge test files.
- vitest.config.ts at project root, scoped to
  resources/js/admin/routeforge/**/*.test.ts. happy-dom provides the
  minimal window + DOM globals lib/i18n.ts depends on.
- package.json gains 'test': 'vitest run' script.
- Added vitest, happy-dom, @types/node as devDependencies.

Task 4.6.3 stays N/A — FlightNumberAssigner was removed per the
Section 4 banner; no PHP equivalent to test. Section 6.4.7's planned
PHP↔TS shared fixtures (tests/fixtures/routeforge/generator/) also
N/A for the same reason; TS generator tests stand alone.

Quality gates green:
- tsc --noEmit: clean
- oxlint (40 files / 93 rules): 0 warnings, 0 errors
- oxfmt --check: all formatted
- npm run build: routeforge bundle stays at 26.69 KB gzip
  (Decision 16 budget 60 KB → 33.31 KB headroom)
- vendor/bin/pint --dirty: passed
- vendor/bin/phpstan analyse: OK no errors
- vendor/bin/rector --dry-run: clean for RouteForge files
2026-05-24 11:55:36 -05:00

22 lines
723 B
TypeScript

/**
* Vitest config — RouteForge TS test runner.
*
* Scoped to `resources/js/admin/routeforge/**` so the legacy admin JS tree
* stays outside the type/test sweep. happy-dom provides the minimal `window`
* + DOM globals that `lib/i18n.ts` (and any future client-only modules)
* depend on without bringing in the full jsdom weight.
*
* No transform / plugin config — Vitest reuses vite.config.js when no
* vitest.config is present, but here we want a narrower include scope.
*/
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["resources/js/admin/routeforge/**/*.test.ts"],
environment: "happy-dom",
globals: false,
reporters: "default",
},
});