Skip to content

Commit 57cae11

Browse files
authored
Refactor du mock du temps dans les tests Behat (#2151)
Utiliser un header est limitant car certaines phrases Behat simulent un appel classique de navigateur sans headers, et donc le mock ne fonctionne pas. En passant par un fichier, le mock persiste d'une phrase à l'autre.
1 parent 6e9fe98 commit 57cae11

File tree

7 files changed

+86
-31
lines changed

7 files changed

+86
-31
lines changed

app/config/config_test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
imports:
22
- { resource: config_dev.yml }
3+
- { resource: services_test.yaml }
34

45
framework:
56
test: ~

app/config/services_test.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
services:
2+
AppBundle\Listener\DetectClockMockingListener:
3+
autowire: true
4+
tags: [ kernel.event_listener ]

sources/AppBundle/Listener/DetectClockMockingListener.php

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,32 @@
44

55
namespace AppBundle\Listener;
66

7+
use Afup\Tests\Support\TimeMocker;
78
use Symfony\Component\Clock\Clock;
89
use Symfony\Component\Clock\MockClock;
910
use Symfony\Component\DependencyInjection\Attribute\Autowire;
10-
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
1111
use Symfony\Component\HttpKernel\Event\RequestEvent;
1212

13-
#[AsEventListener]
14-
final class DetectClockMockingListener
13+
final readonly class DetectClockMockingListener
1514
{
16-
public const HEADER = 'X-Test-Mock-Clock';
17-
1815
public function __construct(
1916
#[Autowire('%kernel.environment%')]
20-
private readonly string $env,
17+
private string $env,
2118
) {}
2219

2320
public function __invoke(RequestEvent $event): void
2421
{
2522
if ($this->env !== 'test') {
23+
// Le listener est configuré manuellement uniquement dans l'env de test.
24+
// Mais on ne sait jamais alors, alors on vérifie ici au cas où.
2625
return;
2726
}
2827

29-
if (!$event->isMainRequest()) {
30-
return;
31-
}
32-
33-
$request = $event->getRequest();
34-
35-
if (!$request->headers->has(self::HEADER)) {
36-
return;
37-
}
38-
39-
$headerValue = $request->headers->get(self::HEADER);
40-
41-
if ($headerValue === null || $headerValue === '') {
28+
$currentDateMock = (new TimeMocker())->getCurrentDateMock();
29+
if ($currentDateMock === null) {
4230
return;
4331
}
4432

45-
Clock::set(new MockClock($headerValue));
33+
Clock::set(new MockClock($currentDateMock));
4634
}
4735
}

tests/behat/bootstrap/FeatureContext.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class FeatureContext implements Context
3030
public function __construct()
3131
{
3232
$this->databaseManager = new DatabaseManager(true);
33+
34+
$this->initTimeContext();
3335
}
3436

3537
#[BeforeScenario]

tests/behat/bootstrap/TimeContext.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Afup\Tests\Behat\Bootstrap;
66

7-
use AppBundle\Listener\DetectClockMockingListener;
7+
use Afup\Tests\Support\TimeMocker;
88
use Behat\Hook\BeforeScenario;
99
use Behat\Step\Given;
1010
use Behat\Step\Then;
@@ -13,16 +13,23 @@
1313

1414
trait TimeContext
1515
{
16+
private TimeMocker $timeMocker;
17+
18+
private function initTimeContext(): void
19+
{
20+
$this->timeMocker = new TimeMocker();
21+
}
22+
1623
#[BeforeScenario]
1724
public function clearTestClock(): void
1825
{
19-
$this->minkContext->getSession()->getDriver()->setRequestHeader(DetectClockMockingListener::HEADER, '');
26+
$this->timeMocker->clearCurrentDateMock();
2027
}
2128

2229
#[Given('/^the current date is "(?P<date>[^"]*)"$/')]
2330
public function theCurrentDateIs(string $date): void
2431
{
25-
$this->minkContext->getSession()->getDriver()->setRequestHeader(DetectClockMockingListener::HEADER, $date);
32+
$this->timeMocker->setCurrentDateMock($date);
2633
}
2734

2835
#[Then('the response should contain date :arg1')]

tests/behat/features/Admin/SuperApero/SuperApero.feature

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Feature: Gestion des Super Apéro
44
Scenario: Ajout d'un Super Apéro
55
Given the current date is "2025-01-15 10:00:00"
66
And I am logged in as admin and on the Administration
7-
And I am on "/admin/super-apero/"
7+
And I follow "Super Apéro"
88
Then I should see "Liste des Super Apéros"
99
When I follow "Planifier le Super Apéro 2025"
1010
Then I should see "Ajouter un Super Apéro"
@@ -25,13 +25,13 @@ Feature: Gestion des Super Apéro
2525
Scenario: Activation d'un Super Apéro
2626
Given the current date is "2025-03-11 23:59:59"
2727
And I am logged in as admin and on the Administration
28-
And I am on "/admin/super-apero/"
28+
And I follow "Super Apéro"
2929
Then I should see "Liste des Super Apéros"
3030
And I should see "2025"
3131
And I should see "11/03/2025"
3232
And I should see a green label "Actif"
3333
When the current date is "2025-03-12 00:00:00"
34-
And I am on "/admin/super-apero/"
34+
And I follow "Super Apéro"
3535
Then I should see "Liste des Super Apéros"
3636
And I should see "2025"
3737
And I should see "11/03/2025"
@@ -40,6 +40,10 @@ Feature: Gestion des Super Apéro
4040
Scenario: Un seul Super Apéro possible par année
4141
Given the current date is "2025-01-15 10:00:00"
4242
And I am logged in as admin and on the Administration
43+
And I follow "Super Apéro"
44+
Then I should not see "Planifier le Super Apéro"
45+
Then I should not see "Planifier le Super Apéro 2025"
46+
# Url en dur car le bouton n'est pas affiché si un super apéro existe déjà pour l'année courante
4347
And I am on "/admin/super-apero/add"
4448
When I fill in "super_apero[date]" with "2025-09-20"
4549
And I press "Ajouter"
@@ -48,7 +52,7 @@ Feature: Gestion des Super Apéro
4852
Scenario: Modifier la date d'un Super Apéro
4953
Given the current date is "2025-01-15 10:00:00"
5054
And I am logged in as admin and on the Administration
51-
And I am on "/admin/super-apero/"
55+
And I follow "Super Apéro"
5256
When I follow "modifier_1"
5357
Then I should see "Modifier le Super Apéro 2025"
5458
When I fill in "super_apero[date]" with "2025-06-15"
@@ -60,7 +64,8 @@ Feature: Gestion des Super Apéro
6064
Scenario: Ajouter une ville à un Super Apéro
6165
Given the current date is "2025-01-15 10:00:00"
6266
And I am logged in as admin and on the Administration
63-
And I am on "/admin/super-apero/edit/1"
67+
And I follow "Super Apéro"
68+
When I follow "modifier_1"
6469
When I fill in "super_apero[meetups][nantes][meetupId]" with "11111"
6570
And I fill in "super_apero[meetups][nantes][description]" with "Super Apéro PHP à Nantes"
6671
And I press "Modifier"
@@ -70,7 +75,8 @@ Feature: Gestion des Super Apéro
7075
Scenario: Modifier une ville d'un Super Apéro
7176
Given the current date is "2025-01-15 10:00:00"
7277
And I am logged in as admin and on the Administration
73-
And I am on "/admin/super-apero/edit/1"
78+
And I follow "Super Apéro"
79+
When I follow "modifier_1"
7480
When I fill in "super_apero[meetups][lyon][meetupId]" with "99999"
7581
And I fill in "super_apero[meetups][lyon][description]" with "Super Apéro PHP à Lyon modifié"
7682
And I fill in "super_apero[meetups][paris][description]" with "Super Apéro PHP à Paris modifié"
@@ -82,7 +88,8 @@ Feature: Gestion des Super Apéro
8288
Scenario: Supprimer une ville d'un Super Apéro
8389
Given the current date is "2025-01-15 10:00:00"
8490
And I am logged in as admin and on the Administration
85-
And I am on "/admin/super-apero/edit/1"
91+
And I follow "Super Apéro"
92+
When I follow "modifier_1"
8693
When I fill in "super_apero[meetups][nantes][meetupId]" with ""
8794
And I fill in "super_apero[meetups][nantes][description]" with ""
8895
And I press "Modifier"
@@ -92,7 +99,7 @@ Feature: Gestion des Super Apéro
9299
Scenario: Supprimer un Super Apéro
93100
Given the current date is "2025-01-15 10:00:00"
94101
And I am logged in as admin and on the Administration
95-
And I am on "/admin/super-apero/"
102+
And I follow "Super Apéro"
96103
When I press "supprimer_1"
97104
Then I should see "Le Super Apéro 2025 a été supprimé"
98105
And I should not see "15/06/2025"

tests/support/TimeMocker.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Afup\Tests\Support;
6+
7+
use Symfony\Component\Filesystem\Exception\IOException;
8+
use Symfony\Component\Filesystem\Filesystem;
9+
10+
final readonly class TimeMocker
11+
{
12+
private const MOCK_DIR_PATH = __DIR__ . '/../../var/cache/test/afup/';
13+
private const MOCK_FILE_PATH = self::MOCK_DIR_PATH . 'current-date-mock';
14+
15+
private Filesystem $filesystem;
16+
17+
public function __construct()
18+
{
19+
$this->filesystem = new Filesystem();
20+
}
21+
22+
public function setCurrentDateMock(string $dateString): void
23+
{
24+
$this->filesystem->mkdir(self::MOCK_DIR_PATH);
25+
$this->filesystem->dumpFile(self::MOCK_FILE_PATH, $dateString);
26+
}
27+
28+
public function clearCurrentDateMock(): void
29+
{
30+
try {
31+
$this->filesystem->remove(self::MOCK_FILE_PATH);
32+
} catch (IOException) {
33+
// Il y a une exception aussi si le fichier n'existe pas
34+
// mais ce n'est pas important à propager.
35+
}
36+
}
37+
38+
public function getCurrentDateMock(): ?\DateTimeImmutable
39+
{
40+
try {
41+
return new \DateTimeImmutable($this->filesystem->readFile(self::MOCK_FILE_PATH));
42+
} catch (IOException) {
43+
return null;
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)