Jelajahi Sumber

complete coverage for HelloAssoService

Olivier Massot 2 bulan lalu
induk
melakukan
ca1dd5ffbe
1 mengubah file dengan 496 tambahan dan 0 penghapusan
  1. 496 0
      tests/Unit/Service/HelloAsso/HelloAssoServiceTest.php

+ 496 - 0
tests/Unit/Service/HelloAsso/HelloAssoServiceTest.php

@@ -183,6 +183,58 @@ class HelloAssoServiceTest extends TestCase
         $this->assertInstanceOf(AuthUrl::class, $result);
     }
 
+    /**
+     * @see HelloAssoService::getAuthUrl()
+     */
+    public function testGetAuthUrlWhenOrganizationNotFound(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('getAuthUrl');
+        $organizationId = 1;
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn(null);
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('Organization not found');
+
+        $service->getAuthUrl($organizationId);
+    }
+
+    /**
+     * @see HelloAssoService::getAuthUrl()
+     */
+    public function testGetAuthUrlWhenHelloAssoEntityNotExists(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('getAuthUrl');
+        $organizationId = 1;
+
+        $organization = $this->getMockBuilder(Organization::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn($organization);
+
+        $organization->expects(self::once())
+            ->method('getHelloAsso')
+            ->willReturn(null);
+
+        $this->entityManager->expects(self::once())
+            ->method('persist')
+            ->with(self::isInstanceOf(HelloAsso::class));
+
+        $this->entityManager->expects(self::once())
+            ->method('flush');
+
+        $result = $service->getAuthUrl($organizationId);
+
+        $this->assertInstanceOf(AuthUrl::class, $result);
+    }
+
     /**
      * @see HelloAssoService::connect()
      */
@@ -262,6 +314,103 @@ class HelloAssoServiceTest extends TestCase
         $this->assertSame($helloAssoEntity, $result);
     }
 
+    /**
+     * @see HelloAssoService::connect()
+     */
+    public function testConnectWhenOrganizationNotFound(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('connect');
+        $organizationId = 1;
+        $authorizationCode = 'test-auth-code';
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn(null);
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('Organization not found');
+
+        $service->connect($organizationId, $authorizationCode);
+    }
+
+    /**
+     * @see HelloAssoService::connect()
+     */
+    public function testConnectWhenHelloAssoEntityNotFound(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('connect');
+        $organizationId = 1;
+        $authorizationCode = 'test-auth-code';
+
+        $organization = $this->getMockBuilder(Organization::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn($organization);
+
+        $organization->expects(self::once())
+            ->method('getHelloAsso')
+            ->willReturn(null);
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('HelloAsso entity not found');
+
+        $service->connect($organizationId, $authorizationCode);
+    }
+
+    /**
+     * @see HelloAssoService::connect()
+     */
+    public function testConnectWhenInvalidTokenType(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('connect');
+        $organizationId = 1;
+        $authorizationCode = 'test-auth-code';
+
+        $organization = $this->getMockBuilder(Organization::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $helloAssoEntity = $this->getMockBuilder(HelloAsso::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $challengeVerifier = 'test-verifier';
+        $tokensData = [
+            'access_token' => 'test-access-token',
+            'refresh_token' => 'test-refresh-token',
+            'expires_in' => 3600,
+            'token_type' => 'invalid',
+        ];
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn($organization);
+
+        $organization->expects(self::once())
+            ->method('getHelloAsso')
+            ->willReturn($helloAssoEntity);
+
+        $helloAssoEntity->expects(self::once())
+            ->method('getChallengeVerifier')
+            ->willReturn($challengeVerifier);
+
+        $service->expects(self::once())
+            ->method('fetchAccessToken')
+            ->with($authorizationCode, $challengeVerifier)
+            ->willReturn($tokensData);
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('Invalid token type received');
+
+        $service->connect($organizationId, $authorizationCode);
+    }
+
     /**
      * @see HelloAssoService::makeHelloAssoProfile()
      */
@@ -300,6 +449,52 @@ class HelloAssoServiceTest extends TestCase
         $this->assertInstanceOf(HelloAssoProfile::class, $result);
     }
 
+    /**
+     * @see HelloAssoService::makeHelloAssoProfile()
+     */
+    public function testMakeHelloAssoProfileWhenOrganizationNotFound(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('makeHelloAssoProfile');
+        $organizationId = 1;
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn(null);
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('Organization not found');
+
+        $service->makeHelloAssoProfile($organizationId);
+    }
+
+    /**
+     * @see HelloAssoService::makeHelloAssoProfile()
+     */
+    public function testMakeHelloAssoProfileWhenHelloAssoEntityNotFound(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('makeHelloAssoProfile');
+        $organizationId = 1;
+
+        $organization = $this->getMockBuilder(Organization::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn($organization);
+
+        $organization->expects(self::once())
+            ->method('getHelloAsso')
+            ->willReturn(null);
+
+        $result = $service->makeHelloAssoProfile($organizationId);
+
+        $this->assertInstanceOf(HelloAssoProfile::class, $result);
+        $this->assertFalse($result->isExisting());
+    }
+
     /**
      * @see HelloAssoService::unlinkHelloAssoAccount()
      */
@@ -355,6 +550,55 @@ class HelloAssoServiceTest extends TestCase
         $service->unlinkHelloAssoAccount($organizationId);
     }
 
+    /**
+     * @see HelloAssoService::unlinkHelloAssoAccount()
+     */
+    public function testUnlinkHelloAssoAccountWhenOrganizationNotFound(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('unlinkHelloAssoAccount');
+        $organizationId = 1;
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn(null);
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('Organization not found');
+
+        $service->unlinkHelloAssoAccount($organizationId);
+    }
+
+    /**
+     * @see HelloAssoService::unlinkHelloAssoAccount()
+     */
+    public function testUnlinkHelloAssoAccountWhenHelloAssoEntityNotFound(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('unlinkHelloAssoAccount');
+        $organizationId = 1;
+
+        $organization = $this->getMockBuilder(Organization::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->organizationRepository->expects(self::once())
+            ->method('find')
+            ->with($organizationId)
+            ->willReturn($organization);
+
+        $organization->expects(self::once())
+            ->method('getHelloAsso')
+            ->willReturn(null);
+
+        $this->entityManager->expects(self::never())
+            ->method('persist');
+
+        $this->entityManager->expects(self::never())
+            ->method('flush');
+
+        $service->unlinkHelloAssoAccount($organizationId);
+    }
+
     /**
      * @see HelloAssoService::getResource()
      */
@@ -409,6 +653,80 @@ class HelloAssoServiceTest extends TestCase
         $this->assertSame($expectedData, $result);
     }
 
+    /**
+     * @see HelloAssoService::getResource()
+     */
+    public function testGetResourceWhenIncompleteEntity(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('getResource');
+
+        $helloAssoEntity = $this->getMockBuilder(HelloAsso::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $routeParts = ['organizations', 'test-slug', 'forms'];
+
+        $helloAssoEntity->expects(self::once())
+            ->method('getOrganizationSlug')
+            ->willReturn(null);
+
+        // getToken() won't be called because getOrganizationSlug() returns null first
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('HelloAsso entity incomplete');
+
+        $service->getResource($helloAssoEntity, $routeParts);
+    }
+
+    /**
+     * @see HelloAssoService::getResource()
+     */
+    public function testGetResourceWhenHttpError(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('getResource');
+
+        $helloAssoEntity = $this->getMockBuilder(HelloAsso::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $routeParts = ['organizations', 'test-slug', 'forms'];
+
+        $helloAssoEntity->expects(self::once())
+            ->method('getOrganizationSlug')
+            ->willReturn('test-org-slug');
+
+        $helloAssoEntity->expects(self::atLeastOnce())
+            ->method('getToken')
+            ->willReturn('test-token');
+
+        $service->expects(self::once())
+            ->method('refreshTokenIfNeeded')
+            ->with($helloAssoEntity)
+            ->willReturn($helloAssoEntity);
+
+        $service->expects(self::once())
+            ->method('get')
+            ->willReturn($response);
+
+        $response->expects(self::atLeastOnce())
+            ->method('getStatusCode')
+            ->willReturn(404);
+
+        $response->expects(self::once())
+            ->method('getContent')
+            ->with(false)
+            ->willReturn('Not Found');
+
+        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
+        $this->expectExceptionMessage('Failed to fetch resource: [404] Not Found');
+
+        $service->getResource($helloAssoEntity, $routeParts);
+    }
+
     /**
      * @see HelloAssoService::getHelloAssoEventForms()
      */
@@ -863,6 +1181,65 @@ class HelloAssoServiceTest extends TestCase
         $this->assertSame($expectedTokenData, $result);
     }
 
+    /**
+     * @see HelloAssoService::fetchAccessToken()
+     */
+    public function testFetchAccessTokenWhenHttpError(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('fetchAccessToken');
+
+        $response = $this->getMockBuilder(ResponseInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->httpClient->expects(self::once())
+            ->method('request')
+            ->willReturn($response);
+
+        $response->expects(self::once())
+            ->method('getStatusCode')
+            ->willReturn(400);
+
+        $response->expects(self::once())
+            ->method('getContent')
+            ->with(false)
+            ->willReturn('Bad Request');
+
+        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
+        $this->expectExceptionMessage('Failed to fetch access token: Bad Request');
+
+        $service->fetchAccessToken();
+    }
+
+    /**
+     * @see HelloAssoService::fetchAccessToken()
+     */
+    public function testFetchAccessTokenWhenJsonError(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('fetchAccessToken');
+
+        $response = $this->getMockBuilder(ResponseInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->httpClient->expects(self::once())
+            ->method('request')
+            ->willReturn($response);
+
+        $response->expects(self::once())
+            ->method('getStatusCode')
+            ->willReturn(200);
+
+        $response->expects(self::once())
+            ->method('getContent')
+            ->willReturn('invalid-json');
+
+        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
+        $this->expectExceptionMessage('Failed to parse authentication response:');
+
+        $service->fetchAccessToken();
+    }
+
     /**
      * @see HelloAssoService::updateDomain()
      */
@@ -891,6 +1268,35 @@ class HelloAssoServiceTest extends TestCase
         $service->updateDomain('test-access-token', 'https://test-domain.com');
     }
 
+    /**
+     * @see HelloAssoService::updateDomain()
+     */
+    public function testUpdateDomainWhenHttpError(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('updateDomain');
+
+        $response = $this->getMockBuilder(ResponseInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $service->expects(self::once())
+            ->method('put')
+            ->willReturn($response);
+
+        $response->expects(self::once())
+            ->method('getStatusCode')
+            ->willReturn(403);
+
+        $response->expects(self::once())
+            ->method('getContent')
+            ->willReturn('Forbidden');
+
+        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
+        $this->expectExceptionMessage('Failed to update domain: Forbidden');
+
+        $service->updateDomain('test-access-token', 'https://test-domain.com');
+    }
+
     /**
      * @see HelloAssoService::refreshTokenIfNeeded()
      */
@@ -1034,4 +1440,94 @@ class HelloAssoServiceTest extends TestCase
 
         $this->assertSame($helloAssoEntity, $result);
     }
+
+    /**
+     * @see HelloAssoService::refreshTokens()
+     */
+    public function testRefreshTokensWhenIncompleteEntity(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('refreshTokens');
+
+        $helloAssoEntity = $this->getMockBuilder(HelloAsso::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $helloAssoEntity->expects(self::once())
+            ->method('getRefreshToken')
+            ->willReturn(null);
+
+        // getRefreshTokenCreatedAt() won't be called because getRefreshToken() returns null first
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('HelloAsso entity incomplete');
+
+        $service->refreshTokens($helloAssoEntity);
+    }
+
+    /**
+     * @see HelloAssoService::refreshTokens()
+     */
+    public function testRefreshTokensWhenHttpError(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('refreshTokens');
+
+        $helloAssoEntity = $this->getMockBuilder(HelloAsso::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $response = $this->getMockBuilder(ResponseInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $helloAssoEntity->expects(self::atLeastOnce())
+            ->method('getRefreshToken')
+            ->willReturn('current-refresh-token');
+
+        $helloAssoEntity->expects(self::once())
+            ->method('getRefreshTokenCreatedAt')
+            ->willReturn(new \DateTime());
+
+        $this->httpClient->expects(self::once())
+            ->method('request')
+            ->willReturn($response);
+
+        $response->expects(self::once())
+            ->method('getStatusCode')
+            ->willReturn(401);
+
+        $response->expects(self::once())
+            ->method('getContent')
+            ->with(false)
+            ->willReturn('Unauthorized');
+
+        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
+        $this->expectExceptionMessage('Failed to refresh access token: Unauthorized');
+
+        $service->refreshTokens($helloAssoEntity);
+    }
+
+    /**
+     * @see HelloAssoService::refreshTokenIfNeeded()
+     */
+    public function testRefreshTokenIfNeededWhenIncompleteEntity(): void
+    {
+        $service = $this->getHelloAssoServiceMockFor('refreshTokenIfNeeded');
+
+        $helloAssoEntity = $this->getMockBuilder(HelloAsso::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $helloAssoEntity->expects(self::once())
+            ->method('getRefreshToken')
+            ->willReturn('test-refresh-token');
+
+        $helloAssoEntity->expects(self::once())
+            ->method('getRefreshTokenCreatedAt')
+            ->willReturn(null);
+
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionMessage('HelloAsso entity incomplete');
+
+        $service->refreshTokenIfNeeded($helloAssoEntity);
+    }
 }