465 lines
18 KiB
PHP
465 lines
18 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\User;
|
|
use App\Models\Person;
|
|
use App\Models\Photo;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Foundation\Testing\WithFaker;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Laravel\Sanctum\Sanctum;
|
|
use Tests\TestCase;
|
|
|
|
class MigrantPhotoTest extends TestCase
|
|
{
|
|
use RefreshDatabase, WithFaker;
|
|
|
|
/**
|
|
* Set up authentication for each test
|
|
*/
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// Create and authenticate as admin user for all tests
|
|
$user = User::factory()->create([
|
|
'email' => 'test.admin@example.com',
|
|
'is_admin' => true
|
|
]);
|
|
|
|
Sanctum::actingAs($user, ['*']);
|
|
}
|
|
|
|
/**
|
|
* Test creating a migrant with multiple photos and setting one as profile.
|
|
*/
|
|
public function test_can_create_migrant_with_multiple_photos_and_set_profile(): void
|
|
{
|
|
// Create fake storage disk for testing
|
|
Storage::fake('public');
|
|
|
|
// Create test photo files (using create instead of image to avoid GD dependency)
|
|
$photo1 = UploadedFile::fake()->create('photo1.jpg', 100, 'image/jpeg');
|
|
$photo2 = UploadedFile::fake()->create('photo2.jpg', 100, 'image/jpeg');
|
|
$photo3 = UploadedFile::fake()->create('photo3.jpg', 100, 'image/jpeg');
|
|
|
|
// Create migrant data
|
|
$migrantData = [
|
|
'surname' => $this->faker->lastName,
|
|
'christian_name' => $this->faker->firstName,
|
|
'date_of_birth' => $this->faker->date(),
|
|
'place_of_birth' => $this->faker->city,
|
|
'occupation' => $this->faker->jobTitle,
|
|
'id_card_no' => (string)$this->faker->unique()->randomNumber(6),
|
|
'migration' => [
|
|
'date_of_arrival_aus' => $this->faker->date(),
|
|
'date_of_arrival_nt' => $this->faker->date(),
|
|
'arrival_period' => '1950-1960',
|
|
],
|
|
// Add photos to the request
|
|
'photos' => [$photo1, $photo2, $photo3],
|
|
'captions' => ['First photo', 'Second photo', 'Third photo'],
|
|
'set_as_profile' => 1, // Set the first photo as profile
|
|
];
|
|
|
|
// Make the API request to create a migrant with photos
|
|
$response = $this->postJson('/api/migrants', $migrantData);
|
|
|
|
// Assert the response is successful
|
|
$response->assertStatus(201)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'data' => [
|
|
'person',
|
|
'uploaded_photos',
|
|
],
|
|
'message',
|
|
])
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Person created successfully',
|
|
]);
|
|
|
|
// Get the created person ID
|
|
$personId = $response->json('data.person.person_id');
|
|
|
|
// Assert that the person was created in the database
|
|
$this->assertDatabaseHas('person', [
|
|
'surname' => $migrantData['surname'],
|
|
'christian_name' => $migrantData['christian_name'],
|
|
]);
|
|
|
|
// Assert that 3 photos were created for this person
|
|
$this->assertEquals(3, Photo::where('person_id', $personId)->count());
|
|
|
|
// Assert that exactly one photo is set as profile
|
|
$this->assertEquals(1, Photo::where('person_id', $personId)
|
|
->where('is_profile_photo', true)
|
|
->count());
|
|
|
|
// Get the profile photo
|
|
$profilePhoto = Photo::where('person_id', $personId)
|
|
->where('is_profile_photo', true)
|
|
->first();
|
|
|
|
// Assert that the first photo is the profile (based on caption)
|
|
$this->assertEquals('First photo', $profilePhoto->caption);
|
|
|
|
// Assert that the files were stored in the storage
|
|
foreach (Photo::where('person_id', $personId)->get() as $photo) {
|
|
Storage::disk('public')->assertExists('photos/' . $personId . '/' . $photo->filename);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test updating the profile photo of an existing migrant.
|
|
*/
|
|
public function test_can_change_profile_photo(): void
|
|
{
|
|
// Create fake storage disk for testing
|
|
Storage::fake('public');
|
|
|
|
// Create a migrant
|
|
$person = Person::factory()->create();
|
|
|
|
// Create three photos for this migrant
|
|
$photos = [];
|
|
$captions = ['Photo 1', 'Photo 2', 'Photo 3'];
|
|
|
|
for ($i = 0; $i < 3; $i++) {
|
|
$filename = "photo{$i}.jpg";
|
|
$file = UploadedFile::fake()->create($filename, 100, 'image/jpeg');
|
|
|
|
// Upload the file to the storage
|
|
$path = $file->storeAs("photos/{$person->person_id}", $filename, 'public');
|
|
|
|
// Create the photo record
|
|
$photo = Photo::create([
|
|
'person_id' => $person->person_id,
|
|
'filename' => $filename,
|
|
'original_filename' => $filename,
|
|
'file_path' => Storage::url($path),
|
|
'mime_type' => 'image/jpeg',
|
|
'file_size' => $file->getSize() / 1024,
|
|
'caption' => $captions[$i],
|
|
'is_profile_photo' => $i === 0 // Make the first one the profile initially
|
|
]);
|
|
|
|
$photos[] = $photo;
|
|
}
|
|
|
|
// Now try to set the second photo as the profile
|
|
$response = $this->postJson("/api/migrants/photos/{$photos[1]->id}/set-as-profile");
|
|
|
|
// Assert response is successful
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Profile photo set successfully',
|
|
]);
|
|
|
|
// Assert that now the second photo is the profile
|
|
$this->assertDatabaseHas('photos', [
|
|
'id' => $photos[1]->id,
|
|
'is_profile_photo' => true
|
|
]);
|
|
|
|
// Assert that the first photo is no longer the profile
|
|
$this->assertDatabaseHas('photos', [
|
|
'id' => $photos[0]->id,
|
|
'is_profile_photo' => false
|
|
]);
|
|
|
|
// Assert that only one photo is set as profile
|
|
$this->assertEquals(1, Photo::where('person_id', $person->person_id)
|
|
->where('is_profile_photo', true)
|
|
->count());
|
|
}
|
|
|
|
/**
|
|
* Test updating a migrant with photo operations (upload, set as profile, remove).
|
|
*/
|
|
public function test_can_update_migrant_with_photo_operations(): void
|
|
{
|
|
// Create fake storage disk for testing
|
|
Storage::fake('public');
|
|
|
|
// Create a migrant
|
|
$person = Person::factory()->create([
|
|
'surname' => 'Smith',
|
|
'christian_name' => 'John',
|
|
'occupation' => 'Teacher'
|
|
]);
|
|
|
|
// Create two existing photos for this migrant
|
|
$photos = [];
|
|
$captions = ['Existing Photo 1', 'Existing Photo 2'];
|
|
|
|
for ($i = 0; $i < 2; $i++) {
|
|
$filename = "existing_photo{$i}.jpg";
|
|
$file = UploadedFile::fake()->create($filename, 100, 'image/jpeg');
|
|
|
|
// Upload the file to the storage
|
|
$path = $file->storeAs("photos/{$person->person_id}", $filename, 'public');
|
|
|
|
// Create the photo record
|
|
$photo = Photo::create([
|
|
'person_id' => $person->person_id,
|
|
'filename' => $filename,
|
|
'original_filename' => $filename,
|
|
'file_path' => Storage::url($path),
|
|
'mime_type' => 'image/jpeg',
|
|
'file_size' => $file->getSize() / 1024,
|
|
'caption' => $captions[$i],
|
|
'is_profile_photo' => $i === 0 // Make the first one the profile initially
|
|
]);
|
|
|
|
$photos[] = $photo;
|
|
}
|
|
|
|
// Create a new photo to upload during the update
|
|
$newPhoto = UploadedFile::fake()->create('new_photo.jpg', 100, 'image/jpeg');
|
|
|
|
// Prepare update data
|
|
$updateData = [
|
|
'surname' => 'Smith-Jones', // Update the surname
|
|
'occupation' => 'Professor', // Update the occupation
|
|
'photos' => [$newPhoto], // Upload a new photo
|
|
'captions' => ['New Profile Photo'], // Caption for the new photo
|
|
'set_as_profile' => true, // Set the new photo as profile
|
|
'profile_photo_index' => 0, // Set the first (and only) new photo as profile
|
|
'existing_photos' => [
|
|
// Update caption of the first photo
|
|
[
|
|
'id' => $photos[0]->id,
|
|
'caption' => 'Updated Caption'
|
|
],
|
|
// Remove the second photo (we'll handle this after the update)
|
|
]
|
|
];
|
|
|
|
// Make the API request to update the migrant
|
|
$response = $this->putJson("/api/migrants/{$person->person_id}", $updateData);
|
|
|
|
// Assert the response is successful
|
|
$response->assertStatus(200)
|
|
->assertJsonStructure([
|
|
'success',
|
|
'data' => [
|
|
'person',
|
|
'uploaded_photos',
|
|
],
|
|
'message',
|
|
])
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Person updated successfully',
|
|
]);
|
|
|
|
// Assert the person data was updated
|
|
$this->assertDatabaseHas('person', [
|
|
'person_id' => $person->person_id,
|
|
'surname' => 'Smith-Jones',
|
|
'occupation' => 'Professor'
|
|
]);
|
|
|
|
// Assert that we now have 3 photos (2 existing + 1 new)
|
|
$this->assertEquals(3, Photo::where('person_id', $person->person_id)->count());
|
|
|
|
// Assert that the caption of the first photo was updated
|
|
$this->assertDatabaseHas('photos', [
|
|
'id' => $photos[0]->id,
|
|
'caption' => 'Updated Caption'
|
|
]);
|
|
|
|
// Assert that the new photo was set as profile
|
|
$profilePhoto = Photo::where('person_id', $person->person_id)
|
|
->where('is_profile_photo', true)
|
|
->first();
|
|
$this->assertEquals('New Profile Photo', $profilePhoto->caption);
|
|
|
|
// Assert that the old profile photo is no longer the profile
|
|
$this->assertDatabaseHas('photos', [
|
|
'id' => $photos[0]->id,
|
|
'is_profile_photo' => false
|
|
]);
|
|
|
|
// Now test removing a photo
|
|
$photoToRemove = $photos[1]->id;
|
|
$response = $this->deleteJson("/api/migrants/photos/{$photoToRemove}");
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Photo deleted successfully',
|
|
]);
|
|
|
|
// Assert that the photo was removed from the database
|
|
$this->assertDatabaseMissing('photos', [
|
|
'id' => $photoToRemove
|
|
]);
|
|
|
|
// Assert that the file was removed from storage
|
|
Storage::disk('public')->assertMissing('photos/' . $person->person_id . '/' . $photos[1]->filename);
|
|
|
|
// Assert that we now have 2 photos (originally 2 + 1 new - 1 deleted)
|
|
$this->assertEquals(2, Photo::where('person_id', $person->person_id)->count());
|
|
}
|
|
|
|
/**
|
|
* Test adding a single photo, then multiple photos, and finally deleting photos
|
|
*/
|
|
public function test_can_add_single_and_multiple_photos_and_delete_them(): void
|
|
{
|
|
// Create fake storage disk for testing
|
|
Storage::fake('public');
|
|
|
|
// Create a migrant without photos first
|
|
$migrantData = [
|
|
'surname' => $this->faker->lastName,
|
|
'christian_name' => $this->faker->firstName,
|
|
'date_of_birth' => $this->faker->date(),
|
|
'place_of_birth' => $this->faker->city,
|
|
'occupation' => $this->faker->jobTitle,
|
|
'id_card_no' => (string)$this->faker->unique()->randomNumber(6),
|
|
'migration' => [
|
|
'date_of_arrival_aus' => $this->faker->date(),
|
|
'date_of_arrival_nt' => $this->faker->date(),
|
|
'arrival_period' => '1950-1960',
|
|
]
|
|
];
|
|
|
|
// 1. Create a migrant without any photos
|
|
$response = $this->postJson('/api/migrants', $migrantData);
|
|
|
|
// Assert the response is successful
|
|
$response->assertStatus(201)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Person created successfully',
|
|
]);
|
|
|
|
// Get the created person ID
|
|
$personId = $response->json('data.person.person_id');
|
|
$person = Person::find($personId);
|
|
|
|
// Assert that no photos exist for this person yet
|
|
$this->assertEquals(0, Photo::where('person_id', $personId)->count());
|
|
|
|
// 2. Now add a single photo and set it as profile
|
|
$singlePhoto = UploadedFile::fake()->create('single_photo.jpg', 100, 'image/jpeg');
|
|
$updateData = [
|
|
'photos' => [$singlePhoto],
|
|
'captions' => ['My First Photo'],
|
|
'set_as_profile' => true,
|
|
'profile_photo_index' => 0
|
|
];
|
|
|
|
$response = $this->putJson("/api/migrants/{$personId}", $updateData);
|
|
|
|
// Assert the response is successful
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Person updated successfully',
|
|
]);
|
|
|
|
// Assert that 1 photo was added
|
|
$this->assertEquals(1, Photo::where('person_id', $personId)->count());
|
|
|
|
// Assert that the photo is set as profile
|
|
$this->assertEquals(1, Photo::where('person_id', $personId)
|
|
->where('is_profile_photo', true)
|
|
->count());
|
|
|
|
// Get the photo details
|
|
$firstPhoto = Photo::where('person_id', $personId)->first();
|
|
$this->assertEquals('My First Photo', $firstPhoto->caption);
|
|
$this->assertTrue($firstPhoto->is_profile_photo);
|
|
|
|
// Assert the file was stored
|
|
Storage::disk('public')->assertExists('photos/' . $personId . '/' . $firstPhoto->filename);
|
|
|
|
// 3. Now add multiple additional photos and set one as profile
|
|
$photo1 = UploadedFile::fake()->create('additional1.jpg', 100, 'image/jpeg');
|
|
$photo2 = UploadedFile::fake()->create('additional2.jpg', 100, 'image/jpeg');
|
|
$photo3 = UploadedFile::fake()->create('additional3.jpg', 100, 'image/jpeg');
|
|
|
|
$updateData = [
|
|
'photos' => [$photo1, $photo2, $photo3],
|
|
'captions' => ['Additional 1', 'Additional 2', 'Additional 3'],
|
|
'set_as_profile' => true,
|
|
'profile_photo_index' => 1 // Set the second new photo as profile
|
|
];
|
|
|
|
$response = $this->putJson("/api/migrants/{$personId}", $updateData);
|
|
|
|
// Assert the response is successful
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Person updated successfully',
|
|
]);
|
|
|
|
// Assert that we now have 4 photos (1 existing + 3 new)
|
|
$this->assertEquals(4, Photo::where('person_id', $personId)->count());
|
|
|
|
// Get all photos for this person
|
|
$photos = Photo::where('person_id', $personId)->get();
|
|
|
|
// Assert that exactly one photo is set as profile
|
|
$this->assertEquals(1, $photos->where('is_profile_photo', true)->count());
|
|
|
|
// Find the profile photo
|
|
$profilePhoto = $photos->where('is_profile_photo', true)->first();
|
|
|
|
// Assert that the second new photo was set as profile
|
|
$this->assertEquals('Additional 2', $profilePhoto->caption);
|
|
|
|
// Assert the first photo is no longer the profile
|
|
$this->assertFalse($firstPhoto->fresh()->is_profile_photo);
|
|
|
|
// 4. Change the profile photo using profile_photo_id (existing photo)
|
|
$nonProfilePhoto = $photos->where('caption', 'Additional 1')->first();
|
|
|
|
$updateData = [
|
|
'set_as_profile' => true,
|
|
'profile_photo_id' => $nonProfilePhoto->id
|
|
];
|
|
|
|
$response = $this->putJson("/api/migrants/{$personId}", $updateData);
|
|
|
|
// Assert the response is successful
|
|
$response->assertStatus(200);
|
|
|
|
// Assert that the specified photo is now the profile
|
|
$this->assertTrue($nonProfilePhoto->fresh()->is_profile_photo);
|
|
$this->assertFalse($profilePhoto->fresh()->is_profile_photo);
|
|
|
|
// 5. Delete photos one by one
|
|
$photosToDelete = $photos->whereNotIn('caption', ['Additional 1'])->pluck('id');
|
|
|
|
foreach ($photosToDelete as $photoId) {
|
|
$response = $this->deleteJson("/api/migrants/photos/{$photoId}");
|
|
|
|
$response->assertStatus(200)
|
|
->assertJson([
|
|
'success' => true,
|
|
'message' => 'Photo deleted successfully',
|
|
]);
|
|
|
|
// Assert the photo was removed from the database
|
|
$this->assertDatabaseMissing('photos', [
|
|
'id' => $photoId
|
|
]);
|
|
}
|
|
|
|
// Assert that only one photo remains (the profile photo)
|
|
$this->assertEquals(1, Photo::where('person_id', $personId)->count());
|
|
$this->assertEquals('Additional 1', Photo::where('person_id', $personId)->first()->caption);
|
|
$this->assertTrue(Photo::where('person_id', $personId)->first()->is_profile_photo);
|
|
}
|
|
}
|