316 lines
11 KiB
PHP
316 lines
11 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Http\Livewire\Pay;
|
|
use App\Models\Account;
|
|
use App\Models\Transaction;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use Namu\WireChat\Enums\ConversationType;
|
|
use Namu\WireChat\Enums\MessageType;
|
|
use Namu\WireChat\Models\Conversation;
|
|
use Namu\WireChat\Models\Message;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Tests the "new recipient" confirmation modal shown in the Pay view when the
|
|
* active profile has never had a chat conversation or payment with the
|
|
* selected to-account holder.
|
|
*
|
|
* @group payment
|
|
*/
|
|
class PayNewRecipientConfirmationTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
\DB::table('transaction_types')->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);
|
|
}
|
|
}
|