Skip to content

Commit

Permalink
Tests fonctionels de bout en bout
Browse files Browse the repository at this point in the history
  • Loading branch information
pierrelemee committed Jan 7, 2025
1 parent df93642 commit 6cb8439
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 111 deletions.
1 change: 0 additions & 1 deletion .github/workflows/deploy-develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,5 @@ jobs:
CLEVER_SECRET: ${{ secrets.CLEVER_SECRET }}
CLEVER_TOKEN: ${{ secrets.CLEVER_TOKEN }}
run: |
git rev-parse HEAD
clever link $CC_APP_ID
clever deploy --alias precontentieux-dev --force
1 change: 0 additions & 1 deletion .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,5 @@ jobs:
CLEVER_SECRET: ${{ secrets.CLEVER_SECRET }}
CLEVER_TOKEN: ${{ secrets.CLEVER_TOKEN }}
run: |
echo $CC_APP_ID
clever link $CC_APP_ID
clever deploy --alias precontentieux-prod --force
9 changes: 9 additions & 0 deletions assets/apps/bris_porte/deposer_mon_dossier.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,16 @@ const root = ReactDOM.createRoot(document.getElementById('react-app'));
let queuedChanges = {};


// Déclaration d'une variable globale indiquant si des opérations sont en attentes
declare global {
interface Window { appPendingChanges: boolean; }
}

window.appPendingChanges = window.appPendingChanges || false;

const apiPatch = () => {
if (Object.keys(queuedChanges).length > 0) {
window.appPendingChanges = true;
// Run a PATCH call and store the result as state
fetch(`/api/requerant/dossier/${dossier.id}`, {
method: 'PATCH',
Expand All @@ -39,6 +47,7 @@ const apiPatch = () => {
}).then(
(response) => {
queuedChanges = {};
window.appPendingChanges = false;
}
)//.catch((e) => alert(e))
}
Expand Down
2 changes: 1 addition & 1 deletion config/bundles.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
Knp\Bundle\SnappyBundle\KnpSnappyBundle::class => ['all' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
Sentry\SentryBundle\SentryBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
Pentatrion\ViteBundle\PentatrionViteBundle::class => ['all' => true],
Acsiomatic\DeviceDetectorBundle\AcsiomaticDeviceDetectorBundle::class => ['all' => true],
Expand Down
Empty file removed migrations/.gitignore
Empty file.
36 changes: 36 additions & 0 deletions migrations/Version20250107142052.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250107142052 extends AbstractMigration
{
public function getDescription(): string
{
return 'Amélioration de la suppression en cascade';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE bris_porte DROP CONSTRAINT FK_BC580EED9450CE1E');
$this->addSql('ALTER TABLE bris_porte ADD CONSTRAINT FK_BC580EED9450CE1E FOREIGN KEY (test_eligibilite_id) REFERENCES eligibilite_tests (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE eligibilite_tests DROP CONSTRAINT FK_881877C14A93DAA5');
$this->addSql('ALTER TABLE eligibilite_tests ADD CONSTRAINT FK_881877C14A93DAA5 FOREIGN KEY (requerant_id) REFERENCES requerants (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE eligibilite_tests DROP CONSTRAINT fk_881877c14a93daa5');
$this->addSql('ALTER TABLE eligibilite_tests ADD CONSTRAINT fk_881877c14a93daa5 FOREIGN KEY (requerant_id) REFERENCES requerants (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE bris_porte DROP CONSTRAINT fk_bc580eed9450ce1e');
$this->addSql('ALTER TABLE bris_porte ADD CONSTRAINT fk_bc580eed9450ce1e FOREIGN KEY (test_eligibilite_id) REFERENCES eligibilite_tests (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
}
}
4 changes: 2 additions & 2 deletions src/Entity/BrisPorte.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ class BrisPorte
#[ORM\Column(options: ['default' => false])]
private bool $isPorteBlindee = false;

#[ORM\OneToOne(targetEntity: TestEligibilite::class, cascade: ['persist'])]
#[ORM\JoinColumn(nullable: true)]
#[ORM\OneToOne(targetEntity: TestEligibilite::class, cascade: ['persist', 'remove'])]
#[ORM\JoinColumn(nullable: true, onDelete: 'CASCADE')]
protected ?TestEligibilite $testEligibilite = null;

#[Groups(['dossier:lecture', 'dossier:patch'])]
Expand Down
2 changes: 1 addition & 1 deletion src/Entity/PersonnePhysique.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public function getCommuneNaissance(): ?string
return $this->communeNaissance;
}

public function setCommuneNaissance(?GeoPays $communeNaissance = null): static
public function setCommuneNaissance(?string $communeNaissance = null): static
{
$this->communeNaissance = $communeNaissance;

Expand Down
2 changes: 1 addition & 1 deletion src/Entity/Requerant.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class Requerant implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\OneToOne(inversedBy: 'compte', cascade: ['persist', 'remove'])]
private ?PersonneMorale $personneMorale;

#[ORM\OneToMany(targetEntity: BrisPorte::class, mappedBy: 'requerant', cascade: ['remove'], )]
#[ORM\OneToMany(targetEntity: BrisPorte::class, mappedBy: 'requerant', cascade: ['remove'])]
#[ORM\OrderBy(['dateCreation' => 'ASC'])]
/** @type Collection<BrisPorte> $brisPorte */
protected Collection $dossiers;
Expand Down
4 changes: 2 additions & 2 deletions src/Entity/TestEligibilite.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ class TestEligibilite
#[ORM\Column(nullable: true)]
public ?bool $aContacteBailleur = null;

#[ORM\OneToOne(targetEntity: Requerant::class)]
#[ORM\JoinColumn]
#[ORM\OneToOne(targetEntity: Requerant::class, cascade: ['persist', 'remove'])]
#[ORM\JoinColumn(onDelete: 'CASCADE')]
public ?Requerant $requerant = null;

#[ORM\Column]
Expand Down
26 changes: 14 additions & 12 deletions templates/bris_porte/tester_mon_eligibilite.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,12 @@
>
<fieldset
class="fr-fieldset"
aria-labelledby="checkboxes-inline-legend"
aria-labelledby="eligibilite-test-form-question-estVise"
>
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="checkboxes-inline-legend">
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="eligibilite-test-form-question-estVise">
Êtes-vous la personne visée par l'intervention des forces de l'ordre ?
</legend>
<div class="fr-fieldset__element fr-fieldset__element--inline" id="eligibilite-test-form-question-estVise">
<div class="fr-fieldset__element fr-fieldset__element--inline">
<div class="fr-radio-group">
<input
id="eligibilite-test-form-est-vise-oui"
Expand Down Expand Up @@ -170,9 +170,9 @@
>
<fieldset
class="fr-fieldset"
aria-labelledby="checkboxes-inline-legend"
aria-labelledby="eligibilite-test-form-question-estHebergeant"
>
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="checkboxes-inline-legend">
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="eligibilite-test-form-question-estHebergeant">
Est-ce que la personne recherchée réside ou est hébergée à votre adresse ?
</legend>
<div class="fr-fieldset__element fr-fieldset__element--inline">
Expand Down Expand Up @@ -220,9 +220,9 @@
>
<fieldset
class="fr-fieldset"
aria-labelledby="checkboxes-inline-legend"
aria-labelledby="eligibilite-test-form-question-estProprietaire"
>
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="checkboxes-inline-legend">
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="eligibilite-test-form-question-estProprietaire">
Quel est votre statut par rapport au logement ?
</legend>
<div class="fr-fieldset__element fr-fieldset__element--inline">
Expand Down Expand Up @@ -263,9 +263,9 @@
>
<fieldset
class="fr-fieldset"
aria-labelledby="checkboxes-inline-legend"
aria-labelledby="eligibilite-test-form-question-aContacteAssurance"
>
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="checkboxes-inline-legend">
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="eligibilite-test-form-question-aContacteAssurance">
Avez-vous pris contact avec votre assurance habitation et obtenu une attestation de non prise en charge du sinistre ?
</legend>
<div class="fr-fieldset__element fr-fieldset__element--inline">
Expand Down Expand Up @@ -306,9 +306,9 @@
>
<fieldset
class="fr-fieldset"
aria-labelledby="checkboxes-inline-legend"
aria-labelledby="eligibilite-test-form-question-aContacteBailleur"
>
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="checkboxes-inline-legend">
<legend class="fr-fieldset__legend--regular fr-fieldset__legend" id="eligibilite-test-form-question-aContacteBailleur">
Avez-vous pris contact avec votre bailleur et obtenu une attestation de non prise en charge des réparations ?
</legend>
<div class="fr-fieldset__element fr-fieldset__element--inline">
Expand Down Expand Up @@ -356,7 +356,9 @@
<div class="fr-alert fr-alert--warning fr-my-3w eligibilite-test-form-decision" v-cloak v-if="estDecide('warning_contact_assurance') || estDecide('warning_contact_bailleur')">

<h3 class="fr-alert__title" v-if="estDecide('warning_contact_assurance') && estDecide('warning_contact_bailleur')">Nous ne serons pas en mesure de traiter votre demande d’indemnisation car ces attestations sont des documents essentiels pour s’assurer du respect du principe de la réparation intégrale sans perte ni profit</h3>
<h3 class="fr-alert__title" v-else="">Nous ne serons pas en mesure de traiter votre demande d’indemnisation, car cette attestation est un document essentiel pour s’assurer du respect du principe de la réparation intégrale sans perte ni profit</h3>
<h3 class="fr-alert__title" v-else="">
Nous serons en mesure de traiter votre demande d’indemnisation <u>uniquement si votre dossier est complet</u>. Cependant, vous pouvez créer votre compte et commencer à constituer votre dossier en ligne.
</h3>

<p v-if="estDecide('warning_contact_assurance')">
Nous vous recommandons de prendre contact avec votre assurance habitation dès que possible. En
Expand Down
2 changes: 1 addition & 1 deletion templates/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@
<p>
{% block appelAAction %}
<a class="fr-btn fr-p-3v" href="{{ url('bris_porte_tester_eligibilite') }}">
<span class="text-center full-width">Déposer votre demande d’indemnisation</span>
Déposer votre demande d’indemnisation
</a>
{% endblock appelAAction %}
</p>
Expand Down
98 changes: 97 additions & 1 deletion tests/Functional/AbstractFunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,111 @@

namespace App\Tests\Functional;

use Facebook\WebDriver\Exception\ElementClickInterceptedException;
use Facebook\WebDriver\WebDriverElement;
use Symfony\Component\Panther\Client as PantherClient;
use Symfony\Component\Panther\DomCrawler\Crawler as PantherCrawler;
use Symfony\Component\Panther\PantherTestCase;

abstract class AbstractFunctionalTestCase extends PantherTestCase
{
protected PantherClient $client;

public function devices(): array
{
return [
'mobile' => ['mobile', 428, 926],
'desktop' => ['desktop', 1200, 2000],
];
}
}

// Cas des input 'checkbox‘ ou 'radio':
protected function checkField(string $legend, string $label, bool $exactMatch = false): void
{
$field = $this->getFieldByLabel($label, $legend, $exactMatch);

if (null === $field->getElement(0)) {
throw new \LogicException("Aucun élément trouvé pour le champs de label '$legend' > '$label'");
}

if ('input' !== $field->getTagName()) {
throw new \LogicException("L'élément trouvé pour le champs de label '$legend' > '$label' a un type inattendu {$field->getTagName()} (attendu <input>)");
}

try {
$field->click();
} catch (ElementClickInterceptedException $e) {
// Dans le cas où le label englobe le champs, on se replie sur le clic sur le <label>
$this->client->getCrawler()->filter(sprintf('label[for="%s"]', $field->getAttribute('id')))->first()->click();
}
}

protected function setField(string $label, string $value, bool $exactMatch = false): void
{
$field = $this->getFieldByLabel($label, exactMatch: $exactMatch);

if (null === $field->getElement(0)) {
throw new \LogicException("Aucun élément trouvé pour le champs de label '$label'");
}

switch ($field->getTagName()) {
case 'textarea':
case 'input':
$field->getElement(0)?->clear();
$field->sendKeys($value);
break;
case 'select':
$options = $field->filter('option');
$option = $options->reduce(function (PantherCrawler $o) use ($value) {
return trim($o->getText()) === $value;
})->first();
$option->click();
break;
default:
throw new \LogicException("L'élément trouvé pour le champs de label '$label' a un type inattendu {$field->getTagName()} (attendu <input>, <select> ou <textarea>)");
}
}

protected function getFieldsByLabel(string $label, bool $exactMatch = false): PantherCrawler
{
// Chercher tous les champs (<input>, <select>, <textarea>)
$crawler = $this->client->getCrawler();

return $crawler
->filter('input,select,textarea')
->reduce(function (PantherCrawler $e) use ($label, $crawler, $exactMatch) {
return $crawler
->filter(sprintf('label[for="%s"]', $e->getAttribute('id')))
->reduce(function (WebDriverElement $l) use ($label, $exactMatch) {
return $exactMatch ? trim($l->getText()) === $label : str_contains(trim($l->getText()), $label);
})->count() > 0;
}
);
}

protected function getFieldByLabel(string $label, ?string $legend = null, bool $exactMatch = false): PantherCrawler
{
$fields = $this->getFieldsByLabel($label);

if (null === $legend) {
return $fields->first();
}

$ff = $fields->reduce(function (PantherCrawler $e) use ($legend, $exactMatch) {
// On remonte jusqu'au plus proche fieldset englobant
return 1 === $e->ancestors()
->filter('fieldset')
->first()
->filter('legend')
->reduce(
// On cherche l'élément <legend> dans le fieldset dont le texte est $legend
function (WebDriverElement $l) use ($legend, $exactMatch) {
return $exactMatch ? trim($l->getText()) === $legend : str_contains(trim($l->getText()), $legend);
}
)
->count();
});

return $ff->first();
}
}
Loading

0 comments on commit 6cb8439

Please sign in to comment.