Skip to content

Commit

Permalink
Merge pull request #150 from sorrell/carrier-testing
Browse files Browse the repository at this point in the history
Carrier testing
  • Loading branch information
adrenallen authored Feb 20, 2025
2 parents abfd28e + 4e828d7 commit d4ae9e9
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
APP_NAME="LoadPartner TMS"
APP_ENV=local
APP_KEY=
APP_KEY=base64:amHoMcOUBHwj3/2KKnwNev0hU3EDy22r5+rv57O37KI=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://localhost
Expand Down
10 changes: 7 additions & 3 deletions app/Actions/Carriers/UpdateCarrierGeneral.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

use App\Http\Resources\CarrierResource;
use App\Models\Carrier;
use App\Rules\ValidPhoneNumber;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;

use Propaganistas\LaravelPhone\PhoneNumber;
class UpdateCarrierGeneral
{
use AsAction;
Expand Down Expand Up @@ -35,7 +36,10 @@ public function handle(

public function asController(ActionRequest $request, Carrier $carrier): Carrier
{

if ($request->has('contact_phone') && $request['contact_phone']) {
$phone = new PhoneNumber($request['contact_phone'], 'US');
$request->merge(['contact_phone' => $phone->formatE164()]);
}
$carrier = $this->handle(
carrier: $carrier,
name: $request->validated('name'),
Expand Down Expand Up @@ -67,7 +71,7 @@ public function rules(): array
'dot_number' => ['nullable', 'string'],
'physical_location_id' => ['nullable', 'integer', 'exists:locations,id'],
'contact_email' => ['nullable', 'email', 'max:255'],
'contact_phone' => ['nullable', 'string', 'max:255', 'phone:US'],
'contact_phone' => ['nullable', 'string', new ValidPhoneNumber],
];
}
}
18 changes: 18 additions & 0 deletions app/Rules/ValidPhoneNumber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Rules;

use Propaganistas\LaravelPhone\Rules\Phone;

class ValidPhoneNumber extends Phone
{
public function __construct()
{
$this->countries = explode(',', trim(config('phones.valid_countries')));
}

public function message()
{
return 'The :attribute field must be a valid phone number within a supported country (' . implode(', ', $this->countries) .')';
}
}
14 changes: 14 additions & 0 deletions config/phones.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

return [
/*
|--------------------------------------------------------------------------
| Valid Countries for Phone Numbers
|--------------------------------------------------------------------------
|
| A comma-separated list of ISO 3166-1 alpha-2 country codes that are
| considered valid for phone number validation.
|
*/
'valid_countries' => env('VALID_PHONE_COUNTRIES', 'US,CA'),
];
138 changes: 138 additions & 0 deletions tests/Feature/Carriers/CarrierSecurityTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

namespace Tests\Feature\Carriers;

use App\Actions\Carriers\CreateCarrier;
use App\Models\Location;
use App\Models\Organizations\Organization;
use App\Models\User;
use App\Models\Carrier;
use Illuminate\Support\Facades\Context;
use Inertia\Testing\AssertableInertia;

beforeEach(function () {
$this->setUpOrganization();

$this->location = Location::factory()->create();

// Set up second organization and user
$this->secondUser = User::factory()->create();
$this->secondOrg = Organization::create([
'name' => 'Second Test Organization',
'owner_id' => $this->secondUser->id,
]);
$this->secondUser->organizations()->attach($this->secondOrg);
$this->secondUser->current_organization_id = $this->secondOrg->id;
$this->secondUser->save();

// Store organization IDs and initial active user
$this->firstOrgId = $this->organization->id;
$this->secondOrgId = $this->secondOrg->id;
$this->activeUser = $this->user;

// Helper functions to make tests more readable
$this->switchToFirstOrg = function () {
Context::addHidden('current_organization_id', $this->firstOrgId);
$this->activeUser = $this->user;
};

$this->switchToSecondOrg = function () {
Context::addHidden('current_organization_id', $this->secondOrgId);
$this->activeUser = $this->secondUser;
};

$this->createTestCarrier = function ($name = 'Test Carrier') {
return CreateCarrier::run(name: $name);
};
});

test('it prevents access to carriers from other organizations', function () {
$carrier = ($this->createTestCarrier)();

// Verify first organization access
$response = $this->actingAs($this->activeUser)->get(route('carriers.show', $carrier));
expect($response->status())->toBe(200);

// Verify second organization cannot access
($this->switchToSecondOrg)();
$response = $this->actingAs($this->activeUser)->get(route('carriers.show', $carrier));
expect($response->status())->toBe(404);

// Verify first organization still has access
($this->switchToFirstOrg)();
$response = $this->actingAs($this->activeUser)->get(route('carriers.show', $carrier));
expect($response->status())->toBe(200);
});

test('it prevents updating carriers from other organizations', function () {
// Create carrier in first organization
$response = $this->actingAs($this->activeUser)
->withHeaders(['Accept' => 'application/json'])
->post(route('carriers.store'), [
'name' => 'Test Carrier',
]);
expect($response->status())->toBe(201);

$carrier = Carrier::findOrFail($response->json('id'));
$updateData = [
'name' => 'Updated Name',
'mc_number' => 'MC123456',
'dot_number' => 'DOT789012',
'physical_location_id' => $this->location->id,
'contact_email' => '[email protected]',
'contact_phone' => '(513) 731-4567',
];

// Test update with second organization
($this->switchToSecondOrg)();
$response = $this->actingAs($this->activeUser)->put(route('carriers.update', $carrier), $updateData);
expect($response->status())->toBe(404);

// Verify first organization can still update
($this->switchToFirstOrg)();
$response = $this->actingAs($this->activeUser)->put(route('carriers.update', $carrier), $updateData);
expect($response->status())->toBe(200);
});

test('it prevents deleting carriers from other organizations', function () {
$carrier = ($this->createTestCarrier)();

// Attempt delete from second organization
($this->switchToSecondOrg)();
$response = $this->actingAs($this->activeUser)->delete(route('carriers.destroy', $carrier));
expect($response->status())->toBe(404);

// Verify carrier still exists
($this->switchToFirstOrg)();
expect(Carrier::find($carrier->id))->not->toBeNull();

// Verify first organization can delete
$response = $this->actingAs($this->activeUser)->delete(route('carriers.destroy', $carrier));
expect($response->status())->toBe(200);
});

test('it prevents listing carriers from other organizations', function () {
// Create carriers in first organization
($this->createTestCarrier)('First Org Carrier 1');
($this->createTestCarrier)('First Org Carrier 2');

// Create carrier in second organization
($this->switchToSecondOrg)();
($this->createTestCarrier)('Second Org Carrier');

// Verify second organization only sees its carrier
$response = $this->actingAs($this->activeUser)->get(route('carriers.search'));
$carriers = $response->json();
expect(count($carriers))->toBe(1);
expect($carriers[0]['name'])->toBe('Second Org Carrier');

// Verify first organization only sees its carriers
($this->switchToFirstOrg)();
$response = $this->actingAs($this->activeUser)->get(route('carriers.search'));
$carriers = $response->json();
expect(count($carriers))->toBe(2);
$names = array_column($carriers, 'name');
expect($names)->toContain('First Org Carrier 1');
expect($names)->toContain('First Org Carrier 2');
});

129 changes: 129 additions & 0 deletions tests/Unit/Actions/Carriers/CarrierTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

namespace Tests\Unit\Actions\Carriers;

use App\Actions\Carriers\CreateCarrier;
use App\Actions\Carriers\UpdateCarrierGeneral;
use App\Models\Carrier;
use App\Models\Location;
use Illuminate\Support\Facades\DB;

beforeEach(function () {
$this->location = Location::factory()->create();
});

test('it creates basic carrier with required fields', function () {
// Act
$carrier = CreateCarrier::run(
name: 'Test Carrier',
);

// Assert
expect($carrier)->toBeInstanceOf(Carrier::class);

expect(DB::table('carriers')->where([
'id' => $carrier->id,
'name' => 'Test Carrier',
])->exists())->toBeTrue();
});

test('it creates carrier with all optional fields', function () {
// Act
$carrier = CreateCarrier::run(
name: 'Full Details Carrier',
);

// Act
$updatedCarrier = UpdateCarrierGeneral::run(
carrier: $carrier,
name: 'Updated Carrier Name',
mc_number: 'MC123456',
dot_number: 'DOT789012',
physical_location_id: $this->location->id,
contact_email: '[email protected]',
contact_phone: '(555) 123-4567',
);

// Assert
expect($updatedCarrier)->toBeInstanceOf(Carrier::class);

expect(DB::table('carriers')->where([
'id' => $updatedCarrier->id,
'name' => 'Updated Carrier Name',
'mc_number' => 'MC123456',
'dot_number' => 'DOT789012',
'physical_location_id' => $this->location->id,
'contact_email' => '[email protected]',
'contact_phone' => '(555) 123-4567',
])->exists())->toBeTrue();
});

test('it updates carrier general details partially', function () {
// Create initial carrier
$carrier = CreateCarrier::run(
name: 'Initial Carrier',
);

// Act - update only some fields
$updatedCarrier = UpdateCarrierGeneral::run(
carrier: $carrier,
name: 'New Name',
mc_number: 'MC999999',
);

// Assert
expect(DB::table('carriers')->where([
'id' => $carrier->id,
'name' => 'New Name',
'mc_number' => 'MC999999',
])->exists())->toBeTrue();

// Verify other fields remain null
expect($updatedCarrier->dot_number)->toBeNull();
expect($updatedCarrier->physical_location_id)->toBeNull();
expect($updatedCarrier->contact_email)->toBeNull();
expect($updatedCarrier->contact_phone)->toBeNull();
});

test('it updates carrier contact information', function () {
// Create initial carrier
$carrier = CreateCarrier::run(
name: 'Contact Test Carrier',
);

// Act
$updatedCarrier = UpdateCarrierGeneral::run(
carrier: $carrier,
contact_email: '[email protected]',
contact_phone: '(555) 999-8888',
);

// Assert
expect(DB::table('carriers')->where([
'id' => $carrier->id,
'contact_email' => '[email protected]',
'contact_phone' => '(555) 999-8888',
])->exists())->toBeTrue();
});

test('it updates carrier location', function () {
// Create initial carrier
$carrier = CreateCarrier::run(
name: 'Location Test Carrier',
);

$newLocation = Location::factory()->create();

// Act
$updatedCarrier = UpdateCarrierGeneral::run(
carrier: $carrier,
physical_location_id: $newLocation->id,
);

// Assert
expect($updatedCarrier->physical_location_id)->toBe($newLocation->id);
expect(DB::table('carriers')->where([
'id' => $carrier->id,
'physical_location_id' => $newLocation->id,
])->exists())->toBeTrue();
});

0 comments on commit d4ae9e9

Please sign in to comment.