# BEEB BEEB — Full-Project Testing Plan

> Complete phased plan for building out PHPUnit Unit + Feature tests across the three application
> surfaces — **Web** (Admin dashboard), **API** (Client rider app + Provider investor app), and
> **Landing** (public marketing site). Tests are organized into folders that mirror
> `app/Http/Controllers` 1:1 so any controller maps directly to a predictable test path.

**Status legend:** `[ ]` not started · `[~]` in progress · `[x]` done

---

## 0. Current state (baseline, as found)

- Only `tests/Unit/ExampleTest.php` and `tests/Feature/ExampleTest.php` exist (default Laravel stubs).
- `phpunit.xml` pins `phpunit/phpunit: ^8.5` (Laravel 9 normally pairs with `^9.5`).
- `fakerphp/faker` is only a transitive dependency, not declared in `require-dev`.
- No model factories except the unused default `UserFactory` (no `User` model in this app —
  auth models are `Admin`, `Client`, `Provider`).
- `phpunit.xml` has SQLite lines commented out; as-is, tests would hit the real `beeb` MySQL DB.
- Decision made: **tests run against a dedicated MySQL test database** (not SQLite), to match
  production engine behavior exactly (collations, JSON columns, `ENUM`, etc.).
- Rich seeders already exist (`ClientSeeder`, `SaraProviderSeeder`, `AdminTableSeeder`,
  `VehicleSeeder`, `RideSeeder`, `SettlementSeeder`, `WalletSeeder`, ...) — factories should reuse
  their data shapes rather than inventing new ones.

### Route/controller → test-area map

| Area | Routing | Controllers | Guard |
|---|---|---|---|
| **Web** | `routes/web.php` + `routes/dashboard/*.php` (prefix `/admin`) | `app/Http/Controllers/Admin/*` | `admin` (session) |
| **API — Client** | `routes/api.php` + `routes/api/client.php` | `app/Http/Controllers/Api/Client/*` | `client` (token) |
| **API — Provider** | `routes/api.php` + `routes/api/provider.php` | `app/Http/Controllers/Api/Provider/*` | `provider` (token) |
| **API — Shared** | `routes/api.php` root | `app/Http/Controllers/Api/*` (Area, Fqs, Contact, Static, ExportPdf...) | mixed / none |
| **Landing** | `routes/site.php` + `routes/api/site.php` | `app/Http/Controllers/Site/*` | none |

---

## 1. Target folder structure

```
tests/
├── TestCase.php
├── CreatesApplication.php
├── Support/
│   ├── Concerns/
│   │   ├── ActsAsAdmin.php
│   │   ├── ActsAsClient.php
│   │   ├── ActsAsProvider.php
│   │   └── SeedsLookupTables.php
│   └── TestCases/
│       ├── AdminTestCase.php
│       ├── ClientApiTestCase.php
│       ├── ProviderApiTestCase.php
│       └── LandingTestCase.php
│
├── Unit/
│   ├── Web/
│   ├── Api/
│   │   ├── Client/
│   │   ├── Provider/
│   │   └── Shared/
│   ├── Landing/
│   └── Common/           # Enums, Traits, Rules, Resources, Observers, Services, Casts
│
└── Feature/
    ├── Web/
    │   ├── Auth/
    │   ├── ClientManagement/
    │   ├── ProviderManagement/
    │   ├── Rides/
    │   ├── Scooters/
    │   ├── Settlements/
    │   ├── Finance/
    │   ├── Packages/
    │   ├── RolesAndPermissions/
    │   └── Cms/
    ├── Api/
    │   ├── Client/
    │   │   ├── Auth/
    │   │   ├── Profile/
    │   │   ├── RideFlow/
    │   │   ├── Wallet/
    │   │   ├── Subscription/
    │   │   ├── Notifications/
    │   │   └── Complain/
    │   ├── Provider/
    │   │   ├── Auth/
    │   │   ├── Profile/
    │   │   ├── EntityUpdate/
    │   │   ├── Settlements/
    │   │   └── Notifications/
    │   └── Shared/
    └── Landing/
```

---

## Phase 0 — Test infrastructure

- [x] Bump `phpunit/phpunit` to `^9.5` in `composer.json` `require-dev`.
- [x] Add `fakerphp/faker: ^1.21` explicitly to `require-dev`.
- [x] Create a dedicated MySQL test database (e.g. `beeb_testing`) on the same server.
- [x] Add `.env.testing` (or `phpunit.xml` `<php>` server vars) with:
  - `DB_CONNECTION=mysql`, `DB_HOST`, `DB_PORT`, `DB_DATABASE=beeb_testing`, `DB_USERNAME`, `DB_PASSWORD`
  - `APP_ENV=testing`, `CACHE_DRIVER=array`, `SESSION_DRIVER=array`, `QUEUE_CONNECTION=sync`,
    `MAIL_MAILER=array`, `TELESCOPE_ENABLED=false`
- [x] Verify migrations run cleanly against a fresh `beeb_testing` DB (`php artisan migrate --database=...`).
- [x] Update `tests/TestCase.php` to optionally auto-seed lookup tables via a lightweight trait.
- [x] Create `tests/Support/Concerns/ActsAsAdmin.php`, `ActsAsClient.php`, `ActsAsProvider.php` —
  each replicates exactly how the real `AuthController@login` issues/stores a token for that guard,
  so tests can do `$this->actingAsClient($client)` and get a working `Authorization: Bearer ...` header.
- [x] Create `tests/Support/Concerns/SeedsLookupTables.php` for `Country`/`City`/`Area`/`Role`/`Permission`.
- [x] Create base test case classes in `tests/Support/TestCases/` (`AdminTestCase`, `ClientApiTestCase`,
  `ProviderApiTestCase`, `LandingTestCase`), all extending `Tests\TestCase` + `RefreshDatabase`.
- [x] Write model factories (based on existing seeders' data shapes) for:
  - [x] `AdminFactory`
  - [x] `ClientFactory`
  - [x] `ProviderFactory`
  - [x] `ScooterFactory`
  - [x] `RideFactory`
  - [x] `SubscriptionPackageFactory`
  - [x] `ClientSubscriptionFactory`
  - [x] `WalletFactory`
  - [x] `WalletTransactionFactory`
  - [x] `WalletChargeRequestFactory`
  - [x] `SettlementFactory`
  - [x] `ComplainFactory`
  - [x] `NotificationFactory`
  - [x] `AreaFactory`
  - [x] `CountryFactory`
  - [x] `CityFactory`
  - [x] `PaymentTransactionFactory`
  - [x] `RoleFactory` / `PermissionFactory`
- [x] Scaffold the empty `tests/Unit/*` and `tests/Feature/*` subfolders above; delete the two
  `ExampleTest.php` stubs once replaced by real smoke tests.
- [x] Rewrite `phpunit.xml` testsuites to one-per-folder (see below).
- [x] Add `composer.json` scripts: `test`, `test:web`, `test:api`, `test:landing`, `test:unit`, `test:feature`.

**`phpunit.xml` testsuite block:**

```xml
<testsuites>
    <testsuite name="Unit-Web">       <directory suffix="Test.php">./tests/Unit/Web</directory></testsuite>
    <testsuite name="Unit-Api">       <directory suffix="Test.php">./tests/Unit/Api</directory></testsuite>
    <testsuite name="Unit-Landing">   <directory suffix="Test.php">./tests/Unit/Landing</directory></testsuite>
    <testsuite name="Unit-Common">    <directory suffix="Test.php">./tests/Unit/Common</directory></testsuite>
    <testsuite name="Feature-Web">     <directory suffix="Test.php">./tests/Feature/Web</directory></testsuite>
    <testsuite name="Feature-Api">     <directory suffix="Test.php">./tests/Feature/Api</directory></testsuite>
    <testsuite name="Feature-Landing"> <directory suffix="Test.php">./tests/Feature/Landing</directory></testsuite>
</testsuites>
```

---

## Phase 1 — API: Client (rider app) — Tier 1 priority

`app/Http/Controllers/Api/Client/*`

- [x] `Feature/Api/Client/Auth/RegisterTest.php` — register, activate (OTP), resend-code
- [x] `Feature/Api/Client/Auth/LoginTest.php` — login, verify-login, logout, delete-account
- [x] `Feature/Api/Client/Auth/ForgetPasswordTest.php` — forget/check-code/reset
- [x] `Feature/Api/Client/Profile/GetProfileTest.php`
- [x] `Feature/Api/Client/Profile/UpdateProfileTest.php` — update, change-lang, check/update password
- [x] `Feature/Api/Client/Profile/PhoneUpdateTest.php` — send/verify old & new phone codes
- [x] `Feature/Api/Client/Profile/UpdateEmailTest.php` — `UpdateEmailController` change/verify
- [x] `Feature/Api/Client/Profile/ContactTest.php`
- [x] `Feature/Api/Client/RideFlow/RideLifecycleTest.php` — full `RideFlowController` state machine:
  `SCANNING → ACTIVE → ENDING → COMPLETED` happy path
- [x] `Feature/Api/Client/RideFlow/RideCancellationTest.php` — invalid transitions at each stage
- [x] `Feature/Api/Client/RideFlow/RideBalanceTest.php` — balance runs out mid-ride, `balance_low`,
  `can_start_ride` computed flags on `ClientResource`
- [x] `Feature/Api/Client/RideFlow/RideHistoryTest.php` — `RideController` listing/details
- [x] `Feature/Api/Client/Wallet/WalletBalanceTest.php`
- [x] `Feature/Api/Client/Wallet/WalletTopUpTest.php` — charge request creation, transactions list
- [x] `Feature/Api/Client/Subscription/SubscriptionPurchaseTest.php`
- [x] `Feature/Api/Client/Subscription/SubscriptionStatusTest.php` — expiry reminders/expired states
- [x] `Feature/Api/Client/Notifications/NotificationListTest.php` — list, switch-notify, mark read
- [x] `Feature/Api/Client/Complain/ComplainTest.php` — create/list/status
- [x] `Feature/Api/Client/Scooter/ScooterMapTest.php` — `ScooterController` map/discovery endpoints
- [x] `Feature/Api/Client/Home/HomeTest.php`

---

## Phase 2 — API: Provider (investor app) — Tier 1 priority

`app/Http/Controllers/Api/Provider/*`

- [x] `Feature/Api/Provider/Auth/LoginTest.php` — login (email/password, no OTP), `needApproval` branch
- [x] `Feature/Api/Provider/Auth/ForgetPasswordTest.php`
- [x] `Feature/Api/Provider/Profile/GetProfileTest.php` — `is_verified`/`has_vehicles` computed flags
- [x] `Feature/Api/Provider/Profile/UpdateProfileTest.php`
- [x] `Feature/Api/Provider/EntityUpdate/EntityUpdateRequestTest.php` — profile update-request workflow
- [x] `Feature/Api/Provider/Settlements/SettlementRequestTest.php` — request/list/status
- [x] `Feature/Api/Provider/Settlements/SettlementDetailsTest.php`
- [x] `Feature/Api/Provider/Dashboard/DashboardTest.php`
- [x] `Feature/Api/Provider/Notifications/NotificationListTest.php`
- [x] `Feature/Api/Provider/Complain/ComplainTest.php`

---

## Phase 3 — API: Shared endpoints

`app/Http/Controllers/Api/*` (root)

- [x] `Feature/Api/Shared/AreaTest.php`
- [x] `Feature/Api/Shared/CountriesAndCitiesTest.php`
- [x] `Feature/Api/Shared/FqsTest.php`
- [x] `Feature/Api/Shared/ContactTest.php`
- [x] `Feature/Api/Shared/StaticContentTest.php` — `StaticController`
- [x] `Feature/Api/Shared/SettingTest.php`
- [x] `Feature/Api/Shared/ExportPdfTest.php`
- [x] `Feature/Api/Shared/MarksNotificationsAsReadTest.php`

---

## Phase 4 — Web: Admin dashboard

`app/Http/Controllers/Admin/*` — ~35 controllers; grouped and prioritized by business impact.

### Tier 1 — critical

- [x] `Feature/Web/Auth/LoginTest.php` — login + OTP verify + resend-otp + logout
- [x] `Feature/Web/ClientManagement/ClientCrudTest.php` — list/show/create/update/delete
- [x] `Feature/Web/ClientManagement/ClientBlockApproveTest.php`
- [x] `Feature/Web/ProviderManagement/ProviderCrudTest.php`
- [x] `Feature/Web/ProviderManagement/ProviderApprovalTest.php` — approve/reject + `rejection_reason`
- [x] `Feature/Web/Rides/RideOversightTest.php` — `RideController` list/filter/details
- [x] `Feature/Web/Scooters/ScooterCrudTest.php`
- [x] `Feature/Web/Settlements/SettlementApprovalTest.php` — approve/reject provider settlement requests
- [x] `Feature/Web/Finance/FinanceReportTest.php`

### Tier 2 — important

- [x] `Feature/Web/RolesAndPermissions/RoleCrudTest.php`
- [x] `Feature/Web/RolesAndPermissions/AdminCrudTest.php` — `AdminController`
- [x] `Feature/Web/Packages/PackageCrudTest.php`
- [x] `Feature/Web/Complains/ComplainManagementTest.php`
- [x] `Feature/Web/Notifications/NotificationManagementTest.php`
- [x] `Feature/Web/Areas/AreaCrudTest.php`, `CountryCrudTest.php`, `CityCrudTest.php`
- [x] `Feature/Web/EntityUpdate/EntityUpdateReviewTest.php`
- [x] `Feature/Web/Sms/SmsTest.php`

### Tier 3 — smoke-level (CMS/content)

- [x] `Feature/Web/Cms/IntroSettingsTest.php` — `IntroController`, `IntroSiteController`, `IntroSetting`
- [x] `Feature/Web/Cms/IntroSlidersTest.php`
- [x] `Feature/Web/Cms/IntroFqsTest.php` — `IntroFqsController` + `IntroFqsCategoryController`
- [x] `Feature/Web/Cms/IntroHowWorkTest.php`
- [x] `Feature/Web/Cms/IntroPartnerTest.php`
- [x] `Feature/Web/Cms/IntroReviewTest.php`
- [x] `Feature/Web/Cms/IntroServiceTest.php`
- [x] `Feature/Web/Cms/IntroSocialTest.php`
- [x] `Feature/Web/Cms/IntroMessagesTest.php`
- [x] `Feature/Web/Cms/PagesTest.php`
- [x] `Feature/Web/Cms/SeoTest.php`
- [x] `Feature/Web/Cms/SocialTest.php`
- [x] `Feature/Web/Cms/AppIntroTest.php`
- [x] `Feature/Web/Misc/ImageControllerTest.php`
- [x] `Feature/Web/Misc/ExcelExportTest.php`
- [x] `Feature/Web/Misc/InputsCopyControllerTest.php`
- [x] `Feature/Web/Misc/SettingControllerTest.php`
- [x] `Feature/Web/Misc/ContactControllerTest.php`
- [x] `Feature/Web/Home/DashboardHomeTest.php`

---

## Phase 5 — Landing (public site)

`app/Http/Controllers/Site/*` + `routes/api/site.php`

- [x] `Feature/Landing/HomeTest.php` — `IntroController@index`
- [x] `Feature/Landing/ClientsMoreTest.php`
- [x] `Feature/Landing/PrivacyPolicyTest.php`
- [x] `Feature/Landing/DeleteAccountPageTest.php`
- [x] `Feature/Landing/ContactUsTest.php` — `send-message` + rate limit (`throttle:5,1`) on `api/site/contact-us`
- [x] `Feature/Landing/NewsletterTest.php` — `subscribe-email` + `api/site/newsletter`
- [x] `Feature/Landing/LanguageSwitchTest.php` — `/lang/{lang}`
- [x] `Feature/Landing/ArticlesTest.php` — list + details
- [x] `Feature/Landing/ApiSiteHomeTest.php` — `api/site/home`
- [x] `Feature/Landing/ApiSiteDirectoryTest.php` — `api/site/clients`, `/providers`, `/companies`
- [x] `Feature/Landing/PaymentRedirectTest.php` — `PaymentController@getHyperPay`, payment status redirect view
- [x] `Feature/Landing/FallbackRouteTest.php` — unknown URL redirects to `intro`

---

## Phase 6 — Unit tests: core domain logic (cross-cutting, parallel with 1-5)

- [x] `Unit/Common/Enums/RideStatusTest.php` — valid transitions per `docs/domain-context.md`
- [x] `Unit/Common/Enums/ScooterStatusTest.php`
- [x] `Unit/Common/Enums/NotificationTypeEnumTest.php`
- [x] `Unit/Common/Enums/SettlementStatusTest.php`, `ComplainStatusEnumTest.php`, `PaymentStatusTest.php`
- [x] `Unit/Common/Resources/ClientResourceTest.php` — `is_profile_completed`, `in_ride`, `balance_low`, `can_start_ride`
- [x] `Unit/Common/Resources/ProviderResourceTest.php` — `is_verified`, `has_vehicles`
- [x] `Unit/Common/Traits/ResponseTraitTest.php` — API response envelope shape
- [x] `Unit/Common/Traits/PaginationTraitTest.php`
- [x] `Unit/Common/Traits/SearchTraitTest.php`
- [x] `Unit/Common/Traits/GeneralTraitTest.php`, `ModelTraitTest.php`
- [x] `Unit/Common/Rules/LanguageMatchRuleTest.php`
- [x] `Unit/Common/Services/SettingServiceTest.php` — business constants (Appendix C)
- [x] `Unit/Common/Services/PaymentServiceTest.php`
- [x] `Unit/Common/Observers/WalletTransactionObserverTest.php`
- [x] `Unit/Common/Observers/SupplierObserverTest.php`
- [x] `Unit/Common/Casts/DateTimeCastTest.php`

---

## Phase 7 — CI integration

- [x] GitHub Actions workflow: PHP 8.2 + MySQL service container (matching `beeb_testing` config).
- [x] Matrix job per area: `web`, `api`, `landing` (each running its `composer test:*` script).
- [x] Migrate `beeb_testing` fresh on each run (`php artisan migrate:fresh --seed=false`).
- [x] Coverage report (PCOV or Xdebug) uploaded as artifact; start gate at ~40-50%, ratchet up over time.
- [x] Block merge on any failing suite; make coverage gate a warning initially, hard-fail later.

---

## Suggested execution order

1. **Phase 0** (infra) — blocks everything else.
2. **Phase 1** (Client API) and **Phase 6** (Unit/Common) in parallel — highest business value + reusable across all other phases.
3. **Phase 2** (Provider API).
4. **Phase 4 Tier 1** (Admin critical) — benefits from factories built in 1-2.
5. **Phase 3** (API Shared) and **Phase 5** (Landing) — lower risk, can slot in anytime.
6. **Phase 4 Tier 2/3** (Admin secondary/CMS) — lowest priority, smoke-level acceptable.
7. **Phase 7** (CI) — once there's meaningful coverage to protect.
