Skip to content
Snippets Groups Projects
Commit fc2a42bd authored by Fabrice Gangler's avatar Fabrice Gangler :art:
Browse files

chore: add some helper traits

parent 5b4d67c7
No related branches found
No related tags found
1 merge request!29Feat user login change password forgot password
<?php
/*
* This file is part of the Comptoir-du-Libre software.
* <https://gitlab.adullact.net/Comptoir/comptoir-du-libre>
*
* Copyright (c) ADULLACT <https://adullact.org>
* Association des Développeurs et Utilisateurs de Logiciels Libres
* pour les Administrations et les Collectivités Territoriales
*
* Comptoir-du-Libre is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU Affero General Public License
* along with this software. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>.
*/
declare(strict_types=1);
namespace App\Service\Mailer;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mime\Email;
trait MailerTrait
{
/**
* Add common technical email headers
* - X-Priority
* - X-Auto-Response-Suppress
*/
public function addCommonTechnicalEmailHeaders(
TemplatedEmail|Email &$email
): void {
$email->priority(Email::PRIORITY_HIGH);
$email->getHeaders()->addTextHeader('X-Auto-Response-Suppress', 'OOF, DR, RN, NRN, AutoReply');
// this non-standard header tells compliant autoresponders ("email holiday mode")
// to not reply to this message because it's an automated email
}
}
<?php
/*
* This file is part of the Comptoir-du-Libre software.
* <https://gitlab.adullact.net/Comptoir/comptoir-du-libre>
*
* Copyright (c) ADULLACT <https://adullact.org>
* Association des Développeurs et Utilisateurs de Logiciels Libres
* pour les Administrations et les Collectivités Territoriales
*
* Comptoir-du-Libre is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU Affero General Public License
* along with this software. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>.
*/
declare(strict_types=1);
namespace App\tests\CommonHelpers;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\RawMessage;
trait TestHelperEmailTrait
{
/**
* Check that content of html and text versions contain $text
*/
public function assertEmailBodyContains(RawMessage $email, string $text, string $message = ''): void
{
$this->assertEmailHtmlBodyContains(email: $email, text: $text, message: $message);
$this->assertEmailTextBodyContains(email: $email, text: $text, message: $message);
}
/**
* Check common technical email headers:
* - X-Priority
* - X-Auto-Response-Suppress
*/
public function checkCommonTechnicalEmailHeaders(
TemplatedEmail|RawMessage $email
): void {
$this->assertEmailHasHeader($email, "X-Priority");
$this->assertEmailHeaderSame($email, "X-Priority", "2 (High)");
$this->assertEmailHasHeader($email, "X-Auto-Response-Suppress");
$this->assertEmailHeaderSame($email, "X-Auto-Response-Suppress", "OOF, DR, RN, NRN, AutoReply");
// this non-standard header tells compliant autoresponders ("email holiday mode")
// to not reply to this message because it's an automated email
}
/**
* Check correspondents email headers:
* - TO and FROM email HEADERS
* - others correspondents email HEADERS (Bcc, Cc, Reply-To) are missing, except for Bcc if specified
*/
public function checkCommonCorrespondentsEmailHeaders(
TemplatedEmail|RawMessage $email,
string $expectedEmailTo,
string $expectedEmailFrom,
bool $bccIsExpected = false,
string $expectedEmailBcc = '',
): void {
# Check TO and FROM email HEADERS
$this->assertEmailAddressContains($email, 'From', "$expectedEmailFrom");
$this->assertEmailAddressContains($email, 'To', "$expectedEmailTo");
$emailToAddresses = $email->getTo();
$emailFromAddresses = $email->getFrom();
$this->assertCount(1, $emailToAddresses);
$this->assertCount(1, $emailFromAddresses);
$this->assertInstanceOf(Address::class, $emailToAddresses[0]);
$this->assertInstanceOf(Address::class, $emailFromAddresses[0]);
$this->assertSame("$expectedEmailTo", $emailToAddresses[0]->getAddress());
$this->assertSame("$expectedEmailFrom", $emailFromAddresses[0]->getAddress());
# Check others correspondents email HEADERS
$this->assertEmailNotHasHeader($email, "Reply-To");
$this->assertEmailNotHasHeader($email, "Cc");
if ($bccIsExpected === false) {
$this->assertEmailNotHasHeader($email, "Bcc");
} elseif (empty($expectedEmailBcc)) {
$this->assertEmailHasHeader($email, "Bcc");
} else {
$this->assertEmailHasHeader($email, "Bcc");
$this->assertEmailAddressContains($email, 'Bcc', "$expectedEmailBcc");
}
}
}
<?php
/*
* This file is part of the Comptoir-du-Libre software.
* <https://gitlab.adullact.net/Comptoir/comptoir-du-libre>
*
* Copyright (c) ADULLACT <https://adullact.org>
* Association des Développeurs et Utilisateurs de Logiciels Libres
* pour les Administrations et les Collectivités Territoriales
*
* Comptoir-du-Libre is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU Affero General Public License
* along with this software. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>.
*/
declare(strict_types=1);
namespace App\Tests\Functional;
use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpFoundation\Response;
trait TestHelperFormTrait
{
public function checkFormField(
Crawler $crawler,
string $htmlFormName,
string $fieldIdsuffix,
array $fieldAttributes = [ 'type' => 'text'],
string $labelText = '',
string $helpText = '',
string $fieldHtmlTag = 'input',
) {
$fieldId = $htmlFormName . "_$fieldIdsuffix";
if ($labelText !== '') {
$this->checkAttribute($crawler, "label[for=$fieldId]", ['_text' => $labelText]);
}
if ($helpText !== '') {
$this->checkAttribute($crawler, "#$fieldId" . '_help', ['_text' => $helpText]);
$fieldAttributes['aria-describedby'] = $fieldId . '_help';
}
$this->checkAttribute($crawler, "$fieldHtmlTag#$fieldId", $fieldAttributes);
}
public function commonCheckerIfFormFieldIsInvalid(
Crawler $crawler,
string $cssFilterOfInvadFormField,
string $cssFilterOfInvalidFeedback,
string $invalidFeedback,
array $expectedFieldAttributes = ['class' => 'form-control is-invalid'],
): void {
$this->checkAttribute(
crawler: $crawler,
cssFilter: "$cssFilterOfInvadFormField",
attributesExpected: $expectedFieldAttributes
);
$this->assertSelectorTextContains("$cssFilterOfInvalidFeedback", "$invalidFeedback");
}
public function commonCheckerWhenFormIsSentWithMissingOrEmptyField(
KernelBrowser $kernelBrowser,
array $validFormData,
string $formName,
string $fieldName,
string $fieldRepeatName = null,
string $invalidFeedback = 'This field is mandatory.',
array $expectedFieldAttributes = ['class' => 'form-control is-invalid'],
bool $checkEmptyField = true,
bool $checkMissingField = true,
string $methodNameToSendFormWithWrongData = 'methodNameToSendFormWithWrongData'
): void {
$fielFullName = "${formName}[${fieldName}]";
$fielId = "#${formName}_${fieldName}";
if (!\is_null($fieldRepeatName)) {
$fielFullName = "${formName}[${fieldName}][${fieldRepeatName}]";
$fielId = "#${formName}_${fieldName}_${fieldRepeatName}";
if ($fieldRepeatName === 'second') {
$fielId = "#${formName}_${fieldName}_first";
}
}
// Field is missing
if ($checkMissingField === true) {
$formDataWithMissingField = $validFormData;
unset($formDataWithMissingField["$fielFullName"]);
$crawler = $this->$methodNameToSendFormWithWrongData(
$formDataWithMissingField,
$kernelBrowser
);
$this->commonCheckerIfFormFieldIsInvalid(
crawler: $crawler,
cssFilterOfInvadFormField: "$fielId",
cssFilterOfInvalidFeedback: '.invalid-feedback',
invalidFeedback: $invalidFeedback,
expectedFieldAttributes: $expectedFieldAttributes
);
}
// Field is empty
if ($checkEmptyField === true) {
$formDataWithEmptyField = $validFormData;
$formDataWithEmptyField["$fielFullName"] = '';
$crawler = $this->$methodNameToSendFormWithWrongData(
$formDataWithEmptyField,
$kernelBrowser
);
$this->commonCheckerIfFormFieldIsInvalid(
crawler: $crawler,
cssFilterOfInvadFormField: "$fielId",
cssFilterOfInvalidFeedback: '.invalid-feedback',
invalidFeedback: $invalidFeedback,
expectedFieldAttributes: $expectedFieldAttributes
);
}
}
private function getCurrentHashOfUserPassword(string $userEmail): string
{
$userRepository = static::getContainer()->get(UserRepository::class);
$user = $userRepository->findOneByEmail($userEmail);
return $user->getPassword();
}
private function resetUserPasswordInDatabaseWithProvidedPasswordHash(
string $userEmail,
string $newUserPasswordHash
): void {
$userRepository = static::getContainer()->get(UserRepository::class);
$user = $userRepository->findOneByEmail($userEmail);
$user->setPassword($newUserPasswordHash);
$userRepository->save(entity: $user, flush: true);
$this->assertSame(
$newUserPasswordHash,
$this->getCurrentHashOfUserPassword($userEmail)
);
}
private function checkPasswordHasBeenChangedInDatabase(
string $userEmail,
string $initialUserPasswordHash
): void {
$currentUserPasswordHash = $this->getCurrentHashOfUserPassword($userEmail);
$this->assertNotSame("$initialUserPasswordHash", "$currentUserPasswordHash");
$this->assertSame(\strlen("$initialUserPasswordHash"), \strlen("$currentUserPasswordHash"));
}
public function commonCheckWhenFormIsSentWithoutSimilarNewPasswordFields(
KernelBrowser $kernelBrowser,
array $validFormData,
string $formName,
string $fieldName,
int $minPasswordLength,
string $methodNameToSendFormWithWrongData = 'methodNameToSendFormWithWrongData'
): void {
$NewPassword_first = $this->generateRandomString($minPasswordLength + 2);
$NewPassword_second = "bad_repeat_NewPassword_" . $NewPassword_first;
$formData = $validFormData;
$formData["${formName}[${fieldName}][first]"] = $NewPassword_first;
$formData["${formName}[${fieldName}][second]"] = $NewPassword_second;
$crawler = $this->$methodNameToSendFormWithWrongData(
$formData,
$kernelBrowser
);
$this->commonCheckerIfFormFieldIsInvalid(
crawler: $crawler,
cssFilterOfInvadFormField: "#${formName}_${fieldName}_first",
cssFilterOfInvalidFeedback: '.invalid-feedback',
invalidFeedback: 'The new password fields must match.',
);
}
public function commonCheckWhenFormIsSentWithTooSmallRepeatPassword(
KernelBrowser $kernelBrowser,
array $validFormData,
string $formName,
string $fieldName,
int $minPasswordLength,
string $methodNameToSendFormWithWrongData = 'methodNameToSendFormWithWrongData'
): void {
$tooSmallPasswords = [
'1', // very small password size (1 characters)
'123', // very small password size (3 characters)
$this->generateRandomString($minPasswordLength - 2), // password is 2 character short of required size
$this->generateRandomString($minPasswordLength - 1), // password is 1 character short of required size
];
foreach ($tooSmallPasswords as $tooSmallPassword) {
$formData = $validFormData;
$formData["${formName}[${fieldName}][first]"] = $tooSmallPassword;
$formData["${formName}[${fieldName}][second]"] = $tooSmallPassword;
$crawler = $this->$methodNameToSendFormWithWrongData(
$formData,
$kernelBrowser
);
$this->commonCheckerIfFormFieldIsInvalid(
crawler: $crawler,
cssFilterOfInvadFormField: "#${formName}_${fieldName}_first",
cssFilterOfInvalidFeedback: '.invalid-feedback',
invalidFeedback: 'Password size is too small.',
);
}
}
/**
* Check that the user can only login with his new password
* - Logout current user
* - User can not login with his old password
* - User can login wtih his new password
*
* @param KernelBrowser $kernelBrowser
* @param string $userEmail
* @param string $newPlainPassword used to test that user can login wtih his new password
* @param string $oldPlainPassword used to test that user can not login with his old password
* @return void
*/
private function checkUserCanLoginOnlyWithNewPassword(
KernelBrowser $kernelBrowser,
string $userEmail,
string $newPlainPassword,
string $oldPlainPassword
): void {
// Logout current user
$crawler = $kernelBrowser->request('GET', '/account/logout');
$this->assertResponseStatusCodeSame(Response::HTTP_FOUND); // HTTP status code = 302
$this->assertResponseHeaderSame("Location", 'http://localhost/');
// User can not login with his old password
$this->commonCheckerUserCanNotLogin(
mail: "$userEmail",
password: "$oldPlainPassword",
kernelBrowser: $kernelBrowser,
);
// User can login wtih his new password
$this->commonCheckerUserCanLoginV2(
kernelBrowser: $kernelBrowser,
mail: "$userEmail",
password: "$newPlainPassword"
);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment