owner = User::factory()->create(); $this->workspace = Workspace::factory()->create(['user_id' => $this->owner->id]); $this->account = SocialAccount::factory()->x()->create([ 'workspace_id' => $this->workspace->id, 'status' => Status::Connected, 'username' => 'testuser', ]); }); test('refresh job calls refreshToken (not verify) on the verifier', function () { $verifier = mock(ConnectionVerifier::class); $verifier->shouldReceive('refreshToken')->once()->with( Mockery::on(fn ($account) => $account->id === $this->account->id) ); $verifier->shouldNotReceive('verify'); app()->instance(ConnectionVerifier::class, $verifier); (new RefreshSocialToken($this->account))->handle($verifier); }); test('refresh job marks account as TokenExpired when refresh_token is rejected', function () { Queue::fake(); $verifier = mock(ConnectionVerifier::class); $verifier->shouldReceive('refreshToken')->once()->andThrow( new TokenExpiredException('refresh_token revoked') ); app()->instance(ConnectionVerifier::class, $verifier); (new RefreshSocialToken($this->account))->handle($verifier); expect($this->account->fresh()->status)->toBe(Status::TokenExpired); expect($this->account->fresh()->error_message)->toBe('refresh_token revoked'); // Notification dispatched because account transitioned from Connected. Queue::assertPushed(SendNotification::class); }); test('refresh job logs warning on non-token errors and leaves status alone', function () { Log::shouldReceive('warning')->once()->withArgs(function ($message, $context) { return $message === 'Proactive token refresh failed' && $context['account_id'] === $this->account->id && $context['error'] === 'network blip'; }); $verifier = mock(ConnectionVerifier::class); $verifier->shouldReceive('refreshToken')->once()->andThrow(new RuntimeException('network blip')); app()->instance(ConnectionVerifier::class, $verifier); (new RefreshSocialToken($this->account))->handle($verifier); expect($this->account->fresh()->status)->toBe(Status::Connected); }); test('refresh job does NOT mark account expired when platform is unavailable', function () { Queue::fake(); Log::shouldReceive('warning')->once()->withArgs(function ($message, $context) { return $message === 'Token refresh skipped: platform unavailable' && $context['account_id'] === $this->account->id && str_contains($context['error'], '503'); }); $verifier = mock(ConnectionVerifier::class); $verifier->shouldReceive('refreshToken')->once()->andThrow( new PlatformUnavailableException('X API returned 503 during token refresh', 503) ); app()->instance(ConnectionVerifier::class, $verifier); (new RefreshSocialToken($this->account))->handle($verifier); expect($this->account->fresh()->status)->toBe(Status::Connected); Queue::assertNotPushed(SendNotification::class); });