mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 00:02:15 +01:00
Added tests
This commit is contained in:
committed by
Constantin Graf
parent
c5c129b239
commit
24775d2c47
@@ -132,7 +132,8 @@
|
|||||||
"pestphp/pest-plugin": true,
|
"pestphp/pest-plugin": true,
|
||||||
"php-http/discovery": true,
|
"php-http/discovery": true,
|
||||||
"wikimedia/composer-merge-plugin": true
|
"wikimedia/composer-merge-plugin": true
|
||||||
}
|
},
|
||||||
|
"process-timeout": 900
|
||||||
},
|
},
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"prefer-stable": true
|
"prefer-stable": true
|
||||||
|
|||||||
@@ -5,12 +5,9 @@ declare(strict_types=1);
|
|||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
use App\Enums\Weekday;
|
use App\Enums\Weekday;
|
||||||
use App\Mail\VerifyUpdatedEmailMail;
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Service\TimezoneService;
|
use App\Service\TimezoneService;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
use Illuminate\Support\Facades\URL;
|
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
class ProfileInformationTest extends TestCase
|
class ProfileInformationTest extends TestCase
|
||||||
@@ -39,66 +36,4 @@ class ProfileInformationTest extends TestCase
|
|||||||
$user = $user->fresh();
|
$user = $user->fresh();
|
||||||
$this->assertEquals($user->name, $user->name);
|
$this->assertEquals($user->name, $user->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_pending_email_verification_redirects_with_danger_banner_when_email_already_in_use(): void
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
User::factory()->create([
|
|
||||||
'email' => 'taken@example.com',
|
|
||||||
'is_placeholder' => false,
|
|
||||||
]);
|
|
||||||
$user = User::factory()->create([
|
|
||||||
'email' => 'current@example.com',
|
|
||||||
'pending_email' => 'taken@example.com',
|
|
||||||
]);
|
|
||||||
$this->actingAs($user);
|
|
||||||
$verificationUrl = URL::temporarySignedRoute(
|
|
||||||
'users.verify-email-change',
|
|
||||||
now()->addMinutes(60),
|
|
||||||
[
|
|
||||||
'user' => $user->getKey(),
|
|
||||||
'email' => 'taken@example.com',
|
|
||||||
],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
$response = $this->get($verificationUrl);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
$response->assertRedirect(route('dashboard'));
|
|
||||||
$response->assertSessionHas('bannerStyle', 'danger');
|
|
||||||
$response->assertSessionHas('bannerText', 'The email address is already in use.');
|
|
||||||
$user = $user->fresh();
|
|
||||||
$this->assertEquals('current@example.com', $user->email);
|
|
||||||
$this->assertEquals('taken@example.com', $user->pending_email);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_stale_pending_email_verification_link_is_rejected(): void
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
$user = User::factory()->create([
|
|
||||||
'email' => 'current@example.com',
|
|
||||||
'pending_email' => 'newer@example.com',
|
|
||||||
]);
|
|
||||||
$this->actingAs($user);
|
|
||||||
$verificationUrl = URL::temporarySignedRoute(
|
|
||||||
'users.verify-email-change',
|
|
||||||
now()->addMinutes(60),
|
|
||||||
[
|
|
||||||
'user' => $user->getKey(),
|
|
||||||
'email' => 'older@example.com',
|
|
||||||
],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
$response = $this->get($verificationUrl);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
$response->assertForbidden();
|
|
||||||
$user = $user->fresh();
|
|
||||||
$this->assertEquals('current@example.com', $user->email);
|
|
||||||
$this->assertEquals('newer@example.com', $user->pending_email);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
253
tests/Unit/Endpoint/Web/UserEndpointTest.php
Normal file
253
tests/Unit/Endpoint/Web/UserEndpointTest.php
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit\Endpoint\Web;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Web\UserController;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\URL;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
|
||||||
|
#[CoversClass(UserController::class)]
|
||||||
|
class UserEndpointTest extends EndpointTestAbstract
|
||||||
|
{
|
||||||
|
public function test_pending_email_verification_updates_email_and_redirects_with_success_banner(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$this->travelTo(Carbon::parse('2024-01-02 12:00:00', 'UTC'));
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'new@example.com',
|
||||||
|
'email_verified_at' => null,
|
||||||
|
]);
|
||||||
|
$this->actingAs($user);
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
[
|
||||||
|
'user' => $user->getKey(),
|
||||||
|
'email' => 'NEW@EXAMPLE.COM',
|
||||||
|
],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertRedirect(route('dashboard'));
|
||||||
|
$response->assertSessionHas('bannerStyle', 'success');
|
||||||
|
$response->assertSessionHas('bannerText', 'Your email address has been updated successfully.');
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('new@example.com', $user->email);
|
||||||
|
$this->assertNull($user->pending_email);
|
||||||
|
$this->assertTrue(now()->equalTo($user->email_verified_at));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_pending_email_verification_is_rejected_for_another_authenticated_user(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'new@example.com',
|
||||||
|
]);
|
||||||
|
$this->actingAs(User::factory()->create());
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
[
|
||||||
|
'user' => $user->getKey(),
|
||||||
|
'email' => 'new@example.com',
|
||||||
|
],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertForbidden();
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('current@example.com', $user->email);
|
||||||
|
$this->assertSame('new@example.com', $user->pending_email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_pending_email_verification_without_email_is_rejected(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'new@example.com',
|
||||||
|
]);
|
||||||
|
$this->actingAs($user);
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
['user' => $user->getKey()],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertForbidden();
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('current@example.com', $user->email);
|
||||||
|
$this->assertSame('new@example.com', $user->pending_email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_pending_email_verification_with_non_string_email_is_rejected(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'new@example.com',
|
||||||
|
]);
|
||||||
|
$this->actingAs($user);
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
[
|
||||||
|
'user' => $user->getKey(),
|
||||||
|
'email' => ['new@example.com'],
|
||||||
|
],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertForbidden();
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('current@example.com', $user->email);
|
||||||
|
$this->assertSame('new@example.com', $user->pending_email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_stale_pending_email_verification_link_is_rejected(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'newer@example.com',
|
||||||
|
]);
|
||||||
|
$this->actingAs($user);
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
[
|
||||||
|
'user' => $user->getKey(),
|
||||||
|
'email' => 'older@example.com',
|
||||||
|
],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertForbidden();
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('current@example.com', $user->email);
|
||||||
|
$this->assertSame('newer@example.com', $user->pending_email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_pending_email_verification_redirects_with_danger_banner_when_email_already_in_use(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
User::factory()->create([
|
||||||
|
'email' => 'taken@example.com',
|
||||||
|
'is_placeholder' => false,
|
||||||
|
]);
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'taken@example.com',
|
||||||
|
]);
|
||||||
|
$this->actingAs($user);
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
[
|
||||||
|
'user' => $user->getKey(),
|
||||||
|
'email' => 'taken@example.com',
|
||||||
|
],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertRedirect(route('dashboard'));
|
||||||
|
$response->assertSessionHas('bannerStyle', 'danger');
|
||||||
|
$response->assertSessionHas('bannerText', 'The email address is already in use.');
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('current@example.com', $user->email);
|
||||||
|
$this->assertSame('taken@example.com', $user->pending_email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_pending_email_verification_ignores_placeholder_users_with_the_same_email(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
User::factory()->placeholder()->create([
|
||||||
|
'email' => 'new@example.com',
|
||||||
|
]);
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'new@example.com',
|
||||||
|
'email_verified_at' => null,
|
||||||
|
]);
|
||||||
|
$this->actingAs($user);
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
[
|
||||||
|
'user' => $user->getKey(),
|
||||||
|
'email' => 'new@example.com',
|
||||||
|
],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertRedirect(route('dashboard'));
|
||||||
|
$response->assertSessionHas('bannerStyle', 'success');
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('new@example.com', $user->email);
|
||||||
|
$this->assertNull($user->pending_email);
|
||||||
|
$this->assertNotNull($user->email_verified_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_pending_email_verification_with_invalid_signature_is_rejected(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->create([
|
||||||
|
'email' => 'current@example.com',
|
||||||
|
'pending_email' => 'new@example.com',
|
||||||
|
]);
|
||||||
|
$this->actingAs($user);
|
||||||
|
$verificationUrl = URL::temporarySignedRoute(
|
||||||
|
'users.verify-email-change',
|
||||||
|
now()->addMinutes(60),
|
||||||
|
[
|
||||||
|
'user' => $user->getKey(),
|
||||||
|
'email' => 'new@example.com',
|
||||||
|
],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($verificationUrl.'&invalid');
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertForbidden();
|
||||||
|
$user->refresh();
|
||||||
|
$this->assertSame('current@example.com', $user->email);
|
||||||
|
$this->assertSame('new@example.com', $user->pending_email);
|
||||||
|
}
|
||||||
|
}
|
||||||
131
tests/Unit/Service/Dto/UserAgentDtoTest.php
Normal file
131
tests/Unit/Service/Dto/UserAgentDtoTest.php
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit\Service\Dto;
|
||||||
|
|
||||||
|
use App\Service\Dto\UserAgentDto;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
#[CoversClass(UserAgentDto::class)]
|
||||||
|
class UserAgentDtoTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_chrome_on_windows_is_detected_as_a_desktop_browser(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
||||||
|
$agent = new UserAgentDto;
|
||||||
|
$agent->setUserAgent($userAgent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$platform = $agent->platform();
|
||||||
|
$browser = $agent->browser();
|
||||||
|
$isDesktop = $agent->isDesktop();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$this->assertSame('Windows', $platform);
|
||||||
|
$this->assertSame('Chrome', $browser);
|
||||||
|
$this->assertTrue($isDesktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_edge_is_detected_before_chrome(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0';
|
||||||
|
$agent = new UserAgentDto;
|
||||||
|
$agent->setUserAgent($userAgent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$browser = $agent->browser();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$this->assertSame('Edge', $browser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_iphone_safari_is_detected_as_a_non_desktop_browser(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
|
||||||
|
$agent = new UserAgentDto;
|
||||||
|
$agent->setUserAgent($userAgent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$platform = $agent->platform();
|
||||||
|
$browser = $agent->browser();
|
||||||
|
$isDesktop = $agent->isDesktop();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$this->assertSame('iOS', $platform);
|
||||||
|
$this->assertSame('Safari', $browser);
|
||||||
|
$this->assertFalse($isDesktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_ipad_is_detected_as_non_desktop(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$userAgent = 'Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
|
||||||
|
$agent = new UserAgentDto;
|
||||||
|
$agent->setUserAgent($userAgent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$isDesktop = $agent->isDesktop();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$this->assertFalse($isDesktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_unknown_user_agent_has_no_platform_or_browser_and_is_a_desktop(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$agent = new UserAgentDto;
|
||||||
|
$agent->setUserAgent('CustomClient/1.0');
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$platform = $agent->platform();
|
||||||
|
$browser = $agent->browser();
|
||||||
|
$isDesktop = $agent->isDesktop();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$this->assertNull($platform);
|
||||||
|
$this->assertNull($browser);
|
||||||
|
$this->assertTrue($isDesktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_cloudfront_desktop_header_is_detected_as_desktop(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$agent = new UserAgentDto;
|
||||||
|
$agent->setUserAgent('Amazon CloudFront');
|
||||||
|
$agent->setHttpHeaders([
|
||||||
|
'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' => 'true',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$isDesktop = $agent->isDesktop();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$this->assertTrue($isDesktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_cached_values_are_resolved_for_the_current_user_agent(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$agent = new UserAgentDto;
|
||||||
|
$agent->setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36');
|
||||||
|
$agent->platform();
|
||||||
|
$agent->browser();
|
||||||
|
$agent->isDesktop();
|
||||||
|
$agent->setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) Version/17.0 Mobile/15E148 Safari/604.1');
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$platform = $agent->platform();
|
||||||
|
$browser = $agent->browser();
|
||||||
|
$isDesktop = $agent->isDesktop();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$this->assertSame('iOS', $platform);
|
||||||
|
$this->assertSame('Safari', $browser);
|
||||||
|
$this->assertFalse($isDesktop);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user