Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ default:
paths:
- '%paths.base%/tests/behat'
contexts:
- FeatureContext
- Afup\Tests\Behat\Bootstrap\FeatureContext
- Behat\MinkExtension\Context\MinkContext
extensions:
Behat\MinkExtension:
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
"Afup\\Site\\Tests\\": "tests/unit/Afup/",
"Afup\\Tests\\Support\\": "tests/support/",
"Afup\\Tests\\Stubs\\PHPStan\\": "tests/stubs/phpstan/",
"Afup\\Tests\\Behat\\Bootstrap\\": "tests/behat/bootstrap/",
"AppBundle\\Tests\\": "tests/unit/AppBundle/",
"AppBundle\\IntegrationTests\\": "tests/integration/AppBundle/",
"PlanetePHP\\IntegrationTests\\": "tests/integration/PlanetePHP/"
Expand Down
40 changes: 40 additions & 0 deletions tests/behat/bootstrap/ApiContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Afup\Tests\Behat\Bootstrap;

use Behat\Step\Then;
use PHPUnit\Framework\Assert;
use Symfony\Component\JsonPath\JsonCrawler;

trait ApiContext
{
#[Then('/^the response should be in json$/')]
public function assertResponseShouldBeInJson(): void
{
$this->assertResponseHeaderEquals('Content-Type', 'application/json');
Assert::assertJson($this->minkContext->getSession()->getPage()->getContent());
}

#[Then('/^the json response has the key "(?P<key>[^"]*)" with value "(?P<value>(?:[^"]|\\")*)"$/')]
public function assertResponseHasJsonKeyAndValue(string $key, string $value): void
{
$crawler = new JsonCrawler($this->minkContext->getSession()->getPage()->getContent());

$foundValue = $crawler->find($key);

Assert::assertCount(1, $foundValue);
Assert::assertSame($value, $foundValue[0]);
}

#[Then('/^the json response has no key "(?P<key>[^"]*)"$/')]
public function assertResponseHasNoJsonKey(string $key): void
{
$crawler = new JsonCrawler($this->minkContext->getSession()->getPage()->getContent());

$foundValue = $crawler->find($key);

Assert::assertEmpty($foundValue);
}
}
48 changes: 48 additions & 0 deletions tests/behat/bootstrap/AuthContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Afup\Tests\Behat\Bootstrap;

use Behat\Step\Given;
use Behat\Step\When;

trait AuthContext
{
#[Given('I am logged in as admin and on the Administration')]
public function iAmLoggedInAsAdminAndOnTheAdministration(): void
{
$this->iAmLoggedInAsAdmin();
$this->minkContext->clickLink('Administration');
}

#[Given('I am logged in as admin')]
public function iAmLoggedInAsAdmin(): void
{
$this->iAmLoggedInWithTheUserAndThePassword('admin', 'admin');
}

#[Given('I am logged-in with the user :username and the password :password')]
public function iAmLoggedInWithTheUserAndThePassword(string $username, string $password): void
{
$this->minkContext->visitPath('/admin/login');
$this->minkContext->fillField('utilisateur', $username);
$this->minkContext->fillField('mot_de_passe', $password);
$this->minkContext->pressButton('Se connecter');
$this->minkContext->assertPageContainsText('Espace membre');
}

#[When('I request a password reset for :arg1')]
public function iRequestAPasswordReset(string $arg1): void
{
$this->minkContext->iAmOnHomepage();
$this->minkContext->assertPageContainsText("Tous les trois mois, des nouvelles de L'AFUP");
$this->minkContext->clickLink("Se connecter");
$this->minkContext->assertPageContainsText("Email ou nom d'utilisateur");
$this->minkContext->clickLink("Mot de passe perdu");
$this->minkContext->assertPageContainsText("Mot de passe perdu");
$this->minkContext->fillField("form_email", $arg1);
$this->minkContext->pressButton("Demander un nouveau mot de passe");
$this->minkContext->assertPageContainsText("Votre demande a été prise en compte. Si un compte correspond à cet email vous recevez un nouveau mot de passe rapidement.");
}
}
182 changes: 182 additions & 0 deletions tests/behat/bootstrap/EmailContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
<?php

declare(strict_types=1);

namespace Afup\Tests\Behat\Bootstrap;

use AppBundle\Event\Model\Event;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use Behat\Hook\BeforeScenario;
use Behat\Mink\Exception\ExpectationException;
use Behat\Step\Then;
use Symfony\Component\Filesystem\Filesystem;

trait EmailContext
{
private const MAILCATCHER_URL = 'http://mailcatcher:1080';

#[BeforeScenario('@clearAllMailInscriptionAttachments')]
public function beforeScenarioClearAllMailInscriptionAttachments(): void
{
$filesystem = new Filesystem();
$filesystem->remove(Event::getInscriptionAttachmentDir());
}

#[BeforeScenario('@clearAllSponsorFiles')]
public function beforeScenarioClearAllSponsorFiles(): void
{
$filesystem = new Filesystem();
$filesystem->remove(Event::getSponsorFileDir());
}

#[BeforeScenario('@clearEmails')]
public function clearEmails(): void
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, self::MAILCATCHER_URL . '/messages');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

curl_exec($ch);
if (curl_errno($ch) !== 0) {
throw new \RuntimeException('Error : ' . curl_error($ch));
}

curl_close($ch);
}

#[Then('I should only receive the following emails:')]
public function theFollowingEmailsShouldBeReceived(TableNode $expectedEmails): void
{
$expectedEmailsArray = [];
foreach ($expectedEmails as $expectedEmail) {
$expectedEmailsArray[] = [
'to' => $expectedEmail['to'],
'subject' => $expectedEmail['subject'],
];
}


$content = file_get_contents(self::MAILCATCHER_URL . '/messages');
$decodedContent = json_decode($content, true);

$foundEmails = [];
foreach ($decodedContent as $mail) {
$foundEmails[] = [
'to' => implode(',', $mail['recipients']),
'subject' => $mail['subject'],
];
}

if ($foundEmails !== $expectedEmailsArray) {
throw new ExpectationException(
sprintf(
'The emails are not the expected ones "%s" (expected "%s")',
var_export($foundEmails, true),
var_export($expectedEmailsArray, true),
),
$this->minkContext->getSession()->getDriver(),
);
}
}

#[Then('the checksum of the attachment :filename of the message of id :id should be :md5sum')]
public function theChecksumOfTheAttachmentOfTheMessageOfIdShouldBe(string $filename, string $id, string $md5sum): void
{
$infos = json_decode(file_get_contents(self::MAILCATCHER_URL . '/messages/' . $id . '.json'), true);

$cid = null;
foreach ($infos['attachments'] as $attachment) {
if ($attachment['filename'] === $filename) {
$cid = $attachment['cid'];
}
}

if (null === $cid) {
throw new ExpectationException(
sprintf('Attachment with name %s not found', $filename),
$this->minkContext->getSession()->getDriver(),
);
}

$attachmentContent = file_get_contents(self::MAILCATCHER_URL . '/messages/' . $id . '/parts/' . $cid);
$actualMd5sum = md5($attachmentContent);

if ($actualMd5sum !== $md5sum) {
throw new ExpectationException(
sprintf('The md5sum of %s, if not %s (found %s)', $filename, $md5sum, $actualMd5sum),
$this->minkContext->getSession()->getDriver(),
);
}
}

#[Then('the plain text content of the message of id :id should be :')]
public function thePlainTextContentOfTheMessageOfIdShouldBe(string $id, PyStringNode $expectedContent): void
{
$content = file_get_contents(self::MAILCATCHER_URL . '/messages/' . $id . '.plain');
$expectedContentString = $expectedContent->getRaw();

$content = str_replace("\r\n", "\n", $content);

if ($content !== $expectedContentString) {
throw new ExpectationException(
sprintf(
"The content \n%s\nis not the expected one \n%s\n",
var_export($content, true),
var_export($expectedContentString, true),
),
$this->minkContext->getSession()->getDriver(),
);
}
}

#[Then('I should receive an email')]
public function iShouldReceiveAnEmail(): void
{
$content = file_get_contents(self::MAILCATCHER_URL . '/messages');
$emails = json_decode($content, true);

if (count($emails) !== 1) {
throw new ExpectationException(
'The email has not been received.',
$this->minkContext->getSession()->getDriver(),
);
}
}

#[Then('the email should contain a full URL starting with :arg1')]
public function theEmailShouldContainAFullUrlStartingWith(string $arg1): void
{
$content = file_get_contents(self::MAILCATCHER_URL . '/messages');
$decodedContent = json_decode($content, true);

$foundEmails = [];
foreach ($decodedContent as $mail) {
$foundEmails[] = [
'id' => $mail['id'],
'to' => $mail['to'] ?? $mail['recipients'][0],
'subject' => $mail['subject'],
];
}

if (count($foundEmails) !== 1) {
throw new ExpectationException(
'The email has not been received.',
$this->minkContext->getSession()->getDriver(),
);
}

$content = file_get_contents(self::MAILCATCHER_URL . '/messages/' . $foundEmails[0]['id'] . '.plain');
if (!str_contains($content, $arg1)) {
throw new ExpectationException(
sprintf(
'The email content does not contain the expected URL "%s" (expected "%s")',
$content,
$arg1,
), $this->minkContext->getSession()->getDriver(),
);
}
}
}
Loading