stripeService = $this->createMock(StripeService::class); $this->userRepo = $this->createMock(EntityRepository::class); $this->em = $this->createMock(EntityManagerInterface::class); $this->em->method('getRepository')->willReturnCallback(function (string $class) { return match ($class) { User::class => $this->userRepo, default => $this->createMock(EntityRepository::class), }; }); } private function createOrganizer(string $stripeId, bool $charges = false, bool $payouts = false): User { $user = new User(); $user->setEmail('orga-'.uniqid().'@test.fr'); $user->setFirstName('Test'); $user->setLastName('Orga'); $user->setPassword('hashed'); $user->setRoles(['ROLE_ORGANIZER']); $user->setStripeAccountId($stripeId); $user->setStripeChargesEnabled($charges); $user->setStripePayoutsEnabled($payouts); $user->setCompanyName('Asso Test'); return $user; } private function createCommandTester(): CommandTester { $command = new StripeSyncCommand( $this->em, $this->stripeService, ); $app = new Application(); $app->addCommand($command); return new CommandTester($app->find('app:stripe:sync')); } public function testSyncUpdatesStripeStatus(): void { $user = $this->createOrganizer('acct_123'); $this->userRepo->method('findAll')->willReturn([$user]); $this->stripeService->method('retrieveAccountStatus') ->with('acct_123') ->willReturn(['charges_enabled' => true, 'payouts_enabled' => true]); $tester = $this->createCommandTester(); $tester->execute([]); self::assertTrue($user->isStripeChargesEnabled()); self::assertTrue($user->isStripePayoutsEnabled()); self::assertStringContainsString('1 synced', $tester->getDisplay()); self::assertSame(0, $tester->getStatusCode()); } public function testSyncDetectsChanges(): void { $user = $this->createOrganizer('acct_456', true, true); $this->userRepo->method('findAll')->willReturn([$user]); $this->stripeService->method('retrieveAccountStatus') ->willReturn(['charges_enabled' => true, 'payouts_enabled' => false]); $tester = $this->createCommandTester(); $tester->execute([]); self::assertTrue($user->isStripeChargesEnabled()); self::assertFalse($user->isStripePayoutsEnabled()); self::assertStringContainsString('UPDATED', $tester->getDisplay()); } public function testSyncWithNoOrganizers(): void { $this->userRepo->method('findAll')->willReturn([]); $tester = $this->createCommandTester(); $tester->execute([]); self::assertStringContainsString('No organizers', $tester->getDisplay()); self::assertSame(0, $tester->getStatusCode()); } public function testSyncHandlesStripeError(): void { $user = $this->createOrganizer('acct_bad'); $this->userRepo->method('findAll')->willReturn([$user]); $this->stripeService->method('retrieveAccountStatus') ->willThrowException(new \RuntimeException('Account not found')); $tester = $this->createCommandTester(); $tester->execute([]); self::assertStringContainsString('1 error', $tester->getDisplay()); self::assertSame(1, $tester->getStatusCode()); } public function testSyncSkipsOrganizersWithoutStripeAccount(): void { $userWithStripe = $this->createOrganizer('acct_ok'); $userWithoutStripe = new User(); $userWithoutStripe->setEmail('no-stripe@test.fr'); $userWithoutStripe->setFirstName('No'); $userWithoutStripe->setLastName('Stripe'); $userWithoutStripe->setPassword('hashed'); $userWithoutStripe->setRoles(['ROLE_ORGANIZER']); $this->userRepo->method('findAll')->willReturn([$userWithStripe, $userWithoutStripe]); $this->stripeService->method('retrieveAccountStatus') ->willReturn(['charges_enabled' => true, 'payouts_enabled' => false]); $tester = $this->createCommandTester(); $tester->execute([]); self::assertStringContainsString('Syncing 1 organizer', $tester->getDisplay()); self::assertStringContainsString('1 synced', $tester->getDisplay()); self::assertTrue($userWithStripe->isStripeChargesEnabled()); self::assertFalse($userWithStripe->isStripePayoutsEnabled()); } }