logger = new Logger('Test applicatif'); $handler = new StreamHandler('php://stdout', Logger::DEBUG); $formatter = new LineFormatter( "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n", 'Y-m-d H:i:s' ); $handler->setFormatter($formatter); $this->logger->pushHandler($handler); // Boot le kernel symfony et récupère l'entity manager // @see https://symfony.com/doc/current/testing.html#retrieving-services-in-the-test self::bootKernel(); $this->em = static::getContainer()->get(EntityManagerInterface::class); // Purge DB before populating new fixtures $this->purgeDb(); $this->logger->info('Database purged'); // Définit les fixtures et flush $this->loadFixtures(); $this->em->flush(); // Instancie le client qui exécutera les requêtes à l'api // @see https://symfony.com/doc/current/testing.html#making-requests $this->client = static::createClient(); } protected function purgeDb() { if (!preg_match('/.*test.*/', $this->em->getConnection()->getDatabase())) { throw new \RuntimeException("The DB name shall contain 'test' in its name to be purge"); } $this->em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 0;'); $purger = new ORMPurger($this->em); $purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE); $purger->purge(); $this->resetAutoIncrement(); $this->em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 1;'); } protected function resetAutoIncrement() { $connection = $this->em->getConnection(); $schemaManager = $connection->getSchemaManager(); foreach ($schemaManager->listTableNames() as $tableName) { $connection->executeStatement("ALTER TABLE $tableName AUTO_INCREMENT = 1;"); } } /** * Create and persist the fixtures (do not flush). * * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#same-entities-used-in-these-docs */ protected function loadFixtures(): void { $adminEbag = PersonFactory::createOne( [ 'username' => 'ebag', 'password' => 'password', ] ); $personOfOtherOrganization = PersonFactory::createOne( [ 'username' => 'intruOfRoot', 'password' => 'password', ] ); $student = PersonFactory::createOne([ 'username' => 'studentEbag', 'password' => 'password', ]); $contactPoint = ContactPointFactory::createOne([ 'contactType' => ContactPointTypeEnum::PRINCIPAL, ]); $parameters = ParametersFactory::createOne([ 'educationPeriodicity' => PeriodicityEnum::MONTHLY, 'financialDate' => new \DateTime(), 'musicalDate' => new \DateTime(), 'startCourseDate' => new \DateTime(), 'endCourseDate' => new \DateTime(), 'average' => 20, 'editCriteriaNotationByAdminOnly' => true, 'smsSenderName' => 'MySender', 'logoDonorsMove' => false, 'subDomain' => 'subdomain', 'website' => 'https://www.example.com', 'otherWebsite' => 'https://www.otherwebsite.com', 'customDomain' => 'https://www.customdomain.com', 'desactivateOpentalentSiteWeb' => false, 'bulletinPeriod' => BulletinPeriodEnum::YEAR, 'bulletinWithTeacher' => false, 'bulletinPrintAddress' => false, 'bulletinSignatureDirector' => true, 'bulletinDisplayLevelAcquired' => true, 'bulletinShowEducationWithoutEvaluation' => false, 'bulletinViewTestResults' => false, 'bulletinShowAbsences' => false, 'bulletinShowAverages' => true, 'bulletinOutput' => BulletinOutputEnum::SEND_BY_EMAIL, 'bulletinEditWithoutEvaluation' => true, 'bulletinReceiver' => SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS, 'usernameSMS' => '2iosinterne', 'passwordSMS' => '2iosot74', 'showAdherentList' => true, 'studentsAreAdherents' => false, 'timezone' => TimeZoneEnum::EUROPE_PARIS, 'advancedEducationNotationType' => AdvancedEducationNotationTypeEnum::BY_EDUCATION, 'sendAttendanceEmail' => true, 'sendAttendanceSms' => true, 'generateAttendanceReport' => true, 'consultPedagogicResult' => true, 'consultTeacherListing' => true, 'periodValidation' => true, ]); $parameters2 = ParametersFactory::createOne([ 'educationPeriodicity' => PeriodicityEnum::MONTHLY, 'financialDate' => new \DateTime(), 'musicalDate' => new \DateTime(), 'startCourseDate' => new \DateTime(), 'endCourseDate' => new \DateTime(), 'average' => 20, 'editCriteriaNotationByAdminOnly' => true, 'smsSenderName' => 'toto', 'logoDonorsMove' => false, 'subDomain' => 'subdomain', 'website' => 'https://www.toto.com', 'otherWebsite' => 'https://www.toto.com', 'customDomain' => 'https://www.toto.com', 'desactivateOpentalentSiteWeb' => false, 'bulletinPeriod' => BulletinPeriodEnum::YEAR, 'bulletinWithTeacher' => false, 'bulletinPrintAddress' => false, 'bulletinSignatureDirector' => true, 'bulletinDisplayLevelAcquired' => true, 'bulletinShowEducationWithoutEvaluation' => false, 'bulletinViewTestResults' => false, 'bulletinShowAbsences' => false, 'bulletinShowAverages' => true, 'bulletinOutput' => BulletinOutputEnum::SEND_BY_EMAIL, 'bulletinEditWithoutEvaluation' => true, 'bulletinReceiver' => SendToBulletinEnum::STUDENTS_AND_THEIR_GUARDIANS, 'usernameSMS' => 'toto', 'passwordSMS' => 'toto', 'showAdherentList' => true, 'studentsAreAdherents' => false, 'timezone' => TimeZoneEnum::EUROPE_PARIS, 'advancedEducationNotationType' => AdvancedEducationNotationTypeEnum::BY_EDUCATION, 'sendAttendanceEmail' => true, 'sendAttendanceSms' => true, 'generateAttendanceReport' => true, 'consultPedagogicResult' => true, 'consultTeacherListing' => true, 'periodValidation' => true, ]); $organization = OrganizationFactory::createOne([ 'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901, 'principalType' => PrincipalTypeEnum::NATIONAL_FEDERATION, 'name' => 'Root', 'parameters' => $parameters, 'siretNumber' => '34919841600035', 'identifier' => 'FR042100000050', ]); $network1 = NetworkFactory::createOne([ 'name' => 'Network 1', 'logo' => 'logo', 'url' => 'https://www.network1.com', ]); $network2 = NetworkFactory::createOne([ 'name' => 'Network 2', 'logo' => 'logo', 'url' => 'https://www.network2.com', ]); $cmfNetwork = NetworkFactory::createOne([ 'name' => 'CMF', 'logo' => 'logo', 'url' => 'https://www.cmf.com', ]); $networkOrganization = NetworkOrganizationFactory::createOne([ 'network' => $cmfNetwork, 'organization' => $organization, 'startDate' => new \DateTime('2001-01-01'), 'endDate' => new \DateTime('2031-12-31'), 'leadingCause' => 'leadingCause', ]); $billingSetting = BillingSettingFactory::createOne([ 'organization' => $organization, ]); $residenceArea = ResidenceAreaFactory::createOne([ 'label' => 'Résidence 1', 'billingSetting' => $billingSetting, ]); $organization2 = OrganizationFactory::createOne([ 'legalStatus' => LegalEnum::ASSOCIATION_LAW_1901, 'principalType' => PrincipalTypeEnum::NATIONAL_FEDERATION, 'name' => 'Other Organization', 'parameters' => $parameters2, ]); $settings2 = SettingsFactory::createOne([ 'product' => SettingsProductEnum::SCHOOL_PREMIUM, 'organization' => $organization2, 'modules' => ['BillingAdministration'], ]); $mobyteUserStatus = MobytUserStatusFactory::createOne([ 'organizationId' => $organization->getId(), 'active' => true, 'amount' => 100, 'money' => 100, ]); $cycle = CycleFactory::createOne([ 'organization' => $organization, 'label' => 'Cycle 1', 'cycleEnum' => CycleEnum::CYCLE_1, ]); $settings = SettingsFactory::createOne([ 'product' => SettingsProductEnum::SCHOOL_PREMIUM, 'organization' => $organization, 'modules' => [ 'Sms' => true, // 'BillingAdministration' => true, ], ]); $educationTimings = EducationTimingFactory::createOne([ 'organization' => $organization, 'timing' => 45, ]); $educationTimings2 = EducationTimingFactory::createOne([ 'organization' => $organization2, 'timing' => 60, ]); $subdomain = SubdomainFactory::createOne([ 'organization' => $organization, 'subdomain' => 'subdomain', 'active' => true, ]); $event = EventFactory::createOne([ 'organization' => $organization, 'name' => 'My event', 'datetimeStart' => new \DateTime(), 'datetimeEnd' => new \DateTime(), 'visibility' => VisibilityEnum::PUBLIC_VISIBILITY, ]); $this->user = AccessFactory::createOne([ 'person' => $adminEbag, 'organization' => $organization, 'roles' => ['ROLE_ADMIN', 'ROLE_ADMIN_CORE', 'ROLE_SUPER_ADMIN', 'ROLE_ORGANIZATION_VIEW', 'ROLE_ORGANIZATION'], 'adminAccess' => true, 'activityYear' => 2021, ]); $accessWithNoRole = AccessFactory::createOne([ 'person' => $student, 'organization' => $organization, 'roles' => ['ROLE_STUDENT'], 'adminAccess' => false, ]); $acccesFromOtherOrganization = AccessFactory::createOne([ 'person' => $personOfOtherOrganization, 'organization' => $organization2, 'roles' => ['ROLE_ADMIN', 'ROLE_ADMIN_CORE', 'ROLE_SUPER_ADMIN', 'ROLE_ORGANIZATION_VIEW', 'ROLE_ORGANIZATION'], 'adminAccess' => true, ]); $this->logger->info('User created in loadFixture: ', [ 'id' => $this->user->getId(), 'username' => $this->user->getPerson()->getUsername(), 'roles' => $this->user->getRoles(), 'organization' => $this->user->getOrganization()->getName(), 'billingSetting' => $this->user->getOrganization()->getBillingSetting()->getId(), ]); } /** * Send a requests, parse the hydra response and return an object or a Collection. * * @param array $data * @param array $headers */ protected function request(string $method, string $route, ?array $data = null, array $headers = []): ResponseInterface { if ($this->user) { $headers = array_merge( ['x-accessid' => $this->user->getId(), 'authorization' => 'BEARER '.$this->securityToken], $headers ); } $parameters = ['headers' => $headers]; if ($data) { $parameters['json'] = $data; } return $this->client->request( $method, $route, $parameters ); } /** * Send a GET request and return the response parsed content. * * @param array $headers */ protected function get(string $route, array $headers = []): ResponseInterface { return $this->request( Request::METHOD_GET, $route, null, $headers ); } /** * Send a PUT request and return the response parsed content. * * @param array $data * @param array $headers */ protected function put(string $route, array $data, array $headers = []): ResponseInterface { return $this->request( Request::METHOD_PUT, $route, $data, $headers ); } /** * Send a POST request and return the response parsed content. * * @param array $data * @param array $headers */ protected function post(string $route, array $data, array $headers = []): ResponseInterface { return $this->request( Request::METHOD_POST, $route, $data, $headers ); } /** * Send a DELETE request and return the response parsed content. * * @param array $headers */ protected function delete(string $route, array $headers = []): ResponseInterface { return $this->request( Request::METHOD_DELETE, $route, null, $headers ); } /** * Login as the given Access user. * * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface */ public function loginAs() { $access = $this->em->getRepository(Access::class)->find(1); $person = $access->getPerson(); $response = $this->post( '/login_check', ['username' => $person->getUsername(), 'password' => $person->getPassword()] ); $content = $response->getContent(); $decodedContent = json_decode($content); // Vérifier que le token est présent if (!isset($decodedContent->token)) { throw new \Exception('Token not found in response'); } $this->securityToken = $decodedContent->token; $this->user = $access; } /** * Login as the given Access user. * * @return void * * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface */ public function loginAsStudent() { // on récupère l'access qui a l'id 641003 dans l'entity manager $access = $this->em->getRepository(Access::class)->find(2); $person = $access->getPerson(); $response = $this->post( '/login_check', ['username' => $person->getUsername(), 'password' => $person->getPassword()] ); $content = $response->getContent(); $this->securityToken = json_decode($content)->token; $this->user = $access; } /** * Login as the given Access user. * * @return void * * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface */ public function loginAsintruOfRoot() { $access = $this->em->getRepository(Access::class)->find(3); $person = $access->getPerson(); $response = $this->post( '/login_check', ['username' => $person->getUsername(), 'password' => $person->getPassword()] ); $content = $response->getContent(); $this->securityToken = json_decode($content)->token; $this->user = $access; } /** * Assert that the response has the expected status code and is well formated. */ protected function validateCollectionSchema(string $resourceClass, int $expectedStatus = 200): void { $this->assertResponseStatusCodeSame($expectedStatus); if ($expectedStatus == 200) { $this->assertResponseIsSuccessful(); } // Asserts that the returned content type is JSON-LD (the default) $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform // >>> Issue with the json typed PublicStructure::addresses properties // $this->assertMatchesResourceCollectionJsonSchema($resourceClass); } }