diff --git a/lib/AuditLogs.php b/lib/AuditLogs.php index c453d39..65d7c12 100644 --- a/lib/AuditLogs.php +++ b/lib/AuditLogs.php @@ -39,7 +39,7 @@ class AuditLogs * * @return Resource\AuditLogCreateEventStatus */ - public function createEvent($organizationId, $event, $idempotencyKey = null) + public function createEvent($organizationId, $event, ?string $idempotencyKey = null) { $eventsPath = "audit_logs/events"; @@ -73,7 +73,7 @@ public function createEvent($organizationId, $event, $idempotencyKey = null) * @return Resource\AuditLogExport */ - public function createExport($organizationId, $rangeStart, $rangeEnd, $actions = null, $actors = null, $targets = null, $actorNames = null, $actorIds = null) + public function createExport($organizationId, $rangeStart, $rangeEnd, ?array $actions = null, ?array $actors = null, ?array $targets = null, ?array $actorNames = null, ?array $actorIds = null) { $createExportPath = "audit_logs/exports"; diff --git a/lib/Client.php b/lib/Client.php index d50352b..ea5c6ff 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -46,7 +46,7 @@ public static function setRequestClient($requestClient) * * @return array */ - public static function request($method, $path, $headers = null, $params = null, $withAuth = false) + public static function request($method, $path, ?array $headers = null, ?array $params = null, $withAuth = false) { $url = self::generateUrl($path); @@ -105,7 +105,7 @@ public static function generateBaseHeaders($withAuth = false) * * @return string */ - public static function generateUrl($path, $params = null) + public static function generateUrl($path, ?array $params = null) { $url = WorkOS::getApiBaseUrl() . $path; diff --git a/lib/DirectorySync.php b/lib/DirectorySync.php index 4fa5671..a065880 100644 --- a/lib/DirectorySync.php +++ b/lib/DirectorySync.php @@ -27,13 +27,13 @@ class DirectorySync * @return array{?string, ?string, Resource\Directory[]} An array containing the Directory ID to use as before and after cursor, and an array of Directory instances */ public function listDirectories( - $domain = null, - $search = null, + ?string $domain = null, + ?string $search = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $organizationId = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $organizationId = null, + ?string $order = null ) { $directoriesPath = "directories"; $params = [ @@ -78,12 +78,12 @@ public function listDirectories( * @return array{?string, ?string, Resource\DirectoryGroup[]} An array containing the Directory Group ID to use as before and after cursor, and an array of Directory Group instances */ public function listGroups( - $directory = null, - $user = null, + ?string $directory = null, + ?string $user = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $order = null ) { $groupsPath = "directory_groups"; @@ -156,12 +156,12 @@ public function getGroup($directoryGroup) * @throws Exception\WorkOSException */ public function listUsers( - $directory = null, - $group = null, + ?string $directory = null, + ?string $group = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $order = null ) { $usersPath = "directory_users"; diff --git a/lib/Exception/BaseRequestException.php b/lib/Exception/BaseRequestException.php index ae26f6d..7bcac60 100644 --- a/lib/Exception/BaseRequestException.php +++ b/lib/Exception/BaseRequestException.php @@ -25,7 +25,7 @@ class BaseRequestException extends \Exception implements WorkOSException * @param Response $response * @param null|string $message Exception message */ - public function __construct($response, $message = null) + public function __construct($response, ?string $message = null) { $this->response = $response; diff --git a/lib/Exception/GenericException.php b/lib/Exception/GenericException.php index 481de48..c84658f 100644 --- a/lib/Exception/GenericException.php +++ b/lib/Exception/GenericException.php @@ -17,7 +17,7 @@ class GenericException extends \Exception implements WorkOSException * @param string $message Exception message * @param null|array $data Blob */ - public function __construct($message, $data = null) + public function __construct($message, ?array $data = null) { $this->message = $message; diff --git a/lib/MFA.php b/lib/MFA.php index abdb358..5f65372 100644 --- a/lib/MFA.php +++ b/lib/MFA.php @@ -21,9 +21,9 @@ class MFA */ public function enrollFactor( $type, - $totpIssuer = null, - $totpUser = null, - $phoneNumber = null + ?string $totpIssuer = null, + ?string $totpUser = null, + ?string $phoneNumber = null ) { $enrollPath = "auth/factors/enroll"; @@ -79,7 +79,7 @@ public function enrollFactor( */ public function challengeFactor( $authenticationFactorId, - $smsTemplate = null + ?string $smsTemplate = null ) { if (!isset($authenticationFactorId)) { $msg = "Incomplete arguments: 'authentication_factor_id' is a required parameter"; diff --git a/lib/Organizations.php b/lib/Organizations.php index 283be2e..d0922a5 100644 --- a/lib/Organizations.php +++ b/lib/Organizations.php @@ -26,11 +26,11 @@ class Organizations * @throws Exception\WorkOSException */ public function listOrganizations( - $domains = null, + ?array $domains = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $order = null ) { $organizationsPath = "organizations"; $params = [ @@ -76,12 +76,12 @@ public function listOrganizations( */ public function createOrganization( $name, - $domains = null, - $allowProfilesOutsideOrganization = null, - $idempotencyKey = null, - $domain_data = null, - $externalId = null, - $metadata = null + ?array $domains = null, + ?bool $allowProfilesOutsideOrganization = null, + ?string $idempotencyKey = null, + ?array $domain_data = null, + ?string $externalId = null, + ?array $metadata = null ) { $idempotencyKey ? $headers = array("Idempotency-Key: $idempotencyKey") : $headers = null; $organizationsPath = "organizations"; @@ -126,13 +126,13 @@ public function createOrganization( */ public function updateOrganization( $organization, - $domains = null, - $name = null, - $allowProfilesOutsideOrganization = null, - $domain_data = null, - $stripeCustomerId = null, - $externalId = null, - $metadata = null + ?array $domains = null, + ?string $name = null, + ?bool $allowProfilesOutsideOrganization = null, + ?array $domain_data = null, + ?string $stripeCustomerId = null, + ?string $externalId = null, + ?array $metadata = null ) { $organizationsPath = "organizations/{$organization}"; diff --git a/lib/Portal.php b/lib/Portal.php index 3364aa9..c361b2a 100644 --- a/lib/Portal.php +++ b/lib/Portal.php @@ -23,7 +23,7 @@ class Portal * * @return Resource\PortalLink */ - public function generateLink($organization, $intent, $returnUrl = null, $successUrl = null) + public function generateLink($organization, $intent, ?string $returnUrl = null, ?string $successUrl = null) { $generateLinkPath = "portal/generate_link"; $params = [ diff --git a/lib/RequestClient/CurlRequestClient.php b/lib/RequestClient/CurlRequestClient.php index 5edb6db..b5b9115 100644 --- a/lib/RequestClient/CurlRequestClient.php +++ b/lib/RequestClient/CurlRequestClient.php @@ -20,7 +20,7 @@ class CurlRequestClient implements RequestClientInterface * * @return array An array composed of the result string, response headers and status code */ - public function request($method, $url, $headers = null, $params = null) + public function request($method, $url, ?array $headers = null, ?array $params = null) { if (empty($headers)) { $headers = array(); diff --git a/lib/RequestClient/RequestClientInterface.php b/lib/RequestClient/RequestClientInterface.php index b2fe0dd..a140240 100644 --- a/lib/RequestClient/RequestClientInterface.php +++ b/lib/RequestClient/RequestClientInterface.php @@ -19,5 +19,5 @@ interface RequestClientInterface * * @return array An array composed of the result string, response headers and status code */ - public function request($method, $url, $headers, $params); + public function request($method, $url, ?array $headers = null, ?array $params = null); } diff --git a/lib/Resource/WebhookResponse.php b/lib/Resource/WebhookResponse.php index 3f2032c..8731a82 100644 --- a/lib/Resource/WebhookResponse.php +++ b/lib/Resource/WebhookResponse.php @@ -41,7 +41,7 @@ class WebhookResponse * @return self * @throws \InvalidArgumentException */ - public static function create($type, $secret, $verdict, $errorMessage = null) + public static function create($type, $secret, $verdict, ?string $errorMessage = null) { if (!in_array($type, [self::USER_REGISTRATION_ACTION, self::AUTHENTICATION_ACTION])) { throw new \InvalidArgumentException('Invalid response type'); diff --git a/lib/SSO.php b/lib/SSO.php index 6eed387..dcc57a4 100644 --- a/lib/SSO.php +++ b/lib/SSO.php @@ -33,9 +33,9 @@ public function getAuthorizationUrl( $state, $provider = null, $connection = null, - $organization = null, - $domainHint = null, - $loginHint = null + ?string $organization = null, + ?string $domainHint = null, + ?string $loginHint = null ) { $authorizationPath = "sso/authorize"; @@ -219,13 +219,13 @@ public function getConnection($connection) * @throws Exception\WorkOSException */ public function listConnections( - $domain = null, - $connectionType = null, - $organizationId = null, + ?string $domain = null, + ?string $connectionType = null, + ?string $organizationId = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $order = null ) { $connectionsPath = "connections"; $params = [ diff --git a/lib/UserManagement.php b/lib/UserManagement.php index a277fb1..6045ab9 100644 --- a/lib/UserManagement.php +++ b/lib/UserManagement.php @@ -36,14 +36,14 @@ class UserManagement public function createUser( $email, - $password = null, - $firstName = null, - $lastName = null, - $emailVerified = null, - $passwordHash = null, - $passwordHashType = null, - $externalId = null, - $metadata = null + ?string $password = null, + ?string $firstName = null, + ?string $lastName = null, + ?bool $emailVerified = null, + ?string $passwordHash = null, + ?string $passwordHashType = null, + ?string $externalId = null, + ?array $metadata = null ) { $path = "user_management/users"; $params = [ @@ -119,15 +119,15 @@ public function getUserByExternalId($externalId) */ public function updateUser( $userId, - $firstName = null, - $lastName = null, - $emailVerified = null, - $password = null, - $passwordHash = null, - $passwordHashType = null, - $externalId = null, - $metadata = null, - $email = null + ?string $firstName = null, + ?string $lastName = null, + ?bool $emailVerified = null, + ?string $password = null, + ?string $passwordHash = null, + ?string $passwordHashType = null, + ?string $externalId = null, + ?array $metadata = null, + ?string $email = null ) { $path = "user_management/users/{$userId}"; @@ -163,12 +163,12 @@ public function updateUser( * @throws Exception\WorkOSException */ public function listUsers( - $email = null, - $organizationId = null, + ?string $email = null, + ?string $organizationId = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $order = null ) { $path = "user_management/users"; @@ -222,13 +222,13 @@ public function deleteUser($userId) * @param string $userId User ID * @param string $organizationId Organization ID * @param string|null $roleSlug Role Slug - * @param string|null $roleSlugs Role Slugs + * @param array|null $roleSlugs Role Slugs * * @throws Exception\WorkOSException * * @return Resource\OrganizationMembership */ - public function createOrganizationMembership($userId, $organizationId, $roleSlug = null, $roleSlugs = null) + public function createOrganizationMembership($userId, $organizationId, ?string $roleSlug = null, ?array $roleSlugs = null) { $path = "user_management/organization_memberships"; @@ -309,13 +309,13 @@ public function deleteOrganizationMembership($organizationMembershipId) * * @param string $organizationMembershipId Organization Membership ID * @param string|null $role_slug The unique slug of the role to grant to this membership. - * @param string|null $role_slugs The unique slugs of the roles to grant to this membership. + * @param array|null $role_slugs The unique slugs of the roles to grant to this membership. * * @throws Exception\WorkOSException * * @return Resource\OrganizationMembership */ - public function updateOrganizationMembership($organizationMembershipId, $roleSlug = null, $roleSlugs = null) + public function updateOrganizationMembership($organizationMembershipId, ?string $roleSlug = null, ?array $roleSlugs = null) { $path = "user_management/organization_memberships/{$organizationMembershipId}"; @@ -356,13 +356,13 @@ public function updateOrganizationMembership($organizationMembershipId, $roleSlu * @return array{?string, ?string, Resource\OrganizationMembership[]} An array containing the Organization Membership ID to use as before and after cursor, and a list of Organization Memberships instances */ public function listOrganizationMemberships( - $userId = null, - $organizationId = null, - $statuses = null, + ?string $userId = null, + ?string $organizationId = null, + ?array $statuses = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $order = null ) { $path = "user_management/organization_memberships"; @@ -467,10 +467,10 @@ public function reactivateOrganizationMembership($organizationMembershipId) */ public function sendInvitation( $email, - $organizationId = null, - $expiresInDays = null, - $inviterUserId = null, - $roleSlug = null + ?string $organizationId = null, + ?int $expiresInDays = null, + ?string $inviterUserId = null, + ?string $roleSlug = null ) { $path = "user_management/invitations"; @@ -556,12 +556,12 @@ public function findInvitationByToken($invitationToken) * @return array{?string, ?string, Resource\Invitation[]} An array containing the Invitation ID to use as before and after cursor, and a list of Invitations instances */ public function listInvitations( - $email = null, - $organizationId = null, + ?string $email = null, + ?string $organizationId = null, $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null + ?string $before = null, + ?string $after = null, + ?string $order = null ) { $path = "user_management/invitations"; @@ -663,12 +663,12 @@ public function getAuthorizationUrl( $redirectUri, $state = null, $provider = null, - $connectionId = null, - $organizationId = null, - $domainHint = null, - $loginHint = null, - $screenHint = null, - $providerScopes = null + ?string $connectionId = null, + ?string $organizationId = null, + ?string $domainHint = null, + ?string $loginHint = null, + ?string $screenHint = null, + ?array $providerScopes = null ) { $path = "user_management/authorize"; @@ -750,7 +750,7 @@ public function getAuthorizationUrl( * * @return Resource\AuthenticationResponse */ - public function authenticateWithPassword($clientId, $email, $password, $ipAddress = null, $userAgent = null) + public function authenticateWithPassword($clientId, $email, $password, ?string $ipAddress = null, ?string $userAgent = null) { $path = "user_management/authenticate"; $params = [ @@ -785,8 +785,8 @@ public function authenticateWithSelectedOrganization( $clientId, $pendingAuthenticationToken, $organizationId, - $ipAddress = null, - $userAgent = null + ?string $ipAddress = null, + ?string $userAgent = null ) { $path = "user_management/authenticate"; $params = [ @@ -817,7 +817,7 @@ public function authenticateWithSelectedOrganization( * * @return Resource\AuthenticationResponse */ - public function authenticateWithCode($clientId, $code, $ipAddress = null, $userAgent = null) + public function authenticateWithCode($clientId, $code, ?string $ipAddress = null, ?string $userAgent = null) { $path = "user_management/authenticate"; $params = [ @@ -847,7 +847,7 @@ public function authenticateWithCode($clientId, $code, $ipAddress = null, $userA * * @return Resource\AuthenticationResponse */ - public function authenticateWithEmailVerification($clientId, $code, $pendingAuthenticationToken, $ipAddress = null, $userAgent = null) + public function authenticateWithEmailVerification($clientId, $code, $pendingAuthenticationToken, ?string $ipAddress = null, ?string $userAgent = null) { $path = "user_management/authenticate"; $params = [ @@ -883,8 +883,8 @@ public function authenticateWithMagicAuth( $clientId, $code, $userId, - $ipAddress = null, - $userAgent = null + ?string $ipAddress = null, + ?string $userAgent = null ) { $path = "user_management/authenticate"; $params = [ @@ -917,9 +917,9 @@ public function authenticateWithMagicAuth( public function authenticateWithRefreshToken( $clientId, $refreshToken, - $ipAddress = null, - $userAgent = null, - $organizationId = null + ?string $ipAddress = null, + ?string $userAgent = null, + ?string $organizationId = null ) { $path = "user_management/authenticate"; $params = [ @@ -956,8 +956,8 @@ public function authenticateWithTotp( $pendingAuthenticationToken, $authenticationChallengeId, $code, - $ipAddress = null, - $userAgent = null + ?string $ipAddress = null, + ?string $userAgent = null ) { $path = "user_management/authenticate"; $params = [ @@ -988,7 +988,7 @@ public function authenticateWithTotp( * * @return Resource\AuthenticationFactorAndChallengeTotp */ - public function enrollAuthFactor($userId, $type, $totpIssuer = null, $totpUser = null) + public function enrollAuthFactor($userId, $type, ?string $totpIssuer = null, ?string $totpUser = null) { $path = "user_management/users/{$userId}/auth_factors"; @@ -1234,7 +1234,7 @@ public function getMagicAuth($magicAuthId) */ public function createMagicAuth( $email, - $invitationToken = null + ?string $invitationToken = null ) { $path = "user_management/magic_auth"; @@ -1315,7 +1315,7 @@ public function getJwksUrl(string $clientId) * * @return string */ - public function getLogoutUrl(string $sessionId, string $return_to = null) + public function getLogoutUrl(string $sessionId, ?string $return_to = null) { if (!isset($sessionId) || empty($sessionId)) { throw new Exception\UnexpectedValueException("sessionId must not be empty"); diff --git a/tests/WorkOS/AuditLogsTest.php b/tests/WorkOS/AuditLogsTest.php index 54127fc..310cfaa 100644 --- a/tests/WorkOS/AuditLogsTest.php +++ b/tests/WorkOS/AuditLogsTest.php @@ -111,6 +111,37 @@ public function testCreateExport() $this->assertSame($exportFixture, $auditLogExport->toArray()); } + public function testCreateExportWithNullOptionalParams() + { + $path = "audit_logs/exports"; + + $organizationId = "org_123"; + $rangeStart = "2022-08-18T18:07:10.822Z"; + $rangeEnd = "2022-08-18T18:07:10.822Z"; + // The implementation filters out null values, so they won't be in the params array + $params = [ + "organization_id" => $organizationId, + "range_end" => $rangeEnd, + "range_start" => $rangeStart + ]; + + $result = $this->createExportResponseFixture(); + + $this->mockRequest( + Client::METHOD_POST, + $path, + null, + $params, + true, + $result + ); + + $auditLogExport = $this->al->createExport($organizationId, $rangeStart, $rangeEnd, null, null, null, null, null); + $exportFixture = $this->createExportFixture(); + + $this->assertSame($exportFixture, $auditLogExport->toArray()); + } + public function testGetExport() { $auditLogExportId = "123"; diff --git a/tests/WorkOS/ClientTest.php b/tests/WorkOS/ClientTest.php index 3bc6ec7..654ce9b 100644 --- a/tests/WorkOS/ClientTest.php +++ b/tests/WorkOS/ClientTest.php @@ -185,6 +185,46 @@ public function testClientThrowsRequestExceptionsWithErrors($statusCode, $except } } + public function testClientRequestWithNullHeadersAndParams() + { + $this->withApiKeyAndClientId(); + + $path = "some/place"; + $result = json_encode(["data" => "test"]); + + // Client::request always generates base headers even when null is passed + // When $withAuth is false (default), it still includes User-Agent header + $this->mockRequest( + Client::METHOD_GET, + $path, + null, + null, + false, + $result + ); + + $response = Client::request(Client::METHOD_GET, $path, null, null); + $this->assertSame(["data" => "test"], $response); + } + + public function testClientGenerateUrl() + { + $this->withApiKeyAndClientId(); + + $path = "test/path"; + $url = Client::generateUrl($path); + $this->assertStringContainsString($path, $url); + } + + public function testClientGenerateUrlWithNullParams() + { + $this->withApiKeyAndClientId(); + + $path = "test/path"; + $url = Client::generateUrl($path, null); + $this->assertStringContainsString($path, $url); + } + // Providers public static function requestExceptionTestProvider() { diff --git a/tests/WorkOS/UserManagementTest.php b/tests/WorkOS/UserManagementTest.php index cb52713..9326bed 100644 --- a/tests/WorkOS/UserManagementTest.php +++ b/tests/WorkOS/UserManagementTest.php @@ -75,6 +75,40 @@ public function testUpdateUser() $this->assertSame($user, $response->toArray()); } + public function testUpdateUserWithNullOptionalParams() + { + $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; + $path = "user_management/users/{$userId}"; + + $result = $this->createUserResponseFixture(); + + $params = [ + "first_name" => null, + "last_name" => null, + "email_verified" => null, + "password" => null, + "password_hash" => null, + "password_hash_type" => null, + "external_id" => null, + "metadata" => null, + "email" => null + ]; + + $this->mockRequest( + Client::METHOD_PUT, + $path, + null, + $params, + true, + $result + ); + + $user = $this->userFixture(); + + $response = $this->userManagement->updateUser("user_01H7X1M4TZJN5N4HG4XXMA1234", null, null, null, null, null, null, null, null, null); + $this->assertSame($user, $response->toArray()); + } + public function testAuthorizationURLInvalidInputs() { $this->expectException(Exception\UnexpectedValueException::class); @@ -423,6 +457,35 @@ public function testEnrollAuthFactor() $this->assertSame($enrollUserAuthChallengeFixture, $enrollFactorTotp->authenticationChallenge->toArray()); } + public function testEnrollAuthFactorWithNullOptionalParams() + { + $userId = "user_123456"; + $path = "user_management/users/{$userId}/auth_factors"; + $params = [ + "type" => "totp", + "totp_user" => null, + "totp_issuer" => null + ]; + + $result = $this->enrollAuthFactorResponseFixture(); + + $this->mockRequest( + Client::METHOD_POST, + $path, + null, + $params, + true, + $result + ); + + $enrollFactorTotp = $this->userManagement->enrollAuthFactor($userId, "totp", null, null); + $enrollUserAuthFactorFixture = $this->enrollAuthFactorFixture(); + $enrollUserAuthChallengeFixture = $this->enrollAuthChallengeFixture(); + + $this->assertSame($enrollUserAuthFactorFixture, $enrollFactorTotp->authenticationFactor->toArray()); + $this->assertSame($enrollUserAuthChallengeFixture, $enrollFactorTotp->authenticationChallenge->toArray()); + } + public function testAuthenticateWithRefreshToken() { $path = "user_management/authenticate"; @@ -550,6 +613,39 @@ public function testCreateUser() $this->assertSame($user, $response->toArray()); } + public function testCreateUserWithNullOptionalParams() + { + $path = "user_management/users"; + + $result = $this->createUserResponseFixture(); + + $params = [ + "email" => "test@test.com", + "password" => null, + "first_name" => null, + "last_name" => null, + "email_verified" => null, + "password_hash" => null, + "password_hash_type" => null, + "external_id" => null, + "metadata" => null + ]; + + $this->mockRequest( + Client::METHOD_POST, + $path, + null, + $params, + true, + $result + ); + + $user = $this->userFixture(); + + $response = $this->userManagement->createUser("test@test.com", null, null, null, null, null, null, null, null); + $this->assertSame($user, $response->toArray()); + } + public function testGetEmailVerification() { $emailVerificationId = "email_verification_01E4ZCR3C56J083X43JQXF3JK5"; @@ -943,6 +1039,35 @@ public function testCreateOrganizationMembershipWithRoleSlugs() $this->assertSame($organizationMembership, $response->toArray()); } + public function testCreateOrganizationMembershipWithNullRoleParams() + { + $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; + $orgId = "org_01EHQMYV6MBK39QC5PZXHY59C3"; + $path = "user_management/organization_memberships"; + + $result = $this->organizationMembershipResponseFixture(); + + // When both roleSlug and roleSlugs are null, neither should be in params + $params = [ + "organization_id" => $orgId, + "user_id" => $userId, + ]; + + $this->mockRequest( + Client::METHOD_POST, + $path, + null, + $params, + true, + $result + ); + + $organizationMembership = $this->organizationMembershipFixture(); + + $response = $this->userManagement->createOrganizationMembership($userId, $orgId, null, null); + $this->assertSame($organizationMembership, $response->toArray()); + } + public function testGetOrganizationMembership() { $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; @@ -1132,6 +1257,26 @@ public function testUpdateOrganizationMembershipWithRoleSlugs() $this->assertSame($this->organizationMembershipFixture(), $response->toArray()); } + public function testUpdateOrganizationMembershipWithNullRoleParams() + { + $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; + $path = "user_management/organization_memberships/{$organizationMembershipId}"; + + $result = $this->organizationMembershipResponseFixture(); + + // When both roleSlug and roleSlugs are null, params should be empty array + $this->mockRequest( + Client::METHOD_PUT, + $path, + null, + [], + true, + $result + ); + + $response = $this->userManagement->updateOrganizationMembership($organizationMembershipId, null, null); + $this->assertSame($this->organizationMembershipFixture(), $response->toArray()); + } public function testDeactivateOrganizationMembership() { @@ -1215,6 +1360,43 @@ public function testSendInvitation() $this->assertSame($response->toArray(), $expected); } + public function testSendInvitationWithNullOptionalParams() + { + $path = "user_management/invitations"; + + $result = $this->invitationResponseFixture(); + + // The implementation includes null values in params + $params = [ + "email" => "someemail@test.com", + "organization_id" => null, + "expires_in_days" => null, + "inviter_user_id" => null, + "role_slug" => null + ]; + + $this->mockRequest( + Client::METHOD_POST, + $path, + null, + $params, + true, + $result + ); + + $response = $this->userManagement->sendInvitation( + "someemail@test.com", + null, + null, + null, + null + ); + + $expected = $this->invitationFixture(); + + $this->assertSame($response->toArray(), $expected); + } + public function testGetInvitation() { $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5";