| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- <?php
- use Illuminate\Http\UploadedFile;
- use Illuminate\Support\Facades\Storage;
- use Webkul\DataTransfer\Models\Import;
- use function Pest\Laravel\deleteJson;
- use function Pest\Laravel\get;
- use function Pest\Laravel\postJson;
- use function Pest\Laravel\putJson;
- beforeEach(function () {
- Storage::fake('private');
- });
- it('should return the data transfer imports index page', function () {
- // Act and Assert.
- $this->loginAsAdmin();
- get(route('admin.settings.data_transfer.imports.index'))
- ->assertOk()
- ->assertSeeText(trans('admin::app.settings.data-transfer.imports.index.title'));
- });
- it('should return the create page of data transfer import', function () {
- // Act and Assert.
- $this->loginAsAdmin();
- get(route('admin.settings.data_transfer.imports.create'))
- ->assertOk()
- ->assertSeeText(trans('admin::app.settings.data-transfer.imports.create.title'));
- });
- it('should fail validation when required fields are not provided when storing import', function () {
- // Act and Assert.
- $this->loginAsAdmin();
- postJson(route('admin.settings.data_transfer.imports.store'))
- ->assertJsonValidationErrorFor('type')
- ->assertJsonValidationErrorFor('action')
- ->assertJsonValidationErrorFor('validation_strategy')
- ->assertJsonValidationErrorFor('allowed_errors')
- ->assertJsonValidationErrorFor('field_separator')
- ->assertJsonValidationErrorFor('file')
- ->assertUnprocessable();
- });
- it('should fail validation with invalid file type when storing import', function () {
- // Arrange
- $file = UploadedFile::fake()->create('invalid.txt', 100, 'text/plain');
- // Act and Assert.
- $this->loginAsAdmin();
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertJsonValidationErrorFor('file')
- ->assertUnprocessable();
- });
- it('should successfully store import with CSV file', function () {
- // Arrange
- Storage::fake('private');
- $csvContent = "email,first_name,last_name\njohn@example.com,John,Doe";
- $file = UploadedFile::fake()->createWithContent('customers.csv', $csvContent);
- // Act and Assert.
- $this->loginAsAdmin();
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'customers',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertRedirect()
- ->assertSessionHas('success');
- $this->assertDatabaseHas('imports', [
- 'type' => 'customers',
- 'action' => 'append',
- 'state' => 'pending',
- ]);
- });
- it('should accept CSV file with text/plain MIME type (small files)', function () {
- // Arrange
- Storage::fake('private');
- $csvContent = "id,name\n1,Test";
- $file = UploadedFile::fake()->createWithContent('test.csv', $csvContent);
- // Act and Assert.
- $this->loginAsAdmin();
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 0,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertRedirect()
- ->assertSessionHas('success');
- });
- it('should successfully store import with XML file', function () {
- // Arrange
- Storage::fake('private');
- $xmlContent = '<?xml version="1.0"?><customers><customer email="test@example.com"/></customers>';
- $file = UploadedFile::fake()->createWithContent('customers.xml', $xmlContent);
- // Act and Assert.
- $this->loginAsAdmin();
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'customers',
- 'action' => 'delete',
- 'validation_strategy' => 'skip-errors',
- 'allowed_errors' => 5,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertRedirect()
- ->assertSessionHas('success');
- $this->assertDatabaseHas('imports', [
- 'type' => 'customers',
- 'action' => 'delete',
- ]);
- });
- it('should return the edit page for an existing import', function () {
- // Arrange
- $import = Import::create([
- 'type' => 'products',
- 'state' => 'pending',
- 'file_path' => 'imports/test.csv',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- ]);
- // Act and Assert.
- $this->loginAsAdmin();
- get(route('admin.settings.data_transfer.imports.edit', $import->id))
- ->assertOk()
- ->assertSeeText(trans('admin::app.settings.data-transfer.imports.edit.title'));
- });
- it('should successfully update an existing import', function () {
- // Arrange
- Storage::fake('private');
- $import = Import::create([
- 'type' => 'products',
- 'state' => 'pending',
- 'file_path' => 'imports/old.csv',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- ]);
- $csvContent = "sku,name\nSKU-001,Product 1";
- $newFile = UploadedFile::fake()->createWithContent('products.csv', $csvContent);
- // Act and Assert.
- $this->loginAsAdmin();
- putJson(route('admin.settings.data_transfer.imports.update', $import->id), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 15,
- 'field_separator' => ',',
- 'file' => $newFile,
- ])
- ->assertRedirect()
- ->assertSessionHas('success');
- $import->refresh();
- expect($import->allowed_errors)->toBe(15);
- expect($import->state)->toBe('pending');
- });
- it('should allow updating import without providing a new file', function () {
- // Arrange
- Storage::fake('private');
- $import = Import::create([
- 'type' => 'customers',
- 'state' => 'pending',
- 'file_path' => 'imports/existing.csv',
- 'allowed_errors' => 10,
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'field_separator' => ',',
- ]);
- // Act and Assert.
- $this->loginAsAdmin();
- putJson(route('admin.settings.data_transfer.imports.update', $import->id), [
- 'type' => 'customers',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 20,
- 'field_separator' => ',',
- ])
- ->assertRedirect()
- ->assertSessionHas('success');
- $import->refresh();
- expect($import->allowed_errors)->toBe(20);
- expect($import->file_path)->toBe('imports/existing.csv');
- });
- it('should successfully delete an import', function () {
- // Arrange
- Storage::fake('private');
- $import = Import::create([
- 'type' => 'products',
- 'file_path' => 'imports/test.csv',
- 'state' => 'pending',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- ]);
- Storage::disk('private')->put($import->file_path, 'test content');
- // Act and Assert.
- $this->loginAsAdmin();
- deleteJson(route('admin.settings.data_transfer.imports.delete', $import->id))
- ->assertOk()
- ->assertJsonFragment(['message' => trans('admin::app.settings.data-transfer.imports.delete-success')]);
- $this->assertDatabaseMissing('imports', [
- 'id' => $import->id,
- ]);
- });
- it('should return import page with stats', function () {
- // Arrange
- $import = Import::create([
- 'type' => 'customers',
- 'state' => 'pending',
- 'file_path' => 'imports/customers.csv',
- 'processed_rows_count' => 0,
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- ]);
- // Act and Assert.
- $this->loginAsAdmin();
- get(route('admin.settings.data_transfer.imports.import', $import->id))
- ->assertOk()
- ->assertSeeText($import->type);
- });
- it('should validate action field with correct syntax', function () {
- // Arrange
- Storage::fake('private');
- $file = UploadedFile::fake()->createWithContent('test.csv', 'data');
- // Act and Assert
- $this->loginAsAdmin();
- // Valid action values should pass
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertRedirect();
- // Invalid action value should fail
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'invalid_action',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertJsonValidationErrorFor('action')
- ->assertUnprocessable();
- });
- it('should validate validation_strategy field with correct syntax', function () {
- // Arrange
- Storage::fake('private');
- $file = UploadedFile::fake()->createWithContent('test.csv', 'data');
- // Act and Assert
- $this->loginAsAdmin();
- // Valid validation_strategy values should pass
- foreach (['stop-on-errors', 'skip-errors'] as $strategy) {
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => $strategy,
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertRedirect();
- }
- // Invalid validation_strategy value should fail
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => 'invalid_strategy',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertJsonValidationErrorFor('validation_strategy')
- ->assertUnprocessable();
- });
- it('should accept all supported file formats', function () {
- // Arrange
- Storage::fake('private');
- $this->loginAsAdmin();
- $formats = [
- 'csv' => 'text/csv',
- 'xml' => 'text/xml',
- 'xls' => 'application/vnd.ms-excel',
- 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
- ];
- foreach ($formats as $extension => $mimeType) {
- $file = UploadedFile::fake()->create("test.{$extension}", 100, $mimeType);
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertRedirect();
- }
- });
- it('should handle process_in_queue option correctly', function () {
- // Arrange
- Storage::fake('private');
- $this->loginAsAdmin();
- // Test with process_in_queue enabled
- $file = UploadedFile::fake()->createWithContent('queue_test.csv', 'test data content');
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'customers',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- 'process_in_queue' => 1,
- ])
- ->assertRedirect()
- ->assertSessionHas('success');
- // Verify the import with process_in_queue = 1 exists
- $importWithQueue = Import::where('process_in_queue', 1)->latest()->first();
- expect($importWithQueue)->not->toBeNull();
- expect($importWithQueue->process_in_queue)->toBe(1);
- expect($importWithQueue->type)->toBe('customers');
- // Test without process_in_queue (should default to 0)
- $file2 = UploadedFile::fake()->createWithContent('no_queue_test.csv', 'different test data');
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'delete',
- 'validation_strategy' => 'skip-errors',
- 'allowed_errors' => 5,
- 'field_separator' => ';',
- 'file' => $file2,
- ])
- ->assertRedirect();
- // Verify the import without process_in_queue defaults to 0
- $importWithoutQueue = Import::where('type', 'products')
- ->where('action', 'delete')
- ->where('field_separator', ';')
- ->latest()
- ->first();
- expect($importWithoutQueue)->not->toBeNull();
- expect($importWithoutQueue->process_in_queue)->toBe(0);
- });
- it('should sanitize filename when storing import', function () {
- // Arrange
- Storage::fake('private');
- $file = UploadedFile::fake()->createWithContent('../../malicious.csv', 'data');
- // Act and Assert
- $this->loginAsAdmin();
- postJson(route('admin.settings.data_transfer.imports.store'), [
- 'type' => 'products',
- 'action' => 'append',
- 'validation_strategy' => 'stop-on-errors',
- 'allowed_errors' => 10,
- 'field_separator' => ',',
- 'file' => $file,
- ])
- ->assertRedirect();
- $import = Import::latest()->first();
- // Verify the filename is sanitized (contains hash and unique ID)
- expect($import->file_path)->toContain('imports/');
- expect($import->file_path)->not()->toContain('../');
- });
|