service = app(ProviderService::class); } public function test_aprovar_prestador_dispara_push_de_cadastro_aprovado(): void { $provider = $this->makeProvider(); $this->withDeviceToken($provider->user); $push = $this->mockPushService(); $push->shouldReceive('sendToUser') ->once() ->withArgs(function (User $user, $notification) use ($provider) { return $user->is($provider->user) && $notification instanceof CadastroAprovadoPush; }); $approved = $this->service->approve($provider->id); $this->assertSame(ApprovalStatusEnum::ACCEPTED->value, $approved->approval_status->value); } public function test_update_para_accepted_dispara_push(): void { $provider = $this->makeProvider(); $this->withDeviceToken($provider->user); $push = $this->mockPushService(); $push->shouldReceive('sendToUser')->once(); $this->service->update($provider->id, [ 'approval_status' => ApprovalStatusEnum::ACCEPTED->value, ]); } public function test_update_que_nao_muda_o_status_nao_dispara_push(): void { $provider = $this->makeProvider(); $this->withDeviceToken($provider->user); $push = $this->mockPushService(); $push->shouldNotReceive('sendToUser'); $this->service->update($provider->id, ['birth_date' => '1991-02-02']); } public function test_aprovar_prestador_ja_aprovado_nao_reenvia_push(): void { $provider = $this->makeProvider(ApprovalStatusEnum::ACCEPTED); $this->withDeviceToken($provider->user); $push = $this->mockPushService(); $push->shouldNotReceive('sendToUser'); $this->service->approve($provider->id); } /** * Rede de seguranca extra: mesmo que a transicao seja detectada de novo * (reprovar e reaprovar, por exemplo), o log impede o envio duplicado. */ public function test_push_ja_registrada_no_log_nao_e_reenviada(): void { $provider = $this->makeProvider(); $this->withDeviceToken($provider->user); PushNotificationLog::query()->create([ 'label' => (new CadastroAprovadoPush)->label(), 'user_id' => $provider->user->id, 'target' => PushNotificationTargetEnum::PRESTADOR->value, 'category' => PushNotificationCategoryEnum::TRANSACIONAL->value, 'sent_at' => now()->subDay(), ]); $push = $this->mockPushService(); $push->shouldNotReceive('sendToUser'); $this->service->approve($provider->id); } public function test_prestador_sem_device_token_ativo_nao_dispara_push(): void { $provider = $this->makeProvider(); $this->withDeviceToken($provider->user, active: false); $push = $this->mockPushService(); $push->shouldNotReceive('sendToUser'); $approved = $this->service->approve($provider->id); $this->assertSame(ApprovalStatusEnum::ACCEPTED->value, $approved->approval_status->value); } public function test_token_de_outro_app_nao_dispara_push_do_prestador(): void { $provider = $this->makeProvider(); $this->withDeviceToken($provider->user, appType: PushNotificationTargetEnum::CLIENTE); $push = $this->mockPushService(); $push->shouldNotReceive('sendToUser'); $this->service->approve($provider->id); } public function test_falha_no_envio_da_push_nao_impede_a_aprovacao(): void { $provider = $this->makeProvider(); $this->withDeviceToken($provider->user); $push = $this->mockPushService(); $push->shouldReceive('sendToUser') ->once() ->andThrow(new \RuntimeException('FCM indisponivel')); $approved = $this->service->approve($provider->id); $this->assertSame(ApprovalStatusEnum::ACCEPTED->value, $approved->approval_status->value); } // private function mockPushService(): MockInterface { return $this->mock(PushNotificationService::class); } private function makeProvider(?ApprovalStatusEnum $status = null): Provider { $user = User::query()->create([ 'name' => 'Prestador Teste', 'email' => 'prestador'.uniqid().'@teste.com', 'password' => 'secret', 'type' => UserTypeEnum::PROVIDER->value, ]); $provider = Provider::query()->create([ 'user_id' => $user->id, 'document' => '06767310905', 'birth_date' => '1990-01-01', 'approval_status' => ($status ?? ApprovalStatusEnum::PENDING)->value, ]); return $provider->load('user'); } private function withDeviceToken( User $user, bool $active = true, ?PushNotificationTargetEnum $appType = null, ): DeviceToken { return DeviceToken::query()->create([ 'user_id' => $user->id, 'token' => 'tok_'.uniqid(), 'platform' => 'android', 'app_type' => ($appType ?? PushNotificationTargetEnum::PRESTADOR)->value, 'active' => $active, ]); } }