insertOrIgnore([ ['id' => 1, 'name' => 'worked_hours', 'label' => 'Worked Hours', 'icon' => 'clock'], ['id' => 6, 'name' => 'migration', 'label' => 'Migration', 'icon' => 'arrow-path'], ]); } private function actingAsUserWithAccount(): array { $user = User::factory()->create(); $account = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $user->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); $this->actingAs($user, 'web'); session(['activeProfileType' => User::class]); session(['activeProfileId' => $user->id]); return [$user, $account]; } private function toAccountDetails(User $recipient, Account $recipientAccount): array { return [ 'accountId' => $recipientAccount->id, 'accountName' => $recipientAccount->name, 'holderId' => $recipient->id, 'holderType' => User::class, 'holderName' => $recipient->name, 'holderLocation' => 'Testville', 'holderPhoto' => $recipient->profile_photo_path, ]; } /** @test */ public function selecting_a_recipient_with_no_history_opens_the_confirmation_modal() { [$user, ] = $this->actingAsUserWithAccount(); $recipient = User::factory()->create(); $recipientAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $recipient->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $this->toAccountDetails($recipient, $recipientAccount)); $response->assertSet('isNewRecipientModalOpen', true); $response->assertSet('toAccountId', null); } /** @test */ public function selecting_a_recipient_with_a_prior_transaction_skips_the_modal() { [$user, $userAccount] = $this->actingAsUserWithAccount(); $recipient = User::factory()->create(); $recipientAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $recipient->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); Transaction::factory()->create([ 'from_account_id' => $userAccount->id, 'to_account_id' => $recipientAccount->id, 'transaction_type_id' => 1, ]); $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $this->toAccountDetails($recipient, $recipientAccount)); $response->assertSet('isNewRecipientModalOpen', false); $response->assertSet('toAccountId', $recipientAccount->id); } /** @test */ public function selecting_a_recipient_with_a_prior_transaction_in_reverse_direction_skips_the_modal() { [$user, $userAccount] = $this->actingAsUserWithAccount(); $recipient = User::factory()->create(); $recipientAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $recipient->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); Transaction::factory()->create([ 'from_account_id' => $recipientAccount->id, 'to_account_id' => $userAccount->id, 'transaction_type_id' => 1, ]); $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $this->toAccountDetails($recipient, $recipientAccount)); $response->assertSet('isNewRecipientModalOpen', false); $response->assertSet('toAccountId', $recipientAccount->id); } private function createPrivateConversation(User $user, User $recipient): Conversation { $conversation = new Conversation(); $conversation->type = ConversationType::PRIVATE; $conversation->save(); $conversation->participants()->create([ 'participantable_type' => User::class, 'participantable_id' => $user->id, 'role' => \Namu\WireChat\Enums\ParticipantRole::PARTICIPANT, ]); $conversation->participants()->create([ 'participantable_type' => User::class, 'participantable_id' => $recipient->id, 'role' => \Namu\WireChat\Enums\ParticipantRole::PARTICIPANT, ]); return $conversation; } /** @test */ public function selecting_a_recipient_who_only_sent_messages_without_a_reply_still_shows_the_modal() { [$user, ] = $this->actingAsUserWithAccount(); $recipient = User::factory()->create(); $recipientAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $recipient->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); $conversation = $this->createPrivateConversation($user, $recipient); // Recipient messaged the active profile, but the active profile never replied. Message::create([ 'body' => 'Hello there', 'sendable_type' => User::class, 'sendable_id' => $recipient->id, 'conversation_id' => $conversation->id, 'type' => MessageType::TEXT, ]); $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $this->toAccountDetails($recipient, $recipientAccount)); $response->assertSet('isNewRecipientModalOpen', true); $response->assertSet('toAccountId', null); } /** @test */ public function selecting_a_recipient_the_active_profile_previously_messaged_skips_the_modal() { [$user, ] = $this->actingAsUserWithAccount(); $recipient = User::factory()->create(); $recipientAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $recipient->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); $conversation = $this->createPrivateConversation($user, $recipient); Message::create([ 'body' => 'Hi, thanks for reaching out', 'sendable_type' => User::class, 'sendable_id' => $user->id, 'conversation_id' => $conversation->id, 'type' => MessageType::TEXT, ]); $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $this->toAccountDetails($recipient, $recipientAccount)); $response->assertSet('isNewRecipientModalOpen', false); $response->assertSet('toAccountId', $recipientAccount->id); } /** @test */ public function internal_transfer_to_own_profile_skips_the_modal() { [$user, $userAccount] = $this->actingAsUserWithAccount(); $secondOwnAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $user->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); $details = [ 'accountId' => $secondOwnAccount->id, 'accountName' => $secondOwnAccount->name, 'holderId' => $user->id, 'holderType' => User::class, 'holderName' => $user->name, 'holderLocation' => 'Testville', 'holderPhoto' => $user->profile_photo_path, ]; $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $details); $response->assertSet('isNewRecipientModalOpen', false); $response->assertSet('toAccountId', $secondOwnAccount->id); } /** @test */ public function confirming_new_recipient_applies_the_pending_selection() { [$user, ] = $this->actingAsUserWithAccount(); $recipient = User::factory()->create(); $recipientAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $recipient->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $this->toAccountDetails($recipient, $recipientAccount)) ->call('confirmNewRecipient'); $response->assertSet('isNewRecipientModalOpen', false); $response->assertSet('toAccountId', $recipientAccount->id); $response->assertSet('toHolderName', $recipient->name); } /** @test */ public function cancelling_new_recipient_clears_the_pending_selection() { [$user, ] = $this->actingAsUserWithAccount(); $recipient = User::factory()->create(); $recipientAccount = Account::factory()->create([ 'accountable_type' => User::class, 'accountable_id' => $recipient->id, 'limit_min' => -1000, 'limit_max' => 1000, ]); $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $this->toAccountDetails($recipient, $recipientAccount)) ->call('cancelNewRecipient'); $response->assertSet('isNewRecipientModalOpen', false); $response->assertSet('toAccountId', null); $response->assertSet('pendingToAccountDetails', null); $response->assertDispatched('focus-to-account-search'); $response->assertDispatchedTo(\App\Http\Livewire\ToAccount::class, 'resetForm'); } /** @test */ public function unrecognised_holder_type_is_treated_as_unfamiliar_without_error() { [$user, ] = $this->actingAsUserWithAccount(); $details = [ 'accountId' => 999999, 'accountName' => 'Fake Account', 'holderId' => 1, 'holderType' => 'App\\Models\\NotARealModel', 'holderName' => 'Fake Holder', 'holderLocation' => 'Nowhere', 'holderPhoto' => null, ]; $response = Livewire::test(Pay::class) ->dispatch('toAccountDetails', $details); $response->assertSet('isNewRecipientModalOpen', true); } }