Skip to content

Commit f01b140

Browse files
authored
[IP-99]: Uploads / Imports for Clients, Payments, Invoices, etcetera (#100)
* Making export possible refs #85 * Some more Export tests refs #85 * Some more Import tests refs #99
1 parent 7db3afb commit f01b140

File tree

5 files changed

+1340
-0
lines changed

5 files changed

+1340
-0
lines changed
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
<?php
2+
3+
namespace Modules\Clients\Feature\Modules;
4+
5+
use Illuminate\Foundation\Testing\RefreshDatabase;
6+
use Livewire\Livewire;
7+
use Modules\Clients\Filament\Company\Resources\Contacts\Pages\ListContacts;
8+
use Modules\Clients\Models\Contact;
9+
use Modules\Core\Tests\AbstractCompanyPanelTestCase;
10+
use PHPUnit\Framework\Attributes\Group;
11+
use PHPUnit\Framework\Attributes\Test;
12+
13+
class ClientsExportImportTest extends AbstractCompanyPanelTestCase
14+
{
15+
use RefreshDatabase;
16+
17+
#[Test]
18+
#[Group('export')]
19+
public function export_contacts_downloads_csv_with_correct_data(): void
20+
{
21+
/* Arrange */
22+
$contacts = Contact::factory()->for($this->company)->count(3)->create();
23+
24+
/* Act */
25+
$component = Livewire::actingAs($this->user)
26+
->test(ListContacts::class)
27+
->mountAction('export')
28+
->callMountedAction();
29+
$response = $component->lastResponse;
30+
31+
/* Assert */
32+
$this->assertEquals(200, $response->status());
33+
$this->assertTrue(
34+
in_array(
35+
$response->headers->get('content-type'),
36+
[
37+
'text/csv',
38+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
39+
]
40+
)
41+
);
42+
$content = $response->getContent();
43+
$lines = preg_split('/\r?\n/', mb_trim($content));
44+
$this->assertGreaterThanOrEqual(2, count($lines));
45+
$this->assertCount($contacts->count() + 1, $lines);
46+
foreach ($contacts as $contact) {
47+
$this->assertStringContainsString($contact->name, $content);
48+
}
49+
}
50+
51+
#[Test]
52+
#[Group('export')]
53+
public function export_contacts_downloads_excel_with_correct_data(): void
54+
{
55+
/* Arrange */
56+
$contacts = Contact::factory()->for($this->company)->count(3)->create();
57+
58+
/* Act */
59+
$component = Livewire::actingAs($this->user)
60+
->test(ListContacts::class)
61+
->mountAction('export', ['format' => 'xlsx'])
62+
->callMountedAction();
63+
$response = $component->lastResponse;
64+
65+
/* Assert */
66+
$this->assertEquals(200, $response->status());
67+
$this->assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $response->headers->get('content-type'));
68+
$content = $response->getContent();
69+
// Check for XLSX file signature (PK\x03\x04)
70+
$this->assertStringStartsWith('PK', $content);
71+
}
72+
73+
#[Test]
74+
#[Group('export')]
75+
public function export_contacts_with_no_records(): void
76+
{
77+
/* Arrange */
78+
// No contacts created
79+
80+
/* Act */
81+
$component = Livewire::actingAs($this->user)
82+
->test(ListContacts::class)
83+
->mountAction('export')
84+
->callMountedAction();
85+
$response = $component->lastResponse;
86+
87+
/* Assert */
88+
$this->assertEquals(200, $response->status());
89+
$content = $response->getContent();
90+
$lines = preg_split('/\r?\n/', mb_trim($content));
91+
$this->assertGreaterThanOrEqual(1, count($lines)); // Only header row
92+
}
93+
94+
#[Test]
95+
#[Group('export')]
96+
public function export_contacts_with_special_characters(): void
97+
{
98+
/* Arrange */
99+
$contacts = Contact::factory()->for($this->company)->for($this->company)->create(['name' => 'Jöhn Dœ, "Test"', 'email' => '[email protected]']);
100+
101+
/* Act */
102+
$component = Livewire::actingAs($this->user)
103+
->test(ListContacts::class)
104+
->mountAction('export')
105+
->callMountedAction();
106+
$response = $component->lastResponse;
107+
108+
/* Assert */
109+
$this->assertEquals(200, $response->status());
110+
$content = $response->getContent();
111+
$this->assertStringContainsString('Jöhn Dœ', $content);
112+
$this->assertStringContainsString('"Test"', $content);
113+
$this->assertStringContainsString('[email protected]', $content);
114+
}
115+
116+
#[Test]
117+
#[Group('import')]
118+
public function import_contacts_with_empty_file(): void
119+
{
120+
/* Arrange */
121+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', '');
122+
123+
/* Act */
124+
Livewire::actingAs($this->user)
125+
->test(ListContacts::class)
126+
->mountAction('import')
127+
->set('data.file', $file)
128+
->callMountedAction();
129+
130+
/* Assert */
131+
$this->assertDatabaseCount('contacts', 0);
132+
}
133+
134+
#[Test]
135+
#[Group('import')]
136+
public function import_contacts_with_only_headers(): void
137+
{
138+
/* Arrange */
139+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', "name,email\n");
140+
141+
/* Act */
142+
Livewire::actingAs($this->user)
143+
->test(ListContacts::class)
144+
->mountAction('import')
145+
->set('data.file', $file)
146+
->callMountedAction();
147+
148+
/* Assert */
149+
$this->assertDatabaseCount('contacts', 0);
150+
}
151+
152+
#[Test]
153+
#[Group('import')]
154+
public function import_contacts_with_invalid_columns(): void
155+
{
156+
/* Arrange */
157+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', "foo,bar\nabc,def\n");
158+
159+
/* Act */
160+
$component = Livewire::actingAs($this->user)
161+
->test(ListContacts::class)
162+
->mountAction('import')
163+
->set('data.file', $file)
164+
->callMountedAction();
165+
166+
/* Assert */
167+
$this->assertDatabaseCount('contacts', 0);
168+
// Optionally, assert error message if your import action provides one
169+
}
170+
171+
#[Test]
172+
#[Group('import')]
173+
public function import_contacts_with_duplicate_records(): void
174+
{
175+
/* Arrange */
176+
$csv = "name,email\nDup User,[email protected]\nDup User,[email protected]\n";
177+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', $csv);
178+
179+
/* Act */
180+
Livewire::actingAs($this->user)
181+
->test(ListContacts::class)
182+
->mountAction('import')
183+
->set('data.file', $file)
184+
->callMountedAction();
185+
186+
/* Assert */
187+
$this->assertDatabaseCount('contacts', 2); // or 1 if your import deduplicates
188+
}
189+
190+
#[Test]
191+
#[Group('import')]
192+
public function import_contacts_with_invalid_data_types(): void
193+
{
194+
/* Arrange */
195+
$csv = "name,email\n12345,not-an-email\n";
196+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', $csv);
197+
198+
/* Act */
199+
$component = Livewire::actingAs($this->user)
200+
->test(ListContacts::class)
201+
->mountAction('import')
202+
->set('data.file', $file)
203+
->callMountedAction();
204+
205+
/* Assert */
206+
// Depending on your validation, this may fail or create a record
207+
$this->assertDatabaseHas('contacts', ['name' => '12345', 'email' => 'not-an-email']);
208+
}
209+
210+
#[Test]
211+
#[Group('import')]
212+
public function import_contacts_with_large_file(): void
213+
{
214+
/* Arrange */
215+
$rows = [];
216+
for ($i = 0; $i < 1000; $i++) {
217+
$rows[] = "User{$i},user{$i}@example.com";
218+
}
219+
$csv = "name,email\n" . implode("\n", $rows);
220+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', $csv);
221+
222+
/* Act */
223+
Livewire::actingAs($this->user)
224+
->test(ListContacts::class)
225+
->mountAction('import')
226+
->set('data.file', $file)
227+
->callMountedAction();
228+
229+
/* Assert */
230+
$this->assertDatabaseCount('contacts', 1000);
231+
}
232+
233+
#[Test]
234+
#[Group('import')]
235+
public function import_contacts_with_extra_columns(): void
236+
{
237+
/* Arrange */
238+
$csv = "name,email,extra\nExtra User,[email protected],something\n";
239+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', $csv);
240+
241+
/* Act */
242+
Livewire::actingAs($this->user)
243+
->test(ListContacts::class)
244+
->mountAction('import')
245+
->set('data.file', $file)
246+
->callMountedAction();
247+
248+
/* Assert */
249+
$this->assertDatabaseHas('contacts', ['name' => 'Extra User', 'email' => '[email protected]']);
250+
}
251+
252+
#[Test]
253+
#[Group('import')]
254+
public function import_contacts_with_missing_required_columns(): void
255+
{
256+
/* Arrange */
257+
$csv = "name\nMissing Email\n";
258+
$file = \Illuminate\Http\UploadedFile::fake()->createWithContent('contacts.csv', $csv);
259+
260+
/* Act */
261+
$component = Livewire::actingAs($this->user)
262+
->test(ListContacts::class)
263+
->mountAction('import')
264+
->set('data.file', $file)
265+
->callMountedAction();
266+
267+
/* Assert */
268+
// Should not create a record if email is required
269+
$this->assertDatabaseCount('contacts', 0);
270+
}
271+
}

0 commit comments

Comments
 (0)