Add feature tests for CSKH Excel import and database backup CLI commands
This commit is contained in:
1614
package-lock.json
generated
Normal file
1614
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
55
tests/Feature/ExportBackupTest.php
Normal file
55
tests/Feature/ExportBackupTest.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
uses(\Illuminate\Foundation\Testing\RefreshDatabase::class);
|
||||
|
||||
test('export backup command exports database tables to json and writes manifest', function () {
|
||||
// Create some data
|
||||
User::factory()->count(3)->create();
|
||||
Product::create(['name' => 'Sunrise Suite A1', 'status' => 'active']);
|
||||
Product::create(['name' => 'Sunset Suite A2', 'status' => 'active']);
|
||||
|
||||
$backupPath = base_path('tests/Feature/backups_test');
|
||||
|
||||
// Clean backup directory if it exists
|
||||
if (File::isDirectory($backupPath)) {
|
||||
File::deleteDirectory($backupPath);
|
||||
}
|
||||
|
||||
// Run backup command
|
||||
$this->artisan('app:export-backup', [
|
||||
'--path' => $backupPath,
|
||||
'--tables' => 'users,products',
|
||||
'--pretty' => true
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Verify backup folder created
|
||||
$directories = File::directories($backupPath);
|
||||
expect($directories)->toHaveCount(1);
|
||||
|
||||
$backupDir = $directories[0];
|
||||
|
||||
// Verify files created
|
||||
expect(File::exists("{$backupDir}/manifest.json"))->toBeTrue();
|
||||
expect(File::exists("{$backupDir}/users.json"))->toBeTrue();
|
||||
expect(File::exists("{$backupDir}/products.json"))->toBeTrue();
|
||||
|
||||
// Verify manifest contents
|
||||
$manifest = json_decode(File::get("{$backupDir}/manifest.json"), true);
|
||||
expect($manifest['tables']['users'])->toBe(3);
|
||||
expect($manifest['tables']['products'])->toBe(2);
|
||||
expect($manifest['total_rows'])->toBe(5);
|
||||
|
||||
// Verify products contents
|
||||
$productsJson = json_decode(File::get("{$backupDir}/products.json"), true);
|
||||
expect($productsJson)->toHaveCount(2);
|
||||
expect($productsJson[0]['name'])->toBe('Sunrise Suite A1');
|
||||
expect($productsJson[1]['name'])->toBe('Sunset Suite A2');
|
||||
|
||||
// Clean up backup directory
|
||||
File::deleteDirectory($backupPath);
|
||||
});
|
||||
127
tests/Feature/ImportCskhTest.php
Normal file
127
tests/Feature/ImportCskhTest.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Feedback;
|
||||
use App\Models\FeedbackChannel;
|
||||
use App\Models\FeedbackInteraction;
|
||||
use App\Models\Handover;
|
||||
use App\Models\Product;
|
||||
use App\Models\ProductService;
|
||||
use App\Models\User;
|
||||
|
||||
uses(\Illuminate\Foundation\Testing\RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
// Seed a default user since the importer associates interactions with the first user
|
||||
User::factory()->create([
|
||||
'name' => 'Default Agent',
|
||||
'email' => 'agent@test.com',
|
||||
]);
|
||||
|
||||
// Create a default FeedbackChannel (ID 1) which is required by the importer
|
||||
FeedbackChannel::create([
|
||||
'name' => 'Email',
|
||||
'slug' => 'email',
|
||||
'icon' => 'heroicon-o-envelope',
|
||||
'color' => '#3b82f6'
|
||||
]);
|
||||
});
|
||||
|
||||
test('cskh import command processes rows correctly in dry run and active modes', function () {
|
||||
// Create temporary CSV file inside the project directory so WSL has easy access
|
||||
$csvPath = base_path('tests/Feature/cskh_test.csv');
|
||||
|
||||
// Headers: Mã căn hộ, Họ tên KH, BÀN GIÀO CĂN HỘ, TÌNH TRẠNG, HỢP ĐỒNG THUÊ, HĐ HỢP TÁC KINH DOANH, TỰ DOANH, Phí QL, Lịch Sử khách hàng
|
||||
$headers = [
|
||||
'Mã căn hộ',
|
||||
'Họ tên KH',
|
||||
'BÀN GIÀO CĂN HỘ',
|
||||
'TÌNH TRẠNG',
|
||||
'HỢP ĐỒNG THUÊ',
|
||||
'HĐ HỢP TÁC KINH DOANH',
|
||||
'TỰ DOANH',
|
||||
'Phí QL',
|
||||
'Lịch Sử khách hàng'
|
||||
];
|
||||
|
||||
$row1 = [
|
||||
'A1-101',
|
||||
'Nguyen Van A',
|
||||
'{"date":"2026-01-01 00:00:00.000000","timezone_type":3,"timezone":"UTC"}',
|
||||
'Đã bàn giao căn hộ cho KH',
|
||||
'Số HĐ: HĐ-001, Giá: 10M, Thời hạn: 1 năm',
|
||||
'',
|
||||
'',
|
||||
'Đã thu phí QL tháng 1',
|
||||
"KH báo hỏng bóng đèn\nKỹ thuật đã sửa xong"
|
||||
];
|
||||
|
||||
$row2 = [
|
||||
'A1-102',
|
||||
'Tran Thi B',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'HĐ hợp tác BCC-123',
|
||||
'Doanh nghiệp B',
|
||||
'',
|
||||
'Khách hàng thắc mắc hóa đơn tiền nước'
|
||||
];
|
||||
|
||||
$fp = fopen($csvPath, 'w');
|
||||
// Write UTF-8 BOM for Excel support
|
||||
fprintf($fp, chr(0xEF).chr(0xBB).chr(0xBF));
|
||||
fputcsv($fp, $headers);
|
||||
fputcsv($fp, $row1);
|
||||
fputcsv($fp, $row2);
|
||||
fclose($fp);
|
||||
|
||||
// 1. Dry run execution
|
||||
$this->artisan('app:import-cskh', [
|
||||
'file_path' => $csvPath,
|
||||
'--dry-run' => true
|
||||
])
|
||||
->expectsOutputToContain('Total rows in file: 2')
|
||||
->expectsOutputToContain('New Products')
|
||||
->assertExitCode(0);
|
||||
|
||||
// Verify no records created in dry-run
|
||||
expect(Product::count())->toBe(0);
|
||||
expect(Customer::count())->toBe(0);
|
||||
expect(Contract::count())->toBe(0);
|
||||
expect(Handover::count())->toBe(0);
|
||||
expect(ProductService::count())->toBe(0);
|
||||
expect(Feedback::count())->toBe(0);
|
||||
|
||||
// 2. Active run execution
|
||||
$this->artisan('app:import-cskh', [
|
||||
'file_path' => $csvPath
|
||||
])
|
||||
->expectsOutputToContain('Total rows in file: 2')
|
||||
->assertExitCode(0);
|
||||
|
||||
// Verify records created
|
||||
expect(Product::count())->toBe(2);
|
||||
expect(Customer::count())->toBe(2);
|
||||
expect(Contract::count())->toBe(2); // 1 Lease (row1) and 1 BCC (row2)
|
||||
expect(Handover::count())->toBe(1); // row1 has handover, row2 doesn't
|
||||
expect(ProductService::count())->toBe(1); // row2 has Self-Business
|
||||
expect(Feedback::count())->toBe(2); // both have feedback logs
|
||||
expect(FeedbackInteraction::count())->toBe(3); // row1 has 2 lines, row2 has 1 line
|
||||
|
||||
// Verify relationships and fields
|
||||
$productA = Product::where('name', 'A1-101')->first();
|
||||
expect($productA)->not->toBeNull();
|
||||
|
||||
$handover = Handover::where('product_id', $productA->id)->first();
|
||||
expect($handover)->not->toBeNull();
|
||||
expect($handover->handover_date)->toBe('2026-01-01');
|
||||
|
||||
$contract = Contract::where('product_id', $productA->id)->first();
|
||||
expect($contract)->not->toBeNull();
|
||||
expect($contract->type)->toBe('lease'); // type is a string 'lease'
|
||||
|
||||
// Clean up temporary file
|
||||
@unlink($csvPath);
|
||||
});
|
||||
Reference in New Issue
Block a user