37 - Fix dev environment: paths, PHP version, testing DB, env isolation
This commit is contained in:
parent
dd5f1c514e
commit
c388452942
32 changed files with 88 additions and 509 deletions
7
.env.testing
Normal file
7
.env.testing
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
APP_ENV=testing
|
||||
APP_KEY=base64:+7T2RuonhTIij1yLp3rTOv2uQlYJh0TQulu20MlCA+s=
|
||||
|
||||
DB_DATABASE=testing
|
||||
|
||||
SESSION_DRIVER=array
|
||||
CACHE_STORE=array
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
|
@ -19,7 +20,7 @@ public function index(): JsonResponse
|
|||
public function current(): JsonResponse
|
||||
{
|
||||
// Get the first/default user (since no auth)
|
||||
$user = \App\Models\User::first();
|
||||
$user = User::first();
|
||||
$asset = $user ? $user->asset : null;
|
||||
|
||||
return response()->json([
|
||||
|
|
@ -41,11 +42,11 @@ public function setCurrent(Request $request)
|
|||
);
|
||||
|
||||
// Get or create the first/default user (since no auth)
|
||||
$user = \App\Models\User::first();
|
||||
$user = User::first();
|
||||
|
||||
if (! $user) {
|
||||
// Create a default user if none exists
|
||||
$user = \App\Models\User::create([
|
||||
$user = User::create([
|
||||
'name' => 'Default User',
|
||||
'email' => 'user@example.com',
|
||||
'password' => 'password', // This will be hashed automatically
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public function create(Request $request): Response
|
|||
/**
|
||||
* Handle an incoming new password request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ public function create(Request $request): Response
|
|||
/**
|
||||
* Handle an incoming password reset link request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ public function create(): Response
|
|||
/**
|
||||
* Handle an incoming registration request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Foundation\Auth\EmailVerificationRequest;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ public function __invoke(EmailVerificationRequest $request): RedirectResponse
|
|||
}
|
||||
|
||||
if ($request->user()->markEmailAsVerified()) {
|
||||
/** @var \Illuminate\Contracts\Auth\MustVerifyEmail $user */
|
||||
/** @var MustVerifyEmail $user */
|
||||
$user = $request->user();
|
||||
|
||||
event(new Verified($user));
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Milestone;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MilestoneController extends Controller
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Pricing\AssetPrice;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
|
|
@ -12,7 +13,7 @@ class PricingController extends Controller
|
|||
public function current(): JsonResponse
|
||||
{
|
||||
// Get the first/default user (since no auth)
|
||||
$user = \App\Models\User::first();
|
||||
$user = User::first();
|
||||
$assetId = $user ? $user->asset_id : null;
|
||||
|
||||
$price = AssetPrice::current($assetId);
|
||||
|
|
@ -30,7 +31,7 @@ public function update(Request $request)
|
|||
]);
|
||||
|
||||
// Get the first/default user (since no auth)
|
||||
$user = \App\Models\User::first();
|
||||
$user = User::first();
|
||||
|
||||
if (! $user || ! $user->asset_id) {
|
||||
return back()->withErrors(['asset' => 'Please set an asset first.']);
|
||||
|
|
@ -48,7 +49,7 @@ public function update(Request $request)
|
|||
public function history(Request $request): JsonResponse
|
||||
{
|
||||
// Get the first/default user (since no auth)
|
||||
$user = \App\Models\User::first();
|
||||
$user = User::first();
|
||||
$assetId = $user ? $user->asset_id : null;
|
||||
|
||||
$limit = $request->get('limit', 30);
|
||||
|
|
@ -60,7 +61,7 @@ public function history(Request $request): JsonResponse
|
|||
public function forDate(Request $request, string $date): JsonResponse
|
||||
{
|
||||
// Get the first/default user (since no auth)
|
||||
$user = \App\Models\User::first();
|
||||
$user = User::first();
|
||||
$assetId = $user ? $user->asset_id : null;
|
||||
|
||||
$price = AssetPrice::forDate($date, $assetId);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
use App\Models\Transactions\Purchase;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
|
||||
class PurchaseController extends Controller
|
||||
{
|
||||
|
|
@ -30,7 +29,7 @@ public function store(Request $request)
|
|||
$calculatedTotal = $validated['shares'] * $validated['price_per_share'];
|
||||
if (abs($calculatedTotal - $validated['total_cost']) > 0.01) {
|
||||
return back()->withErrors([
|
||||
'total_cost' => 'Total cost does not match shares × price per share.'
|
||||
'total_cost' => 'Total cost does not match shares × price per share.',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class HandleAppearance
|
|||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Requests\Auth;
|
||||
|
||||
use Illuminate\Auth\Events\Lockout;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
|
|
@ -22,7 +23,7 @@ public function authorize(): bool
|
|||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
|
@ -35,7 +36,7 @@ public function rules(): array
|
|||
/**
|
||||
* Attempt to authenticate the request's credentials.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function authenticate(): void
|
||||
{
|
||||
|
|
@ -55,7 +56,7 @@ public function authenticate(): void
|
|||
/**
|
||||
* Ensure the login request is not rate limited.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function ensureIsNotRateLimited(): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
* @method static where(string $string, string $value)
|
||||
* @method static find(int $id)
|
||||
* @method static orderBy(string $string)
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $symbol
|
||||
* @property string|null $full_name
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models\Pricing;
|
||||
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -13,6 +14,7 @@
|
|||
* @method static where(string $string, string $string1, string $date)
|
||||
* @method static updateOrCreate(string[] $array, float[] $array1)
|
||||
* @method static orderBy(string $string, string $string1)
|
||||
*
|
||||
* @property Carbon $date
|
||||
* @property float $price
|
||||
*/
|
||||
|
|
@ -33,10 +35,10 @@ class AssetPrice extends Model
|
|||
|
||||
public function asset(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(\App\Models\Asset::class);
|
||||
return $this->belongsTo(Asset::class);
|
||||
}
|
||||
|
||||
public static function current(int $assetId = null): ?float
|
||||
public static function current(?int $assetId = null): ?float
|
||||
{
|
||||
$query = static::latest('date');
|
||||
|
||||
|
|
@ -49,7 +51,7 @@ public static function current(int $assetId = null): ?float
|
|||
return $latestPrice ? $latestPrice->price : null;
|
||||
}
|
||||
|
||||
public static function forDate(string $date, int $assetId = null): ?float
|
||||
public static function forDate(string $date, ?int $assetId = null): ?float
|
||||
{
|
||||
$query = static::where('date', '<=', $date)
|
||||
->orderBy('date', 'desc');
|
||||
|
|
@ -71,7 +73,7 @@ public static function updatePrice(int $assetId, string $date, float $price): se
|
|||
);
|
||||
}
|
||||
|
||||
public static function history(int $assetId = null, int $limit = 30): Collection
|
||||
public static function history(?int $assetId = null, int $limit = 30): Collection
|
||||
{
|
||||
$query = static::orderBy('date', 'desc')->limit($limit);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Providers\AppServiceProvider;
|
||||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
AppServiceProvider::class,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|
|
@ -62,7 +64,7 @@
|
|||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||
'model' => env('AUTH_MODEL', User::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
FROM docker.io/library/php:8.2-fpm
|
||||
FROM docker.io/library/php:8.3-fpm
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
|
|
@ -23,7 +23,7 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
|||
WORKDIR /var/www/html
|
||||
|
||||
# Copy and set up container start script
|
||||
COPY docker/dev/podman/container-start.sh /usr/local/bin/container-start.sh
|
||||
COPY docker/dev/container-start.sh /usr/local/bin/container-start.sh
|
||||
RUN chmod +x /usr/local/bin/container-start.sh
|
||||
|
||||
EXPOSE 8000 5173
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Create .env file if it doesn't exist
|
||||
if [ ! -f /var/www/html/.env ]; then
|
||||
|
|
@ -12,7 +13,7 @@ sed -i 's/DB_DATABASE=incr$/DB_DATABASE=incr_dev/' /var/www/html/.env
|
|||
if ! grep -q "APP_KEY=base64:" /var/www/html/.env; then
|
||||
# Generate a new key and set it directly
|
||||
NEW_KEY=$(php -r "echo 'base64:' . base64_encode(random_bytes(32));")
|
||||
sed -i "s/APP_KEY=/APP_KEY=$NEW_KEY/" /var/www/html/.env
|
||||
sed -i "s|^APP_KEY=.*|APP_KEY=$NEW_KEY|" /var/www/html/.env
|
||||
fi
|
||||
|
||||
# Install dependencies if needed
|
||||
|
|
|
|||
|
|
@ -1,26 +1,16 @@
|
|||
services:
|
||||
app:
|
||||
build:
|
||||
context: ../../..
|
||||
context: ../..
|
||||
dockerfile: docker/dev/Dockerfile
|
||||
container_name: incr-dev-app
|
||||
restart: unless-stopped
|
||||
working_dir: /var/www/html
|
||||
environment:
|
||||
- APP_ENV=local
|
||||
- APP_DEBUG=true
|
||||
- APP_KEY=base64:YOUR_APP_KEY_HERE
|
||||
- DB_CONNECTION=mysql
|
||||
- DB_HOST=db
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=incr_dev
|
||||
- DB_USERNAME=incr_user
|
||||
- DB_PASSWORD=incr_password
|
||||
- VITE_PORT=5173
|
||||
volumes:
|
||||
- ../../../:/var/www/html:Z
|
||||
- ../../:/var/www/html:Z
|
||||
- app_node_modules:/var/www/html/node_modules
|
||||
- app_vendor:/var/www/html/vendor
|
||||
ports:
|
||||
- "8000:8000"
|
||||
- "5173:5173"
|
||||
|
|
@ -41,6 +31,7 @@ services:
|
|||
- MYSQL_ROOT_PASSWORD=root_password
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
- ./mysql-init:/docker-entrypoint-initdb.d:ro
|
||||
ports:
|
||||
- "3307:3306"
|
||||
healthcheck:
|
||||
|
|
@ -69,4 +60,3 @@ volumes:
|
|||
db_data:
|
||||
driver: local
|
||||
app_node_modules:
|
||||
app_vendor:
|
||||
2
docker/dev/mysql-init/create-testing-db.sql
Normal file
2
docker/dev/mysql-init/create-testing-db.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
CREATE DATABASE IF NOT EXISTS `testing` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
GRANT ALL PRIVILEGES ON `testing`.* TO 'incr_user'@'%';
|
||||
20
phpunit.xml
20
phpunit.xml
|
|
@ -18,15 +18,15 @@
|
|||
</include>
|
||||
</source>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<env name="DB_DATABASE" value="testing"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="PULSE_ENABLED" value="false"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="TELESCOPE_ENABLED" value="false"/>
|
||||
<env name="APP_ENV" value="testing" force="true"/>
|
||||
<env name="APP_MAINTENANCE_DRIVER" value="file" force="true"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4" force="true"/>
|
||||
<env name="CACHE_STORE" value="array" force="true"/>
|
||||
<env name="DB_DATABASE" value="testing" force="true"/>
|
||||
<env name="MAIL_MAILER" value="array" force="true"/>
|
||||
<env name="PULSE_ENABLED" value="false" force="true"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync" force="true"/>
|
||||
<env name="SESSION_DRIVER" value="array" force="true"/>
|
||||
<env name="TELESCOPE_ENABLED" value="false" force="true"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\AssetController;
|
||||
use App\Http\Controllers\Transactions\PurchaseController;
|
||||
use App\Http\Controllers\Pricing\PricingController;
|
||||
use App\Http\Controllers\Milestones\MilestoneController;
|
||||
use App\Http\Controllers\Pricing\PricingController;
|
||||
use App\Http\Controllers\Transactions\PurchaseController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Inertia\Inertia;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AuthenticationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_login_screen_can_be_rendered()
|
||||
{
|
||||
$response = $this->get('/login');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_users_can_authenticate_using_the_login_screen()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->post('/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
}
|
||||
|
||||
public function test_users_can_not_authenticate_with_invalid_password()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$this->assertGuest();
|
||||
}
|
||||
|
||||
public function test_users_can_logout()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->post('/logout');
|
||||
|
||||
$this->assertGuest();
|
||||
$response->assertRedirect('/');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Tests\TestCase;
|
||||
|
||||
class EmailVerificationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_email_verification_screen_can_be_rendered()
|
||||
{
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/verify-email');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_email_can_be_verified()
|
||||
{
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
Event::fake();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1($user->email)]
|
||||
);
|
||||
|
||||
$response = $this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
Event::assertDispatched(Verified::class);
|
||||
$this->assertTrue($user->fresh()->hasVerifiedEmail());
|
||||
$response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
|
||||
}
|
||||
|
||||
public function test_email_is_not_verified_with_invalid_hash()
|
||||
{
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$verificationUrl = URL::temporarySignedRoute(
|
||||
'verification.verify',
|
||||
now()->addMinutes(60),
|
||||
['id' => $user->id, 'hash' => sha1('wrong-email')]
|
||||
);
|
||||
|
||||
$this->actingAs($user)->get($verificationUrl);
|
||||
|
||||
$this->assertFalse($user->fresh()->hasVerifiedEmail());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PasswordConfirmationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_confirm_password_screen_can_be_rendered()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/confirm-password');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_password_can_be_confirmed()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->post('/confirm-password', [
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
$response->assertSessionHasNoErrors();
|
||||
}
|
||||
|
||||
public function test_password_is_not_confirmed_with_invalid_password()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)->post('/confirm-password', [
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$response->assertSessionHasErrors();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Notifications\ResetPassword;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PasswordResetTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_reset_password_link_screen_can_be_rendered()
|
||||
{
|
||||
$response = $this->get('/forgot-password');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_reset_password_link_can_be_requested()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/forgot-password', ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class);
|
||||
}
|
||||
|
||||
public function test_reset_password_screen_can_be_rendered()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/forgot-password', ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) {
|
||||
$response = $this->get('/reset-password/'.$notification->token);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public function test_password_can_be_reset_with_valid_token()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post('/forgot-password', ['email' => $user->email]);
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
|
||||
$response = $this->post('/reset-password', [
|
||||
'token' => $notification->token,
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect(route('login'));
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RegistrationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_registration_screen_can_be_rendered()
|
||||
{
|
||||
$response = $this->get('/register');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function test_new_users_can_register()
|
||||
{
|
||||
$response = $this->post('/register', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('dashboard', absolute: false));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DashboardTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_guests_are_redirected_to_the_login_page()
|
||||
{
|
||||
$this->get('/dashboard')->assertRedirect('/login');
|
||||
}
|
||||
|
||||
public function test_authenticated_users_can_visit_the_dashboard()
|
||||
{
|
||||
$this->actingAs($user = User::factory()->create());
|
||||
|
||||
$this->get('/dashboard')->assertOk();
|
||||
}
|
||||
}
|
||||
|
|
@ -14,12 +14,12 @@ public function test_can_create_milestone(): void
|
|||
{
|
||||
$milestone = Milestone::create([
|
||||
'target' => 1500,
|
||||
'description' => 'First milestone'
|
||||
'description' => 'First milestone',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('milestones', [
|
||||
'target' => 1500,
|
||||
'description' => 'First milestone'
|
||||
'description' => 'First milestone',
|
||||
]);
|
||||
|
||||
$this->assertEquals(1500, $milestone->target);
|
||||
|
|
@ -38,7 +38,7 @@ public function test_can_fetch_milestones_via_api(): void
|
|||
$response->assertJsonCount(2);
|
||||
$response->assertJson([
|
||||
['target' => 1500, 'description' => 'First milestone'],
|
||||
['target' => 3000, 'description' => 'Second milestone']
|
||||
['target' => 3000, 'description' => 'Second milestone'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Settings;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PasswordUpdateTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_password_can_be_updated()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from('/settings/password')
|
||||
->put('/settings/password', [
|
||||
'current_password' => 'password',
|
||||
'password' => 'new-password',
|
||||
'password_confirmation' => 'new-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect('/settings/password');
|
||||
|
||||
$this->assertTrue(Hash::check('new-password', $user->refresh()->password));
|
||||
}
|
||||
|
||||
public function test_correct_password_must_be_provided_to_update_password()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from('/settings/password')
|
||||
->put('/settings/password', [
|
||||
'current_password' => 'wrong-password',
|
||||
'password' => 'new-password',
|
||||
'password_confirmation' => 'new-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasErrors('current_password')
|
||||
->assertRedirect('/settings/password');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Settings;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ProfileUpdateTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_profile_page_is_displayed()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->get('/settings/profile');
|
||||
|
||||
$response->assertOk();
|
||||
}
|
||||
|
||||
public function test_profile_information_can_be_updated()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->patch('/settings/profile', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect('/settings/profile');
|
||||
|
||||
$user->refresh();
|
||||
|
||||
$this->assertSame('Test User', $user->name);
|
||||
$this->assertSame('test@example.com', $user->email);
|
||||
$this->assertNull($user->email_verified_at);
|
||||
}
|
||||
|
||||
public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->patch('/settings/profile', [
|
||||
'name' => 'Test User',
|
||||
'email' => $user->email,
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect('/settings/profile');
|
||||
|
||||
$this->assertNotNull($user->refresh()->email_verified_at);
|
||||
}
|
||||
|
||||
public function test_user_can_delete_their_account()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->delete('/settings/profile', [
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasNoErrors()
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertGuest();
|
||||
$this->assertNull($user->fresh());
|
||||
}
|
||||
|
||||
public function test_correct_password_must_be_provided_to_delete_account()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this
|
||||
->actingAs($user)
|
||||
->from('/settings/profile')
|
||||
->delete('/settings/profile', [
|
||||
'password' => 'wrong-password',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertSessionHasErrors('password')
|
||||
->assertRedirect('/settings/profile');
|
||||
|
||||
$this->assertNotNull($user->fresh());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue