From 9a9a901d46995c5d1545a10b9fdb47cef1f3b3ed Mon Sep 17 00:00:00 2001 From: Daan Meijer Date: Tue, 16 Jun 2026 10:30:50 +0200 Subject: [PATCH] tests --- tests/Browser/RealtimeChatTest.php | 67 ++++++++++++++++++++++++++ tests/DuskTestCase.php | 44 ++++++++++++++++++ tests/Feature/MediaTest.php | 75 ++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 tests/Browser/RealtimeChatTest.php create mode 100644 tests/DuskTestCase.php create mode 100644 tests/Feature/MediaTest.php diff --git a/tests/Browser/RealtimeChatTest.php b/tests/Browser/RealtimeChatTest.php new file mode 100644 index 0000000..6979ba1 --- /dev/null +++ b/tests/Browser/RealtimeChatTest.php @@ -0,0 +1,67 @@ +create([ + 'name' => 'TU Test User', + 'email' => 'test-owner@example.com', + 'password' => bcrypt('password'), + ]); + + $participant = User::factory()->create([ + 'name' => 'Submissive Bob', + 'email' => 'test-sub@example.com', + 'password' => bcrypt('password'), + ]); + + $dynamic = Dynamic::create([ + 'name' => 'The Test Sanctuary', + 'rules' => 'Rules for realtime testing.', + ]); + + $dynamic->participants()->attach($owner->id, ['role' => 'owner']); + $dynamic->participants()->attach($participant->id, ['role' => 'participant']); + + // 2. Spawn two separate browser sessions/browsers in parallel + $this->browse(function (Browser $sessionA, Browser $sessionB) use ($dynamic, $owner, $participant) { + + // --- SESSION A: Owner --- + $sessionA->loginAs($owner) + ->visit(route('dynamics.show', $dynamic)) + ->waitForText('The Test Sanctuary') + ->assertSee('TU Test User'); // Verify loaded in as Owner + + // --- SESSION B: Participant --- + $sessionB->loginAs($participant) + ->visit(route('dynamics.show', $dynamic)) + ->waitForText('The Test Sanctuary') + ->assertSee('Submissive Bob'); // Verify loaded in as Submissive/Participant + + // --- REAL-TIME COMMUNICATING --- + // Owner types and sends a message in chat + $sessionA->type('#content', 'Hello Submissive Bob, did you complete your daily chores?') + ->click('.c-chat__button') + ->waitForText('Hello Submissive Bob'); + + // Since websockets broadcast in real-time, Session B receives it without reloading + $sessionB->waitForText('Hello Submissive Bob', 5) + ->assertSee('Hello Submissive Bob, did you complete your daily chores?'); + + // Participant replies in real-time + $sessionB->type('#content', 'Yes Master, everything is complete and logged in the ledger!') + ->click('.c-chat__button') + ->waitForText('Yes Master, everything is complete'); + + // Session A receives the reply in real-time without reloading + $sessionA->waitForText('Yes Master, everything is complete', 5) + ->assertSee('Yes Master, everything is complete and logged in the ledger!'); + }); +}); diff --git a/tests/DuskTestCase.php b/tests/DuskTestCase.php new file mode 100644 index 0000000..296db4a --- /dev/null +++ b/tests/DuskTestCase.php @@ -0,0 +1,44 @@ +addArguments(collect([ + $this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080', + '--disable-gpu', + '--headless=new', + '--no-sandbox', + '--disable-dev-shm-usage', + ])->unless(static::runningInSail(), function (collect $arguments) { + return $arguments->push('--disable-smooth-scrolling'); + })->all()); + + return RemoteWebDriver::create( + $_ENV['DUSK_DRIVER_URL'] ?? env('DUSK_DRIVER_URL') ?? 'http://localhost:9515', + DesiredCapabilities::chrome()->setCapability(ChromeOptions::CAPABILITY, $options) + ); + } +} diff --git a/tests/Feature/MediaTest.php b/tests/Feature/MediaTest.php new file mode 100644 index 0000000..8382afd --- /dev/null +++ b/tests/Feature/MediaTest.php @@ -0,0 +1,75 @@ +create(); + $dynamic = Dynamic::factory()->create(); + $dynamic->participants()->attach($user->id, ['role' => 'owner']); + $ledger = Ledger::factory()->create(['dynamic_id' => $dynamic->id]); + + $this->actingAs($user); + + // 1. Test attaching media to a mutation + $file1 = UploadedFile::fake()->image('proof1.jpg'); + $file2 = UploadedFile::fake()->image('proof2.png'); + + $response = $this->post(route('dynamics.ledgers.mutations.store', [$dynamic, $ledger]), [ + 'amount' => 50, + 'description' => 'Completed deep clean', + 'media' => [$file1, $file2], + ]); + + $response->assertSessionHasNoErrors(); + $response->assertRedirect(); + + $mutation = Mutation::firstWhere('description', 'Completed deep clean'); + expect($mutation)->not->toBeNull(); + expect($mutation->media)->toHaveCount(2); + expect($mutation->media->first()->file_name)->toBe('proof1.jpg'); + expect($mutation->media->last()->file_name)->toBe('proof2.png'); + + Storage::disk('public')->assertExists($mutation->media->first()->file_path); + Storage::disk('public')->assertExists($mutation->media->last()->file_path); + + // 2. Test attaching media to a ledger + $file3 = UploadedFile::fake()->image('rules.jpg'); + $response = $this->post(route('dynamics.ledgers.store', $dynamic), [ + 'name' => 'Worship Ledger', + 'rules' => 'Specific rules', + 'alignment' => 'neutral', + 'media' => [$file3], + ]); + + $response->assertSessionHasNoErrors(); + $response->assertRedirect(); + + $newLedger = Ledger::firstWhere('name', 'Worship Ledger'); + expect($newLedger)->not->toBeNull(); + expect($newLedger->media)->toHaveCount(1); + expect($newLedger->media->first()->file_name)->toBe('rules.jpg'); + + // 3. Test attaching media to a chat message + $chat = $dynamic->chat; + $file4 = UploadedFile::fake()->image('chat_img.jpg'); + $response = $this->post(route('chats.messages.store', $chat), [ + 'content' => 'Check this out!', + 'media' => [$file4], + ]); + + $response->assertRedirect(); + + $message = Message::firstWhere('content', 'Check this out!'); + expect($message)->not->toBeNull(); + expect($message->media)->toHaveCount(1); + expect($message->media->first()->file_name)->toBe('chat_img.jpg'); +});