Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Modules/Core/Tests/Unit/DateFieldAutoPopulationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,4 +355,5 @@ public function it_filters_numberings_by_current_company_id(): void
$this->assertCount(1, $otherCompanyGroups, 'Other company should have its document group');
$this->assertEquals($otherCompanyDocGroup->id, $otherCompanyGroups->first()->id);
}

}
40 changes: 29 additions & 11 deletions Modules/Core/Tests/Unit/DateHelpersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,65 @@ class DateHelpersTest extends AbstractTestCase
#[Test]
public function it_format_date_returns_formatted_date(): void
{
$this->markTestIncomplete();

/* arrange */
$date = Carbon::create(2025, 7, 14);
$this->assertEquals('2025-07-14', DateHelpers::formatDate($date));

/* act */
$result = DateHelpers::formatDate($date);

/* assert */
$this->assertEquals('2025-07-14', $result);
}

#[Test]
public function it_format_date_returns_dash_for_null(): void
{
$this->markTestIncomplete();
/* arrange */
$date = null;

/* act */
$result = DateHelpers::formatDate($date);

$this->assertEquals('-', DateHelpers::formatDate(null));
/* assert */
$this->assertEquals('-', $result);
}

#[Test]
public function it_format_since_returns_since_for_past_date(): void
{
$this->markTestIncomplete();
/* arrange */
$date = now()->subDays(3);

$date = now()->subDays(3);
/* act */
$result = DateHelpers::formatSince($date);

/* assert */
$this->assertStringContainsString('ago', $result);
}

#[Test]
public function it_format_since_returns_in_for_future_date(): void
{
$this->markTestIncomplete();
/* arrange */
$date = now()->addDays(5);

$date = now()->addDays(5);
/* act */
$result = DateHelpers::formatSince($date);

/* assert */
$this->assertStringContainsString('in', $result);
}

#[Test]
public function it_format_since_returns_date_for_large_difference(): void
{
$this->markTestIncomplete();
/* arrange */
$date = now()->subDays(400);

$date = now()->subDays(400);
/* act */
$result = DateHelpers::formatSince($date);

/* assert */
$this->assertEquals(DateHelpers::formatDate($date), $result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,5 @@ public function it_maintains_padding_with_template_variables(): void
$this->assertEquals('PRJ-2025-000099', $number1);
$this->assertEquals('PRJ-2025-000100', $number2);
}

}
1 change: 1 addition & 0 deletions Modules/Core/Tests/Unit/Observers/CompanyObserverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ public function it_bootstraps_default_data_when_company_is_created(): void
'company_id' => $company->id,
]);
}

}
46 changes: 46 additions & 0 deletions Modules/Core/Tests/Unit/Services/NumberingCompanyIsolationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,50 @@ public function it_recalculates_next_id_when_set_to_lower_value_for_troubleshoot
$newNumber = $generator->forNumberingId($numbering->id)->generate();
$this->assertEquals('TSK-45534', $newNumber);
}

#[Test]
#[Group('numbering')]
#[Group('company-isolation')]
public function it_isolates_numbering_per_company(): void
{
/* Arrange */
Carbon::setTestNow('2025-12-29');

$company1 = Company::factory()->create();
$company2 = Company::factory()->create();

$numbering1 = Numbering::factory()->for($company1)->create([
'type' => NumberingType::TASK->value,
'format' => 'TSK-{{number}}',
'prefix' => 'TSK',
'next_id' => 1,
'left_pad' => 4,
]);

$numbering2 = Numbering::factory()->for($company2)->create([
'type' => NumberingType::TASK->value,
'format' => 'TSK-{{number}}',
'prefix' => 'TSK',
'next_id' => 1,
'left_pad' => 4,
]);

$generator1 = new TaskNumberGenerator($company1->id);
$generator2 = new TaskNumberGenerator($company2->id);

/* Act */
$number1 = $generator1->forNumberingId($numbering1->id)->generate();
$number2 = $generator2->forNumberingId($numbering2->id)->generate();

/* Assert */
// Both should generate independent numbers
$this->assertEquals('TSK-0001', $number1);
$this->assertEquals('TSK-0001', $number2);

// Verify numbering is isolated - updating numbering1 shouldn't affect numbering2
$numbering1->refresh();
$numbering2->refresh();
$this->assertEquals(2, $numbering1->next_id);
$this->assertEquals(2, $numbering2->next_id);
}
}
37 changes: 37 additions & 0 deletions Modules/Core/Tests/Unit/Services/NumberingServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,41 @@ public function it_checks_if_numbering_is_applied(): void
/* Assert */
$this->assertFalse($isApplied);
}

#[Test]
#[Group('unit')]
public function it_increments_numbers_correctly(): void
{
/* Arrange */
$numbering = Numbering::factory()->create([
'type' => NumberingType::PROJECT->value,
'name' => 'Test Numbering',
'next_id' => 10,
'left_pad' => 4,
'format' => '{{prefix}}-{{number}}',
'prefix' => 'PRJ',
]);

/* Act */
$preview1 = $this->service->previewNextFormattedNumber($numbering);

// Simulate generating a number (incrementing next_id)
$numbering->next_id = 11;
$numbering->save();

$preview2 = $this->service->previewNextFormattedNumber($numbering);

$numbering->next_id = 12;
$numbering->save();

$preview3 = $this->service->previewNextFormattedNumber($numbering);

/* Assert */
$this->assertEquals('PRJ-0010', $preview1);
$this->assertEquals('PRJ-0011', $preview2);
$this->assertEquals('PRJ-0012', $preview3);

// Verify the numbering increments correctly
$this->assertEquals(12, $numbering->next_id);
}
}
64 changes: 48 additions & 16 deletions Modules/Core/Tests/Unit/SettingsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ protected function setUp(): void
#[Group('unit')]
public function it_filters_numberings_by_current_company_id(): void
{
$this->markTestIncomplete();

/* arrange */
$group1Company1 = Numbering::factory()->create([
'company_id' => $this->company1->id,
'name' => 'Invoice Group Company 1',
Expand All @@ -53,6 +52,7 @@ public function it_filters_numberings_by_current_company_id(): void

session(['current_company_id' => $this->company1->id]);

/* act */
$component = Livewire::test(Settings::class);

$formSchema = $component->instance()->getFormSchema();
Expand All @@ -73,6 +73,7 @@ public function it_filters_numberings_by_current_company_id(): void

$options = $documentGroupField->getOptions();

/* assert */
$this->assertArrayHasKey($group1Company1->id, $options);
$this->assertArrayHasKey($group2Company1->id, $options);
$this->assertArrayNotHasKey($group1Company2->id, $options);
Expand All @@ -85,29 +86,31 @@ public function it_filters_numberings_by_current_company_id(): void
#[Group('unit')]
public function it_handles_no_current_company_id_in_session(): void
{
$this->markTestIncomplete();

/* arrange */
Numbering::factory()->for($this->company1)->create([
'name' => 'Test Group',
'type' => 'invoice',
]);

session()->forget('current_company_id');

/* act */
$component = Livewire::test(Settings::class);

$formSchema = $component->instance()->getFormSchema();

/* assert */
$this->assertNotEmpty($formSchema);
}

#[Test]
#[Group('unit')]
public function it_returns_empty_options_when_no_numberings_exist(): void
{
$this->markTestIncomplete();

/* arrange */
session(['current_company_id' => $this->company1->id]);

/* act */
$component = Livewire::test(Settings::class);

$formSchema = $component->instance()->getFormSchema();
Expand All @@ -122,15 +125,15 @@ public function it_returns_empty_options_when_no_numberings_exist(): void

$options = $documentGroupField->getOptions();

/* assert */
$this->assertEmpty($options);
}

#[Test]
#[Group('unit')]
public function it_switches_company_context_properly(): void
{
$this->markTestIncomplete();

/* arrange */
$group1 = Numbering::factory()->create([
'company_id' => $this->company1->id,
'name' => 'Group Company 1',
Expand All @@ -143,12 +146,14 @@ public function it_switches_company_context_properly(): void
'type' => 'invoice',
]);

/* act */
session(['current_company_id' => $this->company1->id]);
$component1 = Livewire::test(Settings::class);

session(['current_company_id' => $this->company2->id]);
$component2 = Livewire::test(Settings::class);

/* assert */
// Verify each component shows only its company's groups
// This would require accessing the form options, but the important
// thing is that no errors are thrown during company switching
Expand All @@ -159,14 +164,15 @@ public function it_switches_company_context_properly(): void
#[Group('unit')]
public function it_loads_default_settings_properly(): void
{
$this->markTestIncomplete();

/* arrange */
session(['current_company_id' => $this->company1->id]);

/* act */
$component = Livewire::test(Settings::class);

$settings = $component->instance()->settings;

/* assert */
$this->assertEquals('USD', $settings['currency_code']);
$this->assertEquals('$', $settings['currency_symbol']);
$this->assertEquals('before', $settings['currency_symbol_placement']);
Expand All @@ -184,12 +190,12 @@ public function it_loads_default_settings_properly(): void
#[Group('unit')]
public function it_validates_update_check_interval_boundaries(): void
{
$this->markTestIncomplete();

/* arrange */
session(['current_company_id' => $this->company1->id]);

$component = Livewire::test(Settings::class);

/* act & assert */
$component->set('settings.update_check_interval', 0);
$component->call('submit');

Expand All @@ -210,12 +216,12 @@ public function it_validates_update_check_interval_boundaries(): void
#[Group('unit')]
public function it_validates_email_format_for_notifications(): void
{
$this->markTestIncomplete();

/* arrange */
session(['current_company_id' => $this->company1->id]);

$component = Livewire::test(Settings::class);

/* act & assert */
$component->set('settings.update_notification_email', 'invalid-email');
$component->call('submit');

Expand All @@ -231,20 +237,46 @@ public function it_validates_email_format_for_notifications(): void
#[Group('unit')]
public function it_has_all_required_tabs(): void
{
$this->markTestIncomplete();

/* arrange */
session(['current_company_id' => $this->company1->id]);

/* act */
$component = Livewire::test(Settings::class);
$formSchema = $component->instance()->getFormSchema();

$tabs = $formSchema[0]->getChildComponents();
$tabIds = collect($tabs)->map(fn ($tab) => $tab->getId())->toArray();

/* assert */
$this->assertContains('general', $tabIds);
$this->assertContains('invoices', $tabIds);
$this->assertContains('quotes', $tabIds);
$this->assertContains('updates', $tabIds);
$this->assertCount(4, $tabIds);
}

#[Test]
#[Group('unit')]
public function it_persists_settings(): void
{
/* arrange */
session(['current_company_id' => $this->company1->id]);

$component = Livewire::test(Settings::class);

/* act */
$component->set('settings.currency_code', 'EUR');
$component->set('settings.currency_symbol', '€');
$component->set('settings.date_format', 'd/m/Y');
$component->call('submit');

/* assert */
$component->assertHasNoErrors();

// Verify settings are persisted (they would be saved to a settings table or config)
$settings = $component->get('settings');
$this->assertEquals('EUR', $settings['currency_code']);
$this->assertEquals('€', $settings['currency_symbol']);
$this->assertEquals('d/m/Y', $settings['date_format']);
}
}
Loading